Commodore 64 SID music programming with BASIC – playing a note

Although machine language is what we really need for C64 music programming, BASIC may be more than acceptable for some experiments on SID music programming.

As Commodore 64 BASIC V2 doesn’t provide specialised commands for music, SID music programming using this interpreter is just a matter of POKE instructions.

I’ve already provided you with some tutorials dealing with composing C64 music with Goattracker. But if you are interested on actually coding what you are hearing, then this article may be of help.

We will start by just playing a note. Nothing very exciting, but many concepts are required even for this very basic task.

I’ve already introduced musical notes and very rough music theory concepts on the Goattracker tutorials, so if you need to dust off such topics please refer to them.

 

Frequencies of notes

Each note on a piano keyboard has its own frequency. The higher the frequency, the higher the sound. In other words, the frequency is the pitch of a sound.

We can compute the frequency of any note by starting from the frequency of a particular note that we are using as a reference. Usually, notes frequencies are referred to A4, the A note on the fourth octave, which has a frequency of 440 Hz.

The A3 note, which is an A note on the third octave, has a frequency that is half the frequency of A4, that is, 220 Hz. The A5 note, an A note on the fifth octave, has a frequency which doubles the frequency of A4 instead. So, A5 frequency is 880 Hz.

On each octave we have twelve half tones. That means, seven “full” notes (natural notes) and five sharp notes. Sharp notes may be seen as detuned notes used to make melodies richer. Natural notes are the white keys on a piano keyboard, sharp notes are the black ones.

To make the SID chip play a note, we must know what frequency matches that note. The following formula will be of help:

\[ f_n=f_0 \cdot a^n \]

\( f_n \)​ is the frequency we want to compute. It’s the frequency of the note we want to play, which is ​\( n \)​ half steps away from the reference note.

\( f_0 \)​ is the reference note. As we know, it is usually 440 Hz, the frequency of A4.

\( a \)​ is a constant, which equals ​\( 2^{1/12} \)​.

\( n \)​ is the number of half steps from the reference note. It can be either positive or negative. If the note we want to compute the frequency of can be found on the piano keyboard before A4, then ​\( n \)​ will be negative, otherwise it will be positive.

For instance, if we want to compute the frequency of C4, we have:

\[ \large \begin{align} & n = -9 \\ \\ & f_{-9}= f_0 \cdot a^{-9}=440 \; \cdot \left( 2^{1/12}\right) ^ {-9} = 261.626 \approx 261 Hz\end{align} \]

If we let ​\( 2^{1/12} \approx 1.05946 \)​, then we can use the following simplified formula:

\[ f_n = 440 \; \cdot \; 1.05946^n \]

We must note that physical frequencies values are different from the values used by the SID. In particular, the SID frequency ​\( f_{nSID} \)​ is:

\[ f_{nSID}=16.94 \cdot f_n \]

To make things simpler, we can just take:

\[ f_{0SID}=f_0 \cdot 16.94 = 440 \cdot 16.94 \approx 7454 \]

and use this value as the reference value, instead of 440 Hz. The program that will be presented at the end of this article will just do this.

Note: you may wonder why the SID frequency value is not the same as the phisical frequency value. As we can obviously poke only integer numbers in memory, the factor 16.94 acts as some sort of integer math offset. This way, despite the use of integer numbers, we can adjust the frequency of a note with a resolution of 1/17 of a hertz. This allows for very fine tuning of sound frequency and very smooth portamentos. This is something that really sets apart the SID chip from other home computer audio chips of the time.

 

Playing a note with the SID chip

Now, let’s have a look at the easiest way to play a single note with the Commodore 64 SID chip.

SID registers are used as a means of communicating with the SID chip. Those registers are mapped on RAM, just like VIC-II registers, so playing a note is just a matter of putting some values on RAM memory. And as we know, the POKE instruction is just what we need for that.

Each sound has a volume, a waveform, an envelope and, of course, a frequency.

On a SID chip, three voices are available. That means, up to three notes being played at the same time are possible. However, we will only use voice 1 for the moment.

The volume for all voices is set by using register 54296 decimal of the SID chip. Since the base address of the SID chip is 54272, if we put S = 54272, then the volume register is S+24. This is much easier to remember.

Volume can range from 0 (silence) to 15 (full volume).

So, to set full volume we code:

POKE S+24,15

Of course, we are assuming the variable S has been assigned the value 54272 already.

The waveform can be seen as the shape of a sound. On a SID, we have four waveforms available. On this tutorial, we will only use two waveforms: triangle and sawtooth. For voice 1, those waveforms can be selected by turning on bit 4 and bit 5 of register 54276 decimal (S+4 using the variable S for SID base address).

However, instead of POKEing the waveform value on that register, we will just store it on a variable called WF. Why? It will be clear in a few moments.

So, if we want to use triangle waveform, we will code:

WF = 16

And, if we want to use sawtooth waveform, we will have to code instead:

WF = 32

 

The envelope may be seen has the way the volume changes while a note is being played. When you start a note, you may suddenly hear it at full volume. Then, when you stop that note, you may have it just disappear instantly. This is the behaviour of an organ. When you press a key, you just hear the note at full volume. As soon as you release the key, the sound stops instantly.

But, other instruments have different behaviours. For instance, on a piano, even if you keep a key depressed, the note will eventually fade away. So, a piano has a different envelope than an organ.

A volume envelope has four phases:

  • attack: this is the phase when a given note appears. It may get instantly at full volume, or it can slowly grow from volume zero. For voice 1, the value on bits 4-7 of register 54277 (or S + 5) tells how much time will be required to reach full volume. This value will range from 0 to 15. The greater the value, the greater the time required to reach full volume. Note that when POKEd, the attack value must be multiplied by 16.
  • decay: this is the phase when the volume of a given note lowers. The bigger the duration of this phase, the lower volume level we will end up with. Decay value ranges from 0 to 15, and it is set for voice 1 by using bits 0 – 3 of register 54277 (S+5). For example, this value will be set to 0 for an organ: the sound must be at full volume for the whole duration of a note.
  • sustain: this is the volume level after the decay phase. It can range from 0 to 15 and it is set, for voice 1, by bits 4-7 of register 54278 decimal (S+6). A 0 value means no sound, a value of 15 means that the volume will be sustained to the peak volume reached during the attack phase. Like the attack value, when POKEd the sustain value must be multiplied by 16.
  • release: when the piano key is released, the note may take some time to fade or may fade instantly. This depends on the value on bits 0 -3 of register 54278 (S+6). The bigger the value, the bigger the time needed for the note to fade away. For example, on an organ this value must be set to 0 (the note must fade instantly when the key is released).

 

Finally, the frequency\( f_n \)​ of the note to be played using voice 1 can be selected by setting registers 54272 and 54273 (S and S+1). Register 54272 will hold the low byte of the SID frequency value ​\( f_{nSID} \)​, while 54273 will hold the high byte. We can just use the formula presented above, then split the result in high byte and low byte:

HI = INT(BYTE / 256)

LOW = BYTE - 256 * HI

Before we can play a note, we still need one last thing.

 

The gate bit: our way to depress a key and release it

If you want to play a note on a piano, you need to depress a key and then release it. This is easy to do on a real instrument… but how it can be done on a SID? The gate bit is what we need.

For voice 1, the gate bit is bit 0 of register 54276 (S+4). When this bit is turned on, the attack / decay / sustain phases take place. That means, the note starts. When the gate bit is turned off, the release phase starts, so the note fades away according to the release value.

So, turning on the gate bit is the same as depressing a key on the piano keyboard. And turning off the gate bit is the same as releasing a key on the piano keyboard.

We will have to set the waveform and the gate bit at the same time. This is due to the fact that SID registers cannot be read. So, we cannot use separate instructions to select the waveform and to turn on the gate bit. For instance, the following code will NOT work:

POKE S+4, 16: POKE S+4, PEEK(S+4) OR 1: REM WRONG

So, we are forced to code something like this:

WF=16: POKES+4, WF+1

So, the instruction:

POKES+4, WF+1

will turn on the gate bit and will set the required waveform at the same time, hold by the variable WF.

Similarly, the instruction:

POKES+4, WF+0

will turn off the gate bit maintaining the desired waveform. This is important, otherwise another unwanted waveform may be used on the release phase!

Of course, WF+0 can be replaced with simply WF. But, I have added a 0 just to make it clear that we are setting the gate bit to 0.

Now we have all we need to play a note.

 

Our BASIC program

This simple program will play a C4 note using sawtooth waveform on voice 1.

 

DOWNLOAD: musical note with Commodore 64 BASIC

 

You will find many comments on the code while listing, for your convenience.

 

SID music programming

 

The note being played can be changed by adjusting the value of line 25. For instance, if you want to play a C5, you will just need to assign N the value 3. In facts, C5 is 3 half-tones past A4. Changing the value of N to 5 will play a D5 note instead.

Envelope parameters are set on lines 50 and 55. All parameters range from 0 to 15, but as we already know attack and sustain values are multiplied by 16. In facts, they live in the highest four bits of their register.

The duration of a note is the amount of time the gate bit is maintained set to on. This value is set on line 65.

On line 70, the gate bit is set to on. The attack phase starts. In other words, the note starts.

After the duration loop on line 75 ends, line 80 starts the release phase by turning off the gate bit. The piano key is released. The note does not disappear instantly, as we have a value of 10 for the release parameter (please see again line 55). You may try to change the release value to 0. Then, the note will stop instantly.

This program uses the sawtooth waveform. To hear the triangle waveform, replace the value of WF with 16 (line 45).

Previous Entries Very basic BASIC: drawing tilted ellipses (Commodore 64) Next Entries Commodore 64 SID music programming with BASIC – playing a simple one voice tune

Leave a Reply

*