Classic Computer Magazine Archive COMPUTE! ISSUE 53 / OCTOBER 1984 / PAGE 177

Commodore 64 Music: Happy Birthday

Jim Butterfield, Associate Editor

"The trouble is," said my friend Andrew, "that you can't find the programs which are most wanted. For example, a program that plays 'Happy Birthday to You' is needed for several reasons. First, the 64 is often given as a birthday present; this should be its first program. Second, the computer is a member of the family, and should play a part in the celebrations…"

It didn't seem too hard a job to me. The music-playing program already existed in BASIC, and BASIC programs are easy to change and expand. The musically inclined SID chip gave BASIC lots of time to do extra things.

The music should be written rather slowly (people tend to sing along rather sluggishly), and the words should come up on the screen. A bouncing ball could be achieved by using sprites, but I chose a simpler approach.

Let's program along; I'll give brief notes on what's happening.

100 PRINT CHR$(147); CHR$(154)

Let's clear the screen, set the color to light blue (that's normal).

101 READ S : IF S = 0 GOTO 109
102 READ S$ : GOSUB 1000
103 READ X1, Y1, X2, Y2, X3, Y3
104 GOTO 101

The above code runs through the DATA statements, printing the words of the song. The subroutine at line 1000 does the actual printing; we'll look at it later.

109 RESTORE : PRINT CHR$(19); CHR$(5)

We back up to the start of the DATA statements with the RESTORE command. Now we HOME the cursor and change our printing color to white.

110 L1 = 54272 : L2 = 54279: L3 = 54286
120 Hl = Ll + l : H2 = L2 + l : H3 = L3 + l
130 Vl = Ll + 4 : V2 = L2 + 4 : V3 = L3 + 4
140 POKE 54296, 15

This sets the locations of the various instruments in the SID chip. L and H will be the low and high parts of the frequency (pitch) for each note. V will be the "action" location where we strike the note. And we turn the volume up to its maximum value of 15.

150 POKE Vl + l, 9 : POKE Vl + 2, 0
160 POKE V2 + 1, 36 : POKE V2 + 2, 36
170 POKE V3 + 1, 18 : POKE V3 + 2, 170

This sets the "envelope" for each voice. Voice 1 is bell-like; voice 2 sounds something like a harmonica; and voice 3 has the sound of a bass guitar. As part of our POKE sequence we set the following characteristics:

Attack —how fast the sound appears. This will be fast for the bell and guitar, rather slow for the harmonica.

Decay —how quickly the initial sound settles. This will be fairly slow for the bell, fast for harmonica and guitar.

Sustain —at what level the sound will "hold" once it's settled in. Bell and guitar won't hold the sound at all; it must fade away. The harmonica can keep the sound going for some time.

Release —how long it will take for the sound to die away. The bell dies almost instantly; the harmonica holds for a brief period; and the bass guitar continues to sound longer after it has been plucked.

180 T = TI

We'll be using the timer TI to control the timing of each note. Synchronize your watches; here comes the music-playing part.

200 POKE V1,16 : POKE V2, 32: POKE V3, 16

Release all the instruments. Let go of the string, stop blowing, take your finger off the keys. We must do this each time before we can start the next note. You might observe that the bell and guitar use a value of 16 for a mellow triangle sound; the harmonica uses a more raspy "saw­tooth" created by value 32.

210 READ S : IF S = 0 GOTO 290
212 READ S$ : GOSUB 1000

Read the timing of the next note. If it's zero, quit. Read the word or part of a word that goes with a note. Print it (this time in white).

220 READ X1, Y1, X2, Y2, X3, Y3

Get the pitch of each of the three notes. If an in­strument is silent this time around, its pitch will be given as zero in the DATA statement.

230 IF X1 THEN POKE H1, X1: POKE L1, Yl: POKE V1, 17
240 IF X2 THEN POKE H2, X2: POKE L2, Y2: POKE V2, 33
250 IF X3 THEN POKE H3, X3: POKE L3, Y3: POKE V3, 17

For each instrument: If its pitch is not zero, set the pitch and hit the note. You will see that we make the note sound by adding 1 to the waveform value. Compare these values with the ones shown in line 200, above.

260 T = T + S
270 IF T > TI GOTO 270
280 GOTO 200

We calculate the note's timing, and wait until the proper amount of time has passed. Then we go back and get the next note.

290 FOR J = L1 TO 54296 : POKE J, 0: NEXT J
295 PRINT CHR$(154): END

Finally, we clear all the SID music registers, change the printing color back to light blue, and stop.

Here come the DATA statements to play the music and write the words. Note that whenever a word ends with a period or comma, it will be printed and then a new line will be started.

300 DATA 40, "{2 SPACES}HAP", 34, 75, 0, 0, 0, 0
310 DATA 20, " PY ", 34, 75, 0, 0, 0, 0
320 DATA 60, " BIRTH ", 38, 126, 28, 214, 5, 185
330 DATA 60, " DAY ", 34, 75, 28, 214, 0, 0
340 DATA 60, " TO ", 45, 198, 38, 126, 5, 185
350 DATA 60, " YOU ", 43, 52, 30, 141, 4, 73
360 DATA 60, " , " , 0, 0, 0, 0, 0, 0
370 DATA 40, "{2 SPACES}HAP", 34, 75, 0, 0, 0, 0
380 DATA 20, " PY ", 34, 75, 0, 0, 0, 0
390 DATA 60, " BIRTH ", 38, 126, 30, 141, 6, 108
400 DATA 60, " DAY ", 34, 75, 30, 141, 0, 0
410 DATA 60, " TO ", 51, 97, 34, 75, 4, 73
420 DATA 60, " YOU ", 45, 198, 28, 214, 5, 185
430 DATA 60, " , ", 0, 0, 0, 0, 0, 0
440 DATA 40, "{2 SPACES} HAP", 34, 75, 0, 0, 0, 0
450 DATA 20, " PY ", 34, 75, 0, 0, 0, 0
460 DATA 60, " BIRTH ", 68, 149, 22, 227, 5, 185
470 DATA 60, " DAY ", 57, 172, 25, 177, 0, 0
480 DATA 60, " DEAR ", 45, 198, 28, 214, 7, 53
500 DATA 60, " AN " , 21, 154, 30, 141, 7, 163
510 DATA 60, " DREW ", 19, 63, 30, 141, 0, 0
520 DATA 60, " , ", 0, 0, 0, 0, 0, 0
530 DATA 40, "{2 SPACES} HAP", 61, 126, 0, 0, 0, 0
540 DATA 20, " PY ", 61, 126, 0, 0, 0, 0
550 DATA 60, " BIRTH ", 57, 172, 34, 75, 8, 147
560 DATA 60, " DAY ", 45, 198, 28, 214, 0, 0
600 DATA 60, " TO ", 51, 97, 30, 141, 4, 73
610 DATA 60, " YOU. ", 45, 198, 28, 214, 2, 220
620 DATA 0
1000 PRINT S$; : IF RIGHT$(S$, 1) < " 0 " THEN PRINT
1010 RETURN

Finally, we see a subroutine at 1000 to print the word or part word, and to test if it ends in a nonalphabetic character. If so, a new line will be started. Be sure to include the semicolon after the PRINT statement in line 1000.

Copyright © 1983 Jim Butterfield