16-Bit Music
Fred Tedsen
Did you know that you can improve the tuning of your Atari's notes and extend its range dramatically? Normally you can only choose among 256 notes with the ordinary SOUND command. These subroutines let you have more than 65,000 frequencies to make music that's more precise and pleasant to hear.

As I listened to my Atari play a new song that I had entered from a magazine listing, I could hear that some of the notes were not quite right. The music extended into the third octave above middle C, and though the tune was recognizable, some of the notes were off pitch enough to make listening to the tune unpleasant. I decided that it was time for me to investigate 16-bit music. What I discovered was not only that the accuracy of the notes could be improved dramatically, but also that the effective range could be more than doubled.

How SOUND Works

Before we discuss 16-bit music, let's take a look at what is happening when we use the SOUND statement, or in other words, eight-bit sound, in Atari BASIC. The following registers in the POKEY chip are used for sound generation:

AUDF1 (53760) - Audio Frequency Register 1
AUDC1 (53761) - Audio Control Register 1
AUDF2 (53762) - Audio Frequency Register 2
AUDC2 (53763) - Audio Control Register 2
AUDF3 (53764) - Audio Frequency Register 3
AUDC3 (53765) - Audio Control Register 3
AUDF4 (53766) - Audio Frequency Register 4
AUDC4 (53767) - Audio Control Register 4
AUDCTL (53768) - Audio Mode Control Register

The audio control registers are used to set volume (low order four bits) and sound content (high order bits). Thus there are 16 different volume settings and a variety of sounds available. For this discussion we are concerned only with pure tones, corresponding to SOUND x,x,10,x.

the audio frequency registers are used to control the divide by N circuits. These circuits use the contents of the frequency registers to divide a "clock" frequency to produce different output frequencies. Since they are one-byte registers, they are referred to as eight-bit dividers. The output frequency is determined by the formula F0 = F/(2 × (AUDF + 1)), where F is the clock frequency and AUDF the value in the audio frequency register. With a normal clock rate of 64 kilohertz (or more exactly 63,921 cycles per second), the frequency range is about 125 hertz to 32 kilohertz.

The effective range for music is limited to about four octaves. This is because the tuning accuracy of notes being produced becomes progressively worse as the frequency gets higher. Figure 1 illustrates this very clearly. It shows how far out of tune, measured in "cents," each note in the four octave range is. (A cent is 1/100 of a half-step. A sound which is 50 cents sharp or flat is exactly halfway between two notes.) Notes which are less than ten cents out of tune are usually acceptable, though two notes played together could sound bad if their combined inaccuracy is too large. For example, if you play a note which is eight cents flat followed by a higher note which is eight cents sharp, the second note will probably sound out of tune.

Figure 1. Tuning Inaccuracy of Musical Notes in Cents Using 8-Bit Dividers
Figure 1

Tuning inaccuracy results from having a limited number of values to use as dividers. With an eight-bit divider, only 256 unique frequencies can be produced. The A note in the fourth octave should be 440 cycles per second. To produce this note on the Atari, the number 72 is used as a divider. The resulting frequency is 437.8 hertz, whith is 8.6 cents flat. If instead we use a 71 as a divider, the output frequency is 443.9 hertz. This note is 15.3 cents sharp and is obviously a poorer choice than the note using 72. The choices become more restricted as the notes get higher. For the A note in the sixth octave, for example, 17 produces a note which is 15.3 cents sharp, while 18 produces a note 78.4 cents flat (closer to G# than A).

Fine-tuning: 16-Bit Dividers

Luckily, the Atari provides a solution to this problem: 16-bit dividers. With a 16-bit divider 65,536 different output frequencies are possible. For example, to reproduce tha A in octave 6, we could use either 502 (1.8 cents flat) or 501 (1.6 cents sharp) and not able to hear any difference. Figure 2 shows how dramatically the range and accuracy are improved.

Figure 2. Tuning Inaccuracy of Musical Notes in Cents Using 16-Bit Dividers
Figure 2

More accurate tuning does not come without a price. Sixteen-bit dividers are obtained by combining frequency registers: AUDF1 with AUDF2, or AUDF3 with AUDF4. This gives us a choice of one 16-bit and two eight-bit voices, or two 16-bit voices. We also cannot use the SOUND statement, even for the eight-bit voices, as it will confuse our settings for the 16-bit sound. As it turns out, this is not much of a problem since machine language routines to play the music are simple and have the added advantage of being faster than separate SOUND statements.

Now let's look at how 16-bit sound is set up. The audio mode control register has four bits for this purpose:

Bit 6—Clock channel 1 with 1.79 megahertz instead of 64 kilohertz Bit 5—Clock channel 3 with 1.79 megahertz Bit 4—Combine channels 1 and 2 Bit 3—Combine channels 3 and 4

The other bits in AUDCTL have no bearing on this discussion, so we will ignore them. If you are curious, see Chapters 2 and 3 the Hardware Manual.

The 1.79 megahertz (1.78979 megahertz, to be exact) clock rate is required to obtain the full range of output frequencies. The formula for determining output frequency is a little different: F0 = F/(2 × (AUDF + 7)). In this case, AUDF is the two-byte frequency register value. The second register of the pair is the low order byte, either AUDF2 or AUDF4. For example, to use 1049 as a divider with registers 1 and 2, we would POKE 4 in AUDF3 and 25 in AUDF1.

16-Bit Subroutines

Now take a look at the BASIC 16-bit sound subroutines. The first plays one 16-bit and two eight-bit voices, and the second plays two 16-bit voices. Notice the SOUND 0,0,0,0 at the beginning of each routine. This statement must be included to initialize POKEY for sound. The POKE 53768,X initializes AUDCTL for 16-bit sound, either one or two voices. Remember that any SOUND statement executed later will reset this register to zero.

To use these subroutines, simply copy one or the other into your program and do a GOSUB 20100 once at the beginning of the program. Then, to play music, do the appropriate machine language call, X = USR(ADR(HF1$),N1,V1,N2,V2,N3,V3) OR X = USR(ADR(HF2$),N1,V1,N2,V2). Nx is the note to be played and Vx is the volume. N1 is the 16-bit voice in the three-voice routine. You don't need to pass parameters for unused voices. For example, if you want only the 16-bit voice in the three-voice routine, you can use X = USR(ADR(HF1$),N1,V1), but to use only an eight-bit voice you would have to use X = USR(ADR(HF1$),0,0,N2,V2).

The note tables give you the most accurate values for four octaves of eight-bit and nine octaves of 16-bit notes. In a practical sense, the first octave of 16-bit notes is not usable because there are some loud harmonics which tend to mask the actual note being played. You can get some good sounds if you hook up to a stereo amplifier, however. Notice that the eight-bit value for F# in the third octave is 172 rather than 173 as shown in the BASIC Reference Manual. 173 produces a note which is more than 12 cents flat, while the note from 172 is only 2.4 cents flat.

16-Bit and 8-Bit Note Table
NOTE 16-BIT 8-BIT     NOTE 16-BIT 8-BIT  
C 27357   OCTAVE 1 C 848 30 OCTAVE 6
C# 25821   C# 800 28
D 24372   D 755 26
D# 23003   D# 712 25
E 21712   E 672 23
F 20493   F 634 22
F# 19342   F# 598 21
G 18256   G 564 19
G# 17231   G# 532 18
A 16264   A 501 17
A# 15351   A# 473 16
B 14489   B 446 15  
C 13675   OCTAVE 2 C 421 14 OCTAVE 7
C# 12907   C# 397
D 12182   D 374
D# 11498   D# 353
E 10852   E 332
F 10243   F 313
F# 9668   F# 295
G 9125   G 278
G# 8612   G# 262
A 8128   A 247
A# 7672   A# 233
B 7241   B 219  
C 6834 243 OCTAVE 3 C 207   OCTAVE 8
C# 6450 230   C# 195
D 6088 217   D 183
D# 5746 204   D# 173
E 5423 193   E 163
F 5118 182   F 153
F# 4830 172   F# 144
G 4559 162   G 136
G# 4303 153   G# 128
A 4061 144   A 120
A# 3832 136   A# 113
B 3617 128   B 106  
C 3414 121 OCTAVE 4 C 100   OCTAVE 9
C# 3222 114   C# 94
D 3040 108   D 88
D# 2869 102   D# 83
E 2708 96   E 78
F 2555 91   F 73
F# 2412 85   F# 69
G 2276 81   G 64
G# 2148 76   G# 60
A 2027 72   A 57
A# 1913 68   A# 53
B 1805 64   B 50  
C 1703 60 OCTAVE 5 C 46   OCTAVE 10
C# 1607 57  
D 1517 53  
D# 1431 50  
E 1350 47  
F 1274 45  
F# 1202 42  
G 1134 40  
G# 1070 37  
A 1010 35  
A# 953 33  
B 899 31  

Program 1. 16-Bit Sound Routine
20010 REM 
20020 REM 1 16-BIT & 2 8-BIT VOICES
20030 REM 
20040 REM X=USR(ADR(HF1$),N1,V1,N2,V2,N3,V3)
20050 REM 
20100 SOUND 0,0,0,0:X=64+16:POKE 53768,X
20110 DIM HF1$(56):RESTORE 20140
20120 FOR I=1 TO 56:READ X:HF1$(I,I)=CHR$(X):NEXT I
20130 RETURN 
20140 DATA 104,170,104,141,2,210,104,141,0,210,104,104,41,15,9,160,141,3,210
20150 DATA 224,2,240,32,104,104,141,4,210,104,104,41,15,9,160,141,5,210
20160 DATA 224,4,240,14,104,104,141,6,210,104,104,41,15,9,160,141,7,210,96

Listing. 16-Bit Sound Routine.
Download (Saved BASIC) / Download (Listed BASIC)

Program 2. 16-Bit Sound Routine 2
20010 REM 
20020 REM 2 16-BIT VOICES
20030 REM 
20040 REM X=USR(ADR(HF2$),N1,V1,N2,V2)
20050 REM 
20100 SOUND 0,0,0,0:X=(64+16)+(32+8):POKE 53768,X
20110 DIM HF2$(41):RESTORE 20140
20120 FOR I=1 TO 41:READ X:HF2$(I,I)=CHR$(X):NEXT I
20130 RETURN 
20140 DATA 104,170,104,141,2,210,104,141,0,210,104,104,41,15,9,160,141,3,210
20150 DATA 224,2,240,17
20160 DATA 104,141,6,210,104,141,4,210,104,104,41,15,9,160,141,7,210,96

Listing. 16-Bit Sound Routine 2.
Download (Saved BASIC) / Download (Listed BASIC)

Return to Table of Contents | Previous Section | Next Section