--- title: "Voice" id: 57759 type: "computer_media" slug: "voice" url: "http://localhost/computer_media/voice/" markdown_url: "http://localhost/computer_media/voice.md" published_at: "2024-10-26T16:49:15+00:00" modified_at: "2026-03-30T21:16:31+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/10/3_VOICER.png" excerpt: "A BASIC shell drives embedded machine code to sample spoken words, build voiceprints from eight repetitions, and recognise up to ten stored vocabulary entries." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 1000" slug: "ts1000" taxonomy: "post_tag" url: "http://localhost/tag/ts1000/" model: - name: "Timex/Sinclair 1000" slug: "ts-1000" taxonomy: "model" url: "http://localhost/model/ts-1000/" indiv: - name: "Brad Bennett" slug: "brad-bennett" taxonomy: "indiv" url: "http://localhost/indiv/brad-bennett/" genre: - name: "Speech Recognition" slug: "speech-recognition" taxonomy: "genre" url: "http://localhost/type/speech-recognition/" media_contents: - id: 57780 title: "CassFile2" type: "computer_media" url: "http://localhost/computer_media/cassfile2-2/" media_type: "Program" programmers: - name: "Brad Bennett" slug: "brad-bennett" taxonomy: "indiv" url: "http://localhost/indiv/brad-bennett/" download_url: "https://archive.org/download/timex-sinclair-software-archive/CassFile2%20%28198x%29%28Various%29%28TS1000%29%28US%29%28Program%29.zip/CassFile2%20%28198x%29%28Various%29%28TS1000%29%28US%29%28Program%29%2FA%20Side%2F3_VOICER.tzx" mediadate: "1983" images: - url: "http://localhost/wp-content/uploads/2024/10/3_VOICER.png" article_media: - id: 24526 title: "Say What?" type: "article" url: "http://localhost/article/say-what/" media_type_tags: "Software, Speech Recognition" --- This program implements a voice recognition system using machine code routines embedded in a REM statement at line 1. The system samples audio through the ZX81/TS1000 speaker/microphone port, builds “voiceprints” by recording a spoken word eight times and averaging the results into a 1412-element array, then compares new samples against up to ten stored voiceprints to identify recognised words. Machine code entry points at USR 16520, USR 16575, USR 16615, USR 16641, and USR 16707 handle audio sampling, display, filing, and recognition respectively, with the code loaded at address 16520 (0x4088) within the REM data. The BASIC shell provides a five-option menu using computed GOTO arithmetic (line 75: `GOTO S*200`) to dispatch to voiceprint display, filing, recognition, file clearing, and string listing routines. *** ## Program Analysis ### Program Structure The program is divided into six functional modules, dispatched by a computed `GOTO S*200` at line 75. Each module occupies a block starting at a multiple of 200: | Lines | Module | | --- | --- | | 1–5 | Machine code payload (REM), warnings, integrity check | | 10–80 | Initialisation, menu, and dispatch | | 200–275 | Voiceprint Display | | 400–520 | Voiceprint Filing (record and store) | | 600–640 | Recognition | | 800–830 | Clear Files | | 1000–1040 | Display String File | | 1200 | STOP (option 6) | | 1300–1310 | User instructions (in inverse video REM text) | | 9000–9050 | SAVE and author credits | ### Machine Code Payload The entire machine code routine is stored in the `REM` statement at line 1, beginning at address 16514 (the start of the REM text). The first six bytes (`\1C` × 6) are padding; the executable code starts at offset 6 within the REM, placing key entry points at the following addresses: | Address (decimal) | Address (hex) | Purpose | | --- | --- | --- | | 16520 | 0x4088 | Audio sampler — fills screen RAM with audio data | | 16575 | 0x40BF | Voiceprint display renderer | | 16615 | 0x40E7 | Store one of 8 audio samples to voiceprint buffer | | 16641 | 0x4101 | Average 8 samples and file voiceprint at position R | | 16707 | 0x4143 | Recognition — compare live sample against stored prints | Line 5 performs a checksum/integrity test: `IF USR 16758<>64 THEN PRINT AT 10,10;"BAD LOAD"`. Address 16758 (0x4176) points to a short routine at the end of the REM block that returns a value in the BC register used as the USR result; if the machine code loaded correctly it returns 64. ### Audio Sampling Technique The sampler at USR 16520 reads from the ZX81 keyboard/tape port (IN instruction targeting port 0xFE or similar) in a tight Z80 loop, writing samples directly to the 1K display file starting at 0x5800 (decimal 22528). This repurposes the screen RAM as a 768-byte sample buffer. The BASIC variables `POKE 16576`/`POKE 16577` set a 16-bit pointer (little-endian) that the machine code uses to know where in screen RAM to write, allowing the display offset to be shifted by menu options 5 and 8 (lines 265–270). ### Voiceprint Filing Logic Filing (lines 400–485) records the spoken word eight times in a loop (`FOR I=0 TO 7`). Each iteration calls the sampler (USR 16520), POKEs the loop index into address 25997 (`POKE 25997,I`), then calls USR 16615 to accumulate the sample into an averaging buffer. After the loop, `POKE 25996,R` sets the file slot number and USR 16641 divides the accumulated samples and stores the result. Up to 10 voiceprints are supported, indexed 1–10 and paired with label strings in the `DIM T$(10,10)` array. ### Recognition The recognition loop (lines 600–640) repeatedly calls the sampler and then USR 16707, which compares the live screen-RAM sample against all stored voiceprints. It returns the best-match index via a POKE to address 25999; the BASIC reads this with `PEEK 25999+1` (adding 1 to convert from 0-based to 1-based) and prints the corresponding `T$` label. Pressing any key returns to the menu. ### Key BASIC Idioms - **Computed GOTO:**`GOTO S*200` (line 75) dispatches to each module without a chain of IF statements. - **FAST/SLOW toggling:**`FAST` is set before all machine code calls and `SLOW` before any display or input, managing the ZX81 display driver correctly. - **PAUSE 30 between samples** (line 475) gives the user a brief gap between the eight recording passes. - **Clear files** (lines 815–825) POKEs zeros across addresses 26000–26640 (the voiceprint data area) in addition to clearing the `T$` string array. ### Memory Map Summary | Address range | Contents | | --- | --- | | 16514–16758 | Machine code in REM line 1 | | 22528–23295 | Display file (reused as audio sample buffer) | | 25996 | File slot parameter for USR 16641 | | 25997 | Sample iteration index (0–7) for USR 16615 | | 25999 | Recognition result index written by USR 16707 | | 26000–26640 | Voiceprint data store (10 × ~64 bytes) | ### Bugs and Anomalies - Line 75 dispatches `GOTO S*200` for S=1–6, mapping option 6 to line 1200 (`STOP`). However, option 5 maps to line 1000, not 1000 — this is correct. Option 3 maps to line 600, option 4 to line 800, all consistent. - The recognition display uses `T$(PEEK 25999+1)`. Since `PEEK` has higher precedence than `+`, this correctly evaluates as `T$((PEEK 25999)+1)`. - Line 1310’s instructions contain the typo “RECGONIZED” (twice: “RECGONIZED” and “RECGONITION”) — these are in the original inverse-video REM text. - The `DIM C(1412)` at line 10 allocates a floating-point array of 1412 elements (each 5 bytes = 7060 bytes). This array does not appear to be referenced anywhere in the BASIC; it likely exists purely to reserve RAM for the machine code’s voiceprint working area above `RAMTOP`, or is a vestige of an earlier pure-BASIC version. ## Source Code ``` 1 REM \1C\1C\1C\1C\1C\1C\21\00\58\06\FF\36\00\05\23\C2\8D\40\06\FF\21\00\58\0E\FE\ED\78\F2\9B\40\2C\ED\78\FA\A0\40\34\05\C8\ED\78\FA\A9\40\2E\00\11\DC\FF\1B\7A\B3\C8\ED\78\F2\B3\40\C3\A0\40\21\00\58\0E\00\1E\40\CD\CF\40\23\0C\1D\20\F8\C9\7E\A7\C8\FE\2B\38\02\3E\2B\47\C5\D5\E5\CD\B2\0B\E1\D1\C1\05\C2\D9\40\C9\06\40\21\A0\61\3A\8D\65\85\6F\11\00\58\D5\11\08\00\19\D1\1A\77\13\05\20\F4\C9\01\28\64\21\A8\61\CD\26\41\7B\02\03\3E\68\B9\20\F5\3A\8C\65\01\40\00\21\50\65\09\3D\20\FC\11\28\64\EB\ED\B0\C9\C5\3E\08\01\00\00\11\00\00\4E\EB\09\EB\3D\23\20\F8\06\03\97\CB\1A\CB\1B\05\20\F8\C1\C9\21\90\65\01\FF\00\C5\11\00\58\0E\00\06\40\1A\96\30\02\2F\3C\81\30\02\3E\FF\4F\23\13\05\20\EF\79\C1\B9\32\D8\59\30\05\4F\78\32\8F\65\04\3E\0A\B8\20\D4\C9\21\88\40\97\06\EE\86\23\05\20\FB\4F\C9\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C\1C 2 REM % %U%S%E% %G%O%T%O% %2%0% %D%O% %N%O%T% %R%U%N 3 REM % %O%R% %W%I%L%L% %C%L%E%A%R% %V%O%I%C%E%-% % 4 REM % %P%R%I%N%T%S%.% %A%F%T%E%R% %S%A%V%I%N%G% % 5 IF USR 16758<>64 THEN PRINT AT 10,10;"BAD LOAD" 10 DIM C(1412) 15 DIM T$(10,10) 20 CLS 25 PRINT AT 7,1 30 PRINT TAB 12;"MENU" 35 PRINT TAB 6;"1. VOICEPRINT DISPLAY" 40 PRINT TAB 6;"2. VOICEPRINT FILE" 45 PRINT TAB 6;"3. RECOGNITION" 50 PRINT TAB 6;"4. CLEAR FILES" 55 PRINT TAB 6;"5. DISPLAY STRING FILE" 60 PRINT TAB 6;"6. STOP" 62 PRINT ,,,,,,TAB 8;"INPUT SELECTION" 65 FAST 70 INPUT S 75 IF S<=6 THEN GOTO S*200 80 GOTO 70 199 REM **VOICEPRINT DISPLAY** 200 RAND USR 16520 205 LET K=22528 210 CLS 215 POKE 16577,INT (K/256) 220 POKE 16576,K-256*INT (K/256) 225 RAND USR 16575 230 PRINT AT 2,20;"AGAIN? (Y/N)" 235 SLOW 240 IF INKEY$="" THEN GOTO 240 245 FAST 250 LET B$=INKEY$ 255 IF B$="N" THEN GOTO 20 260 IF B$="Y" THEN GOTO 200 265 IF B$="5" AND K<=22719 THEN LET K=K+1 270 IF B$="8" AND K>=22529 THEN LET K=K-1 275 GOTO 210 399 REM **VOICEPRINT FILE** 400 CLS 405 PRINT AT 10,1;"ENTER STRING TO BE RECOGNIZED" 410 INPUT Z$ 415 PRINT AT 12,1;"ENTER FILE POSITION" 420 INPUT R 425 LET T$(R)=Z$ 430 PRINT AT 14,1;"PRESS ENTER TO BEGIN" 435 INPUT F$ 440 CLS 445 FOR I=0 TO 7 450 RAND USR 16520 455 POKE 25997,I 460 RAND USR 16615 465 PRINT AT 10,16;I+1 470 SLOW 475 PAUSE 30 480 FAST 485 NEXT I 490 POKE 25996,R 495 RAND USR 16641 500 PRINT AT 12,13;"AGAIN (Y/N)" 505 INPUT B$ 510 IF B$="Y" THEN GOTO 400 515 IF B$="N" THEN GOTO 20 520 GOTO 505 599 REM **RECOGNITION** 600 RAND USR 16520 605 RAND USR 16707 610 CLS 615 PRINT AT 12,10;T$(PEEK 25999+1) 620 SLOW 625 PAUSE 60 630 FAST 635 IF INKEY$<>"" THEN GOTO 20 640 GOTO 600 799 REM **CLEAR FILES** 800 FOR I=1 TO 10 805 LET T$(I)="" 810 NEXT I 815 FOR I=26000 TO 26640 820 POKE I,0 825 NEXT I 830 GOTO 20 999 REM **DISPLAY STRING** 1000 CLS 1005 FOR I=1 TO 10 1010 PRINT AT (5+I),10;I;". ";T$(I) 1015 NEXT I 1020 PRINT ,,,," PRESS ANY KEY TO CONTINUE" 1025 SLOW 1030 IF INKEY$="" THEN GOTO 1030 1035 FAST 1040 GOTO 20 1200 STOP 1300 REM % %S%Y%N%C% %N%O%V%/%D%E%C% %8%3% 1305 REM \!!% %B%R%A%D% %B%E%N%N%E%T%T% \!!\!! 1310 REM % %U%S%E% %T%A%P%E% %R%E%C%O%R%D%E%R% %E%A%R% %T%O% %E%A%R%.% %U%S%E% %B%L%A%N%K% %T%A%P%E% %A%N%D% %S%E%T% % %T%O% %R%E%C%O%R%D%.% %E%N%T%E%R% %2%.% %A%N%D% %S%P%E%A%K% % % %W%O%R%D% %8% %T%I%M%E%S% %T%O% %M%A%K%E% %V%O%I%C%E%P%R%I%N%T%.%O%N%E% %S%A%Y%A%B%L%E% %W%O%R%D%S% %W%O%R%K% %B%E%S%T%.% % % % %E%N%T%E%R% %3%.% %A%N%D% %R%E%P%E%A%T% %W%O%R%D%.% %T%H%E% % % %W%O%R%D% %W%I%L%L% %P%R%I%N%T% %T%O% %S%C%R%E%E%N% %I%F% %I%T% %I%S% %R%E%C%G%O%N%I%Z%E%D%.% %E%N%T%E%R% %1%.% %T%O% %S%E%E% % %V%O%I%C%E%P%R%I%N%T%.% %S%P%E%A%K% %W%O%R%D% %O%R% %S%O%U%N%D% %I%N%T%O% %S%P%E%A%K%E%R%.% %W%I%L%L% %D%I%S%P%L%A%Y% %V%O%I%C%E%P%R%I%N%T%.% % %U%S%E% %C%L%E%A%R% %B%E%F%O%R%E% %S%A%V%E% %I%F%N%O%T% %S%A%V%I%N%G% %V%O%I%C%E%P%R%I%N%T%S%.% %P%R%O%G%R%A%M% %W%I%L%L% %S%A%V% %1%0% %V%O%I%C%E%P%R%I%N%T%S%.% % % % % % % % %A%L%T%E%R%N%A%T%E% %A%M%P% %M%I%K%E% %M%I%G%H%T% %M%A%K%E% % % %R%E%C%G%O%N%I%T%I%O%N% %B%E%T%T%E%R%.\..\..\..\..\..\..\..\..\..\..\..\..\.. 9000 SAVE "VOIC%E" 9010 LIST 1300 9020 REM ROBERT SCHIMKE... 9030 REM 1005 WESTWIND CIRCLE 9040 REM PLACENTIA,CALIFORNIA 9050 REM 9267O USA ```