--- title: "Musical Christmas with TS 2068" id: 52275 type: "computer_media" slug: "musical-christmas-with-ts-2068" url: "http://localhost/computer_media/musical-christmas-with-ts-2068/" markdown_url: "http://localhost/computer_media/musical-christmas-with-ts-2068.md" published_at: "2023-12-17T18:42:28+00:00" modified_at: "2026-03-30T21:44:15+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2019/02/20230809-041332.jpg" excerpt: "A BASIC Christmas jukebox plays Silent Night, Jingle Bells, and Joy to the World using clever DATA-driven note sequencing and ON ERR end-of-song detection." 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/" indiv: - name: "Oleg D. Jefimenko" slug: "oleg-d-jefimenko" taxonomy: "indiv" url: "http://localhost/indiv/oleg-d-jefimenko/" genre: - name: "Holiday" slug: "holiday" taxonomy: "genre" url: "http://localhost/type/holiday/" - name: "Music" slug: "music" taxonomy: "genre" url: "http://localhost/type/music/" media_type: "Program" programmers: - name: "Oleg D. Jefimenko" slug: "oleg-d-jefimenko" taxonomy: "indiv" url: "http://localhost/indiv/oleg-d-jefimenko/" download_url: "https://archive.org/download/timex-sinclair-software-archive/Musical%20Christmas%20with%20TS%202068%20%281985%29%28Jefimenko%2C%20Oleg%29%28US%29%28TS2068%29%28Program%29.zip" mediadate: "1985" images: - url: "http://localhost/wp-content/uploads/2023/12/SCR-20260329-qvop.png" article_media: - id: 37906 title: "Musical Christmas with TS 2068" type: "article" url: "http://localhost/article/musical-christmas-with-ts-2068/" - id: 46980 title: "Musical Christmas with TS 2068" type: "article" url: "http://localhost/article/musical-christmas-with-ts-2068-3/" - id: 45025 title: "Musical Christmas with TS 2068" type: "article" url: "http://localhost/article/musical-christmas-with-ts-2068-2/" - id: 45729 title: "Musical Xmas with TS 2068" type: "article" url: "http://localhost/article/musical-xmas-with-ts-2068/" media_type_tags: "Holiday, Music" --- This program plays three Christmas songs — Silent Night, Jingle Bells, and Joy to the World — using the BEEP command with note frequency and duration values stored in DATA statements. A table-of-contents menu lets the user select a song by number, and ON ERR is used to detect when the DATA stream is exhausted, signaling the end of a piece. A special sentinel value of 99 for the frequency triggers a pause (rest) rather than a tone, implemented by substituting PAUSE for BEEP. After playback, the user may replay the song, loop it continuously, or return to the song selection menu. *** ## Program Analysis ### Program Structure The program is divided into a title/menu section (lines 10–230) and three song DATA blocks anchored at lines 1000, 1200, and 1400. Song selection uses a formula: `RESTORE n*200+800`, which maps song numbers 1, 2, and 3 to DATA line offsets 1000, 1200, and 1400 respectively. Each song block begins with a name string and a tempo scalar, followed by pairs of (frequency-semitone, duration-divisor) values. ### Note Playback Engine The playback loop at lines 130–160 reads two values per iteration: `f` (pitch in semitones above middle C) and `v` (a duration divisor). The actual duration passed to BEEP or PAUSE is `t/v`, where `t` is the tempo scalar read at line 90. A frequency value of 99 is used as a rest sentinel — when `f=99`, the program executes `PAUSE t/v*60` (line 150) instead of `BEEP`, converting the beat duration to frames at 60 fields per second. ### End-of-Song Detection via ON ERR Rather than embedding an explicit terminator count or end marker in the DATA, the program uses `ON ERR GO TO 170` (line 130) to catch the “Out of DATA” error that occurs when `READ` runs past the end of the current song’s data block. Line 170 then clears the error trap with `ON ERR RESET` and checks a flag variable `z$` to decide whether to loop continuously. ### Continuous Play Mode When the user selects option “2” (play continuously), `z$` is set to `"2"` at line 220. After the ON ERR fires and the check at line 170 passes, the program executes `RESTORE n*200+810` — note the offset of +810 rather than +800 — which skips the name and tempo DATA entry and re-reads from the first note pair directly, then jumps back to the playback loop at line 130 for seamless looping. ### Menu and Display The title screen (lines 10–20) prints “CHRISTMAS MUSIC” alternating in INK 1 and INK 3 across 13 rows using a FOR loop. The table-of-contents loop at line 60 uses `RESTORE i*200+800` and reads only the song name `n$` for display, cleanly reusing the same offset formula used for playback. PAPER color attributes are used throughout for visual separation of UI regions. ### Data Format Each song’s DATA is structured as follows: 1. Song name string (e.g., `"Silent Night"`) 2. Tempo scalar `t` (a floating-point value tuned per song) 3. Alternating pairs: semitone offset `f`, duration divisor `v` Duration divisors appear as arithmetic expressions directly in the DATA (e.g., `8/3`, `4/3`), which BASIC evaluates when read, providing fractional beat lengths for dotted notes without requiring floating-point literals to be hand-calculated. ### Notable Techniques - Using `ON ERR` as a natural end-of-data signal avoids the need for a terminator value or note count. - Arithmetic expressions in DATA lines (e.g., `8/3`) allow compact notation of triplet and dotted rhythms. - The `RESTORE n*200+810` trick skips the song header to enable seamless looping without re-reading the name or tempo. - The rest sentinel value 99 is handled by branching at line 140 before BEEP is called, avoiding an out-of-range frequency error. - `PAUSE 0` followed by `INKEY$` at line 220 is used as an efficient single-keypress wait. ### Potential Issues - The continuous-play `RESTORE n*200+810` assumes the song name and tempo occupy exactly two DATA items starting at offset +800, which holds for all three songs but would break if the header DATA were on a different relative line. - Line 220 sets `z$` and immediately checks it, but the `ON ERR GO TO 170` is only re-armed when playback starts at line 130 — if the user re-selects via line 90, the trap is re-armed correctly on the next pass through line 130. ## Source Code ``` 10 BORDER 4: PAPER 6: CLS : FOR a=0 TO 12 20 PRINT INK 1;"CHRISTMAS MUSIC";TAB 17; INK 3;"CHRISTMAS MUSIC": NEXT a 30 PRINT AT 18,1; PAPER 5;"Press ENTER to select a song" 40 PAUSE 0 50 CLS : PRINT PAPER 5;"****** Table of Contents *******": PRINT ''''''' 60 FOR i=1 TO 3: RESTORE i*200+800: READ n$: PRINT i;TAB 4;n$: NEXT i 70 PRINT PAPER 5;AT 20,0;"Enter the number of the composi-tion that you want to play " 80 INPUT n: CLS : LET z$="" 90 RESTORE n*200+800: READ n$,t 100 CLS : PRINT PAPER 5;"********* Now Playing **********";AT 21,0;"********* Now Playing **********" 110 PRINT AT 10,(31-LEN n$)/2;n$ 120 PRINT PAPER 3; INK 7;AT 20,0;" To stop, press SHIFT + BREAK " 130 READ f,v: ON ERR GO TO 170 140 IF f<>99 THEN GO TO 160 150 PAUSE t/v*60: GO TO 130 160 BEEP t/v,f: GO TO 130 170 ON ERR RESET : IF z$="2" THEN RESTORE n*200+810: GO TO 130 180 CLS : PAPER 7: PRINT AT 7,0;"Press 1 to play again. " 190 PRINT "Press 2 to play continuously. " 200 PRINT ;"Press 0 to play another song. " 210 PAPER 6 220 PAUSE 0: LET z$=INKEY$: IF z$="1" OR z$="2" THEN GO TO 90 230 IF z$="0" THEN GO TO 50 1000 DATA "Silent Night",1.8 1010 DATA 7,8/3,9,8,7,4,4,4/3,7,8/3,9,8,7,4,4,4/3,14,2,14,4,11,4/3,12,2,12,4,7,4/3,9,2,9,4,12,8/3,11,8,9,4,7,8/3 1020 DATA 9,8,7,4,4,4/3,9,2,9,4,12,8/3,11,8,9,4,7,8/2,9,8,7,4,4,4/3,14,2,14,4,17,4,14,4,11,4,12,4/3,16,1,12,4 1030 DATA 7,4,4,4,7,4,5,4,2,4,0,1 1200 DATA "Jingle Bells",.8 1210 DATA 13,4,13,4,13,4,99,4,13,4,13,4,13,4,99,4,13,4,16,4,9,4,11,4,13,4/3,99,4,14,4,14,4,14,4,14,4,14,4,13,4 1220 DATA 13,4,99,4,13,4,11,4,11,4,13,4,11,4,99,4,16,4,99,4,13,4,13,4,13,4,99,4,13,4,13,4,13,4,99,4,13,4,16,4 1230 DATA 9,4,11,4,13,4/3,99,4,14,4,14,4,14,4,14,4,14,4,13,4,13,4,99,4,16,4,16,4,14,4,11,4,9,4,99,4,21,4,99,4 1400 DATA "Joy to the World",2.5 1410 DATA 24,4,23,5.33,21,16,19,2.67,17,8,16,4,14,4,12,8/3,19,8,21,2.67,21,8,23,2.67,23,8,24,2,99,16,24,8,24,8,23,8,21,8,19,8,19,5.33 1420 DATA 17,16,16,8,24,8,24,8,23,8,21,8,19,8,19,5.33,17,16,16,8,16,8,16,8,16,8,16,8,16,16,17,16,19,16/5,99,16,17,16,16,16,14,8 1430 DATA 14,8,14,8,14,16,16,16,17,16/5,99,16,16,16,14,16,12,8,24,4,21,8,19,5.33,17,16,16,8,17,8,16,4,14,4,12,2 ```