Chapter 19: SOUND

BASin

Chapter 19: SOUND

Summary

BEEP, PLAY

Depending upon which model you are using, the Spectrum had two methods of generating sound. The original 48k model comes equipped with a loudspeaker, which is driven by the BEEP command. It is capable of outputting a single channel of sound (i.e, no more than one note at a time).

The 128k Spectrums have, as well as the loudspeaker, a sound chip called the AY-3-8912. This chip is capable of generating much more complex sounds, and can play up to three of them at once. The chip is driven using the PLAY command. Note that using the PLAY command will indicate to BASin that you are working on a 128k program. For information about this, and limitations the 128k BASIC has, see here.

The BEEP command

The loudspeaker is sounded by using the BEEP statement,

BEEP duration, pitch

where, as usual, 'duration' and 'pitch' represent any numerical expressions. The duration is given in seconds, and the pitch is given in semitones above middle C using negative numbers for notes below middle C.

Here is a diagram to show the pitch values of all the notes in one octave on the piano:

To get higher or lower notes, you have to add or subtract 12 for each octave that you go up or down.

The simplest way to compose a tune in BASin is to use the BEEP Composer, but here are some tips for creating a tune in code.

If you have a piano in front of you when you are programming a tune, this diagram will probably be all that you need to work out the pitch values. If, however, you are transcribing straight from some written music, then we suggest that you draw a diagram of the stave with the pitch value written against each line and space, taking the key into account.

For example, type:

10 PRINT "Frere Gustav"
20 BEEP 1,0: 
   BEEP 1,2: 
   BEEP .5,3: 
   BEEP .5,2: 
   BEEP 1,0
30 BEEP 1,0: 
   BEEP 1,2: 
   BEEP .5,3: 
   BEEP .5,2: 
   BEEP 1,0
40 BEEP 1,3: 
   BEEP 1,5: 
   BEEP 2,7
50 BEEP 1,3: 
   BEEP 1,5: 
   BEEP 2,7
60 BEEP .75,7: 
   BEEP .25,8: 
   BEEP .5,7: 
   BEEP .5,5: 
   BEEP .5,3: 
   BEEP .5,2: 
   BEEP 1,0
70 BEEP .75,7: 
   BEEP .25,8: 
   BEEP .5,7: 
   BEEP .5,5: 
   BEEP .5,3: 
   BEEP .5,2: 
   BEEP 1,0
80 BEEP 1,0: 
   BEEP 1,-5: 
   BEEP 2,0
90 BEEP 1,0: 
   BEEP 1,-5: 
   BEEP 2,0

When you run this, you should get the funeral march from Mahler's first symphony, the bit where the goblins bury the US Cavalry man.

Suppose for example that your tune is written in the key of C minor, like the Mahler above. The beginning looks like this:

and you can write in the pitch values of the notes like this:

We have put in two ledger lines, just for good measure. Note how the E flat in the key signature affects not only the E in the top space, flattening it from 16 to 15, but also the E on the bottom line, flattening it from 4 to 3. It should now be quite easy to find the pitch value of any note on the stave.

If you want to change the key of the piece, the best thing is to set up a variable key and insert key+ before each pitch value: thus the second line becomes

20 BEEP 1,key+0: 
   BEEP 1,key+2: 
   BEEP .5,key+3: 
   BEEP .5,key+2: 
   BEEP 1,key+0

Before you run a program you must give key the appropriate value - 0 for C minor, 2 for D minor, 12 for C minor an octave up, and so on. You can get the computer in tune with another instrument by adjusting key, using fractional values.

You also have to work out the durations of all the notes. Since this is a fairly slow piece, we have allowed one second for a crotchet and based the rest on that, half a second for a quaver and so on.

More flexible is to set up a variable crotchet to store the length of a crotchet and specify the durations in terms of this. Then line 20 would become

20 BEEP crotchet,key+0: 
   BEEP crotchet,key+2: 
   BEEP crotchet/2,key+3: 
   BEEP crotchet/2,key+2: 
   BEEP crotchet,key+0

(You will probably want to give crotchet and key shorter names.)

By giving crotchet appropriate values, you can easily vary the speed of the piece.

Remember that because there is only one loudspeaker in the computer you can only play one note at a time, so you are restricted to unharmonized tunes. If you want any more you must sing it yourself.

Try programming tunes in for yourself - start off with fairly simple ones like 'Three Blind Mice'. If you have neither piano nor written music, get hold of a very simple instrument like a tin whistle or a recorder, and work the tunes out on that. You could make a chart showing the pitch value for each note that you can play on this instrument.

Type:

FOR n=0 TO 1000: 
BEEP .5,n: 
NEXT n

This will play notes as high as it can, and then stop with error report B Integer out of range. You can print out n to find out how high it did actually get.

Try the same thing, but going down into the low notes. The very lowest notes will just sound like clicks; in fact the higher notes are also made of clicks in the same way, but faster, so that the ear cannot distinguish them.

Only the middle range of notes are really any good for music; the low notes sound too much like clicks, and the high notes are thin and tend to warble a bit.

Type in this program line:

10 BEEP .5,0: 
   BEEP .5,2: 
   BEEP .5,4: 
   BEEP .5,5: 
   BEEP .5,7: 
   BEEP .5,9: 
   BEEP .5,11: 
   BEEP .5,12: 
   STOP

This plays the scale of C major, which uses all the white notes on the piano from middle C to the next C up. The way this scale is tuned is exactly the same as on a piano, and is called even-tempered tuning because the pitch interval of a semitone is the same all the way up the scale. A violinist, however, would play the scale very slightly differently, adjusting all the notes to make them sound more pleasing to the ear. He can do this just by moving his fingers very slightly up or down the string in a way that a pianist can't.

The natural scale, which is what the violinist plays, comes out like this:

20 BEEP .5,0: 
   BEEP .5,2.039: 
   BEEP .5,3.86: 
   BEEP .5,4.98: 
   BEEP .5,7.02: 
   BEEP .5,8.84: 
   BEEP .5,10.88: 
   BEEP .5,12: 
   STOP

You may or may not be able to detect any difference between these two; some people can. The first noticeable difference is that the third note is slightly flatter in the naturally tempered scale. If you are a real perfectionist, you might like to program your tunes to use this natural scale instead of the even-tempered one. The disadvantage is that although it works perfectly in the key of C, in other keys it works less well - they all have their own natural scales - and in some keys it works very badly indeed. The even-tempered scale is only slightly off, and works equally well in all keys.

This is less of a problem on the computer, of course, because you can use the trick of adding on a variable key.

Some music - notably Indian music - uses intervals of pitch smaller than a semitone. You can program these into the BEEP statement without any trouble; for instance the quartertone above middle C has a pitch value of .5.

You can make the keyboard beep instead of clicking by

POKE 23609,255

The second number in this determines the length of the beep (try various values between 0 and 255). When it is 0, the beep is so short that it sounds like a soft click.

If you are interested in doing more with sound from the Spectrum, like hearing the sound that BEEP makes on something other the internal speaker, you will find that the signal is present on both the 'MIC' and the 'EAR' sockets. It will be at a higher level on the 'EAR' socket, but otherwise they are the same. You may use this to connect an earphone or a pair of headphones to your Spectrum. This will not cut out the internal loudspeaker. If you are really keen to make a lot of noise you could connect it up to an amplifier - the 'MIC' socket will probably give about the right level - or you could record the sound onto tape and get the Spectrum to play along with itself.

You will not damage the Spectrum even if you short-circuit the 'MIC' or 'EAR' sockets, so experiment to find which gives the best output for what you want to do.

The PLAY command

The PLAY command allows you to make more complex pieces of music. However, it is a 128k only command, and will not run on a standard 48k Spectrum. See the chapter on BASin and the 128k for more details about this.

In the examples that follow, it is important that you type in the string expressions exactly as shown in upper case and lower case letters, ie. the example "ga" should not be typed in as "Ga", "gA" or "GA".

Type in this command (don't worry about what it means just yet)...

PLAY "ga"

Two notes were played - the second slightly higher than the first. The difference between the notes is called a tone. Now try...

PLAY "g$a"

Again there were two notes played - the first one was the same as the previous example, but there was less of a jump to the second. If you didn't hear the difference, then try the first example followed by the second again. The second example has half the difference between notes, and this is called a semitone.

When you're happy with semitones, try this...

PLAY "gD"

This sort of difference is called a fifth, and occurs quite often in music of all types. With that example ringing in your ears, type...

PLAY "gG"

Although (hopefully) you noticed that there was a much bigger difference that time than for the fifth, the two notes somehow sounded much more similar. This is called an octave, and is the point at which music starts to 'repeat itself'. Don't worry about that unduly, just remember what an octave sounds like.

PLAY is much more flexible than BEEP - it can play up to three voices in harmony with all manner of effects, and gives a much higher quality of sound. It's also much easier to use. For example, to play A above middle C for half a second, type in...

PLAY "a"

... and to play the C major scale (which needed a program to itself before), use...

PLAY "cdefgabC"

Notice that the last C in the example above is in upper case. This tells the PLAY command to play it in an octave higher than the lower case c. A scale, by the way, is the term used for a set of notes between two Cs. Why major? There are two main classes of scale, major and minor, and this is just musical shorthand for describing the two different sets. Just for interest, the C minor scale sounds like this...

PLAY "cd$efg$a$bC"

Preceding a note by $ drops it by a semitone (flattens it), and preceding a note by # raises it by a semitone (sharpens it). The PLAY command spans 9 octaves, and can be told which to use by having the upper case O followed by a number, in the list of notes that it is given. Type in this little program...

10 LET o$="O5"
20 LET n$="DECcg"
30 LET a$=o$+n$
40 PLAY a$

There are a few new things in this program. Firstly, PLAY is just as happy with a string variable as with a string constant. In other words, providing that a$ has been set up beforehand, PLAY a$ works just as well as PLAY "O5DECcg". In fact, using variables in PLAY statements has distinct advantages, and we shall be doing this from now on.

Notice also that the string a$ has been 'built up' by combining two smaller strings o$ and n$. While this doesn't make much difference at this sort of level, PLAY can cope with strings many thousands of notes long, and the only sensible way of creating and editing those strings from BASIC is to combine lots of smaller strings in this way.

Now run the above program. Edit line 10 so that "O5" becomes "O7", and run it again, or if you want to make a big spaceship, make it "O2". If you don't specify an octave number for a particular string, then BASin assumes that you want octave 5. Here is a diagram of the notes and octave numbers which correspond to the standard even-tempered music scale.

There is a lot of overlap, so for example, "O3D" is the same as "O4d". This makes it easier to write tunes without having to change octave all the time. Some of the notes in the lowest octaves (0 and 1) aren't very accurate for technical reasons, and so the computer just makes a brave attempt at getting as close as possible.

PLAY can also handle many different lengths of note. Edit the program above so that line 10 is now...

10 LET o$="2"

... and run it. Then alter the setting of o$ between "1" and "9". The note length can be changed anywhere in a string by including a number between 1 and 9, and this is effective for all subsequent notes until a new number is encountered. Each of these nine note lengths has a specific musical name, and looks different when written down in musical notation. The following table shows which is which...

Number

Note Name

Musical Symbol

1

Semi-quaver

2

Dotted semi-quaver

3

Quaver

4

Dotted quaver

5

Crotchet

6

Dotted crotchet

7

Minim

8

Dotted minim

9

Semi-breve

PLAY can also cope with triplets, which are three notes played in the time for two. Unlike simple note lengths, the triplet number only applies for the three notes immediately following, and then the previous note length number resumes. The triplet numbers are as follows...

Number

Note Name

Musical Symbol

10

Triplet semi-quaver

11

Triplet quaver

12

Triplet crotchet

PLAY is quite happy about being told to 'shut up'! A timed period during which no notes play is called a rest, and the "&" is used to signify this. The length of the rest it produces is the same as the current note length. To demonstrate, edit lines 10 and 20 to...

10 LET o$="O4"
20 LET n$="DEC&cg;"

Two notes played together without a break are called tied notes, which are signified in a PLAY command by an _ underline, so a crotchet c and a minim c tied together would be "5_7c". (The second value is then used as the note length for all subsequent notes, as before.)

There are 2 occasions when the ambiguity creeps in. Say that a piece of music needs octave 6 and a note length of 2, then...

10 LET o$="O62"

...seems a good bet - but no! The computer will find the O and try to read the number following it. When it finds 62, it will stop with the report n Out of range. In cases like this, there is a 'dummy note' called N that just serves to split things up, so line 10 should be...

10 LET o$="O6N2"

The volume can be set between 0 (minimum) and 15 (maximum) using "V" followed by a number. In practice, only 10 to 16 are likely to be useful, as 1-9 are too soft unless the computer is being used with an amplifier. As previously mentioned, BEEP is louder than a single channel of PLAY, but if all three channels play a note at volume 15, then it should be at the same level as a not produced by BEEP.

Playing more than one channel at the same time is very simple; you just separate lists of notes by commas. Try this new program...

10 LET a$="O4cCcCgGgG"
20 LET b$="O6CaCe$bd$bD"
30 PLAY a$,b$

In general, there is no difference between the three channels, and any string of notes can be put onto any channel. The overall speed of the music, the tempo, must be in the string assigned to channel A (the first string after PLAY), otherwise it will be ignored. To set tempo in beats (crotchets) per minute, use "T" followed by a number between 60 and 240. The standard value is 120, or two crotchets per second. Modify the program above to...

 5 LET t$="T120"
10 LET a$=t$+"O4cCcCgGgG"
20 LET b$="O6CaCe$bd$bD"
30 PLAY a$,b$

...and run it several times, changing line 5 for different tempos.

A common feature in music is the repetition of a group of notes. Any part of a string can be repeated by enclosing it in brackets, so if you change line 10 to...

10 LET a$=t$+"O4(cC)(gG)"

PLAY treats it just the same as the old line 10. If you include a closing bracket, (with no matching opening bracket) then the string up to that point is repeated indefinitely. This is useful for rhythm effects and basslines. To demonstrate, try this (you'll have to use the ESC key to stop the sound)...

PLAY "O4N2cdefgfed)"

...and...

PLAY "O4N2cd(efgf)ed)"

If you set up an infinitely repeating bassline, and then play a melody with it, then it would be nice if the bassline stops when the melody does. There is a device to do this - of PLAY comes across "H" (for Halt) in any of the strings it is playing, then it stops all sound immediately. Run the following program (again, you'll have to use ESC to stop it)...

10 LET a$="cegbdfac"
20 LET b$="O4cC)"
30 PLAY a$,b$

Now modify line 10 to...

10 LET a$="cegbdfaCH"

...and run it again.

So far we've only used notes which start and stop at one level of volume. BASin can alter athe volume of a note while it is playing, so it can start loud and die away like a piano, or rise and fall like a dog growling. To turn these effects on, use "W" (for Waveform) followed by a number between 0 and 7, together with "U" for each channel you want to use the effect on. Any channel with a volume setting ("V") will not respond to "U". This table shows graphically how the volume changes for each setting...

0

Single decay, then off.

1

Single attack, then off.

2

Single decay, then hold.

3

Single attack, then hold.

4

Repeated decay.

5

Repeated attack.

6

Repeated attack-decay.

7

Repeated decay-attack.

This program plays the same note with each effect in turn, so you can compare them against the diagram above.

10 LET a$="UX1000W0C&W1C;&W2C;&W3C;&W4C;&W5C;&W6C;&W7C;"
20 PLAY a$

The U turns on effects, and the W selects which waveform to use. There's also an "X1000". The X sets how long the effect will last for (from 0 to 65535). If you don't include an X then BASin will choose the longest value. Waveforms that settle down (0 to 3 in the table above) after the initial part, work best with X settings of about 1000, whereas repetetive effects (4-7) are more effective with short values like 300. Try varying the X setting in the program above to get some idea of how each works.

The PLAY command isn't limited to pure musical notes. There are also three "white noise" generators (white noise is a sound which is like an un-tuned FM radio or TV), and any of the three channels can play notes, white noise, or a mixture of both. To select a mix of noise and note, you may use "M" followed by a number between 1 and 63. You can work out which number to use from the following table...

Tone Channels Noise Channels

A

B

C

A

B

C

Number

1

2

4

8

16

32

Write down the numbers corresponding to the effects you want, and then add them together. If you wanted A to be noise, B to be tone, and C to be both tone and noise, then add 8, 2, 4, and 32 together to get 46 (the order of the channels is the order of the strings which follow the PLAY command). The best effects can be obtained with the A channel - don't be afraid to experiment.

By now, you'll be writing symphonies. However, it can be difficult to work out just which part of the music a particular section of string is responsible for. To alleviate this problem, your music string may include 'comments' enclosed between ! exclamation marks; for example...

10 LET z$=z$+"CDcE3Ge4_6f! end of the 75th bar !egeA"

The PLAY command will simply 'hop over' any comments in the string.

MIDI programming

The original 128k models of the Spectrum had the ability to control an external MIDI device. BASin emulates this by allowing your programs to drive your MIDI soundcard. For information about setting up this feature, see the relevant options page.

If you have an electronic musical instrument with MIDI, then you can control it using PLAY. Up to 8 channels of music can be sent to synthesisers, drum machines or sequencers. The PLAY command is constructed exactly as described so far in this section, except that each string should include a "Y" followed by a number between 1 and 16. The number after the Y controls which channel the music data is assigned to. Up to eight strings can be used; the first three strings will still be played through the normal Spectrum output, so you might want to turn down the volume. You can also send MIDI programming codes via the PLAY command, using "Z" followed by the code number. Key velocities (loudness) are calculated and sent at 8 times the V setting (so "V6" will send 48 as a key velocity).

So, to send a little tune (in four part harmony) to a four-voice synthesiser (after consulting your synth's handbook to find out how to allocate MIDI channels to different voices), you would use the PLAY command with four strings, each starting with a Y followed by a number. This example program illustrates the PLAY command in some of its full glory...

10 LET a$="Y1T100O2(((1CCg$b))(($E$E$b$D))((GGDF))))"
20 LET b$="Y2O5N&&&&C;$bfG)"
30 LET c$="Y3O4((3C&)C&1CCDD(3$E&)$E&1$E$EEE(3F&)F&1FF$G$G(3G&)G&1GG$EC))"
40 LET d$="Y4N9&&&&&&&&(9EGF7b5CD))"
50 PLAY a$,b$,c$,d$

Summary table

Finally, here is a brief list of the parameters that can be used in the string of a PLAY command, together with any values they may take...

StringFunction
a..g, A..GSpecifies the pitch of the note within the current octave range.
$Specifies that the note which follows must be flattened.
#Specifies that the note which follows must be sharpened.
OSpecifies the octave number to be used (followed by 0 to 8).
1..12Specifies the length of notes to be used.
&Specifies that a rest is to be played.
_Specifies that a tied note is to be played.
NSeparates two numbers.
VSpecifies the volume to be used (followed by 0 to 15).
WSpecifies the volume effect to be used (followed by 0 to 7).
USpecifies that volume effects are to be used in the string.
XSpecifies the duration of the volume effect (followed by 0 to 65535).
TSpecifies the tempo of the music (followed by 60 to 240).
( )Specifies that the enclosed phrase is to be repeated.
! !Specifies that the enclosed text is to be skipped over.
HSpecifies that the PLAY command must stop.
MSpecifies the channel(s) to be used (followed by 0 to 63).
YSpecifies that a MIDI channel is to be used (followed by 1 to 16).
ZSpecifies MIDI programming code (followed by code number).

Exercises

  1. Rewrite the Mahler program so that it uses FOR loops to repeat the bars.
  2. Program the computer so that it plays not only the funeral march, but also the rest of Mahler's first symphony.

Chapter 20

Chapter 18