Sounding Out the Micro (Part 1)
Over the past few months, the Macromusic series has taken us from the humble beginnings of mainframe computers, squawking at each other in the confines of the Bell Telephone Labs to the high-tech wonder of the Lucasfilm Audio Signal Processor blasting Death Stars and the entire 'little people' population of the United States. Now, it's time to start off on a new tack with more immediate practical relevance, namely the synthesis of sound on microcomputers.
For the moment, though, how one actually gets sounds out of the computer is less important than some decision-making as to the nature of the fundamental parameters that constitute sound, which of these need to be varied in something approaching a musical context, and how all this can be best (or easily) achieved.
The starting point of sound synthesis is a series of operations that define two parameters — the frequency and the duration. Both of these involve the essential ingredient of the passage of time; with frequency, the time factor applies to the gap between one event and the next at the level of something like a waveform, ie. between the amplitude high states of square waves; with duration, we're concerned about a timing level one stage up, ie. between one sound (with a certain timing gap) and the next (with a different timing gap). So, the one crucial aspect of sound that needs working on from the word go is time.
One way to ensure that different frequencies and different durations have their say is by making use of the fact that micros can be very accurate time-keepers if they're given the right kind of instructions. In fact, the fundamental concept to ground level micro music is the 'timed loop', a series of instructions that will be entirely consistent in their speed of execution from one minute, hour, or day to the next. By choosing instructions that will both slow execution times down sufficiently to produce oscillations in the audio frequency range, and also effect, by fair means or foul, an analogue output to the waiting world, one should have succeeded in creating a simple digital oscillator capable of sound synthesis at a basic level.
So, what options are available for projecting a micro's timed loop oscillations to the outside world? Well, early micro music enthusiasts quickly discovered various short-cuts to digital-to-analogue conversion, including some that were ingenious, some that were a dead-end, and some that were just plain quirky. In fact, one particular method didn't even involve a direct connection to the micro! This was based on the chance observation that an AM radio tuned to a spare frequency, placed close to the computer, generated sounds as a result of fast-switching computer logic spewing out harmonics that extended into the radio frequency end of the spectrum. By altering instructions in the timed loop, it was actually possible to vary the timbre of sound, but, because of all the other logic switching going on in the average computer, the technique was incredibly noisy and erratic. In the States, RF interference from micros is considered detrimental to public health (like most things that are fun), and most new micros are now obliged to have some form of shielding against such electro-magnetic interference. However, if you're interested in following up this particular historical avenue, the Apple II and Video Genie micros are both pretty effective at making themselves out to be pirate radio stations in sheep's clothing.
Another early method of making the computer annunciate its timing loops centred around the use of a line printer. Hookups between some early computers and their printers gave the computer software control over the action of the printer hammer. By using a timing loop program again, it was fairly easy to make the hammer buzz away over a limited range of pitches. In fact, you could probably replicate the effect on a modern dot-matrix printer, but it's unlikely that anyone (let alone the printer itself) would really benefit from the exercise.
However, there is a modern alternative that's easily tried out which doesn't involve damage to either ear drums or printing heads, ie. the cassette relay on the BBC Micro. The Operating System command *MOTOR switches the relay on (*MOTOR 1) or off (*MOTOR 0), which, in turn, is designed to similarly switch the cassette motor on and off (though I've yet to hear of anyone bothering to do it). Writing a program that repeatedly toggles between these states will instruct the machine to manically flap the cassette relay, and, like the prior inflictions on the printer hammer, that action manifests itself as sound.
10 REM Hammer-klavier program
20 REM for the BBC Micro
50 DATA 12,11,10,9,8,7,6,5,4,3
60 FOR note%=0 TO 9
70 READ pitch%
80 FOR X%=0 TO 15
90 *MOTOR 0
100 FOR Y%=1 TO 3: NEXT
110 *MOTOR 1
120 FOR Z%=0 TO pitch%*5: NEXT
150 UNTIL 0
This program, simple as it is, actually demonstrates pretty well a couple of salient features about the use of timed loops in a sound synthesis context. Basically, Life, the Universe and Everything centres around three nested FOR... NEXT loops. One of these, namely the delay loop on line 100, in between the *MOTOR commands, is peculiar to this program and simply makes sure that the relay isn't toggled off and on at a rate that's beyond its innate capabilities. On some machines, a fast-responding relay may allow one to get away without it, but, on my machine, the loop has to be there to prevent the thing jamming up.
The loop starting on line 80 determines the number of passages around the relay toggling circuit before going on to the next value of pitch%. So, this delay loop effectively determines the duration of a 'note'. The third loop starting on line 120 is the other important practical realisation of our earlier discussion about basic sound parameters. Using values of pitch% read out of the DATA statement, this sets the gap between one off/on toggle of the relay and another, thereby determining the period between the individual relay clicks and, therefore, the frequency of the resultant buzz.
As it stands, the program merely churns out a repeating (sort of) scalic sequence and flashes the cassette motor LED in time — son et lumièrè a la BBC, one might say. Changing the values in the DATA statement should allow something like a tune to be played provided you can reach some sort of conclusions as to the scaling relationship between d% values and pitch. A potentially useful application of the relay-toggling effect is as an apoplexy-inducing sound effect in games and the like. For instance if you change line 120 to 120 FOR Z%=0 TO pitch%: NEXT and replace the REM statements with
10 ENVELOPE 1,1,127,-21,-1,255,121,231,127,-1,0,-127,126,126
you'll then have invader swoops plus an extremely dirty 'grunging' sound coming from within the innards of your BBC Micro. Not for the faint of heart, though.
Well, red herrings and fun aside, what are the other options for sending some sort of manifestation of timing loop machinations to the outside world? Firstly, there's the option of using the cassette port, which, on some machines, can actually allow a two-way exchange of sound info, in addition to the usual loading and saving of data. Thus, the cassette port on the Apple II has been used for such diverse applications as speech synthesis, speech sampling, two- and three-part music synthesis, sending and receiving tape syncs, producing metronomes and click tracks, and as an input for a software-based spectrum analyzer! Remember that all that's achieved with output and input circuitry which is only capable of sending or reading an on or off state (just like the cassette relay, in fact), ie. giving just a single bit of resolution. Note, however, that not all micros provide anything like a free passage to and from the cassette port (the BBC Micro being a case in point) and there are certain reasons why the Apple is uncannily effective as regards these sorts of tricks.
A second possibility is just to use one of the output port bits, with a speaker connected via some suitable hardware. By then toggling this port with POKEs, the speaker cone can be made to flap itself into square wave ecstasy. For instance, if we were playing around with the ZX81 that's now confined to use as an elegant door stop since we got a BBC Micro, and assuming that the LSB of the output port is our focus of attention (address = 11000), then the following few lines will give you a buzz!
10 REM 777777
30 FOR A=1 TO 200
40 POKE 11000,1
50 POKE 11000,0
60 NEXT A
Again, there's a FOR... NEXT loop (from line 30) that's responsible for establishing the duration of the emerging buzz. We could also insert a further loop, using a sequence of values read out of a DATA statement or two to do something about altering the frequency from time to time. The only drawback to this honourable intention is that, like the sounding-out program using the BBC Micro's cassette relay, the range of frequencies will be limited to something of the order of a few hundred Hertz. In this case, the main problem doesn't lie with a relatively immovable bit of mechanics like a relay but with the limited speed of the ZX81's BASIC interpreter. However, there is a solution to the limited frequency range, and that's to use a machine code subroutine that does all the necessary bit toggling.
One of the other problems with the ZX81 is the lack of input/output port facilities, so it's really a lot more straightforward to toggle the mic output of the infamous cassette port — unless, of course, you've got the necessary port circuitry conveniently to hand (the circuit shown on p.68 of the January 1982 issue of E&MM, for instance) — and most basic music programs for the ZX81 seem to follow this tact.
|NEXT:||OUT||(0FFH),A||;Output contents of accumulator (A) to port|
|LD||B,150||;Load register B with delay of 150|
|LOOP:||DJNZ||LOOP||;Decrement B by 1, if not zero remain in LOOP|
|INC||A||; increment A by 1|
|JR||NEXT||;Return to 1st instruction and output bit value|
|0300-||A2||00||LDX||#$00||;Load register X|
|0302-||20||1E||FB||JSR||$FB1E||;Jump to paddle-reading routine (value to X plus accumulator scrambled)|
|0305-||8D||30||C0||STA||$C030||;Accumulator contents to location $C030 (speaker toggle)|
|0309-||20||1E||FB||JSR||$FB1E||;Jump to paddle-reading routine|
|030C-||8D||30||C0||STA||$C030||;Accumulator contents to $C030|
|030F-||4C||00||03||JMP||$0300||;Jump back to beginning of routine|
mu:zines is the result of thousands of hours of effort, and will require many thousands more going forward to reach our goals of getting all this content online.
If you value this resource, you can support this project - it really helps!