--- title: "The Rose" id: 55979 type: "computer_media" slug: "the-rose" url: "http://localhost/computer_media/the-rose/" markdown_url: "http://localhost/computer_media/the-rose.md" published_at: "2024-07-14T13:19:06+00:00" modified_at: "2026-03-30T21:45:59+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/07/SCR-20240714-iqft.png" excerpt: "A fully data-driven BASIC program plays \"The Rose\" note by note, synchronizing split syllable lyrics with three-voice harmony chords from the AY sound chip." 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: 55923 title: "Timex Sinclair Public Domain Library Tape 2003" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-2003/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/TheRose%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/07/SCR-20240714-iqft.png" media_type_tags: "Music" --- # The Rose This program plays and displays the song “The Rose” (made famous by Bette Midler) using the TS2068’s AY-3-8912 sound chip via SOUND commands. Each syllable of the lyrics is stored in DATA statements alongside a chord subroutine number, note duration, and TAB position, which the main loop reads and renders simultaneously as printed text and music. The program uses all three AY chip channels (A, B, and C), with mixer register 7 and tone period registers 0–5 carefully set to produce triadic harmonies such as C major, F major, G major, E minor, and A minor. Line 1900 acts as a “dummy” chord subroutine that simply returns, allowing the data-driven loop to call it when no chord change is needed without special-casing the logic. *** ## Program Analysis ### Program Structure The program is organized into three broad sections: initialization (lines 1–22), the main data-driven performance loop (lines 25–155), and a coda that replays the final phrase (lines 155–170). Supporting subroutines from line 1000 onward handle AY chip configuration and chord voicing. The song’s entire lyric and musical data is encoded in DATA statements (lines 40–160), consumed sequentially by a single `FOR` loop. ### Data-Driven Performance Loop Lines 25–35 form the core engine. Each iteration reads four values: `L$` (a lyric syllable), `C` (a chord subroutine line number), `D` (BEEP duration in seconds), and `P` (a pitch value that doubles as a TAB column multiplier). The sequence is: 1. `PRINT TAB P*1.2;L$` — displays the syllable at a screen column derived from pitch 2. `GO SUB C` — calls the appropriate chord subroutine to set AY registers 3. `BEEP D,P` — plays the note using the built-in BEEP command (which uses the same AY chip) 4. If `P=30`, the screen is cleared, acting as a stanza break trigger Using the pitch value `P` both as a semitone offset for `BEEP` and as a `TAB` column multiplier (scaled by 1.2) is an elegant dual-purpose technique that loosely positions lyrics left-to-right on screen in a way that mirrors melodic contour. ### AY Chip Usage via SOUND The `SOUND` keyword (rendered as `}` in the source) directly writes to AY-3-8912 registers. Register 7 is the mixer control register; the comment in line 2 documents the bit patterns for enabling individual channels: value 56 enables all three tone channels (A, B, C), while values 57–63 selectively enable subsets. The chord subroutines write pairs of low/high bytes to registers 0–5 to set tone periods for all three channels simultaneously. | Line | Chord | Notes (approx.) | | --- | --- | --- | | 1015 | C Major | C, E, G (high octave) | | 1017 | C Major (lower) | C, E, G (lower octave) | | 1018 | C Major inversion | E, G, C (egc voicing) | | 1030 | F Major | F, A, C | | 1035 | G Major | G, B, D | | 1055 | A Minor | A, C, E | | 1060 | E Minor | E, G, B | ### The Dummy Chord Subroutine Line 1900 consists solely of `RETURN` with a REM comment “DUMMY CHORD TO REGULATE DATA.” Rather than adding conditional logic inside the main loop to skip chord calls for notes that fall within an existing harmony, the program stores 1900 as the chord value in the DATA. This keeps the loop body uniform and branchless for every data record. ### Pause and Reset Subroutines Lines 1991, 1995, and 1999 are short utility subroutines called via the same `GO SUB C` mechanism as the chord routines. They handle inter-stanza pauses and AY muting. Line 1999 silences the AY by setting tone period registers for channels A, B, C to zero and disabling the mixer. Line 1996 performs a brief silence, then re-enables all channels with specific envelope values, providing a dynamic effect between verses. ### Initialization Line 1 sets the AY mixer (register 7) to a specific channel configuration and POKEs the system variable at address 23561–23562, which controls the FRAMES counter or a related timing variable, likely to synchronize BEEP behavior. Line 20 sets the FRAMES system variable (address 23692) to 255 to prevent automatic screen timeout, then calls the channel setup subroutine at 1001. ### Line 1003 Anomaly Line 1003 contains only `SOUND` register writes with no `RETURN` statement. It is referenced as a chord number in the DATA at line 160. Without a `RETURN`, execution will fall through into line 1015 and return from there instead. This appears to be a deliberate or inadvertent fall-through that effectively applies both the 1003 AY settings and the C Major voicing of 1015 before returning — an unintentional chord layer or an oversight. ### Screen Display The display uses `PAPER 2` (red), `INK 0` (black), and `BRIGHT 1` for a high-contrast presentation. Lyrics scroll down the screen as each syllable is printed. The stanza-break mechanism (detecting `P=30` in line 30) clears the screen between verses, with ” ” (space) DATA records serving as the sentinel values that carry the value 30 for `P`. ### Notable Techniques - Using lyric pitch (`P`) as both a `BEEP` semitone and a scaled `TAB` column creates an implicit melodic-spatial layout on screen. - Chord subroutine numbers stored directly in DATA avoid any look-up table or conditional dispatch. - The dummy subroutine at 1900 eliminates branching for “no chord change” cases. - All three AY channels are driven in parallel with BEEP to create harmony over the melody. - Line 2 is a REM that serves as inline documentation of all AY mixer register values for channel selection — a useful programmer’s reference embedded in the code. ## Source Code ``` 1 SOUND 7,63: POKE 23561,20: POKE 23562,1 2 REM to enable Channel A:}7,62;B-SOUND 7,61;C-SOUND 7,59;A & B-SOUND 7,60;A & C-SOUND 7,58;B & C-SOUND 7,57;A,B,C--SOUND 7,56 MOST FREQUENT 10 PAPER 2: BRIGHT 1: BORDER 2: INK 0: CLS : PRINT AT 10,7;" T H E R O S E " 15 REM QTR=.5;RAISED AN OCTAVE 20 POKE 23692,255: GO SUB 1001 22 GO SUB 1018: PAUSE 300: CLS 25 FOR B=1 TO 185: READ L$,C,D,P 30 PRINT TAB P*1.2;L$: GO SUB C: BEEP D,P: IF P=30 THEN CLS 35 NEXT B 40 DATA "SOME",1999,.25,12,"SAY",1000,.25,14,"LOVE",1015,1.25,16,"IT",1900,.25,16,"IS",1900,.25,17,"A",1900,.25,16,"RIV",1035,.25,16,"ER",1900,1.25,14 45 DATA "THAT",1900,.25,14,"DROWNS",1030,1.25,12,"THE",1900,.25,12,"TEN-",1035,.25,14,"DER",1900,.25,16,"REED",1015,1,16 47 DATA " ",1991,0,30 50 DATA "SOME",1900,.25,12,"SAY",1015,.25,14,"LOVE",1900,1.25,16,"IT",1900,.25,16,"IS",1015,.25,17,"A",1900,.25,16,"RA-",1035,.25,16,"ZOR",1900,1.25,14,"THAT",1900,.25,14,"LEAVES",1030,1.25,12,"YOUR",1900,.25,12,"HEART",1035,.25,14,"TO",1900,.25,16,"BLEED",1015,1,16 55 DATA " ",1991,0,30 60 DATA "SOME",1015,.25,16,"SAY",1900,.25,17,"LOVE",1018,1.25,19,"IT",1900,.25,19,"IS",1900,.25,19,"A",1900,.25,19,"HUN-",1055,.25,19,"GER,",1900,1.25,12,"AN",1900,.25,16,"END-",1030,1.25,17,"LESS",1900,.25,16,"ACH-",1900,.25,14,"ING",1900,.25,12,"NEED",1035,1.25,9 65 DATA " ",1991,0,30 70 DATA "I",1035,.25,12,"SAY",1900,.25,14,"LOVE",1015,1.25,16,"IT",1900,.25,16,"IS",1900,.25,17,"A",1900,.25,16,"FLOW-",1017,.25,16,"ER",1900,1.25,14,"AND",1900,.25,16,"YOU",1030,1.25,12,"IT'S",1900,.25,12,"ON-",1035,.375,14,"LY",1900,.125,12,"SEED.",1017,1.25,12 75 DATA " ",1999,0,30 80 DATA "IT'S",1000,.25,12,"THE",1900,.25,14,"HEART",1017,1.25,16,"A-",1900,.25,16,"FRAID",1900,.25,17,"OF",1900,.26,16,"BREAK-",1035,.25,16,"ING",1900,1.25,14,"THAT",1900,.25,14,"NEV-",1030,.25,12,"ER",1900,1.25,12,"LEARNS",1035,.25,14,"TO",1900,.25,16,"DANCE.",1015,1.25,16 85 DATA " ",1991,0,30 90 DATA "IT'S",1000,.25,12,"THE",1900,.25,14,"DREAM",1015,1.25,16,"A-",1900,.25,16,"FRAID",1018,.25,17,"OF",1900,.25,16,"WAK-",1035,.25,16,"ING",1900,1.25,14,"THAT",1900,.25,14,"NEV-",1030,.25,14,"ER",1900,1.25,12,"TAKES",1035,.25,14,"THE",1900,.25,16,"CHANCE.",1017,1.25,16 95 DATA " ",1999,0,30 100 DATA "IT'S",1000,.25,16,"THE",1900,.25,17,"ONE",1060,1.25,19,"WHO",1900,.25,19,"WON'T",1900,.25,19,"BE",1900,.25,19,"TAK-",1055,.25,19,"EN",1900,1.25,12,"WHO",1015,.25,16,"CAN",1030,1.25,17,"NOT",1900,.25,16,"SEEM",1900,.25,14,"TO",1900,.25,12,"GIVE,",1035,.25,9," ",1900,.75,7 105 DATA " ",1991,0,30 110 DATA "AND",1035,.25,12,"THE",1900,.25,14,"SOUL",1015,1.25,16,"A-",1900,.25,16,"FRAID",1018,.25,17,"OF",1900,.25,16,"DY-",1035,.25,16,"ING",1900,1.25,14,"THAT",1900,.25,14,"NEV-",1030,.25,14,"ER",1900,.25,12,"LEARNS",1035,.25,14,"TO",1900,.25,12,"LIVE.",1017,2.5,12 115 DATA " ",1999,0,30 120 DATA "WHEN",1000,.25,12,"THE",1900,.25,14,"NIGHT",1015,1.25,16,"HAS",1900,.25,16,"BEEN",1018,.25,17,"TOO",1015,.25,16,"LONE-",1035,.25,16,"LY",1900,1.25,14,"AND",1900,.25,14,"THE",1900,.25,14,"ROAD",1030,.25,12,"HAS",1900,.5,9,"BEEN",1035,.25,14,"TOO",1900,.25,16,"LONG,",1015,1.25,16 125 DATA " ",1991,0,30 130 DATA "AND",1017,.25,12,"YOU",1015,.25,14,"THINK",1900,1.25,16,"THAT",1900,.25,16,"LOVE",1015,.25,17,"IS",1900,.25,16,"ON-",1035,.25,16,"LY",1900,1,14,"FOR",1900,.25,14,"THE",1900,.25,14,"LUCK-",1030,.25,14,"Y",1900,1.25,12,"AND",1035,.25,14,"THE",1900,.25,16,"STRONG,",1017,1.25,16 135 DATA " ",1999,0,30 140 DATA "JUST",1000,.25,16,"RE-",1900,.25,17,"MEM-",1060,1,19,"BER",1900,.25,16,"IN",1900,.25,19,"THE",1900,.25,19,"WIN-",1055,.25,19,"TER",1900,1,12,"FAR",1017,.25,12,"BE-",1015,.25,16,"NEATH",1030,1.25,17,"THE",1900,.25,16,"BIT-",1900,.25,14,"TER",1900,.25,12,"SNOWS",1035,1,9 145 DATA " ",1995,0,30 150 DATA "LIES",1035,.25,12,"THE",1900,.25,14,"SEED",1015,1.25,16,"THAT",1900,.25,16,"WITH",1900,.25,17,"THE",1035,.25,16,"SUN'S",1900,.25,16,"LOVE",1900,1,14,"IN",1900,.25,14,"THE",1900,.25,14,"SPRING",1030,1.25,12," ",1996,0,30,"BE-",1030,.25,12,"COMES",1035,.25,14,"THE",1900,.25,12,"ROSE.",1015,2,12 155 SOUND 7,63: PAUSE 60: FOR E=1 TO 5: READ L$,C,D,P: PRINT TAB P*1.2;L$: GO SUB C: BEEP D,P: NEXT E 160 DATA " ",1000,0,0,"BE-",1030,.25,12,"COMES",1035,.25,14,"THE",1003,.25,12,"ROSE.",1018,2.5,19 170 SOUND 7,63: PAUSE 180: STOP 1000 SOUND 7,56;8,10;9,12;10,16;11,2;12,2;13,13: RETURN : REM ON 1001 SOUND 7,57;9,16;10,16;11,32;12,32;13,8: RETURN : REM channels b & c only 1003 SOUND 8,16;9,16;10,16;11,225;12,225;13,9 1015 SOUND 0,209;1,0;2,165;3,0;4,139;5,0: RETURN : REM C MAJ 1017 SOUND 0,162;1,1;2,75;3,1;4,23;5,1: RETURN : REM LOWER C MAJ 1018 SOUND 0,165;1,0;2,139;3,0;4,104;5,0: RETURN : REM C MAJ chord inversion egc--hi & sweet 1030 SOUND 0,156;1,0;2,124;3,0;4,104;5,0: RETURN : REM F MAJ 1035 SOUND 0,139;1,0;2,110;3,0;4,93;5,0: RETURN : REM G MAJ 1055 SOUND 0,248;1,0;2,209;3,0;4,165;5,0: RETURN : REM A MIN 1060 SOUND 0,165;1,0;2,139;3,0;4,110;5,0: RETURN : REM E MIN 1900 RETURN : REM DUMMY CHORD TO REGULATE DATA 1991 PAUSE 30: RETURN 1995 PAUSE 40: RETURN 1996 SOUND 7,63: PAUSE 30: SOUND 7,56;8,16;9,16;10,16;11,0;12,0;13,13: RETURN 1999 SOUND 7,63;8,0;9,0;10,0: RETURN : REM OFF 9997 STOP 9998 CLEAR : SAVE "THE*ROSE" LINE 1 ```