MUSIC PLAY is a TS2068 program that drives the AY-3-8912 sound chip using raw register writes via the SOUND keyword to play a sequence of musical notes stored as binary data loaded into memory at address 60000. Each note is encoded as three bytes: a fine-tuning value, a coarse-tuning value, and a pause/duration byte, with the sentinel value 255 marking the end of the sequence and 254 indicating a silent pause. The program uses a metallic timbre by configuring envelope generator registers 8, 9, 12, and 13 alongside the mixer register 7. A companion binary file “MUSIC DEMO” of 1594 bytes is saved and loaded separately at address 60000 (6e4 in scientific notation), and a self-list protection check at line 15 uses PEEK 23681 to detect whether a proper entry point was used.
Program Structure
The program is split into two functional segments. Lines 10–160 form the playback engine, and lines 9000–9030 handle loading the companion data file before jumping back to the start. Line 9999 is a standalone save/verify utility and is never reached during normal execution.
- Initialisation (lines 20–30): Sets
tempo(default 5) andstart(default 60000). - Main loop (lines 35–100): Reads three bytes from the data block, interprets them, plays or pauses, waits, and loops.
- Termination (lines 150–160): Reached when the sentinel byte 255 is encountered; executes
STOP. - Data loader (lines 9000–9030): Loads the binary “MUSIC DEMO” file to address 60000 and restarts.
- Save utility (line 9999): Saves both the BASIC program (auto-starting at line 9000) and the 1594-byte data block, then verifies both.
Data Format
Each note record occupies exactly three consecutive bytes starting at start:
| Offset | Variable | Meaning |
|---|---|---|
| +0 | fine | AY fine pitch / control byte (254 = rest, 255 = end) |
| +1 | coarse | AY coarse pitch |
| +2 | pause | Duration unit (multiplied by tempo for PAUSE, by 5 for envelope period) |
The pointer start is advanced by 3 on every iteration at line 40, providing a simple sequential traversal with no array overhead.
AY Sound Chip Usage
Line 70 issues a single chained SOUND statement writing seven AY-3-8912 registers in one call:
0, fine— Channel A fine pitch (low 8 bits)1, coarse— Channel A coarse pitch (high 4 bits)2, fine+1— Channel B fine pitch (slight detuning for a chorus/metallic effect)3, coarse— Channel B coarse pitch8, 16— Channel A amplitude: envelope-controlled mode9, 16— Channel B amplitude: envelope-controlled mode7, 60— Mixer: channels A and B tone enabled, noise off (binary 00111100)13, 0— Envelope shape: hold-decay12, pause*5— Envelope period coarse (duration scales with note length)
Detuning Channel B by one fine-pitch unit (fine+1) relative to Channel A produces the characteristic metallic beating timbre referenced in the comment citing August and October magazine issues.
Control Flow and Sentinel Values
Rather than storing note counts or using a separate length variable, the loop relies on two magic byte values embedded in the data stream itself. fine=254 at line 50 branches past the SOUND call (to line 80) to produce a rest of the specified duration. fine=255 at line 60 exits the loop entirely. This is an economical, data-driven termination scheme.
Entry-Point Protection
Line 15 reads system variable address 23681 (PEEK 23681). If this value is zero the program executes CLS : LIST 9999: STOP, exposing the save/verify line rather than running the player. This acts as a simple guard ensuring the program is entered via the data-loading path at line 9000 (where the LOAD would have set up prerequisites) rather than run cold from line 10.
Notable BASIC Idioms
LOAD "MUSIC DEMO"CODE 6e4— The target address 60000 is written in scientific notation (6e4), a common TS2068 memory optimisation that saves tokenised bytes compared to the full integer literal.SAVE "MUSIC PLAY" LINE 9000— The program auto-runs at line 9000, ensuring the data file is always loaded before playback begins.- The
tempovariable at line 20 provides a single point of adjustment for overall playback speed without touching the data; increasing it slows all notes proportionally.
Content
Source Code
10 REM MUSIC PLAY written by Eric Boisvert ©1986 BYTE POWER
15 IF PEEK 23681=0 THEN CLS : LIST 9999: STOP
20 LET tempo=5: REM tempo
30 LET start=60000: REM start of data to play
35 REM LOOP TO READ AND PLAY
40 LET fine=PEEK start: LET coarse=PEEK (start+1): LET pause=PEEK (start+2): LET start=start+3
50 IF fine=254 THEN GO TO 80: REM if pause (254)
60 IF fine=255 THEN GO TO 150: REM if end (255)
65 REM SET UP FOR METALLIC SOUND and ENVELOPE GENERATIOR (see AUGUST & OCTOBER issues)
70 SOUND 0,fine;1,coarse;2,fine+1;3,coarse;8,16;9,16;7,60;13,0;12,pause*5
80 REM wait for note to finish
90 PAUSE tempo*pause
100 GO TO 35
150 REM END
160 STOP
9000 REM LOAD DATA FILE
9010 REM NOTES MAY BE ANY WHERE
9020 LOAD "MUSIC DEMO"CODE 6e4
9030 GO TO 10
9999 SAVE "MUSIC PLAY" LINE 9000: SAVE "MUSIC DEMO"CODE 6e4,1594: VERIFY "": VERIFY ""CODE
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
