This program is a demonstration reel created for the Long Island Sinclair Timex (L.I.S.T.) user group’s July 1985 meeting, combining animated text display, speech synthesis, and a parametric spirograph-style graphics routine. It loads three separate machine code blocks — at addresses 31983, 59000, and 59206 — handling graphical text rendering, a “Zebra-Talker” speech synthesizer, and supporting routines respectively. The spirograph section (lines 8050–9060) plots parametric curves using DRAW OVER 1 with a trigonometric formula driven by a user-supplied “magic number” divisor, producing a wide variety of Lissajous-like figures. The subroutine at line 70 uses a DATA-driven POKE sequence into machine code at address 32224 to position animated text at different screen rows, then calls USR 32209 and USR 32020 for rendering with BEEP feedback. Screen-channel printing via PRINT #4 runs alongside the machine code text display, and a CLS wipe routine is located via PEEK 23637/23638 to find the system variable pointing to the wipe USR address.
Program Analysis
Program Structure
The program divides into several functional segments:
- Lines 8–11: Setup — sets display attributes, loads three machine code blocks, then jumps into the first MC routine via
RANDOMIZE USR 59206. - Lines 12–21: Welcome sequence — plays a jingle with
BEEP, then displays animated greeting text using the MC text subroutine and mirrors output to channel 4 (PRINT #4). - Lines 45–66: Additional announcement screens crediting Spectrum Computing and introducing “Zebra-Talker”.
- Lines 63: Interactive section — accepts
INPUTfrom the user and speaks/displays it via the MC routines. - Lines 67–68: Launches spirograph via
RANDOMIZE USR 31983, then falls through to line 180. - Lines 70–83: Core BASIC subroutine for animated text positioning and MC calls, plus associated DATA statements.
- Lines 180–205: Spirograph wrapper — calls
GO SUB 8090for plotting and offers Y/N replay loop. - Lines 910–950: Post-demo menu — offers re-run or loading the next program from tape.
- Lines 1000–1002: CLS wipe routine using a dynamically located USR address.
- Lines 8050–9060: Spirograph input and plotting engine.
- Line 9999: SAVE commands for the composite program and its MC code blocks.
Machine Code Integration
Three separate machine code blocks are loaded at startup:
| Address | Purpose |
|---|---|
31983 | Spirograph / graphics routine (784 bytes) |
59000 | Zebra-Talker speech synthesizer (6200 bytes) |
59206 | Entry point called immediately after load (within the 59000 block or a stub) |
The animated text engine uses memory from address 32000 onward: POKE 32000 receives the character code, POKE 32005 receives a computed screen position offset, and POKE 32224+n (for n=1..5) receives parameters from the DATA statements. Execution is triggered with RANDOMIZE USR 32209 (setup) and RANDOMIZE USR 32020 (per-character rendering).
Animated Text Subroutine (Lines 70–76)
The subroutine at line 70 is called with a string in q$ and a preceding RESTORE nn to select a DATA line. It reads 5 bytes, POKEs them into the MC parameter block at 32224, calls USR 32209, then iterates over each character of q$. For each character, it computes a screen offset as b*(n-1)+c where b is the first DATA byte and c is the value PEEKed back from 32005 after the setup call. A BEEP .01,n*4 provides audio feedback scaling with character position.
The five DATA statements map to five fixed screen rows:
| Line | Data | Row (approx.) |
|---|---|---|
78 | 2,2,196,2,0 | Row 2 |
79 | 2,2,79,6,0 | Row 6 |
80 | 2,2,199,10,0 | Row 10 |
81 | 2,2,180,14,0 | Row 14 |
83 | 2,2,244,18,0 | Row 18 |
Spirograph Plotting Engine (Lines 8090–9030)
The core plot uses a polar-to-Cartesian formula with radius growing linearly with angle: r = 0.12 * (y/180 * PI), making it an Archimedean spiral modulated by the step size x. The loop runs from 0 to 40800 in steps of x, giving a different number of iterations and angular sampling for each magic number. The DRAW OVER 1 mode causes lines to XOR with existing pixels, creating interference patterns when paths cross.
The subtraction of PEEK 23677 and PEEK 23678 (the system variables COORDS, holding the last plotted x and y) from the target coordinates converts absolute positions into relative DRAW offsets — a standard technique since DRAW takes relative increments.
A BEEP .006,x/16 inside the loop provides continuous audio whose pitch is fixed relative to the chosen magic number, creating a characteristic tone for each pattern.
Dynamic USR Wipe (Line 1000)
Line 1000 computes the address of a CLS/wipe machine code routine dynamically: wipe = PEEK 23637 + 256*PEEK 23638 + 5. System variables at 23637–23638 hold PROG (the start of the BASIC program area). Adding 5 skips to a specific offset within the system’s own ROM or a resident MC block. This avoids hardcoding an address that might vary, though the +5 offset is still an assumption about the MC layout.
Channel 4 Mirroring
Throughout the announcement sequences, every animated text call via GO SUB 70 is paired with a PRINT #4;... statement. Channel 4 on the TS2068 is the speech/Zebra-Talker channel, so this sends the same text string to the speech synthesizer simultaneously with the visual display, providing spoken output.
Bugs and Anomalies
- Line 21 contains garbled text:
"WELCOME TO THUGH JULIGH MEETING"instead of the intended “WELCOME TO THE JULY 1985 MEETING”. This appears to be a transcription or typing error in the PRINT #4 string (the animated display driven byGO SUB 70would show the correct text). - Line 195 uses
IF INKEY$="Y" OR INKEY$="y"immediately afterPAUSE 0on line 190. SincePAUSE 0waits for any keypress and releases when the key is pressed (but INKEY$ may already be empty by line 195), this could occasionally miss the keypress. A common workaround is to check INKEY$ within the PAUSE or use a variable to capture it first. - Line 900 is referenced by
GO TO 900at line 200 but does not exist in the listing; control would fall through to line 910, which appears to be the intended destination anyway. - Mixed case in variable names:
Q$andq$are used interchangeably in lines 45, 60, and 7000. In Sinclair BASIC these are the same variable, but it creates inconsistency in readability. - Line 1001 contains a
REMwith what appears to be tokenized BASIC keywords stored as data or obfuscated content — this is unusual and may be intentional padding or a corrupted line. - The spirograph section at line 8050 begins with a
REMthat contains attribute-setting code (BORDER 0: PAPER 0: INK INT(RND*7)) but as it is a REM statement, this code never executes; the actual ink/paper for the spirograph is whatever was set previously.
Save Structure
Line 9999 saves the complete package as four tape blocks: the BASIC program ("GREETING" with auto-run at line 8), and three CODE blocks corresponding to the three machine code segments loaded at startup. This mirrors the three LOAD ""CODE statements at line 10 and is a self-documenting distribution format.
Content
Source Code
8 BORDER 1: PAPER 6: INK 9: CLEAR 31980: PRINT AT 10,9;"STILL LOADING"
10 LOAD ""CODE 31983: LOAD ""CODE 59000: LOAD ""CODE
11 RANDOMIZE USR 59206
12 CLS : FOR b=3 TO 17: PRINT AT b,b;"STOP THE TAPE": NEXT b
14 FOR a=0 TO 1: BEEP .65,14: BEEP .65,16: BEEP .65,12: BEEP .65,0: BEEP 1.2,7: PAUSE 20: NEXT a
15 CLS : POKE 23609,30
16 POKE 23607,223
18 RESTORE 78: LET q$="GREETINGS from": GO SUB 70: PRINT #4;"GREETINGS FROM": RESTORE 79: LET q$="L.I.S.T": GO SUB 70: PRINT #4;"LIST": RESTORE 80: LET q$="THE LONG ISLAND": GO SUB 70: PRINT #4;"THE LONG ISLAND": RESTORE 81: LET q$="SINCLAIR TIMEX": GO SUB 70: RESTORE 83: PRINT #4;"SINCLAIR TIMEX": LET q$="GROUP": GO SUB 70: PRINT #4;"GROUP"
20 PAUSE 150: CLS : RESTORE 78: LET q$="AND": GO SUB 70: PRINT #4;"AND": RESTORE 79: LET q$="WELCOME": GO SUB 70: RESTORE 80: LET q$="TO THE": GO SUB 70: RESTORE 81: LET q$="JULY 1985": GO SUB 70: RESTORE 83: LET q$="MEETING": GO SUB 70
21 PRINT #4;"WELCOME TO THUGH JULIGH MEETING"
45 PAUSE 150: RESTORE 78: LET q$="THIS DEMO IS": GO SUB 70: RESTORE 79: LET q$="BROUGHT TO YOU": GO SUB 70: RESTORE 80: LET q$="THANKS TO": GO SUB 70: RESTORE 81: LET Q$="SPECTRUM ": GO SUB 70: RESTORE 83: LET q$="COMPUTING": GO SUB 70
46 PRINT #4;"THIS DEMo IS BROUGHT TO YOU THANKS TO SPECTRUM COMPUTING "
60 PAUSE 150: CLS : RESTORE 78: LET q$="AND": GO SUB 70: RESTORE 79: LET q$="ZEBRA-TALKER": GO SUB 70: RESTORE 80: LET q$=" ": GO SUB 70: RESTORE 81: LET Q$="NOW TRY ": GO SUB 70: RESTORE 83: LET q$="YOUR LUCK.": GO SUB 70
61 PRINT #4;"AND ZEBRA TALKER NOW TRY YOUR LUCK"
63 PAUSE 150: CLS : RESTORE 78: INPUT q$: GO SUB 70: PRINT #4;q$: RESTORE 79: INPUT q$: GO SUB 70: RESTORE 80: PRINT #4;q$: INPUT q$: GO SUB 70: PRINT #4;q$: RESTORE 81: INPUT q$: GO SUB 70: RESTORE 83: PRINT #4;q$: LET q$="Bye-Bye": GO SUB 70: PRINT #4;q$
65 PAUSE 150: CLS : RESTORE 78: LET q$="S/C PROVIDED": GO SUB 70: RESTORE 79: LET q$="FOLLOWING": GO SUB 70: RESTORE 80: LET q$="PROGRAM FOR": GO SUB 70: RESTORE 81: LET q$="THOSE WHO ENJOY": GO SUB 70: RESTORE 83: LET q$="SPECTRO-GRAPHICS": GO SUB 70
66 PAUSE 150: CLS : RESTORE 79: LET Q$=" ## NEXT ## ": GO SUB 70: RESTORE 80: LET Q$=" SPIRO-GRAPHICS ": GO SUB 70
67 PAUSE 160: RANDOMIZE USR 31983
68 CLS : GO TO 180
70 FOR n=1 TO 5: READ a: IF n=1 THEN LET b=a
71 POKE 32224+n,a: NEXT n
72 RANDOMIZE USR 32209
73 LET c=PEEK 32005
74 FOR n=1 TO LEN q$
75 POKE 32005,(b*(n-1)+c): POKE 32000,CODE q$(n)
76 RANDOMIZE USR 32020: BEEP .01,n*4: NEXT n: RETURN
78 DATA 2,2,196,2,0
79 DATA 2,2,79,6,0
80 DATA 2,2,199,10,0
81 DATA 2,2,180,14,0
83 DATA 2,2,244,18,0
180 LET X=202.5: GO SUB 8090: RESTORE 80: LET q$=" AMAZING ISNT IT": GO SUB 70: PAUSE 100
182 CLS : GO SUB 8050
190 RESTORE 80: LET q$="--AGAIN? .Y/N.--": GO SUB 70: PAUSE 0
195 IF INKEY$="Y" OR INKEY$="y" THEN GO TO 182
200 IF INKEY$="N" OR INKEY$="n" THEN GO TO 900
205 RESTORE 80: LET q$=" PRESS 'Y or N'": GO SUB 70: PAUSE 50: GO TO 190
910 PRINT #0;" PRESS A KEY": PAUSE 0
930 CLS : PRINT INVERSE 1;AT 8,7;"'R' TO READ AGAIN";AT 16,6;"'L'TO LOAD NEXT ITEM": PAUSE 0
940 IF INKEY$="R" OR INKEY$="r" THEN CLS : GO TO 18
945 IF INKEY$<>"l" AND INKEY$<>"L" THEN GO TO 930
950 PAPER 7: INK 9: BORDER 7: CLEAR 32599: FOR b=2 TO 18: PRINT AT b,b;"BYE FOR NOW.": PAUSE 1: NEXT b: PRINT #1;" START TAPE TO LOAD NEXT PROG.": LOAD ""
1000 LET wipe=PEEK 23637+256*PEEK 23638+5: RANDOMIZE USR wipe: RETURN
1001 REM >!pY CLS v OR w+ CLS w CLS STR$ PRINT >!LN (!>EXP ( LET OR w# CLS wPI GO SUB R RANDOMIZE STR$ PRINT >EXP ( LET TO LET PRINT NEW OPEN # RETURN LET AND RETURN H ASN STEP kNOT ?...........
1002 RETURN
7000 INPUT Q$: PRINT #4;Q$
7005 GO TO 7000
8050 REM SPIRO-GRAPHICS ROUTINE: BORDER 0: PAPER 0: INK INT (RND*7)
8060 PRINT INK 2;AT 5,0;"TYPE AND ENTER ONE OF THE FOLLOWING NUMBERS.";AT 10,0;"90 90.5 160 181 193.8 194 195 196 197 198 200 202.5 206 210 212 216 225 240 270 271 280 288 300 310 330 350 495 500 600 601 629 631 648 662 668 712 714 716 710 726 730 780 792 810 812 840 "
8070 INPUT "MAGIC NUMBER: ";x
8080 CLS : PRINT INVERSE 1;"NO SELECTED.:";x
8085 IF x=662 THEN PRINT #1;" LANCASHIRE ROSE"
8090 PLOT 128,88: FOR y=0 TO 40800 STEP x
9000 LET r=0.12*(y/180*PI)
9010 BEEP .006,x/16
9020 DRAW OVER 1;128+r*COS (y/180*PI)-PEEK 23677,88+r*SIN (y/180*PI)-PEEK 23678
9030 NEXT y
9040 PAUSE 250
9045 REM eliminate the REM in 9050 if you have a spectrum
9050 REM GO SUB 1000
9060 RETURN
9080 STOP
9999 SAVE "GREETING" LINE 8: SAVE "BIG"CODE 31983,784: SAVE "ZT"CODE 59000,6200: SAVE "sf"CODE 57344,768
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
