Duo-Voice (Beep)

This file is part of Byte Power Spring 1987 . Download the collection to get this file.
Developer(s): Kristian Boisvert
Date: 1987
Type: Program
Platform(s): TS 2068

This program implements a dual-voice music player using the BEEP command, reading note data from two separate blocks of machine-code-stored data in RAM. Voice 1 data is loaded starting at address 50000 (V1) and Voice 2 at 50250 (V2); each note is encoded as two consecutive bytes — pitch value and duration counter respectively. The main loop decrements per-voice counters and fetches the next note via PEEK when the counter reaches zero, then plays both notes in rapid alternation with BEEP .015 to simulate simultaneity. A sentinel value of 255 signals end-of-tune, and a value ≥254 indicates a rest/pause for that voice, which is handled by substituting the other voice’s current note while preserving the original counter. Music data is stored separately as a CODE file named “DUO-MUSIC” loaded to address &H C350 (50000 decimal), spanning 495 bytes.


Program Structure

The program is divided into clearly commented sections, each introduced by a REM block:

  1. Lines 0–10: Variable initialisation. V1 and V2 are set to the base addresses of the two note streams (50000 and 50250). A, A1, B, B1 are zeroed.
  2. Lines 20–70: Main playback loop. Primes both voices (line 20), then enters a tight loop (lines 30–70) that decrements counters, fetches new notes as needed, handles special values, plays both notes, and loops.
  3. Lines 100–120: Subroutine to fetch the next note for Voice 1 via PEEK.
  4. Lines 200–220: Equivalent subroutine for Voice 2.
  5. Lines 9000, 9999: Loader and saver lines for both the BASIC program and the music data CODE block.

Data Format

Each note in the data stream is encoded as two consecutive bytes stored in RAM:

Byte offsetVariableMeaning
+0A / BPitch value (MUSIcomp format; subtract 36 to get semitone offset for BEEP)
+1A1 / B1Duration counter (number of loop iterations to hold this note)

Voice 1 occupies addresses 50000–50249 (250 bytes = 125 notes maximum). Voice 2 occupies 50250–50494 (245 bytes = ~122 notes). The total CODE block is 495 bytes.

Special Sentinel Values

  • 255 — End of music marker. Line 42 halts execution; lines 100 and 200 also guard against overrunning the buffer by returning early once this value is encountered.
  • ≥254 — Rest/pause for a voice. Line 45 handles both voices resting simultaneously with a PAUSE 1. Lines 50 and 55 handle single-voice rests by substituting the other voice’s current pitch, so BEEP still sounds but the resting voice’s counter continues to count down independently.

Dual-Voice Simulation Technique

True simultaneous dual-voice output is not possible with a single BEEP channel. The program approximates polyphony by playing two very short BEEP .015 calls (15 ms each) back-to-back at line 60. At 30 ms per combined pair, the rapid alternation creates the auditory illusion of two concurrent voices — a common technique on single-channel hardware.

The pitch calculation A-36 and B-36 offsets the MUSIcomp data format (which apparently stores semitones with a +36 bias) into the semitone range expected by the BEEP command relative to middle C.

Counter-Based Timing

Rather than encoding note duration directly in milliseconds, each note carries a loop-iteration counter in its second byte (A1 / B1). The counter is decremented once per main loop iteration (lines 30 and 35). Since each iteration plays two 15 ms BEEPs (plus BASIC overhead), the actual note duration is approximately A1 × 30 ms plus interpreter overhead. This keeps timing relative and consistent between voices.

Content

Appears On

Tape-based magazine.

Related Products

Related Articles

Last month we thought we were finished with the SOUND EFFECTS but we found a method of creating a simulated...

Related Content

Image Gallery

Duo-Voice (Beep)

Source Code

    0 
    1 REM DUO-VOICE (BEEP)       
    2 REM RESET 1987 BYTE POWER       
    3 REM WRITTEN BY K. BOISVERT 
    4 
    5 REM INITIALISE VARIABLES
    6 LET A=0: LET A1=0: LET B=0: LET B1=0
   10 LET V1=50000: LET V2=50250
   19 REM GET FIRST NOTES
   20 GO SUB 100: GO SUB 200
   29 REM COUNTER FOR VOICE 1             IF 0 THEN GET NEXT NOTE
   30 LET A1=A1-1: IF A1=0 THEN GO SUB 100
   34 REM COUNTER FOR VOICE 2             IF 0 THEN GET NEXT NOTE
   35 LET B1=B1-1: IF B1=0 THEN GO SUB 200
   41 REM CHECK IF END OF MUSIC           YOU MAY NEED TO CHANGE          THIS FOR YOUR OWN WAY           OF KNOWING WHEN MUSIC           IS FINISHED            
   42 IF A=255 THEN STOP 
   44 REM CHECK IF BOTH A PAUSE
   45 IF A>=254 AND B>=254 THEN PAUSE 1: GO TO 30
   49 REM IF ONLY VOICE 1 IS A            PAUSE THEN PLAY THE             SAME NOTE AS VOICE 2            BUT STILL USING COUNTER         FOR VOICE 1            
   50 IF A>=254 THEN LET A=B
   54 REM IF ONLY VOICE 2 IS A            PAUSE THEN PLAY THE             SAME NOTE AS VOICE 2            BUT STILL USING COUNTER         FOR VOICE 2            
   55 IF B>=254 THEN LET B=A
   59 REM PLAY THE NOTES ONE              RIGHT AFTER THE OTHER           A-36 AND B-36 MEANS             MUSIcomp DATA -36 (TO           GET THE RIGHT NOTE, SEE         SEE MUSIcomp V1.1)              IF YOU PUT YOUR OWN             DATA YOU WILL NOT NEED          TO ALTER THE VALUES OF          A OR B. IF YOU WANT AN          OCTAVE HIGHER, JUST ADD         [-/+] 12 TIMES THE # OF         OCTAVES TO BE ADDED OR          SUBSTRACTED. IE:IF YOU          WANT 3 OCTAVES LOWER,           SUBSTRACT 36.          
   60 BEEP .015,A-36: BEEP .015,B-36
   69 REM COMPLETE LOOP
   70 GO TO 30
   99 REM IF VOICE FINISHED THEN          DO NOT GET ANY MORE             NOTES                  
  100 IF A=255 THEN RETURN 
  109 REM GET NEXT NOTE OF VOICE1
  110 LET A=PEEK V1: LET A1=PEEK (V1+1): LET V1=V1+2
  120 RETURN 
  199 REM IF VOICE FINISHED THEN          DO NOT GET ANY MORE             NOTES                  
  200 IF B=255 THEN RETURN 
  209 REM GET NEXT NOTE OF VOICE2
  210 LET B=PEEK V2: LET B1=PEEK (V2+1): LET V2=V2+2
  220 RETURN 
 8999 REM LOADER
 9000 LOAD "DUO-MUSIC"CODE 5E4,495: RUN 
 9998 REM SAVE PROGRAM
 9999 SAVE "DUO-VOICE" LINE 9000: SAVE "DUO-MUSIC"CODE 5E4,495

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top