This program demonstrates a two-voice simultaneous beeper routine driven by relocatable machine code loaded at address 50000 (5e4). Two system variables at addresses 23728 and 23729 control the pitch of each voice independently, while POKEs at offsets +21 and +27 within the machine code block set the border colour for each voice channel. The BASIC driver demonstrates two sound effects: a sine-wave-like sweep achieved by feeding ABS values of a −250 to 250 loop into the pitch registers, and a plain two-voice beep using simple multiplied indices. The machine code block is only 49 bytes long and is saved and verified separately from the BASIC loader at line 9999.
Program Structure
The program is organised into four functional areas:
- REMs (lines 0–7): Document the machine code interface — duration offset, pitch addresses, border colour offsets within the MC block.
- Sine-wave demo (line 100): Calls the subroutine at 300 for a title banner, then sweeps a variable
xfrom −250 to 250 in steps of 8, pokingABS xandABS (x+4)into 23728/23729 to produce a rising-then-falling two-voice sweep. Duration is fixed at 255/0 (high byte/low byte → 255 iterations). Repeated 4 times viaz. - Plain beep demo (line 200): Uses a simple 1–4 loop, poking
x*4andx*5as pitches with a short duration (10). Repeated 4 times. - Utility lines: Line 300 is a CLS/banner subroutine. Line 9000 is the autostart loader (
LOAD ""CODE 5e4: RUN). Line 9999 handles saving both the BASIC and the 49-byte MC block, then verifies both.
Machine Code Interface
The machine code block resides at address 50000 (5e4) and is exactly 49 bytes long. The BASIC communicates with it through a well-documented set of POKEs:
| Address / Offset | Purpose |
|---|---|
23728 (STRMS+8 area) | Pitch of Voice 1 (2–255) |
23729 | Pitch of Voice 2 (2–255) |
50002 (MC base+2) | Duration low byte |
50003 (MC base+3) | Duration high byte |
50021 (MC base+21) | Border colour for Voice 1 channel (+8 per REM) |
50027 (MC base+27) | Border colour for Voice 2 channel (+24 per REM) |
The MC is described as relocatable, meaning these offsets are self-consistent regardless of load address, as long as the BASIC POKEs are adjusted to match the actual load address.
Notable BASIC Techniques
RANDOMIZE USR 5e4— uses floating-point scientific notation as a compact way to write 50000, saving a byte in the BASIC token stream compared to typing50000.GO SUB 300is reused before each demo section to clear the screen and print the copyright banner to stream 1 (the lower screen), keeping the display clean between modes.PRINT #1;AT 0,0;prints the banner to the lower screen (stream 1), leaving the main screen area free for the demo label printed atAT 10,0.- The
ABS x/ABS (x+4)technique in line 100 converts a bipolar sweep (−250 to 250) into a V-shaped unipolar pitch curve, producing a descend-then-ascend frequency sweep across both voices with a fixed phase offset of 4. - Line 9999 uses
SAVE ... LINE 9000to embed the autostart line number, so the tape loads and immediately chains to the MC loader.
Two-Voice Mechanism
True simultaneous two-voice audio on a single-bit beeper is achieved by rapidly alternating between two square-wave toggling routines at different frequencies within the machine code loop. The border colour changes at each toggle (offsets +21 and +27) are a side-effect of using the OUT (254),A instruction which controls both the EAR/MIC bits and the border colour simultaneously — a standard technique in Spectrum beeper engines. The REM notes at lines 6–7 document these offsets so the programmer can set border colour independently per voice.
Content
Source Code
0 REM Two Voice Beep Written By E Boisvert ©1987 BYTE POWER
2 REM MC RELOCATABLE
3 REM (ADDR OF MC)+2=DURATION (1-65535)
4 REM 23728/9 Pitch Voice 1&2
5 REM PITCH (2 TO 255)
6 REM ADDR+21,BORDER COLOR+8
7 REM ADDR+27,BORDER COLOR+24
10
100 GO SUB 300: PRINT AT 10,0;"SINE WAVE SOUND": FOR z=1 TO 4: FOR x=-250 TO 250 STEP 8: POKE 23728,ABS x: POKE 23729,ABS (x+4): POKE 50002,255: POKE 50003,0: RANDOMIZE USR 5e4: NEXT x: NEXT z
200 GO SUB 300: PRINT AT 10,0;"PLAIN 2 VOICE BEEP": FOR z=1 TO 4: FOR x=1 TO 4: POKE 50002,0: POKE 50003,10: POKE 23728,x*4: POKE 23729,x*5: RANDOMIZE USR 5e4: NEXT x: NEXT z
250 GO TO 100
300 CLS : PRINT #1;AT 0,0;"©1987 BYTE POWER By E Boisvert": RETURN
9000 LOAD ""CODE 5e4: RUN
9999 SAVE "2 BEEP" LINE 9000: SAVE "2. V. BEEP"CODE 5e4,49: VERIFY "": VERIFY ""CODE
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
