--- title: "Sound Pro" id: 53849 type: "computer_media" slug: "sound-pro" url: "http://localhost/computer_media/sound-pro/" markdown_url: "http://localhost/computer_media/sound-pro.md" published_at: "2024-05-13T19:02:05+00:00" modified_at: "2026-03-30T21:45:25+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "An interactive AY sound chip programmer lets you set every register, build multi-step sequences, and play back timed soundscapes — all from a menu-driven interface." 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: "Mill Research" slug: "mill-research" taxonomy: "post_tag" url: "http://localhost/tag/mill-research/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Sound" slug: "sound" taxonomy: "genre" url: "http://localhost/type/sound/" media_contents: - id: 55361 title: "SINCUS Exchange Tape 102 – Utilities & Business" type: "computer_media" url: "http://localhost/computer_media/sincus-exchange-tape-102-utilities-business/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/05/SCR-20240622-sqru.png" - url: "http://localhost/wp-content/uploads/2024/05/SCR-20240622-squb.png" media_type_tags: "Sound" --- # Sound Pro Sound Pro is a menu-driven AY-3-8912 sound chip programmer that lets users interactively set all 14 registers of the chip, store multi-step sound sequences in a 100-step program memory, and play them back with configurable durations. The program uses the TS2068 SOUND keyword to write directly to AY chip registers, covering tone frequency (coarse and fine tuning for channels A, B, and C), noise frequency, channel enable/disable mixing, amplitude with envelope flag, and envelope period and shape. Sound sequences are stored in a two-dimensional array `p(100,15)` where each row holds 14 register values plus a PAUSE duration, allowing up to 100 timed sound steps. The menu dispatch is handled by a computed GOSUB using `GO SUB c*500`, routing each menu selection to a subroutine at a multiple of 500. The envelope shape entry screen includes ASCII waveform illustrations for all standard AY envelope shapes (0–15). *** ## Program Analysis ### Program Structure The program is organized as a main menu loop with subroutines dispatched at multiples of 500. Line `200`–`400` presents the menu and reads a selection `c`, then line `420` routes execution via `GO SUB c*500`. Each subroutine occupies a block starting at `500`, `1000`, `1500`, `2000`, `2500`, `3000`, `3500`, `4000`, `4500`, `5000`, and `6000`. Line `12` carries a REM warning that the program should be entered at line `195` rather than run from line `10`, because lines `20`–`190` initialize state that must be set up before the main menu. ### Data Model Two arrays hold all program state: - `a(15)` — the current “scratch” register set. Elements 1–14 map to AY registers 0–13; element 15 holds the step duration (PAUSE value). - `p(100,15)` — the 100-step sequence store. Each row is a snapshot of `a()` saved by the Program Mode subroutine. The mapping between `a()` index and AY register is consistently `SOUND register, a(register+1)`, so AY register 0 is `a(1)` and AY register 13 is `a(14)`. ### Menu Dispatch The computed-GOSUB idiom at line `420` (`GO SUB c*500`) is an efficient and idiomatic way to dispatch a numeric menu without a chain of IF statements. The validity check at line `410` rejects values outside 1–12, though option 11 has no menu label and its subroutine at `5500` does not exist — selecting 11 would cause an error. Option 10 (execute) and option 9 (print register status) share subroutines at `5000` and `4500` respectively, with `4500` also called internally from the Program Mode subroutine at line `540`. ### AY Register Access via SOUND All register writes use the TS2068 `SOUND` keyword. The execute subroutines (both `5000` and `1000`) write registers in a deliberate order — higher-numbered registers first (7–13), then lower (0–6) — which ensures the envelope and mixer configuration is set before the tone/amplitude registers are written, following good AY programming practice. ### Channel Enable Logic The enable subroutine at line `2500` accumulates a bitmask in `en` by summing user-selected values (1, 2, 4 for tone A/B/C; 8, 16, 32 for noise A/B/C). It then stores `63-en` into `a(8)`, which corresponds to AY register 7 (the mixer). This correctly inverts the sense of the bits, since in the AY chip a *low* bit enables a channel. ### Subroutine Summary | Line | Menu Option | Function | | --- | --- | --- | | `500` | 1 | Program mode — save current `a()` to `p(ps,)` | | `1000` | 2 | Execute stored program sequence with PAUSE timing | | `1500` | 3 | Set amplitude (volume) for channels A, B, or C | | `2000` | 4 | Set note — coarse or fine frequency for A, B, or C | | `2500` | 5 | Enable channels — build mixer byte via bitmask | | `3000` | 6 | Set envelope period (coarse and fine) | | `3500` | 7 | Set envelope shape with waveform selection | | `4000` | 8 | Set noise frequency (0–31) | | `4500` | 9 | Print all 14 register values (also called internally) | | `5000` | 10 | Execute current `a()` immediately via SOUND | | `6000` | 12 | Deactivate all channels; optionally clear `a()` | ### Notable Techniques - The `OVER 1` at line `195` sets XOR-mode printing, carried into the underline decoration. It is reset with `OVER 0` at line `2030` inside the note subroutine. - The step-copy feature in the Program Mode subroutine (lines `700`–`750`) allows a stored step to be loaded back into `a()` for editing before re-saving, enabling incremental composition. - `FLASH 1` is used in the immediate execute (`5000`) and deactivate (`6000`) subroutines as a visual cue that registers are being written, then cleared with `FLASH 0`. - The envelope shape screen at lines `3560`–`3580` renders ASCII art approximations of all AY waveform shapes (saw, ramp, triangle, etc.) directly in BASIC PRINT statements. ### Bugs and Anomalies - Menu option 11 has no label and its target subroutine at `5500` does not exist; selecting 11 will cause a `GO SUB` error. - Line `6060` uses `DIM a(14)` when clearing memory, but the working array is declared as `a(15)` (element 15 stores the duration). This leaves element 15 undefined after a clear, though subsequent use resets it via INPUT. - The frequency register mapping in the note subroutine uses `a(n+v*2-1)` where `n` is 0 (fine) or 1 (coarse) and `v` is 1–3, yielding indices 0–5 for `a()`. Index 0 is out-of-bounds for a 1-based array, so selecting fine tuning for channel A (`n=0, v=1`) attempts to write `a(0)`, which will cause an error. - Line `410` on an out-of-range entry sends the user back to `GO TO 310` (the “9) PRINT register status” PRINT line), not to the menu prompt — a minor UI inconsistency. - The typo “dissabling” at line `6007` is a cosmetic spelling error only. ## Source Code ``` 10 REM /_sound pro\\_ by #MILL RESEARCH# 12 REM goto 195, dont run 20 LET ps=1 30 LET ch=0 170 DIM a(15) 180 LET n=0 185 LET l$="________________________________" 190 DIM p(100,15) 195 OVER 1 200 CLS 210 PRINT TAB (10);"menu" 215 PRINT AT 0,0;l$ 220 PRINT : PRINT 230 PRINT "1) program mode" 240 PRINT "2) execute program" 250 PRINT "3) set volume" 260 PRINT "4) set note" 270 PRINT "5) enable channel" 280 PRINT "6) set envelope period" 290 PRINT "7) program envelope shape" 300 PRINT "8) set noise" 310 PRINT "9) PRINT register status" 320 PRINT "10) execute" 390 PRINT "12) deactivate all channels" 400 INPUT c 410 IF c>12 OR c<1 THEN GO TO 310 420 GO SUB c*500 499 GO TO 200 500 REM program 510 CLS 520 PRINT TAB 10;">Program mode<" 530 PRINT AT 0,0;l$ 540 GO SUB 4500 550 INPUT "is this sound ready to be saved?";x$ 560 IF x$="n" THEN GO TO 700 570 INPUT "enter duration";a(15) 575 PRINT ''"program step: ";ps 580 INPUT "is this the right step?";x$ 590 IF x$="n" THEN INPUT "type step#";ps 595 FOR i=1 TO 15 600 LET p(ps,i)=a(i) 610 NEXT i 620 LET ps=ps+1 690 RETURN 700 INPUT "do you wish to copy another step?";x$ 710 IF x$="n" THEN RETURN 715 INPUT "enter step to copy";n 720 FOR i=1 TO 15 730 LET a(i)=p(n,i) 740 NEXT i 750 GO TO 550 1000 REM execprog 1010 CLS : PRINT TAB (10);"program execution" 1020 PRINT AT 0,0;l$ 1030 INPUT "enter steps to start and finish at";ss 1040 INPUT fs 1045 INPUT "do you wish to print";x$ 1050 FOR i=ss TO fs 1052 CLS 1055 PRINT l$;"step ";i' 1060 FOR j=7 TO 13 1070 IF x$="y" THEN PRINT j,p(i,(j+1)) 1080 SOUND j,p(i,(j+1)) 1090 NEXT j 1100 FOR k=0 TO 6 1110 IF x$="y" THEN PRINT k,p(i,(k+1)) 1120 SOUND k,p(i,(k+1)) 1130 NEXT k 1135 PAUSE p(i,15) 1140 FOR l=0 TO 13 1150 SOUND l,0 1160 NEXT l 1170 NEXT i 1190 RETURN 1500 REM amplitude 1510 CLS 1520 PRINT "type voice to set volume for" 1530 PRINT 1540 PRINT "1) A, 2) B ,3) C" 1550 INPUT V 1560 INPUT "enter volume (0-15, 16 enables envelope)";a(v+8) 1570 INPUT "enter another?";x$ 1580 IF x$="y" THEN GO TO 1500 1590 RETURN 2000 REM note 2005 OVER 1 2010 CLS 2020 PRINT TAB 12;"Tune" 2025 PRINT AT 0,12;"____" 2030 OVER 0 2050 PRINT ''"coarse (0-15)","fine(0-255)" 2060 PRINT 2070 PRINT "channel A=1, B=2, C=3" 2080 INPUT "0)fine or 1) coarse(2 TO RETURN )";n 2085 IF n<>1 AND n<>0 THEN RETURN 2090 INPUT "type channel";v 2100 INPUT "enter tone";tn 2120 LET a(n+v*2-1)=tn 2150 GO TO 2080 2500 REM enable 2505 LET en=0 2510 CLS 2520 PRINT "type each number beside channel to enable and enter 0 to stop" 2530 PRINT 2540 PRINT "tone A=1 B=2 C=4"''"Noise A=8 B=16 C=32" 2550 FOR i=1 TO 6 2560 INPUT n: LET en=en+n 2565 IF n=0 THEN GO TO 2580 2570 NEXT i 2580 LET a(8)=63-en 2590 RETURN 3000 REM envelope period 3010 CLS 3020 PRINT TAB 10;"envelope period" 3030 PRINT AT 0,0;l$ 3040 PRINT : PRINT 3050 PRINT "coarse and fine (0-255)" 3060 INPUT "1) fine 2) coarse 3)menu";n 3070 IF n>2 THEN RETURN 3080 INPUT "period value";pr 3090 LET a(11+n)=pr 3095 GO TO 3060 3500 REM envelope shape 3505 LET ef=0 3510 CLS : PRINT TAB 10;"envelope shape" 3520 PRINT AT 0,0;l$ 3530 PRINT : PRINT 3540 PRINT "Add to enable: 1) hold"'"2) alternate 4) attack 8) continue" 3550 PRINT 'TAB 12;"wave forms" 3560 PRINT '"0 \\________","4 /________"'"8 \\_\\_\\_\\_\\_\\_","9 \\________" 3570 PRINT "10 \\/\\/\\/\\/\\/","11 \\-----"'"12 /_/_/_/_/_/","13 /-------" 3580 PRINT "14 /\\/\\/\\/\\/\\","15 /________" 3590 PRINT '"0) for menu" 3600 INPUT "enter wave form (0-15)";w 3605 FOR i=1 TO 4 3610 INPUT "enter any above effects (1-8) (0 to quit)";n 3620 IF n>8 OR n<1 THEN GO TO 3650 3630 LET ef=ef+n 3640 NEXT i 3650 LET a(14)=w+ef 3690 RETURN 4000 REM noise 4005 CLS 4010 PRINT TAB 14;"noise" 4020 PRINT AT 0,0;l$ 4030 PRINT ''"noise frequency (0-31)"''"higher value= lower frequency" 4040 INPUT "noise rate";n 4050 IF n>31 OR n<0 THEN GO TO 4040 4060 LET a(7)=n 4090 RETURN 4500 REM status 4502 CLS 4505 OVER 0 4510 PRINT TAB 9;"register status" 4515 PRINT AT 0,0;l$ 4520 PRINT ''"register function VAL " 4530 PRINT AT 4,0;l$ 4540 FOR i=0 TO 13 4550 PRINT i;TAB 24;a(i+1) 4560 NEXT i 4570 PAUSE 1000 4590 RETURN 5000 REM execute 5010 FOR i=7 TO 13 5015 REM IF a(i+1)=0 THEN NEXT i 5017 IF i=14 THEN GO TO 5040 5020 SOUND i,a(i+1) 5025 PRINT i,a(i+1) 5030 NEXT i 5040 FLASH 1 5050 REM v 5060 FOR i=0 TO 6 5075 IF i=7 THEN GO TO 5095 5080 SOUND i,a(i+1) 5082 PRINT i,a(i+1) 5085 PAUSE 100 5090 NEXT i 5095 FLASH 0 5099 RETURN 6000 REM deactivate 6002 CLS 6005 FLASH 1 6007 PRINT "dissabling channels" 6010 FOR i=0 TO 13 6020 SOUND i,0 6030 NEXT i 6040 FLASH 0 6050 INPUT "erase memory?";x$ 6060 IF x$="y" THEN DIM a(14) 6070 RETURN 9998 SAVE "Sound Pro": BEEP .4,15: GO TO 1 ```