Classic Computer Magazine Archive COMPUTE! ISSUE 78 / NOVEMBER 1986 / PAGE 61

Atari Sound Commander

James Hague

How would you like to have the ability to create sound effects and music in Atari BASIC without slowing down the rest of your program? "Sound Commander" offers the ability to program sounds that run in the background while other BASIC events are in progress.

One of the strongest features of the Atari eight-bit computer family is its outstanding sound capability. Programmers have done an excellent job of exploiting Atari sound, creating everything from simulated frog croaks to music in four-part harmony. Unfortunately, many of the programs used to create these sounds are written in machine language, which is less widely understood and more difficult to program than BASIC.

Instead of delving into the mysterious world of binary code, many Atari programmers work in Atari BASIC, the language supplied with the computer. Anyone who has created sounds in this language has probably realized that there are three major problems: Complex sounds are difficult to achieve, the timing of a sound loop varies depending on its location in a program, and sound routines occupy a major portion of BASIC'S processing time, thus slowing down the entire program.

"Atari Sound Commander" is a set of machine language subroutines for use with BASIC that solves all three problems. It allows quick and easy manipulation of sound without slowing down BASIC. All you have to do is set up a sound, turn it on, and let it run at the same time as your BASIC program. Best of all, you can use these routines without understanding machine language. Only one BASIC statement is required to activate each sound.

Setting Up

Program 1 is a BASIC loader that installs Sound Commander in memory. When you're finished typing the program, store it on disk or tape with a LIST command (not SAVE) so that you can merge the code with other programs. For example, to list the program to disk with the filename SND.LST, type LIST "D:SND .LST" and press RETURN.

Here's a short example that illustrates the basic mechanics of using Sound Commander. Type in and save this program:

DL 10 DIM S$ (8)
NJ 15 GOSUB 30000
NI 25 FOR A=l TD 8
EC 30 READ B:S$(A,A)=CHR$(B)
OI 35 NEXT A
IM 40 A=USR(SETSND,0,ADR(S$),LEN (S$),80)
KF 45 LIST
KL 50 STOP
OB 55 DATA 170, 25, 170, 50, 170, 75, 170, 100

After you've saved the program, load it back into memory; then use ENTER to merge the lines from Program 1 with the program in memory. This brings Sound Commander into memory without disturbing the existing program lines. Turn up the volume on your TV or monitor; then run the program and notice that the sounds continue in the background while the program lists itself and returns to immediate mode.

Before Sound Commander can be used by a program, it must be initialized. This is accomplished with the statement GOSUB 30000, which installs Sound Commander in the proper memory location. The setup routine is intelligent, meaning that if you have already installed Sound Commander once, it bypasses most of the initialization.

Program 2 is a more complete demonstration, which also includes examples of complex sound effects. Type in and save the program; then reload it into memory. With Program 2 in memory, use ENTER to merge Program 1. When that operation is done, plug a joystick into port 1 and run the program. It displays six numbers and a movable crosshairs shape on the screen. Use the joystick to move the crosshairs onto each of the numbers in turn. Each number generates a different sound. Notice that you can continue moving the crosshairs even while a sound is in progress.

Designing Sounds

Like any sound utility, Sound Commander can't make a sound until you tell it what sort of sound to create. Don't worry; that's not as difficult as it sounds. For this program, a sound is defined as a list of notes, each having its own unique frequency, distortion, and volume, which are represented as numbers. The Atari BASIC manual explains the significance of the frequency, distortion, and volume numbers, which have the same effect here as in the BASIC SOUND command.

It takes only two numbers to define a note. The first number in a note definition represents the note's distortion and volume. This value is computed by multiplying the distortion value by 16 and adding the volume value. For example, if you want a note with a distortion value of 10 and a volume of 8, the first number of that note's definition is 168 (10 * 16 + 8). The second number in a note definition represents the note's frequency. Thus, the numbers 168 and 50 define a note with a distortion of 10, a volume of 8, and a frequency of 50. The numbers 168, 50, 168, 60 define two notes, each having the same distortion and volume, but with different frequencies. The duration of the sound is determined when you actually call Sound Commander with USR (see below).

In order for Sound Commander to process a sound definition, it must be converted into string form. This may sound strange, since strings usually contain characters, but a string is actually nothing more than an array containing numbers in the range 0–255. Storing the values in string form saves space and allows Sound Commander to process the data efficiently.

Before you store a number in a string, of course, it must be converted into character form with the CHR$ function. For instance, the statement A$(1,1) = CHR$(6) stores the number 6 in the first character position of the string A$. For many notes, a program can READ values from DATA statements and store them in a string within a loop.

Commanding The Commander

Once you understand how to define a sound, the rest is easy. One simple USR call causes Sound Commander to play the sound in the background while BASIC continues on its way. Here's a typical USR call for Sound Commander:

DUMMY = USR(SETSND,V,ADR(S$),LEN(S$),L)

The variable DUMMY is required to satisfy the syntax of USR, which takes the form of a BASIC function. Here is an explanation of the other elements in the statement:

SETSND. Defines the location of the machine language routine that starts up the sound. This variable should be defined only once, at the beginning of every program that uses Sound Commander (see Program 1).

V. Defines a voice number (from 0–3) for the sound. If some other sound is already using the voice, Sound Commander turns off the previous sound before it begins the new one.

ADR($S). Defines the address of the string containing the definition of the sound that you wish to play. Substitute the name of your string in place of S$.

LEN(S$). Defines the length of the sound string to be played. Again, substitute your string name for S$. Note that it's not necessary to play an entire string from beginning to end. Many interesting sound effects can be created by playing substrings of a larger string.

L. Defines the length of time to play each note. This value can range from 1–255. A value of one equals 1/60 second. Thus, a value of 60 creates a sound lasting one second, and so on. Low values make the sound play quickly, which is useful for sound effects. Higher values slow down the sound, which is desirable for music.

Once you've performed the USR statement, the sound plays at the desired speed until it is finished, at which time Sound Commander turns it off automatically. While the sound is in progress, BASIC will continue to execute your program, whatever it may be. Now that you understand more about how Sound Commander works, you may want to experiment with the programs to modify the sound they create.

Quiet On The Set

Sound Commander's ability to create sounds in the background is very useful, but has one side effect that's occasionally inconvenient: Once a sound begins, it can't be turned off until it finishes its entire duration. To remedy this, Sound Commander includes a second routine that immediately silences any designated voice or voices. Here is the format for the quiet command:

DUMMY = USR(QUIET, VI, V2…)

Again, the DUMMY variable is present solely for the sake of syntax. Like SETSND, the variable QUIET is predefined by the setup routine and should not be changed while the program runs. This value is followed by a list of the voices you want to turn off. For instance, DUMMY = USR(QUIET,0,3) turns off voices zero and three.

Keep in mind that Sound Commander doesn't disable the normal SOUND command in Atari BASIC. However, it has to use the same sound hardware, so don't try to perform a SOUND command while a Sound Commander sound is in progress. The END statement causes Sound Commander to skip a beat or two, but pressing the break key does not. Input/output activity such as using the disk or tape drive causes Sound Commander to pause. This shouldn't come as a surprise, since not much else can happen during disk and tape I/O, either. The machine language routines used by Sound Commander are stored in page 6 of memory; you should take care that the rest of your program does not disturb that memory area.

For instructions on entering these listings, please refer to "COMPUTE!'s Guide to Typing in Programs" in this issue of compute!.

Program 1: Sound Commander

KO 30000 IF PEEK ( 1564) =104 A ND PEEK(1565)=162 THEN 30020
IJ 30010 RESTORE 30050:FOR A=0 TO 198:READ B:POKE 1564+A,B:NEXT A
JJ 30020 SETSND=1702: QUIET=1741
IP 30030 A=USR(1564)
DF 30040 RESTORE : RETURN
LM 30050 DATA 104, 162, 3, 169, 0, 157
LE 30060 DATA 24, 6, 202, 16, 250, 160
GI 30070 DATA 49, 162, 6, 169, 7, 32
MM 30080 DATA 92, 228, 96, 216, 162, 3
PM 30090 DATA 189, 24, 6, 240, 103, 189
FE 30100 DATA 16, 6, 222, 16, 6, 208
JH 30110 DATA 95, 189, 20, 6, 157, 16
GA 30120 DATA 6, 189, 12, 6, 208, 18
JI 30130 DATA 189, 8, 6, 208, 13, 157
MG 30140 DATA 24, 6, 138, 10, 168, 169
HO 30150 DATA 0, 153, 1, 210, 240, 66
MG 30160 DATA 189, 0, 6, 133, 203, 189
EP 30170 DATA 4, 6, 133, 204, 160, 0
CL 30180 DATA 177, 203, 72, 138, 10, 168
KN 30190 DATA 104, 153, 1, 210, 160, 1
CE 30200 DATA 177, 203, 72, 138, 10, 168
AO 30210 DATA 104, 153, 0, 210, 165, 203
BO 30220 DATA 24, 105, 2, 157, 0, 6
LH 30230 DATA 165, 204, 105, 0, 157, 4
DI 30240 DATA 6, 189, 8, 6, 56, 233
DC 30250 DATA 2, 157, 8, 6, 189, 12
CF 30260 DATA 6, 233, 0, 157, 12, 6
AB 30270 DATA 202, 16, 145, 76, 98, 228
BK 30280 DATA 104, 104, 104, 170, 169, 0
JD 30290 DATA 157, 24, 6, 104, 157, 4
EP 30300 DATA 6, 104, 157, 0, 6, 104
IN 30310 DATA 157, 12, 6, 104, 157, 8
ID 30320 DATA 6, 104, 104, 157, 20, 6
JH 30330 DATA 169, 1, 157, 16, 6, 157
LN 30340 DATA 24, 6, 96, 104, 170, 104
PE 30350 DATA 104, 168, 169, 0, 153, 24
JA 30360 DATA 6, 152, 10, 168, 169, 0
LF 30370 DATA 153, 1, 210, 202, 208, 237, 96

Program 2: Sound Effects Demo

NG 100 GOSUB 5000
EJ 110 ST = STICK (0): IF ST=15THEN 110
JC 120 TX=X+DX(ST-4):TY=Y+DY(ST-4)
FH 130 LOCATE TX, TY, Z
OC 140 IF Z = 42 THEN 110
GL 150 IF Z = 32 THEN COLOR 32:PLOT X,Y:COLOR 171:
       PLOT TX,TY:X=TX:Y=TY:FOR A=l TO 25:NEXT A:GOTO 110
OB 160 POKE 709, INT (RND (0) * 16) *16+INT(RND(0) *3 + 8)
FP 170 A = USR (QUIET, 0, 1, 2, 3)
AB 180 ON Z-16 GOSUB 300, 400, 500, 600, 700, 800
NF 190 IF STICK<0)=ST THEN 190
FN 200 GOTO 110
OG 300 A=USR(SETSND,0,ADR(S1$),LEN(S1$),1)
HE 310 RETURN
OM 400 A = USR (SETSND,0, ADR (S2$),LEN(S2$),4)
HF 410 RETURN
BM 500 A=USR (SETSND, 0,ADR(S3$),LEN(S3$),10)
HG 510 RETURN
OI 600 B = ADR (S4$)
BI 610 A = USR (SETSND, 0, B, 2, 120)
HH 620 A=USR (SETSND, 1, B + 2, 2,120)
HL 630 A = USR ( SETSND, 2, B + 4, 2,120)
HK 640 RETURN
PG 700 A = USR(SETSND,0, ADR (S5$),LEN(S5$),5)
HI 710 RETURN
PI 800 A = USR(SETSND,0. ADR (S6$),LEN(S6$),4)
HJ 810 RETURN
OM 5000 GRAPHICS 17:PQSITI0N 2,11:? #6;"DON'T BO AWAY…"
DJ 5010 QOSUB 30000
GK 5020 DIM DX (10), DY (10)
GO 5030 DIM SI$ (200), S2$ (30), S3$ (100)
PD 5040 DIM S4$ (6), S5$ (24), S6$(14)
GL 5050 FOR A=l TO 10: READ B,C
BL 5060 DX (A)=B: DY (A)=C:NEXTA
EF 5070 FOR A=l TO 199 STEP 2:SI$(A,A)=CHR$(138):S1$(A+1,A+1)=CHR$(A):NEXT A
AG 5080 FOR A=l TO 29 STEP 2:S2$(A,A)=CHR$(175-A/2):S2$(A+l,A+l)=CHR$(70):NEXT A
NG 5090 FOR A=l TO 99 STEP 2:S3$(A,A)=CHR$(170):S3$(A+l,A+l)=CHR$(A/2*5):NEXT A
DM 5100 FOR A=l TO 6:READ B:S4$(A,A)=CHR$(B):NEXT A
GO 5110 FOR A=l TO 24:READ B:S5$(A,A)=CHR$(B):NEXT A
GP 5120 FOR A=l TO 14:READ B:S6$(A,A)=CHR$(B):NEXT A
IE 5500 GRAPHICS 18
LH 5510 POKE 708, 136:POKE 710, 38:POKE 711, 200
ON 5520 COLOR 42: PLOT 0, 1:DRAW TO 19, 1:DRAW TO 19, 11:DRAW TO 0, 11:DRAWTO 0, 1
FG 5530 COLOR 17: PLOT 3, 4: COLOR 18:PLOT 9, 3:COLOR 19:PLOT 16, 4
FD 5540 COLOR 20: PLOT 3, 8: COLOR 21:PLOT 9, 9:COLOR 22:PLOT 16, 8
OF 5550 POSITION 0,0:? #6;"SOund commandar demo"
EM 5560 X = 9: Y = 6:C0L0R 171 : PLOT X, Y
LB 5570 RETURN
PO 6000 DATA 1, 1, 1, -1, 1, 0, 0, 0, -1, 1, -1, -1, -1, 0, 0, 0, 0, 1, 0, -1
FI 6010 DATA 175, 181, 175, 141, 175, 121
JJ 6020 DATA 42, 10, 42, 50, 40, 12, 40, 60, 38, 14, 38, 70,
        36, 16, 36, 80, 34, 18, 34, 90, 32, 20, 32, 100
PO 6030 DATA 204, 40, 202, 50, 200, 60, 198, 70, 200, 60, 202, 50, 204, 40