©1985 / Charles A. Measday
If you're looking for information about the Commodore VIC-20 and C64, visit the famed Toronto PET Users Group; its links page will lead you to more resources on these classic computers.
It was an exciting moment when I first ran Donald J. Eddington's MozartMachine (COMPUTE!, January 1984) and heard my VIC-20 playing real music!
Eddington published a number of articles in various Commodore magazines. See this YouTube video of Eddington's The Grand Improvisor on a Commodore 64.
Reading the article inspired me to write a BluesBand program and examining the Mozart program in more detail suggested some techniques of implementation. After a little work, I had my VIC-20 playing a somewhat random bass pattern, following a standard blues chord progression, and I was the featured soloist "tickling the ivories" on the top row of the keyboard. Wow! Too bad it sounded awful!
My initial endeavor at computer music was disappointing and discouraging.
Taking a last, "I-give-up" look at the VIC-20 Programmer's Reference
Manual, I suddenly noticed that the sound register
values given for different notes were not in an orderly sequence.
Discussion of the problem with a classical guitarist of local fame, Don Sauter, yielded the following facts. First, to go up an octave, you must double the frequency; i.e., the next octave above a 440-Hz A is an 880-Hz A. Second, the twelve half-steps in an octave are equally-spaced with regard to their tone. Mathematically, this means that you must multiply the frequency of a note by the 12-th root of 2 in order to move up one half-step. Because of these facts, the linear sequence of tones you perceive as you plunk your way up the piano keyboard is actually caused by increasing frequency differences between successive half-steps and octaves.
The table of musical notes found on
97 of the
Programmer's Reference Manual shows a similar, but inverse,
relationship: the differences in
POKE values between
successive octaves are halved. For example, the note C has
POKE values of 135, 195, 225, and 250; the differences between
octaves, 60, 30, and 15, are progressively halved. Therefore, you might
POKE values for successive half-steps to be
characterized by decreasing increments. Good guess, but you're wrong! The
first octave (C, C#, D, D#, E, etc., with
POKE values 135,
143, 147, 151, 159, etc.) has the sequence of differences 8, 4, 4, 8, 4, 4,
8, 4, 4, 4, 4, and 4 - clearly not the continually decreasing increments we
How did Commodore get the
POKE values they got and what are
the correct values? The answer to the first question is "I have no idea!".
The answer to the second question can be found buried in the information
about the VIC-20's video interface chip
216-217 of the VIC-20 Programmer's Reference Manual).
The video interface chip uses four registers to turn on or off and set the
frequency of the VIC's bass, alto, soprano, and noise voices. Setting the
most significant bit (
POKE value with
128) of a register turns that voice on; clearing the most significant bit
POKE value with 127) turns the voice off. The
X, used to generate a particular
frequency is calculated as follows:
frequency = clock / (127 - X)
Knowing this formula and our little bit of music theory, we can construct
a new musical note/
POKE value table for the VIC-20. To begin,
we choose a clock value of 3995 for the bass voice (see the NTSC table on
217 in the VIC-20 Programmer's Reference Manual). The
POKE values we will compute, when
POKE'd into the
other voices' registers, give notes shifted up one octave for each voice. A
standard frequency is the 440-hz A; dropping it down four octaves (
-> 220 -> 110 -> 55 -> 27.5) and multiplying it three times
by the 12-th root of 2 (
A -> A# -> B -> C) brings us to
the same C note that the VIC-20 Programmer's Reference Manual
starts its table with. The following
BASIC subroutine, used in
the BluesBand program, sets up the voice parameters and builds
the new table in array
9500 REM MUSIC SETUP 9502 V = 36878 : S1 = 36874 : S2 = 36875 : S3 = 36876 : S4 = 36877 9504 NN = 66 : DIM N(NN) : S = 2^(1/12) : C = 3995 : F = (440/4)*S*S*S 9506 FOR I=1 TO NN : N(I) = 128+INT(127-(C/F)+.5) : F = F*S : NEXT I 9508 RETURN