SRS2000 is a speech recognition system that uses machine code routines loaded from a separate file (“spmc”) to create, store, and compare voiceprints. The system supports up to eight labeled voice samples stored in a string array `v$(8,15)` and uses POKE instructions to pass parameters such as file position, recognition accuracy threshold, and a four-byte sample timing value directly into machine code at address 61440 and above. Voiceprint data is stored as raw CODE blocks at address 62080 (512 bytes) alongside the BASIC string array, allowing save and load of complete recognition sessions by filename. A frequency-spectrum plot routine reads 64 bytes from address 61888 and renders a bar graph scaled to fit a bordered display region. The setup menu includes a conversion routine that decomposes a sample time in seconds into four separate byte-sized countdown components POKEd into consecutive addresses for the machine code timing loop.
Program Analysis
Program Structure
The program is organized as a menu-driven shell with nine options, each handled by a block of code at a line number equal to the menu selection multiplied by 100. The dispatch is performed at line 70 with the idiom GO TO (s*100), routing directly to lines 100, 200, 300, 400, 500, 600, 700, 800, and 900. All menu blocks return to the main menu at line 12 via GO TO 12 rather than through a structured loop. A shared display subroutine at line 1000 centers a string s$ on the screen and is called extensively throughout.
Machine Code Interface
The heavy lifting is delegated to a machine code file loaded via LOAD "spmc" CODE at line 3. Three distinct entry points are used:
RANDOMIZE USR 61440— creates a voiceprint from live audio inputLET w=USR 61443— recognition routine; returns 0 on failure or a slot index (1–8) on matchRANDOMIZE USR 61446— clears all stored voiceprintsRANDOMIZE USR 61459— captures a sample for the spectrum plot
Parameters are passed to the machine code entirely through POKEs into fixed addresses: POKE 61449,r sets the file slot, POKE 61450,ac sets the accuracy threshold, and POKEs to 61451–61454 set the four-byte sample timing decomposition. The raw voiceprint data block lives at 62080 (512 bytes) and is saved and loaded independently of the BASIC data.
Timing Decomposition
The setup option for sample speech time (lines 870–890) converts a floating-point duration in seconds into four separate byte values representing successively finer time quanta, presumably matching a nested countdown loop structure in the machine code. The constants used are:
| Byte | Address | Quantum (seconds) |
|---|---|---|
p1 | 61454 | 285.21 |
p2 | 61453 | 1.1141 |
p3 | 61452 | 4.352e-3 |
p4 | 61451 | 17e-6 (residual fraction) |
Each byte is computed by integer division of the remaining time by the quantum, with the remainder passed to the next stage. Note that p4 stores the raw floating-point residual rather than an integer, which may cause unexpected behavior if the machine code expects a byte value.
Voiceprint Storage
Up to eight voiceprint records are maintained. Each has a corresponding label stored in the string array v$(8,15), which holds word names up to 15 characters long. The raw acoustic data is stored as a 512-byte CODE block at address 62080. On save (lines 400–420), two files are written: one with the suffix "v" for the CODE block and one with the suffix "d" for the DATA array, allowing a complete voice dataset to be archived under a single base filename.
Spectrum Plot Routine
Option 7 (lines 700–780) plots a bar graph of 64 frequency bins read from addresses 61888–61951. Each bin value is scaled by 3 and offset by 50 to fit within a bordered plot area spanning x=32 to x=224 and y=50 to y=150. Each bar is three pixels wide. Values exceeding 150 are clamped. Axis labels (“High”, “Low”, “FREQUENCY”) and a vertical title (“No. of Counts”) are printed using PRINT AT with individual characters to achieve vertical text.
Error Handling
The program uses ON ERR in two distinct ways. At line 2, ON ERR GO TO 10 is used as a startup guard so that if the machine code load fails, execution continues at the main initialization block. At line 11, ON ERR RESET establishes a global fallback. During the load sequence (lines 507–517), error handling is temporarily overridden to GO TO 515 so that a missing voiceprint CODE file does not abort the load of the DATA array; the global handler is restored at line 517.
Key BASIC Idioms
- Computed
GO TOviaGO TO (s*100)replaces a long IF-THEN chain for menu dispatch. - The keypress-wait pattern
LET b$=INKEY$: IF b$="" THEN GO TO …is used consistently before audio capture. - String concatenation builds filenames dynamically:
LET h$=d$+"v"andLET h$=d$+"d". - The centering formula
TAB ((32-LEN (s$))/2)is used throughout for display. - The
SAVE "speech" LINE 2at line 1 causes the program to auto-run at line 2 when loaded.
Potential Anomalies
- The
CLEAR 61439at line 2 sets RAMTOP just below the machine code area, protecting it from BASIC. However, if the program is restarted without reloading, the machine code remains in place but is not reloaded, which could cause issues if memory has been disturbed. p4at line 888 stores the floating-point residual after all integer divisions rather than an integer byte; if the machine code expects a clean integer at address 61451, this could produce incorrect timing.- The recognition return value
wfromUSR 61443is used directly as an index intov$(w)at line 217. If the machine code returns a value outside 1–8, this would cause a subscript error.
Content
Source Code
1 SAVE "speech" LINE 2
2 CLEAR 61439: ON ERR GO TO 10
3 LOAD "spmc"CODE
10 DIM v$(8,15)
11 ON ERR RESET
12 CLS : PRINT : PRINT : PRINT : PRINT : PRINT
15 PRINT " MENU"
20 PRINT : PRINT
25 LET t=5
30 PRINT TAB (t);"1. Create Voiceprint"
35 PRINT TAB (t);"2. Recognize Word"
40 PRINT TAB (t);"3. Clear Files"
45 PRINT TAB (t);"4. Save Voiceprints"
50 PRINT TAB (t);"5. Load Voiceprints"
55 PRINT TAB (t);"6. Display Word File"
57 PRINT TAB (t);"7. Plot Voiceprint"
58 PRINT TAB (t);"8. Setup"
60 PRINT TAB (t);"9. Stop"
65 PRINT : PRINT : PRINT " Input Selection": INPUT s
70 GO TO (s*100)
100 CLS : LET s$="Input File Position": GO SUB 1000: INPUT r
105 POKE 61449,r: REM *** file number**********
110 CLS : LET s$="Input Word": GO SUB 1000: INPUT v$(r)
115 CLS : LET s$="Press Any Key to Start": GO SUB 1000
120 LET b$=INKEY$: IF b$="" THEN GO TO 120
122 CLS
125 RANDOMIZE USR 61440: REM ******* create voiceprint*******
130 CLS : LET s$="Again? (Y/N)": GO SUB 1000: INPUT g$
135 IF g$="y" THEN GO TO 100
140 GO TO 12
200 CLS : LET s$="Press Any Key to Continue": GO SUB 1000
205 LET b$=INKEY$: IF b$="" THEN GO TO 205
207 LET s$="Say a Word": GO SUB 1000
210 LET w=USR 61443: REM ********recognition routine call***
211 IF w<>0 THEN GO TO 215
212 LET s$="I Didn't Recognize That": GO SUB 1000
213 PAUSE 180: GO TO 207
215 LET s$="The Word You Said Was:": GO SUB 1000: PRINT
217 PRINT TAB ((32-LEN v$(w))/2);v$(w)
220 PRINT : PRINT : PRINT : PRINT " Again? (Y/N)"
225 INPUT g$: IF g$="y" THEN GO TO 207
230 GO TO 12
300 RANDOMIZE USR 61446: REM ***clear voiceprints**********
305 FOR i=1 TO 8: LET v$(i)="": NEXT i
310 GO TO 12
400 CLS : LET s$="Input File Name": GO SUB 1000: INPUT d$
405 CLS : LET s$="Saving File "+d$+"...": GO SUB 1000
410 LET h$=d$+"v": SAVE h$CODE 62080,512
415 LET h$=d$+"d": SAVE h$ DATA v$()
420 GO TO 12
500 CLS : LET s$="Input File Name": GO SUB 1000: INPUT d$
505 CLS : LET s$="Loading File "+d$+"...": GO SUB 1000
507 ON ERR GO TO 515
510 LET h$=d$+"v": LOAD h$CODE 62080
515 LET h$=d$+"d": LOAD h$ DATA v$()
517 ON ERR RESET
520 GO TO 12
600 CLS : PRINT : PRINT : PRINT : PRINT
605 FOR i=1 TO 8
610 PRINT TAB (t);i;". ";v$(i): NEXT i
615 PRINT " Press Enter to Continue": INPUT i$
620 GO TO 12
700 CLS : LET s$="Press Any Key to Start": GO SUB 1000
702 LET b$=INKEY$: IF b$="" THEN GO TO 702
703 RANDOMIZE USR 61459
704 CLS
705 FOR i=32 TO 224: PLOT i,50: PLOT i,150: NEXT i
710 FOR i=50 TO 150: PLOT 32,i: PLOT 224,i: NEXT i
715 LET s$="No. of Counts"
720 FOR i=1 TO LEN s$: PRINT AT 2+i,2;s$(i): NEXT i
725 PRINT AT 16,3;"High": PRINT AT 16,27;"Low"
730 PRINT AT 17,12;"FREQUENCY"
735 LET i=32
740 FOR j=0 TO 63
745 LET a=PEEK (61888+j)*3+50
750 IF a>150 THEN LET a=150
755 FOR k=50 TO a: PLOT i,k: PLOT i+1,k: PLOT i+2,k: NEXT k
760 LET i=i+3
765 NEXT j
770 PRINT AT 21,10;"Again? (y/n)": INPUT b$
775 IF b$="y" THEN GO TO 700
780 GO TO 12
800 LET s$="SETUP": GO SUB 1000
805 PRINT : PRINT TAB (t);"1. Recognition Accuracy"
810 PRINT : PRINT TAB (t);"2. Sample Speech Time"
812 PRINT : PRINT TAB (t);"3. Return to Main Menu"
815 PRINT : PRINT : PRINT " Input Selection"
820 INPUT g$
825 IF g$="3" THEN GO TO 12
830 IF g$="1" THEN GO TO 840
835 IF g$="2" THEN GO TO 870
837 GO TO 800
840 LET s$="Input Accuracy Value (0-255)": GO SUB 1000
845 PRINT : PRINT TAB (t);"0 = Most Accurate"
850 PRINT : PRINT TAB (t);"255 = Least Accurate"
855 INPUT ac: POKE 61450,ac: GO TO 800
870 LET s$="Input Sample Time in Seconds": GO SUB 1000
875 INPUT sp
880 LET h1=285.21: LET l1=1.1141: LET h2=4.352e-3
881 LET l2=17e-6
885 LET p1=INT (sp/h1): LET sp=sp-h1*p1
886 LET p2=INT (sp/l1): LET sp=sp-l1*p2
887 LET p3=INT (sp/h2): LET sp=sp-h2*p3
888 LET p4=sp
890 POKE 61451,p4: POKE 61452,p3: POKE 61453,p2: POKE 61454,p1
895 GO TO 800
900 STOP
1000 CLS : PRINT AT 10,0: PRINT TAB ((32-LEN (s$))/2);s$: RETURN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

