Real Echo Example

This file is part of Byte Power December 1986 - January 1987 . Download the collection to get this file.
Date: 1987
Type: Program
Platform(s): TS 2068

This program plays a two-voice rendition of the Toccata by Leonardo Leo with a real-time echo effect using the SOUND command. Voice 1 carries the main melody loaded from a binary block at address 60003, while Voice 2 plays the same music but offset by a configurable delay stored at address 60000 (initially set to a PAUSE/254 rest). Each note is encoded as a three-byte triplet: pitch, second parameter, and duration, in a format described as MUSIcomp-compatible. The volume of the echo voice (channel 9) is intentionally set lower (12 vs. 15) than the main voice (channel 8) to simulate natural echo decay. The program saves both the BASIC loader and a 895-byte machine code music data block to tape, and reloads them together with a single RUN.


Program Structure

The program is organized into a short initialization phase, a main playback loop, two subroutines for advancing note pointers, and a tape save/load section at the end.

  1. Lines 6–10: Initialize voice pointers v1 (60003) and v2 (60000), and poke a REST byte (254) and duration (1) at v2 so the echo starts one note behind.
  2. Lines 15: Prime both voices by calling subroutines 100 and 200 to load the first note of each voice into working variables.
  3. Lines 35–70: Main loop — checks for end-of-music, sets volumes, plays via SOUND, pauses for tempo, decrements duration counters, and fetches the next note when a voice’s counter expires.
  4. Lines 100–120 / 200–220: Subroutines that PEEK the three-byte note record (pitch, second parameter, duration) and advance the respective pointer by 3.
  5. Lines 9000 / 9999: Tape utilities — LOAD ""CODE 60003 loads the music data then RUNs the program; line 9999 saves both the BASIC and 895-byte code block.

Note Data Format

The music is stored as a flat array of 3-byte records starting at address 60003, described as MUSIcomp-compatible. Each record contains:

OffsetVariableMeaning
+0a1 / b1Pitch value passed to SOUND channel register 0 or 1 (or 254=rest, 255=end)
+1a2 / b2Second SOUND parameter (e.g., octave/fine tune) passed to register 1 or 3
+2a3 / b3Duration in loop ticks (decremented each iteration; fetch next note when zero)

The 895-byte code block spans addresses 60003 to 60897, accommodating up to 298 three-byte note records for the main melody, preceded by a short echo-delay header at 60000–60002.

Echo Mechanism

The echo is achieved entirely in BASIC without a second melody data set. Voice 2’s pointer v2 is initialized to 60000 — three bytes before the main melody at 60003. The bytes at 60000–60002 are pre-set by lines 10 to 254, ?, 1 (a one-tick rest), so Voice 2 starts one note-event behind Voice 1. As both pointers advance through the same music data at their own rates, Voice 2 always lags Voice 1, producing the echo. The REM at line 5 notes that the delay (pause) duration is controlled by POKE V2+2,1, making the lag adjustable.

SOUND Command Usage

Line 50 issues a single compound SOUND statement addressing seven AY registers in one call:

  • 8,a4 — Channel A amplitude (main melody volume, 0–15)
  • 9,b4 — Channel B amplitude (echo volume, fixed lower at 12 vs. 15)
  • 7,60 — Mixer register, value 60 (binary 00111100) enables tone on channels A and B, disables noise
  • 0,a1; 1,a2 — Channel A coarse and fine pitch
  • 2,b1; 3,b2 — Channel B coarse and fine pitch

Lines 110 and 210 perform a brief volume-duck before each new note (SOUND 8,14 / SOUND 9,11) to introduce a slight gap between consecutive notes of the same pitch, preventing them from blurring together. The REM explicitly notes this is kept non-zero for “smoother delivery.”

Key BASIC Idioms and Techniques

  • Compound LET statements on a single line (e.g., line 105) minimise line overhead and slightly speed up execution.
  • Duration counters a3/b3 are decremented in the main loop and subroutines are called only on expiry, avoiding unnecessary PEEK operations every tick.
  • The termination check at line 35 requires both voices to signal end-of-music (255) before stopping, preventing premature exit if the two voices have different lengths.
  • PAUSE 4 at line 55 provides a fixed tempo tick; adjusting this value would change playback speed globally.

Content

Appears On

Related Products

Related Articles

This month I will talk about the ‘REAL ECHO’. This one is a little more complicated than the ‘FALSE ECHO’...

Related Content

Image Gallery

Real Echo Example

Source Code

1 REM                                                        REAL ECHO                       WRITTEN BY E & K BOISVERT       ©1986 BYTE POWER                                                TOCCATA BY Leonardo Leo          
    5 REM V1=ADDRESS OF MAIN              MUSIC                                                           V2=ADDRESS OF ECHO              AT FIRST V2 STARTS AT           A PAUSE (DELAY OF ECHO) 
    6 LET v1=60003: LET v2=60000
    9 REM POKE V2,254 FOR THE             DELAY (PAUSE)                                                   POKE V2+2,1 DURATION            OF DELAY                
   10 POKE V2,254: POKE V2+2,1
   14 REM FIND FIRST NOTES OF             VOICE 1 & 2               
   15 GO SUB 100: GO SUB 200
   30 REM 255=END OF MUSIC                254=REST (PAUSE)            (MUSIcomp COMPATIBLE DATA)    
   35 IF a1=255 AND B1=255 THEN STOP 
   39 REM A4 & B4 ARE THE VOLUME          OF VOICE 1 & 2          
   40 LET a4=15: IF a1>=254 THEN LET a4=0
   43 REM VOLUME OF VOICE 2               (ECHO) HAS TO BE LOWER          TO CREATE EFFECT         
   45 LET b4=12: IF b1>=254 THEN LET b4=0
   49 REM PLAY NOTES              
   50 SOUND 8,a4;9,b4;7,60;0,a1;1,a2;2,b1;3,b2
   54 REM TEMPO (PAUSE 4)         
   55 PAUSE 4
   59 REM A3 & B3 DURATION OF             NOTE IF EQUAL 0 THEN            FIND NEXT NOTE          
   60 LET a3=a3-1: IF a3=0 THEN GO SUB 100
   65 LET b3=b3-1: IF b3=0 THEN GO SUB 200
   69 REM COMPLETE LOOP             
   70 GO TO 35
  100 REM FIND NOTE OF VOICE 1            AND ADD 3 TO V1                 (NEXT NOTE OF VOICE 1)  
  105 LET a1=PEEK v1: LET a2=PEEK (v1+1): LET a3=PEEK (v1+2): LET v1=v1+3
  109 REM LOWER VOLUME                    (IF NOT PAUSE OR END)           TO SEPARATE NOTES               (NOT 0 FOR SMOOTHER              DELIVERY)              
  110 IF A1<254 THEN SOUND 8,14
  120 RETURN 
  200 REM FIND NOTE OF VOICE 2            AND ADD 3 TO V2                 (NEXT NOTE OF VOICE 2)  
  205 LET b1=PEEK v2: LET b2=PEEK (v2+1): LET b3=PEEK (v2+2): LET v2=v2+3
  209 REM LOWER VOLUME                    (IF NOT PAUSE OR END)           TO SEPARATE NOTES               (NOT 0 FOR SMOOTHER              DELIVERY)              
  210 IF B1<254 THEN SOUND 9,11
  220 RETURN 
 8999 REM LOAD CODES FOR MUSIC    
 9000 LOAD ""CODE 60003: RUN 
 9999 SAVE "REAL ECHO" LINE 9000: SAVE "MUSIC"CODE 60003,895: VERIFY "REAL ECHO": VERIFY "MUSIC"CODE

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

Scroll to Top