It is well known by most experimenters that music is made up of different frequencies and durations, plus pauses (or rests) of different durations. It is also known that a microprocessor is eminently capable of deriving such frequencies, and outputting them from a serial output port. In the case of the CD1802 microprocessor by RCA, as used in the COSMAC Elf, the Q-output port can be programmed to play a melody, via any suitable amplifier and loudspeaker, or even 10 - 20" of wire!
Several music programs were studied, including those in the November 1977 Interface Age, and in the February 1978 Popular Electronics. While they worked well, within their limitations, it was decided to make a program with some features that would be more flexible. This would enable even a neophyte musician the knowledge to program in his own melodies. Some useful features of the program are:
Each data byte that is used to program a melody has its 8 data bits broken up into 3 parts, as shown in Figure 1. The 4 low bits define the note frequency, the next 3 bits define the duration, while the high bit defines which octave is chosen. The resultant data byte is called a Music Byte.
Note Bits: Whether the note to be coded is in the high or the low octave, the 4 note bits are always coded in HEX-code as the lower HEX-digit, shown in Table 1.
| Music Code: | A | B | C | D | E | F | G | A# / B-flat |
C# / D-flat |
D# / E-flat |
F# / G-flat |
G# / A-flat |
rest |
| Low Hex Digit: | A | B | C | D | E | F | 9 | 4 | 5 | 6 | 7 | 8 | 0 |
In Table 1, a "#" is a sharp, a half-tone above the basic note, and a "flat" is a half tone below the basic note.
Duration Bits: For the duration of a note, music works in a binary fashion. Some basic common notes are quarter notes, eighth notes, sixteenth notes, etc., known as crotchets, quavers and semiquavers, respectively. They sometimes have a dot placed after them, which increases their duration by 50%. Such an increase can easily be coded in a binary system. Some examples are shown in Table 2.
| Music Code | Duration | Duration Bits |
| 1/16 note | 0 0 1 | |
| 1/8 note | 0 1 0 | |
| 3/16 note | 0 1 1 | |
| 1/4 note | 1 0 0 | |
| 3/8 note | 1 1 0 | |
| 1/8 rest | 0 1 0 | |
| 1/4 rest | 1 0 0 |
Octave Bit: The program has one basic low octave of twelve semi-tones programmed into it. This octave includes the seven basic notes labelled A to G, plus the five sharps or flats. To derive the high octave of notes, the program doubles the pitch of these low notes. This is triggered by programming a '1' in the octave bit. Same examples show how the music byte is built up, and then converted to HEX-code:
The program shown in Table 4 is walked-through in some detail below. This has been done to help neophyte programmers like myself and others, to be better able to grasp the use of some of the simple, and extremely useful 1802 program code instructions. To aid in these explanations, an arbitrary first music Byte of B9, (a high octave G, 3/16-note long) has been placed in address 50, the address of the first note of a melody. The 1802 register locations are variously referenced as R-1.0, low-C, high-B, Register-F, etc.
Register-8 is firstly made the stack pointer. Next,address 50 is loaded into low-8. The speed modifier address, 43, is then loaded into low-9. The LDXA instruction then extracts the contents of address 50, (which in the example is Music Byte B9), and puts it in the D-accumulator. The PLO A instruction then stores this B9 in low-A. With a Music Byte of 00 put at the end of a melody, the program branches back to address 01, and repeats the whole melody. This will continue, until a 'Halt' command stops the program.
This is obtained by ANDing 70 with the Music Byte. This masks out both the octave bit, and the note bits, leaving the duration byte, 30. As this is stored in high-B, the complete constant is 30 00. This is equivalent to a decimal number of 3 x 16 x 16 x 16 = 12,288.
This constant is later used in the duration loop, where it will be decremented, while the Q-output is oscillating at the note frequency, until hi-B gets to zero. This gives the note's duration.
As written, with NOP's from address 0E to 16, the speed of the melody is based on the timing the 'composer' puts into each Music Byte, and remains unaltered. Later, it will be shown how to modify the overall speed of the melody, either up or down, by editing some or all of these nine address locations.
The note bits are firstly extracted from the Music byte by ANDing it with 0F. This masks out the duration bits and the octave bit, leaving a note constant of 09. This constant is then OR'd with 40, which produces the address of the note's frequency constant, associated with the particular note itself. Here, 09 OR'd with 40 gives 49, the address in which the frequency constant for note G had been previously inserted. The LDN instruction gets this frequency constant, 33 (or decimal 51); PLO E stores it in low-E.
(Note that by ANDing with 40, all reference notes used in the program are located within addresses 40 through 4F).
The Music Byte is again retrieved by GLO A, and AND'd with 80. This masks out the note and duration bits, and in our example, leaves a '1' in the octave bit. This gives an octave constant of 10. (If a low octave note had been programmed instead, a 00 would have resulted, which would cause the high octave generator to be bypassed.) However it is needed in our example, so the frequency constant is retrieved, and a Shift Right, SHR, is made. This divides 33 (or decimal 51) by two. This produces 19 (or decimal 25), also DF = 1 , (a remainder). Then a '1' is subtracted from the D-register, which is then saved as 18 in low-E. This gives a truer pitch for the high octave notes.
It can now be seen that Q switches on and off, at a rate set by the initial low-E, and a duration set by the initial high-F.
The overall speed of the melody may be too fast or too slow for the melody programmed in. However, a simple change of speed can be made, by modifying the program at address 0E to either SHR or SHL. These two instructions take the contents of the D-accumulator, (in our example, Hex 30), and shift the binary digits one place to the right, or the left, as desired. Thus:
30 = 0011 0000 (count=48); after SHR, 0001 1000 = 18 (count=24)
30 = 0011 0000 (count=48); after SHL, 0110 0000 = 60 (count=96)
If either instruction is used, followed by a save instruction PHI B at address at 0F, the duration constant, and hence the melody speed, will be either doubled or halved, as applicable.
One of the other two alternate speeds can also be programmed into the same addresses. One of these multiplies the original duration constant in register-B by 1.5, and the other by 0.75. Addresses 04 to 06, plus 43, are programmed to temporarily designate register-9 as a stack pointer, only during this speed modifier. The four modifiers are shown in Table 3. An explanation follows of the 0.75 duration modifier, with Hex 30 being the original contents of high-B:
| Memory Location |
Half Duration |
Double Duration |
3/4 x Duration |
3/2 x Duration |
| 0E | F6 (SHR) | FE (SHL) | FE (SHL) | FE |
| 0F | BB (PHI B) | BB | 59 (STR 9) | 59 |
| 10 | C4 | C4 | E9 (SEX 9) | E9 |
| 11 | C4 | C4 | 9B (GHI B) | 9B |
| 12 | C4 | C4 | F6 (SHR) | F6 |
| 13 | C4 | C4 | F5 (SD) | F5 |
| 14 | C4 | C4 | F6 (SHR) | C4 (NOP) |
| 15 | C4 | C4 | BB (PHI B) | BB |
| 16 | C4 | C4 | E8 (SEX 8) | E8 |
FE doubles the 30 to 60
59 stores this 60 at address 43
E9 sets X to 9, making register-9 a temporary stack pointer
9B retrieves the original counter of 30
F6 halves the 30, giving Hex-18
F5 subtracts this 18 from 60 in address 43, giving Hex-48
F6 halves the 48, giving 24
BB stores this modified duration constant back in high-B
E8 resets the stack pointer to 8, for the next Music Byte
Thus, the original duration counter of 30 (or decimal 48), has been changed to 24 (or decimal 36), which is 0.75 times its original value. This means that every duration of note or rest will be lowered, giving an overall speed increase of 4/3 times.
Now comes the interesting task of programming melodies of one's own choice, and then being able to sit back and listen to them, or accompany them on a guitar, or piano, etc.
In Figure 2, the two lines of notes show both octaves that are programmable by the Music Machine. The two lines are prefixed by a symbol called the G-clef. This represents the upper clef of written music, in which most melodies, often with accompanying words, are written. The pitch, or frequency of the notes, is coded by the same Hex-digit, for either the high or low octave note. If a rest (or pause) needs coding, this lower Hex-digit is always coded as a zero. To differentiate between these two octaves, a '1' in bit-8 of the Music Byte changes the frequency to a high octave note.
Note: a half note, called a minim, is split between two music bytes. A dotted minim needs three music bytes. A whole note, called a breve, needs four music bytes.
The two octaves of notes shown in Figure 2 have all been coded with a duration of '4', for a 1/4-note, (a crotchet). Below these notes is a summary of the left-hand Hex-digit options; the only difference between the two rows being, of course, the fact that the high-octave digits are decimal-8 greater than the low-octave digits. This is due to the octave-bit of '1' in the highest bit of the Music Byte.
Figure 3 shows a simple ending to a tune. It is written in the key of C, in 6:8 time. This timing means the equivalent of 6 notes to a bar, each being 1/8 of a whole note in duration. The tune could have been written twice as fast, using a B and 3, instead of E and 6, and a 1 instead of 2, in the first Hex-digit. Note that the sixth note has a new accidental after it, called a 'natural'. It cancels the G# in the same bar, and the note reverts back to G-natural, or just G.
For longer melodies, one of the Speed Modifiers would be put in addresses 0E to 16, as a much easier way to adjust the speed of the melody. Note that the two rests, of duration 4/16 and 2/16, are combined as duration 6/16, to save precious memory space.
The following melody is part of a well known tango. It has been written directly in Hex-code, and should be recognized by almost everyone:
46 2D 40 26 2D 40 26 2D 27 AA 60 46 2D 40 26 2D 40 26 2D 29 A4 60 46 2D 40 26 2D 40 26 2D 27 AA 60 C4 29 40 A6 AD AC 20 94 9A 29 20 4D 29 20 00
Without going any further into music theory, the few introductions into basic music given herein, should be enough to enable a microprocessor experimenter to transcribe a favorite melody into Music Bytes. A musician friend could give assistance, if difficulties are encountered in early attempts at transcription.
To hear the melody, the output at the Q-output port must be made audible. A simple way of achieving this is to connect a short wire to the Q-output, and bring the wire close to the antenna of an A.M. radio. As long as the 1802-chip clock frequency lies in the range of, say, 750kHz to 1600kHz, the radio can be tuned to the clock frequency, and the melody can be heard.
In the author's system, the original 1MHz clock frequency had been increased by installing a 2.01MHz crystal. This simple change enabled reasonably accurate high frequency notes to be generated by the Music Machine. With this crystal, the low-octave note A is about 220Hz, and the high-octave G# is about 784Hz. These frequencies, and all the intermediate ones, have been made as close as possible to those of a properly tuned piano. To accommodate the higher clock frequency, a simple audio 1-transistor amplifier was used, as shown in Figure 4. Any transistor of Beta >= 50 is O.K. The speaker can be 8 ohms or higher. A ratio of 20:1 for T1 works well.
However, the use of a 1MHz clock frequency will not affect the operation of the program. The basic difference will be that the note's frequencies will be halved, and their durations will be doubled. The notes will still be in tune, except that they would be one octave lower than with a 2.01MHz clock frequency. The speed difference can be adjusted, as desired, by using a speed modifier.
Each instruction in the loops shown in Figure 5 takes a total of 16 machine cycles to complete. To program the Q-output to switch ON and OFF at a specific frequency of 'P' Hz, a frequency constant 'Y' must be derived. This is a decimal constant, whose equivalent in Hex-code is put in low-E. The D-accumulator will be decremented Y-times in the inner loop 'X'.
So, low-E = Y, and let K = clock frequency in MHz. Then t = time of 16 machine cycles, or 16/K. Analysis of the overall loop gives:
Time Q is switched on = t + 3t + 3tY + 4t = 8t + 3tY
Time Q is switched off = t + 3t + 3tY + 4t = 8t + 3tY
Time of 1 Q-On/Off cycle = T usec = 16t + 6tY
This gives T = t(16 + 6Y).
But, T = 10^6/P usec, where P = note frequency in Hz.
So 10^6/P = t(16 + 6Y), or 6Y = 10^6/tP - 16, or Y = 10^6/6tP - 8/3.
Substituting t = 16/K, then, we find Y = 10^6K/96P - 2.67.
Example:
Assume K = 2.01MHz; find Y for low-octave G of 392 Hz.
Then Y = (2.01 x 10^6) / (96 x 392) - 2.67 = 50.7 (or 51 as a whole number).
Converting to hex, Y = 33 hexadecimal.
The constant 33 is loaded in address 49 as the frequency constant for low-octave G of 392 Hz. Similar constants can be derived for any clock frequency or any note frequency.
(The actual note frequencies were obtained from: "Reference Data for Radio Engineers", by IT&T Corp.)
A duration constant of 30 00 in Register-F will be decremented 3 x 16 x 16 x 16 times, to 00 00. In our case, we only need high-F to reach zero.
To get high-F to 00, number of decrements = 12288 - 255 = 12033.
During 1-cycle of low-octave-G, the D-accumulator is decremented to zero twice, giving 2 x 51 or 102 decrements.
Now, every time D-accumulator is decremented, so is Register-F.
So, high-F lets Q cycle at 392Hz, or: 12033 / 102 = 117.97 (= 118 times).
But, one cycle of a G of 392Hz is 10^6 / 392 = 2551 usec.
So, duration 30 is equivalent to 118 x 2551 usec = .301 sec.
Similar calculations show that duration:
10 = .10 sec
20 = .20 sec
40 = .41 sec
60 = .61 sec
Check:
Melody No. 2, shown earlier, has the equivalent of 32 1/4-notes in it, each of Hex-duration 40. When played through five times for a total of 160 1/4-notes, the total time taken was 65 seconds.
This gave a duration for '40' time of 65/160 or 0.41 seconds. Thus, the theory agreed with practice.
Another use for this program, with two minor modifications, is to employ it as an audio sweep generator. For this purpose, the codes at addresses 2A, 2C, 2F, 42 and 50 are used. The two modifications are:
In the first Music Byte address of 50, a "Sweep Byte" of 22 is inserted as a first attempt. If the program is now run, it will be seen that 22 is put in low-A; low-B becomes 20; low-C is 02; low-D is 42, (which makes low-E a value of FF from address 42). This low-E of FF is decremented to FE at address 2A, ( or decimal 254). After copying to low-F, the frequency and duration loops are picked up, letting the Q-output oscillate at 81.68 Hz for about 0.2 seconds. The program then branches back to address 2A, where low-E is again decremented, dropping to FD, or decimal 253. This allows Q to oscillate at 82.00 Hz for the next 0.2 seconds. The process repeats, with low-E dropping and the frequency increasing, until low-E reaches 01. Then, the next decrement changes it to 00, and the sweep starts up again at the low frequency. With the author's 2.01 MHz clock frequency, the highest frequency obtainable is about 9 kHz.
It can be seen that as the frequency gets higher, the steps between notes become more apparent, as low-E gets smaller and smaller. That is to say, a decrement of 01 when low-E is 250, only varies the frequency by about 0.4%. However when low-E changes from 9 to 8, a frequency change of about 10% occurs.
With the "Sweep Byte" of 22 in address 50, the total duration for one complete sweep is about 52 seconds. Any "Sweep Byte" from 12 to 72 may be put in address 50; (it must end in a 2). The sweep duration can thus be programmed to last from about 26 secs. to over 3 minutes, The Speed Modifiers of doubling or halving the duration can also be brought into play, if desired.
A possible practical use of this sweep generator is in the testing of a complete audio system. With an oscilloscope on the output of the amplifier, the response to the square-wave output from the Q-port can be examined. With a loudspeaker on the amplifier output, resonances, particularly at the lower frequencies, can be detected.
In conclusion, it is felt that this reasonably simple program will stimulate experimenters to work out further modifications.
00 E8 SEX 8 Use Register-8 as stack ptr. 01 F8 50 LDI 50 1st Music Byte loc'n to R-8.0 03 A8 PLO 8 04 F8 43 LDI 43 Speed modifier loc'n to R-9.0 06 A9 PLO 9 07 72 LDXA Get music byte; advance stk ptr. 08 AA PLO A Store Music Byte in R-A.0 09 32 01 BZ 01 If Music Byte is 00, repeat tune 0B FA 70 ANI 70 AND 70 with B9 0D BB PHI B Store result - duration byte 0E-16 All C4 NOP (See text for speed modifier) 17 8A GLO A Get Music Byte 18 FA 0F ANI 0F AND 0F with B9 1A AC PLO C Store result-note constant = 09 1B F9 40 ORI 40 OR 40 with 09 1D AD PLO D Store result-note loc'n = 49 1E 0D LDN Get freq. constant in locn'n 49 1F AE PLO E Store note freq. constant = 33 20 8A GLO A Get Music Byte 21 FA 80 ANI 80 AND 80 with B9; oct. byte = 10 23 32 2A BZ 2A If oct. byte is 00, go to 2A 25 8E GLO E Get low oct. freq. constant 26 F6 SHR Shift rt., nominally halves 'E' 27 FF 01 SMI 01 Final hi-oct. freq. constant mod'n 29 AE PLO E Store hi-oct. freq. constant 2A C4 NOP Spare (See "New Uses") 2B 9B GHI B Get duration constant 2C BF PHI F Make a copy. (See "New Uses") 2D 9F GHI F Get duration constant 2E 32 04 BZ 04 If hi-F=00, get next Music Byte 30 8E GLO E Get frequency constant 31 FF 01 SMI 01 Decrement freq. const; hold in 'D' 33 2F DEC F Decrement duration constant 34 3A 31 BNZ 31 Back through loop until 'D' = 0 36 8C GLO C Get note constant 37 32 2D BZ 2D If 00, back through duration loop 39 31 3E BQ If Q = 1, go to reset Q 3B 7B SEQ Set Q 3C 30 2D BR 2D Loop back until duration ends 3E 7A REQ Reset Q 3F 30 2D BR 2D Loop back until dur'n ends 41 C4 NOP Spare; end of main program 42 FF (See "New Uses") 43 C4 NOP Reserved loc'n for speed mod'r (Note constants; numbers are for author's system, #s in parentheses are for colorburst/2 crystal) 44 57 (4D) A# (or B-flat) 45 49 (41) C# (or D-flat) 46 41 (3A) D# (or E-flat) 47 36 (30) F# (or G-flat) 48 30 (2B) G# (or A-flat) 49 33 (2D) G 4A 5C (52) A 4B 52 (49) B 4C 4D (45) C 4D 45 (3D) D 4E 3D (36) E 4F 39 (33) F 50 ... 1st Music Byte of melody