--- title: "Spectral Piano" id: 55878 type: "computer_media" slug: "spectral-piano" url: "http://localhost/computer_media/spectral-piano/" markdown_url: "http://localhost/computer_media/spectral-piano.md" published_at: "2024-07-06T17:27:02+00:00" modified_at: "2026-03-30T21:45:27+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/07/SCR-20240705-lbbx.png" excerpt: "A fully interactive piano simulator that draws a graphical keyboard, plays chromatic notes across three octaves, and walks beginners through a multi-screen tutorial." 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 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: "Music" slug: "music" taxonomy: "genre" url: "http://localhost/type/music/" media_contents: - id: 55879 title: "ISTUG Public Domain Library 7" type: "computer_media" url: "http://localhost/computer_media/istug-public-domain-library-7/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Piano%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/07/SCR-20240705-lbbx.png" - url: "http://localhost/wp-content/uploads/2024/07/SCR-20240705-laxl.png" media_type_tags: "Music" --- # Spectral Piano This program implements a piano simulator called “Spectral Piano” that draws a visual keyboard on screen and plays notes using the BEEP command. It defines eight User Defined Graphics (UDGs, characters 144–151) loaded via DATA statements to render the piano key shapes, using block graphics for white and black key visuals. The keyboard spans one octave of white keys mapped to A–J and black keys mapped to W, E, T, Y, U, with octave selection via I/O/P keys and note duration controlled by keys 1–9 in tenths of a second. An introductory subroutine at line 590 displays a multi-screen tutorial with instructions before entering the main play loop. The BEEP arguments use semitone offsets (0–11) combined with an octave offset variable, covering three octaves of the chromatic scale. *** ## Program Analysis ### Program Structure The program is organized into three logical phases. Lines 10–130 initialize the eight UDG characters used to render piano key graphics. Lines 140–580 contain the main keyboard display and play loop. Lines 590–770 form the introductory tutorial subroutine, which is called first via `GO SUB 590` at line 10 and returns to the main loop after the user completes the walkthrough. Lines 780–820 are unreachable dead code following the `GO TO 310` loop. 1. UDG initialization (lines 10–130) 2. Tutorial subroutine (lines 590–770) 3. Keyboard rendering (lines 140–300) 4. Main play loop (lines 310–580) 5. Unreachable cleanup/save code (lines 780–820) ### UDG Definitions Eight UDGs (characters 144–151, accessed as `\a` through `\h`) are loaded from DATA at lines 60–130. They are designed in pairs to represent the tops and bottoms of piano keys. The inner loop at lines 30–50 POKEs each 8-byte bitmap into `USR CHR$ c+n`. The UDGs represent: | UDG | Char code | Role | | --- | --- | --- | | `\a` | 144 | Black key top-left | | `\b` | 145 | Black key top-right | | `\c` | 146 | Black key bottom-left | | `\d` | 147 | Black key bottom-right | | `\e` | 148 | White key pressed top-left | | `\f` | 149 | White key pressed top-right | | `\g` | 150 | White key unpressed top-left | | `\h` | 151 | White key unpressed top-right | ### Keyboard Layout and Note Mapping The visual keyboard is drawn using PLOT/DRAW for the outline (lines 240–250) and PRINT for the key fill characters (lines 260–300). White keys are mapped to letters A–J (7 keys) covering the chromatic white notes C through B, and black keys are mapped to W, E, T, Y, U — a layout matching the physical arrangement of sharps and flats. BEEP arguments for semitone pitch use offsets 0–11 from middle C, combined with the octave offset variable `o` which is set to −12, 0, or +12 by the I, O, and P keys. ### Key Press Visualization When a white key is pressed, the program substitutes the “pressed” UDG pair (`\e\f`) at the correct screen position via `PRINT AT`, calls BEEP, then restores the “unpressed” UDG pair (`\g\h`). Black keys similarly swap between `\a\b` and `\c\d`. This gives a simple but effective visual key-press animation. Because INKEY$ is polled without any wait loop, the main loop at lines 310–580 runs continuously and checks each key sequentially on every pass. ### Notable Techniques - UDGs are addressed via `USR CHR$ c+n` inside a nested FOR loop, efficiently loading all 64 bytes in sequence from DATA. - The `OVER 1` attribute is used on the title screen (line 590) to underline the program title by XORing underscores over the text. - Note duration is stored as a decimal fraction in variable `len` (0.1–0.9), set directly by keys 1–9, avoiding any arithmetic conversion. - The octave variable `o` shifts all BEEP pitch values uniformly by ±12 semitones, keeping note mapping code identical across octaves. - The tutorial subroutine uses multiple `INPUT` statements (lines 690, 710, 730, 740, 760) to page through instructions, with a loop back to `GO SUB 590` if the user answers “n” to the comprehension check. ### Bugs and Anomalies - Line 270 contains `IF n=13 THEN NEXT n`, which attempts to skip column 13 during black key rendering to leave the gap between E and F. However, the loop steps by 2 from 9, producing values 9, 11, 13, 15, 17, 19 — so n=13 is indeed reached, and this workaround is correct in intent, though unusual in style. - The word “Lenght” (should be “Length”) is misspelled in both the tutorial text (line 670) and the on-screen display (line 440), appearing consistently throughout. - Lines 780–800 (`PAUSE 0`, `PAPER 7`/`INK 0`/`BORDER 7`/`FLASH 0`/`CLS`, `STOP`) are unreachable because the main loop at line 580 performs an unconditional `GO TO 310`. These lines appear to be cleanup code that was never wired in. - The variable name `len` shadows the built-in `LEN` function. While BASIC is case-insensitive for keywords, using `len` as a numeric variable works here only because it is never used in a context that would conflict with the string-length function. - Line 750 contains a trailing `REM 32` comment, likely a note to the programmer about the number of characters being cleared, not functional code. ## Source Code ``` 10 GO SUB 590 20 FOR c=144 TO 151 30 FOR n=0 TO 7 40 READ a: POKE USR CHR$ c+n,a 50 NEXT n: NEXT c 60 DATA 15,15,15,15,15,15,7,0 70 DATA 240,240,240,240,240,240,224,128 80 DATA 15,15,15,15,7,0,0,0 90 DATA 240,240,240,240,224,128,128,128 100 DATA 128,128,128,128,128,255,128,128 110 DATA 0,0,0,0,0,255,0,0 120 DATA 128,128,255,128,128,128,128,128 130 DATA 0,0,255,0,0,0,0,0 140 PAPER 2: BORDER 0: CLS 150 REM Varaibles 160 LET a$="middle" 170 LET len=.3 180 LET o=0 190 REM Keyboard 200 PAPER 7 210 FOR n=8 TO 21: FOR m=7 TO 14 220 PRINT AT m,n;" " 230 NEXT m: NEXT n 240 INK 0: PLOT 64,61: DRAW 111,0 250 FOR n=64 TO 162 STEP 16: PLOT n,56: DRAW 0,63: NEXT n 260 FOR n=9 TO 20 STEP 2: FOR m=7 TO 10 270 IF n=13 THEN NEXT n 280 PRINT AT m,n;"\ :\: " 290 NEXT m: PRINT AT m,n;"\c\d" 300 NEXT n 310 REM Notes 320 IF INKEY$="i" THEN LET o=-12: LET a$="bottom" 330 IF INKEY$="o" THEN LET o=0: LET a$="middle" 340 IF INKEY$="p" THEN LET o=12: LET a$=" top" 350 IF INKEY$="1" THEN LET len=.1 360 IF INKEY$="2" THEN LET len=.2 370 IF INKEY$="3" THEN LET len=.3 380 IF INKEY$="4" THEN LET len=.4 390 IF INKEY$="5" THEN LET len=.5 400 IF INKEY$="6" THEN LET len=.6 410 IF INKEY$="7" THEN LET len=.7 420 IF INKEY$="8" THEN LET len=.8 430 IF INKEY$="9" THEN LET len=.9 440 INK 7: PAPER 2: PRINT AT 0,20;"Lenght ";len;" " 450 PRINT AT 16,9;"^";AT 17,7;a$;" C" 460 INK 0: PAPER 7: IF INKEY$="a" THEN PRINT AT 14,8;"\e\f": BEEP len,0+o: PRINT AT 14,8;"\g\h" 470 IF INKEY$="w" THEN PRINT AT 11,9;"\a\b": BEEP len,1+o: PRINT AT 11,9;"\c\d" 480 IF INKEY$="s" THEN PRINT AT 14,10;"\e\f": BEEP len,2+o: PRINT AT 14,10;"\g\h" 490 IF INKEY$="e" THEN PRINT AT 11,11;"\a\b": BEEP len,3+o: PRINT AT 11,11;"\c\d" 500 IF INKEY$="d" THEN PRINT AT 14,12;"\e\f": BEEP len,4+o: PRINT AT 14,12;"\g\h" 510 IF INKEY$="f" THEN PRINT AT 14,14;"\e\f": BEEP len,5+o: PRINT AT 14,14;"\g\h" 520 IF INKEY$="t" THEN PRINT AT 11,15;"\a\b": BEEP len,6+o: PRINT AT 11,15;"\c\d" 530 IF INKEY$="g" THEN PRINT AT 14,16;"\e\f": BEEP len,7+o: PRINT AT 14,16;"\g\h" 540 IF INKEY$="y" THEN PRINT AT 11,17;"\a\b": BEEP len,8+o: PRINT AT 11,17;"\c\d" 550 IF INKEY$="h" THEN PRINT AT 14,18;"\e\f": BEEP len,9+o: PRINT AT 14,18;"\g\h" 560 IF INKEY$="u" THEN PRINT AT 11,19;"\a\b": BEEP len,10+o: PRINT AT 11,19;"\c\d" 570 IF INKEY$="j" THEN PRINT AT 14,20;"\e\f": BEEP len,11+o: PRINT AT 14,20;"\g\h" 580 GO TO 310 590 PAPER 2: CLS : PRINT INK 7;AT 0,7;"Spectral Piano"; OVER 1; INK 7;AT 0,7;"______________" 600 LET n$="ASDFGHJ" 610 LET l=1: FOR n=7 TO 20 STEP 2: PRINT PAPER 7; INK 0;AT 10,n;n$(l): LET l=l+1: NEXT n 620 LET n$="WETYU" 630 LET l=1: FOR n=8 TO 18 STEP 2: IF n=12 THEN NEXT n 640 PRINT PAPER 0; INK 7;AT 8,n;n$(l): LET l=l+1: NEXT n 650 PRINT AT 6,0;"USE THESE KEYS";AT 11,7;"^";AT 12,3;"MIDDLE C" 660 PRINT AT 4,20;"octave keys": PRINT AT 6,22;"I O P" 670 PRINT AT 2,2;"Lenght of note in fractions";AT 3,4;"of a second";AT 4,1;" 1,2,3,4,5,6,7,8,9" 680 PRINT INK 7;AT 14,0;"Spectral Piano is a computer version of a piano.Once you knowhow it works you will soon be trying to play your own tunes." 690 INPUT "When ready press enter";z$ 700 PRINT OVER 1; PAPER 7;AT 12,3;" "; OVER 0; PAPER 2; INK 7;AT 14,0;"The keyboard is set out like that of a real piano.By pressingthe keys A to J (on the second row up)you will get a note from middle C to B.To obtain the sharps and flats press any of the keys displayed in white on black." 710 INPUT "press enter when ready";z$ 720 PRINT INK 7;AT 13,0;"S.p also has a function to alterthe octave you are playing in, and a function to change the lenght of a note. 1-If at any time during playing you wish to change octaves just press key I to get the octave starting at bottom C,key O to get the middle C octave and P to get the top C octave" 730 INPUT "Press enter when ready";z$ 740 PRINT INK 7;AT 9,0;"2.-if at any time during playing you wish to change the duration of the notes you are pressing press any key from 1 to 9.The higher the number the longer the note " 750 FOR n=15 TO 21: PRINT AT n,0,,: NEXT n: REM 32 760 INPUT "Have you understood?(y/n)";z$: IF z$<>"y" THEN GO TO 590 770 RETURN 780 PAUSE 0 790 PAPER 7: INK 0: BORDER 7: FLASH 0: CLS 800 STOP 810 SAVE "PIANO" LINE 0 820 VERIFY "" ```