VideoPlus+®

Some time ago some C source code for the American VCRPlus system was posted to alt.sources by DaviD W. Sanderson (but note that he is not the original author of these programs). I then used these to reverse-engineer the British VideoPlus system by writing a program in BASIC for the Sinclair Spectrum (no really, it's true!).

Steve Hosgood has a DOS version of the VideoPlus system (which can be configured for UK or US) including C source and some information about the difference between UK and US systems, in case Spectrum BASIC is not your forté.

There is also a program with some documentation by Paul Balyoz.

The paper that started it all off was written by Ken Shirriff, Curt Welch and Andy Kinsman. Curt Welch's projects page has a bit of information about the history of that paper and some links.


Below is an ASCII representation of the BASIC VideoPlus program and its data. This program only goes one way: it takes the code number and outputs the programme details. Going the other way requires a trial and error operation which would take far too long in BASIC (although the documentation supplied with Paul Balyoz's program mentioned above suggests this is not necessary after all). The algorithm for going backwards may be inferred from that used in the above-mentioned C program and the tables given in the BASIC program.

The program does not cope well with numbers longer than 6 digits. This is because the encryption algorithm seems to differ significantly for the longer codes and no one has so far been able to reverse-engineer it.

Most of the tables of start and end times are contained within the program. The tables that are loaded in are just the first 192 elements which are in a more or less random order and can be seen as individual assignments in the C programs.

Since this is a Spectrum program, you can also get a snapshot file (compressed) which you can run on a spectrum emulator.

Ian Collier.

   1 CLEAR 39999
  10 GO SUB 1000
  20 INPUT LINE a$: PRINT a$;: LET b$="68150631": GO SUB 1120: PRINT " ->";a$;
  30 IF LEN a$>2 THEN LET b$=a$( LEN a$-2 TO ): LET t$=a$( TO LEN a$-3): GO TO 40
  35 LET b$=a$: LET t$=""
  40 LET x= VAL b$-1: LET quo= INT (x/32): LET rem=x-32*quo: LET day=quo+1
  45 IF day<td THEN LET tm=tm+1: IF tm>12 THEN LET tm=tm-12: LET ty=ty+1
  50 IF LEN a$ >= 4 THEN GO SUB 1160: GO TO 70
  60 LET ofout=0: LET t$="0"
  70 PRINT "."
  75 LET t2c1=rem+day*(tm+1)+ofout: LET t8c5= VAL t$
  77 IF LEN a$>6 THEN PRINT "Date=";day;"/";tm;"/";ty'"Can't decode this long number": GO TO 140
  80 GO SUB 1380
  81 LET cc=cval: LET tt=tval
  90 LET chan=cval+1
 100 PRINT "Date=";day;"/";tm;"/";ty;" Channel=";chan;" (t=";tt;")"
 110 GO SUB 1440
 120 LET s$= STR$ s: LET s$=("000"+s$)( LEN s$ TO ): LET s$=s$( TO 2)+":"+s$(3 TO )
 130 IF l>0 THEN PRINT "Time=";s$;" Length=";l
 140 REM PRINT t$;",";t2c1-32* INT (t2c1/32)
 200 GO TO 10
 899 STOP
 900 PRINT INVERSE 1;a$;: LET b$="9371": GO SUB 1120: PRINT , INVERSE 1;a$
 999 STOP
1000 REM *set time*
1010 LET times=40500: LET lens=40100
1020 IF PEEK 40000=56 THEN LET td= PEEK 40001: LET tm= PEEK 40002: LET ty= PEEK 40003: RETURN 
1030 INPUT "Today's date:";td,"Month:";tm,"Year:";ty
1035 IF ty >= 1900 THEN LET ty=ty-1900
1040 POKE 40001,td: POKE 40002,tm: POKE 40003,ty: POKE 40000,56: GO TO 5000: RETURN 
1050 REM *mixup* c$=mix(a$,b$)
1060 LET a$="00000000"( LEN a$ TO )+a$: LET b$="00000000"( LEN b$ TO )+b$: LET c$="000000000"
1070 FOR i=1 TO 9: FOR j=10-i TO 9
1080 LET ij=i+j-9: LET d= CODE c$(ij)+( CODE a$(i)-48)*( CODE b$(j)-48)
1090 IF d>57 THEN LET d=d-10* INT ((d-48)/10)
1100 LET c$(ij)= CHR$ d
1110 NEXT j: NEXT i: RETURN 
1120 REM *f1* encode a$ with b$
1130 LET n= LEN a$: IF n>8 THEN PRINT "Input ";a$;" is too long": STOP 
1140 GO SUB 1050: LET a$=c$(10-n TO ): IF a$(1)="0" THEN GO TO 1140
1150 RETURN 
1160 REM *offset*  (ofout,t$)=offset(day,ty,t$)
1170 LET off=0: LET d= LEN t$: FOR i=1 TO d: LET off=off+ CODE t$(i)-48: NEXT i
1180 FOR i=0 TO ty-16* INT (ty/16): PRINT ".";: GO SUB 1220: LET off=off+ CODE u$(3)-48: NEXT i
1190 LET t$= STR$ VAL u$: IF LEN t$<d THEN GO TO 1180
1200 LET ofout=off-32* INT (off/32)
1210 RETURN 
1220 REM *maptop* u$=m(day,i,t$,d)
1225 LET u$=("000"+t$)(1+ LEN t$ TO )
1226 IF d>3 THEN RETURN 
1230 LET y=i-16* INT (i/16): LET d2= CODE u$-48: LET d1= CODE u$(2)-48: LET d0= CODE u$(3)-48
1240 LET f0=1: LET f1=y+1: LET f2=f1*(y+2)/2: LET f3=f2*(y+3)/3
1250 LET f1=f1-10* INT (f1/10)
1260 LET f2=f2-10* INT (f2/10)
1270 LET f3=f3-10* INT (f3/10)
1279 LET n0=0: LET n1=0: LET n2=0
1280 IF d=1 THEN LET n0=d0*f0+day*f1
1290 IF d=2 THEN LET n0=d0*f0+d1*f1+day*f2: LET n1=d1*f0+day*f1
1300 IF d=3 THEN LET n0=d0*f0+d1*f1+d2*f2+day*f3: LET n1=d1*f0+d2*f1+day*f2: LET n2=d2*f0+day*f1
1310 LET u$=( STR$ n2)( LEN STR$ n2)+( STR$ n1)( LEN STR$ n1)+( STR$ n0)( LEN STR$ n0)
1320 RETURN 
1330 REM *binary* x$=bin(x)[len y]
1340 LET x$="": FOR i=1 TO y
1350 LET x$= STR$ (x-2* INT (x/2))+x$: LET x= INT (x/2)
1360 NEXT i
1370 RETURN 
1380 REM *bit shuffle*
1390 LET x=t2c1: LET y=5: GO SUB 1330: LET y$=x$: LET x=t8c5: LET y=10: GO SUB 1330
1400 REM LET v$=x$(1)+x$(3)+x$(5)+x$(6)+x$(7)+x$(10)+y$(1)+y$(3)+y$(5): LET w$=x$(2)+x$(4)+x$(8)+x$(9)+y$(2)+y$(4)
1410 LET v$=x$(1)+x$(2)+x$(3)+x$(4)+x$(5)+x$(6)+x$(7)+x$(10)+y$(1)+y$(3)+y$(5): LET w$=x$(8)+x$(9)+y$(2)+y$(4)
1420 LET tval= VAL (" BIN "+v$): LET cval= VAL (" BIN "+w$)
1430 RETURN 
1440 REM look up tval for s,l
1450 IF tval<192 THEN LET s= PEEK (times+tval*2)+256* PEEK (times+1+tval*2): LET l= PEEK (lens+tval*2)+256* PEEK (lens+1+tval*2): RETURN 
1460 IF tval<384 THEN LET l= INT (tval/48-3)*30: LET s=tval-48* INT (tval/48): LET s=100* INT (s/2)+(30 AND s/2 <> INT (s/2))+15: RETURN 
1470 IF tval >= 1914 THEN LET s=tval-1674: LET l= INT (s/48)*30: LET s=s-48* INT (s/48): LET s=2330-100* INT (s/2)-(30 AND s/2 <> INT (s/2)): RETURN 
1480 IF tval<486 THEN LET tval=tval+1530
1490 LET v=tval-486: LET h= INT (v/34): LET v=v-34*h: LET v=v+1+(v>1)
1500 RESTORE 1600: FOR i=0 TO h: READ s,l: NEXT i
1510 LET l=l-5* INT (v/6): LET s=s+5*(v-6* INT (v/6))
1520 RETURN 
1600 DATA 1930,90,2300,90,2330,90,2130,120,2200,120,2300,120,2330,120,0,120,30,120,100,120,130,120
1610 DATA 1730,60,1800,60,1830,60,1900,60,1930,60,2000,60,2030,60
1620 DATA 200,120,230,120,300,120,330,120,400,120,1200,120,1400,120,1530,120
1630 DATA 2100,60,2130,60,2200,60,2230,60,2300,60,2330,60
1640 DATA 1730,30,1800,30,1830,30,1900,30,1930,30,2000,30,2030,30,2100,30,2130,30,2200,30,2230,30,2300,30,2330,30
4000 LET l=0: LET s=0: RETURN 
4990 REM Initialise tables
5000 LOAD "vlengths" CODE lens: LOAD "vstarts" CODE times
5010 RETURN 
6000 LET t=9: FOR x=128 TO 191: PRINT PEEK (41200+2*x)+256* PEEK (41201+2*x);","; PEEK (40100+2*x); TAB t;: LET t=t+9-(27 AND t=18): NEXT x
7000 INPUT x;",";z: LET y=18: GO SUB 1330: PRINT x$;" ";: LET x=z: LET y=5: GO SUB 1330: PRINT x$: GO TO 7000

vlengths (format "p: n" where p is an index and n is a 2-byte number)

  0: 30    28: 30    56: 60    84: 60   112: 90   139: 60   166: 90
  1: 30    29: 60    57: 30    85: 60   113: 30   140: 60   167: 90
  2: 30    30: 90    58: 120   86: 120  114: 30   141: 90   168: 90
  3: 30    31: 30    59: 30    87: 30   115: 120  142: 90   169: 120
  4: 30    32: 30    60: 120   88: 90   116: 30   143: 120  170: 60
  5: 30    33: 30    61: 120   89: 120  117: 120  144: 90   171: 120
  6: 30    34: 30    62: 120   90: 120  118: 120  145: 120  172: 60
  7: 30    35: 60    63: 30    91: 90   119: 30   146: 90   173: 60
  8: 30    36: 30    64: 90    92: 90   120: 90   147: 120  174: 120
  9: 60    37: 60    65: 30    93: 90   121: 60   148: 120  175: 90
 10: 30    38: 120   66: 30    94: 90   122: 60   149: 90   176: 60
 11: 30    39: 60    67: 30    95: 120  123: 60   150: 120  177: 120
 12: 30    40: 30    68: 120   96: 60   124: 120  151: 90   178: 60
 13: 120   41: 30    69: 90    97: 120  125: 90   152: 90   179: 60
 14: 30    42: 30    70: 90    98: 90   126: 60   153: 90   180: 60
 15: 30    43: 30    71: 60    99: 30   127: 60   154: 60   181: 90
 16: 120   44: 120   72: 90   100: 120  128: 90   155: 60   182: 60
 17: 120   45: 30    73: 90   101: 90   129: 120  156: 120  183: 120
 18: 60    46: 30    74: 90   102: 120  130: 120  157: 60   184: 60
 19: 120   47: 30    75: 90   103: 120  131: 90   158: 60   185: 60
 20: 60    48: 120   76: 90   104: 90   132: 60   159: 60   186: 90
 21: 60    49: 30    77: 60   105: 90   133: 60   160: 120  187: 60
 22: 60    50: 60    78: 90   106: 30   134: 120  161: 60   188: 90
 23: 120   51: 60    79: 30   107: 30   135: 90   162: 90   189: 120
 24: 60    52: 30    80: 120  108: 120  136: 90   163: 90   190: 90
 25: 120   53: 30    81: 60   109: 90   137: 120  164: 60   191: 90
 26: 30    54: 120   82: 90   110: 90   138: 120  165: 90
 27: 30    55: 60    83: 120  111: 30

vstarts

  0: 1830   28: 2300   56: 1400   84: 800   112: 2330  139: 1830  166: 430
  1: 1600   29: 1600   57: 1000   85: 700   113: 350   140: 1430  167: 430
  2: 1930   30: 2100   58: 800    86: 2130  114: 200   141: 1130  168: 130
  3: 1630   31: 2100   59: 2330   87: 500   115: 2230  142: 30    169: 1230
  4: 1530   32: 1230   60: 1300   88: 1530  116: 400   143: 830   170: 130
  5: 1730   33: 1330   61: 1200   89: 1130  117: 600   144: 1030  171: 230
  6: 1800   34: 930    62: 900    90: 1100  118: 400   145: 1430  172: 1930
  7: 1430   35: 1300   63: 630    91: 830   119: 230   146: 100   173: 300
  8: 1900   36: 2130   64: 1800   92: 2230  120: 630   147: 730   174: 1030
  9: 1700   37: 1200   65: 600    93: 900   121: 30    148: 2030  175: 200
 10: 1400   38: 1000   66: 530    94: 2130  122: 2230  149: 300   176: 330
 11: 2030   39: 1800   67: 0      95: 1630  123: 100   150: 300   177: 500
 12: 1700   40: 2200   68: 2330   96: 0     124: 30    151: 1330  178: 930
 13: 1600   41: 1200   69: 2200   97: 100   125: 2300  152: 1230  179: 230
 14: 2000   42: 800    70: 1300   98: 1400  126: 1630  153: 230   180: 2030
 15: 1500   43: 830    71: 900    99: 130   127: 830   154: 2130  181: 400
 16: 2000   44: 1700   72: 1630  100: 330   128: 0     155: 1130  182: 1530
 17: 2100   45: 900    73: 1600  101: 1500  129: 1930  156: 1830  183: 430
 18: 2000   46: 2230   74: 1430  102: 1500  130: 930   157: 630   184: 1330
 19: 1800   47: 1030   75: 2000  103: 2300  131: 2030  158: 530   185: 1230
 20: 1900   48: 1900   76: 1830  104: 1900  132: 500   159: 200   186: 330
 21: 2200   49: 730    77: 600   105: 800   133: 1730  160: 1530  187: 1030
 22: 2100   50: 2300   78: 1200  106: 430   134: 200   161: 730   188: 500
 23: 1400   51: 1000   79: 30    107: 300   135: 1930  162: 600   189: 530
 24: 1500   52: 700    80: 130   108: 1330  136: 930   163: 1730  190: 530
 25: 2200   53: 1300   81: 0     109: 1000  137: 1730  164: 400   191: 1100
 26: 1130   54: 700    82: 1700  110: 700   138: 630   165: 730
 27: 1100   55: 1100   83: 0     111: 100