This program generates procedurally randomised synthesiser sounds using the SOUND statement, which maps directly to the AY-3-8912 sound chip. The first section (lines 10–50) produces a sweeping tone by iterating through a randomly determined frequency range with a random step value, then cuts the envelope. Lines 60–80 introduce probabilistic branching: a one-in-two chance of a random pause and a one-in-four chance of jumping to a second sound routine, otherwise looping via RUN. The second section (lines 90–160) creates percussive noise bursts by configuring the noise channel (register 6) and mixing registers, with randomised envelope period and shape values, separated by short busy-wait loops using empty FOR–NEXT. Both sections ultimately loop back with RUN, making the program a continuous generative ambient sound machine.
Program Structure
The program divides into two distinct sound-generation blocks, connected by probabilistic branching:
- Sweep section (lines 10–80): Configures the AY chip’s tone channel, sweeps through a random frequency range, then either loops (
RUN) or falls through to the noise section. - Noise burst section (lines 90–160): Generates rhythmic noise pulses with randomised envelope parameters inside a double FOR–NEXT loop, then unconditionally restarts via
RUN.
AY-3-8912 Register Usage
The SOUND keyword on the TS2068 writes directly to AY-3-8912 registers. The following registers are referenced:
| Register | Function | Used at lines |
|---|---|---|
| 0 (fine pitch) | Channel A tone period low byte | 30 |
| 6 | Noise period | 120 |
| 7 | Mixer control (enable/disable tone & noise per channel) | 10, 120, 150 |
| 8 | Channel A amplitude / envelope flag | 10, 120, 150 |
| 9 | Channel B amplitude | 10, 120, 150 |
| 10 | Channel C amplitude | 10, 120, 150 |
| 11 | Envelope period fine | 30, 120 |
| 12 | Envelope period coarse | 30, 50, 120 |
| 13 | Envelope shape / cycle | 30, 50, 120 |
Line 10 sets the mixer (7,62) to enable all tone outputs while muting noise, and silences channels B and C. Line 50 halts the envelope by writing 12,1;13,0. Line 150 restores a silent mixer state after the noise bursts.
Sweep Mechanism (Lines 20–40)
The FOR I loop at line 20 computes a random start value INT(RND*75)+25 (range 25–99), a random end value INT(RND*75)+20 (range 20–94), and a step of INT(RND*4)*2-5. The step expression yields values from the set {−5, −3, −1, 1} depending on INT(RND*4) ∈ {0,1,2,3}, meaning the sweep can ascend or descend. A step of 0 is impossible because the even multiples are offset by −5 giving only odd and negative-odd results.
Each iteration writes the loop variable I to register 0 (channel A fine pitch) while holding the envelope period and shape constant, producing an audible glide effect on the tone channel.
Probabilistic Flow Control (Lines 60–80)
Two independent random branches control program flow after the sweep:
- Line 60: 50% probability of a
PAUSElasting between 1 and 60 frames (~0.02–1.2 seconds at 50 Hz), adding irregular timing. - Line 70: 25% probability of jumping to the noise section at line 90; otherwise line 80 executes
RUN, restarting the entire program and re-seeding randomness from the existing R register state.
Using RUN rather than GO TO 10 is a deliberate idiom: it clears variables and re-enters the program from scratch, which also resets any BASIC overhead but preserves the pseudo-random sequence implicitly via elapsed time affecting RND.
Noise Burst Section (Lines 90–160)
The outer loop FOR J=RND*1 TO RND*10 at line 90 iterates a random number of times (the non-integer bounds are handled by BASIC’s standard loop rules; the count is effectively 0 to ~10). Inner loops at lines 100–110 and 130–140 are empty busy-wait delays, their duration randomised by INT(RND*4) and INT(RND*10) respectively.
Line 120 is the core noise event: register 6 sets noise period to 16; register 7 value 7 enables noise on all three channels while disabling tone; registers 8–10 all set to 16 enable hardware envelope control for all channels. The envelope period coarse (11, 300+INT(RND*10)) gives a slowly varying period around 300–309. Register 12 receives either 0 or 1 via INT(((RND*2)+.5)/2), and register 13 selects envelope shape 0 or 8 via INT(RND*2)*8, toggling between a single-decay and a continuous-repeat envelope.
Notable Techniques and Anomalies
- The
SOUNDstatement’s semicolon-separated register pairs allow an entire chip configuration to be written in a single BASIC statement, minimising interpreter overhead during time-sensitive sound setup. - Empty
FOR K … NEXT Kloops (lines 100–110, 130–140) serve as deterministic busy-wait delays — a common TS2068 idiom wherePAUSEresolution (one frame) is too coarse. - The expression
INT(((RND*2)+.5)/2)on line 120 is an unusual way to produce a biased coin: it yields 0 whenRND < 0.5and 1 otherwise, equivalent to simplyINT(RND*2), suggesting either stylistic preference or a copy/transcription artifact. - Both sections terminate with unconditional
RUN(lines 80 and 170), ensuring the program never halts during normal execution paths.
Content
Image Gallery
Source Code
10 SOUND 7,62;8,16;9,0;10,0
20 FOR I=INT (RND*75)+25 TO INT (RND*75)+20 STEP INT (RND*4)*2-5
30 SOUND 0,I;11,32;12,100;13,2
40 NEXT I
50 SOUND 12,1;13,0
60 IF INT (RND*2)=1 THEN PAUSE INT ((RND*60)+1)
70 IF INT (RND*4)=1 THEN GO TO 90
80 RUN
90 FOR J=RND*1 TO RND*10
100 FOR K=0 TO INT (RND*4)
110 NEXT K
120 SOUND 6,16;7,7;8,16;9,16;10,16;11,300+INT (RND*10);12,INT (((RND*2)+.5)/2);13,INT (RND*2)*8
130 FOR K=0 TO INT (RND*10)
140 NEXT K
150 SOUND 7,63;8,0;9,0;10,0
160 NEXT J
170 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.