Perfect Pitch

Fred Coffey

"It sounds a bit out of tune," said my musician friend after listening to my Atari's rendition of "The Star Spangled Banner" in two voices. "You should work on pitch control."

"It sounds fine to me the way it is," I protested. "Anyway, let's play Asteroids."

Later I began to wonder just how good the Atari's pitch was. I remembered that the note "A" above "middle C" was usually tuned to 440 cycles per second. And the Atari BASIC Manual said that if I put a "72" in for the pitch control (P) in the command "SOUND 0, P, D, V", I would get the note "A." Was this sound actually 440 Hz?

So I turned to my newly acquired Atari Hardware Manual for help. I finally determined that the Atari controls pitch by dividing an internal 64 kilohertz clock according to the following formula (where "P" is an integer between 0 and 255):

PITCH = 63921.0 / (2 * (P + 1)) (1)

So, if we plug the "72" (which Atari says is our "A" note) into the above equation, we get a pitch of 437.8 Hz. The Atari is out of tune! It is, in fact, not possible to generate a precise "440" note.

But the Atari Hardware Manual does have a solution – we are allowed to switch to 16-bit precision on our note generation as long as we are willing to settle for two voices instead of four.

However, before we can exploit that, we need to learn a new way of controlling sound. We will have to POKE instructions instead of using the BASIC SOUND command. It's really no problem since we can define an exact equivalence to SOUND as follows:

Table 1

 Voice SOUND Command Equivalent POKE 1 SOUND 0, P, D, V POKE 53760, P : POKE 53761, (16 * D) + V 2 SOUND 1, P, D, V POKE 53762, P : POKE 53763, (16 * D) + V 3 SOUND 2, P, D, V POKE 53764, P : POKE 53765, (16 * D) + V 4 SOUND 3, P, D, V POKE 53766, P : POKE 53767, (16 * D) + V

Now we can go on. The Atari has a memory register, at location 53768, which has 256 ways (i.e., one byte) to control sound options. I don't understand most of them yet, but I did sort out a few of them. Just as an example I found that if I "POKE 53768, 1" the Atari switches to a 15 kilohertz clock for sound control, and equation (1) above becomes:

PITCH = 15699.9 / (2 * (P + 1)) (2)

But to get back to our immediate objective of more precise pitch control, I found that if I do a "POKE 53768, 80" then voices one and two merge into a single high-resolution voice. If I "POKE 53768, 120" voices three and four follow suit.

We can control these new combined voices as follows:

Voice 1 + 2

POKE 53760, P1 : POKE 53762, P2 : POKE 53763, (16 * D) + V

Voice 3 + 4

POKE 53764, P1 : POKE 53766, P2 : POKE 53767, (16 * D) + V

You will recognize the distortion (D) and volume (V) terms from the old SOUND commands. But what are these new terms P1 and P2? They are simply a pair of integer sound control terms like the "P" in equations (1) and (2), and they generate a high-precision sound using a 1.79 megahertz clock as follows:

PITCH = 1789790 / (2 * (256 * P2 + P1 + 7)) (3)

Conversely, if we want to know what values to POKE in order to generate an objective pitch, we can solve (or let the computer solve) the following and POKE the values into the computer:

P2 = INT((1789790 / (2 * PITCH) - 7) / 256) (4)
P1 = INT(1789790 / (2 * PITCH) - 7 - 256 * P2 + .5) (5)

To generate a 440 Hz note, then, we can solve the above equations to find that P2 = 7 and P1 = 235. We can then POKE these values to generate our note (which comes out at 439.97 Hz – pretty good!).

So much for the mathematics. Now for a demonstration (Program 1). The demonstration uses two joysticks to control one high-resolution voice and one "normal" voice, and displays the relevant pitch equations on the screen as the equation terms change. You can quickly see how much control over pitch you have in each case.

Program 2 allows you to experiment with different scales of notes – using the best normal Atari approximation and then playing the scale again with high resolution pitch control.

Finally, I was ready to call my musician friend back in. "Listen to this," I said. "I can control pitch to a fraction of a cycle per second. In fact, if I simultaneously sound two notes that are very close to each other, you can hear the combined sound waver as the two wave forms drift in and out of phase and alternately reinforce and cancel each other."

"Not bad," he said. "We call that phenomenon 'beating' and use it to tune instruments precisely against a tuning fork reference."

"Hey," I said, "that means you could play a note on your piano and I could match my Atari note to it precisely by listening to the beat. I've invented a piano tuner!

"Now," I said, "if you'll just tell me the mathematical relationship between the rest of the notes on the musical scale, I'll tune my Atari and we'll hear some real music!"

"Well," he said, "it's not that simple. There are several methods of tuning. It depends on what instrument you're tuning, and even depends on what country you live in. Besides, pitch control isn't the only problem with your Atari sound. For example…"

"It sounds fine to me the way it is," I said. "Let's play Asteroids."

PROGRAM 1. Perfect Pitch

1 REM -------- PROGRAM 1 ---------
2 REM
3 REM
4 GRAPHICS 0 : ? : ? : ? : ? "WHAT FREQUENCY WOULD YOU LIKE TO" : ? "START"; : INPUT FREQ
5 AUDF3 = INT(63921 / (2 * FREQ) - 1 + 0.5)
6 AUDF2 = INT((1789790 / (2 * FREQ) - 7) / 256)
7 AUDF1 = INT((1789790 / (2 * FREQ)) - 7 - 256 * AUDF2 + 0.5)
8 IF FREQ > 125 AND FREQ < 16000 THEN 10
9 ? "ALLOWABLE RANGE 125 TO 16000" : ? "TRY AGAIN"; : INPUT FREQ : GOTO 5
10 GRAPHICS 0 : ? "JOYSTICK #1 CONTROLS HIGH RESOLUTION"
15 ? "FREQUENCY. PRESS BUTTON TO SOUND,"
20 ? "MOVE UP/DOWN FOR SLOW FREQUENCY SHIFT" : ? "OR LEFT/RIGHT FOR FAST SHIFT."
30 ? : ? "JOYSTICK #2 CONTROLS LOW RESOLUTION,"
40 ?"BUTTON TO SOUND OR UP/DOWN FOR SHIFT." : ?
50 REM FOR UNKNOWN REASON FOLLOWING COMMAND NECESSARY FOR RELIABLE OPERATION :
55 SOUND 0, 0, 0, 0 : SOUND 1, 0, 0, 0 : SOUND 2, 0, 0, 0 : SOUND 3, 0, 0, 0
100 POKE 752, 1
110 POKE 53768, 80
130 POKE 53763, 10 * 16 + 15
140 POKE 53765, 10 * 16 + 15
160 IF STICK(0) = 13 THEN AUDF1 = AUDF1 + 1 : IF AUDF1 > 255 THEN AUDF2 = AUDF2 + 1 : AUDF1 = 0
170 IF STICK(0) = 14 THEN AUDF1 = AUDF1 - 1 : IF AUD F1 > 0 THEN AUDF2 = AUDF 2 - 1 : AUDF1 = 255
180 IF STICK(0) = 11 THEN AUDF2 = AUDF2 + 1
190 IF STICK(0) = 7 THEN AUDF2 = AUDF2 - 1
220 IF STICK(1) = 13 THEN AUDF3 = AUDF3 + 1
230 IF STICK(1) = 14 THEN AUDF3 = AUDF3 - 1
240 IF STRIG(0) = 0 THEN POKE 53760, AUDF1 : POKE 53762, AUDF2 : GOTO 260
250 POKE 53760, 0 : POKE 53762, 0
260 IF STRIG(1) = 0 THEN POKE 53764, AUDF3 : GOTO 280
270 POKE 53764, 0
280 FOUT2 = 1789790 / (2 * (AUDF2 * 256 + AUDF1 + 7))
290 FOUT3 = 63921 / (2 * (AUDF3 + 1))
300 POSITION 1, 9 : ?
310 ? "HI RES FREQUENCY : " : ?
320 ? "FREQ = 1789790 / (2 * (";AUDF2; " * 256 + ";AUDF1; " + 7)) {3 SPACES}" : ?
325 ? "{7 SPACES} = "; FOUT2
330 ? : ? : ? "LO RES FREQUENCY : " : ?
340 ? "FREQ = 63921 / (2 * (";AUDF3; " + 1)) {5 SPACES}" : ? : ? "{7 SPACES} = ";FOUT3
500 GOTO 100

PROGRAM 2. Perfect Pitch.

2 REM
5 REM PROGRAM 2
10 REM
20 REM THE FOLLOWING PROGRAM TAKES A GIVEN SCHEDULE OF EIGHT PITCH VALUES
30 REM (I.E. A SCALE) AND PLAYS THE NOTES USING THE BEST NORMAL ATARI
40 REM APPROXIMATION AND THEN USING A "HIGH RESOLUTION" RENDITION
50 REM
60 REM
70 REM
90 REM "EQUAL TEMPERMENT" SCALE
100 DATA 520, 584, 655, 694, 779, 874, 982, 1040
110 DIM PITCH(8), A\$(1)
120 FOR J = 1 TO 8 : READ X : PITCH(J) = X : NEXT J
150 GRAPHICS 0 : ? : ? " NORMAL ATARI {7 SPACES}HIGH RESOLUTION" : ? " ------------{7 SPACES}---------------"
160 ? " P{4 SPACES}PITCH{8 SPACES}P1 P2{3 SPACES}PITCH" : ? " --{4 SPACES}-----{8 SPACES}-- --{3 SPACES}-----"
170 POKE 752, 1
200 REM GENERATE 'NORMAL' ATARI SOUND
210 FOR J = 1 TO 8
220 P = INT(63921 / (2 * PITCH(J)) - 1)
230 SOUND 2, P, 10, 8
240 PITCH = 63921 / (2 * (P + 1))
250 POSITION 3, J + 6 : ? P; " "; PITCH
260 FOR W = 1 TO 200 : NEXT W : NEXT J
270 SOUND 2, 0, 0, 0 : FOR W = 1 TO 500 : NEXT W
300 REM 'HIGH RESOLUTION' SOUND
305 POKE 53768, 80
310 FOR J = 1 TO 8
320 P2 = INT((1789790 / (2 * PITCH(J)) - 7) / 256)
330 P1 = INT(1789790 / (2 * PITCH(J)) - 7 - 256 * P2 + 0.5)
340 POKE 53760, P1 : POKE 53762, P2 : POKE 53763, (16 * 10) + 8
350 PITCH = 1789790 / (2 * (256 * P2 + P1 + 7))
360 POSITION 21, J + 6 : ? P1 : POSITION 25, J + 6 : ? P2; " "; PITCH
370 FOR W = 1 TO 150 : NEXT W : NEXT J
380 POKE 53760, 0 : POKE 53762, 0
400 POSITION 2, 19 : ? " PLAY IT AGAIN (Y OR N)"; : INPUT A\$ : IF A\$ = "Y" THEN 150
410 ? "ENTER 8 NEW PITCH VALUES, ONE AT A" : ? "TIME"
420 FOR J = 1 TO 8 : INPUT X : PITCH(J) = X : NEXT J : GOTO 150