Chapter 05 - Let there be music (Part 2)
It's been a long time between
drinks but as usual, life gets in the way.
I have a renewed
appreciation for people who "don't have a life".
I can see that as an advantage. It means that they are more immune to
the distractions of life and can get on doing with what they
really want to do... like playing on their
CoCo's without interruption! :)
project has taken a major turn with a total redesign of the G-Tracker
program I was developing in the previous chapter. I'm new to the whole making music thing, and I found that my previous work was fraught
with problems and began to see the limitations of the design. But modifying the work I had already done was difficult since
my previous program was written in Assembly Language and while this
gives me maximum speed, it also makes it a lot harder to change
ideas mid stream.
Language is a great language but make sure you clearly understand and
have a clear and solid plan of what you are trying to achieve.
I decided that the best thing to do was a total
redesign. This time though, I decided to use BASIC for a quicker and
easier development path.
BASIC in the past to create utilities and tools to aid the creation of
my games. This time, I
tried to be smart and use Assembly Language because I thought
BASIC would be too slow. It is certainly too slow to actually
play four voices with envelope capabilities but apart from the
music playback, I felt BASIC could do a reasonable job handling the
editor portion of the program.
So the new plan was to write it as a hybrid. That is, BASIC with an Assembly Language music playback routine. The interrupt
driven playback routine I created in my previous G-Tracker program was
used largely unchanged.
I had already spent a lot of time optimizing and refining that code.
On the other hand, the actual music composition editor was given a whole new interface
A new program, a new name.
Game Music Composer is
the new name I have chosen for this redesign. As you can see by the
screenshot on the right, the user interface is very different from the
G-Tracker program I was working on prior.
must admit, I'm
not all that knowledgable with music theory and so I needed something
easier for me to understand. I also can't read music notation or
know music language. I can't even play a musical keyboard!
what better way to create a music composition program than by diving in
blind, programming by the seat of your pants! Now that's the true retro spirit! :)
I should make it clear. This program is not a great music program for use by anyone wanting to create music.
Game Music Composer (GMC) is merely a tool I am developing to help me compose music for my games.
it will be used to create Title and Game Over music for Gunstar. I will
include it as an extra with the game if anyone wants to use it for
BASIC never looked so good!
are lucky to have a very capable and powerful BASIC built in on ROM and
available from immediate power up. It has it's problems, quirks and
could do with a few optimizations but it's better than what much of
the competition had at the time.
GMC is in 100% BASIC except for the actual music playback routine.
It uses the 225
scanline patches for BASIC developed by Robert Gault. The HSCREEN2 mode
is expanded to create a 320x225x16 color display and all the BASIC
graphics commands have been patched to use this extended vertical
resolution. It also has narrower black borders around the screen.
I wish the CoCo3 came with support for this display as standard.
program is operated via keyboard with the screen highlighting the
keyboard controls. It works on the principle of creating a string of
notes on a piano roll timeline. Each note coincides with a key played on the
piano shown on the left of the screen within a 4 octave range.
create 26 (A-Z) single channel music patterns. You then build the
song in the sequencer
by entering the patterns into the desired voice channels
and positions. You can repeat patterns by entering them more than once.
Only one pattern is displayed at a time on the piano roll display.
pattern entry in the sequencer can have its own settings for the envelope which allows some variety in the sound even if they are the same
pattern used throughout the sequence.
overall tempo of the song can be set to 15 different rates.
interrupt driven sound routine generates 4 voices each made up from individual square
wave tone generator routines.
entry on the sequencer has its own envelope control. You can set the Attack (rise
time), Sustain (duration) and Release (fall time) of each note. This can give a bell like effect for each note. You
can also switch to a Fixed volume with the note playing continuously until the
next note value.
It’s a simple software sound chip
engine and is certainly no substitute for a proper sound
chip but it works on every CoCo3 without the need for additional
hardware. It's important to me that everyone can experience the music
playback in my games.
Enough of the rant and make it sing!
Click on this LINK to listen to a short demonstration of a tune I transcribed from some sheet music of a well
known arcade game tune. In the video, you will hear 2 versions of the tune.
The first uses 2 channels of square wave tones with envelope.
second part shows the same tune but with the
main melody copied to a 3rd channel with the notes offset by 2
positions. This makes for a richer harmonic sound as the waves interact
with each other. The final program will have an option
to automate this function with a user selectable offset.
4 channel music
will explain, in simple terms, how I create 4
voice sound using the CoCo’s single channel DAC (Digital-to-Analogue
Converter). This not something new. There have been many 4 voice
music programs for the CoCo. This is just the first
time *I* have ever tried creating one for my games.
DAC resolution is 6 bits which gives a decimal input range of 0 to 63. You
write a number from 0 to 63 to the DAC to obtain 64 different voltage
levels at its output. Sound is created by alternating this voltage.
A simple square wave can be created by alternating
between 2 values. For example, alternating between 0 and 63 will create a
loud square wave sound. Alternating between 0 and 5 will create a soft square
Game Music Creator uses a central resting point of 31 with
the wave alternating on either side. Using values 0 to 31 on either
side of this resting point gives a full volume symetrical swing between 0 and 62.
By adding envelope control that changes the volume during the note, we can
make it fade out or fade in. We can vary the length of the note
by adjusting the speed of the fade.
This is how we create a single tone to the maximum range of the 6 bit
Before I explain how to make 4 of these play simultaneously, it's
important to understand how the DAC is mapped in the CoCo.
The DAC is addressed at location $FF20. The 6 bits of the DAC are
shared with another 2 bits used for the Cassette input and the RS232
|Cassette data input
|RS-232 data output
|DAC Bit 0
|DAC Bit 1
|DAC Bit 2
|DAC Bit 3
|DAC Bit 4
|DAC Bit 5
It's very important to note that the DAC itself is positioned at Bits 2 to 7
of address $FF20. That means that if I were to write the maximum DAC value
of 63 to address $FF20, the bits used will be 0 to 5 of $FF20, meaning
that we are writing to the Cassette input and the RS232 Output.
We must therefore shift the bits of the byte we write to $FF20 by 2 positions so they
occupy Bits 2 to 7. This is easily done in Assembly Language using the
command LSR (Logical Shift Right) twice.
Shifting of the bits fixes a problem that we would otherwise have had. But it also creates another...
Problem Fixed -
We particularly don't want to write to Bit 1 of $FF20 because that
data to the RS232 port. If you had a printer connected here, the
printer (if on) would receive
the data and start printing random garbage. It
may also play havoc with anything else connected to the CoCo's serial
(bit banger) port. Shifting the bits rolls zero's into bits 0 and 1 and therefore keeps the printer quiet.
- Shifting the bits twice uses 4 CPU cycles and when you are trying to
save every cycle possible to obtain maximum speed, this is an unwanted
evil. The higher the speed, the greater the sound fidelity.
Before I explain a fix to this problem, we need to firstly cover the way we mix 4 voices into the one channel of the DAC.
If we have 4 separate sound streams being generated, a simple technique to combine them is using additive synthesis. What this entails is to simply add the 4 values (each 6 bit) together.
example, let's take 4 streams that are each generating the maximum 6
bit DAC value of 63. Thats 63 + 63 + 63 +63 for a total of 252. If we
represent this as binary bits we end up with 11111100.
that bits 0 and 1 (starting from the right) are nicely set at 0 and all the
remaining bits we want for the DAC (bits 2 to 6) contain the maximum 6
bit DAC setting of 111111 (63). This is perfect for our needs and
we don't have to shift the byte twice to get the actual bits into the
DAC. The addition of the 4 values does that automatically.
DON'T GET TOO EXCITED.
It's not quite so perfect. In actual fact, the 4 streams of data will
be more random so lets pick 4 random DAC values and add them
10 + 24 + 15 + 0 makes a total of 49 which in binary bits is 00110001.
Adding four 6 bit numbers actually gives an 8 bit result. But the DAC can only use the
upper 6 bits, what do we do with those extra 2 bits (bits 0 and 1)?
answer is to just ignore them... but you would need to mask them off to zeros (AND
with 252) so as not to effect the Cassette and RS-232. There is a loss
of accuracy with the final additive result
but seeing that these low bits represent the quietest part of the
output, we can get away with it largely unnoticed. The more
bits available on the DAC, the better the sound quality but we only
have 6 bits on the CoCo's built in DAC.
back to the problem I mentioned earlier about using valuable CPU cycles
to achieve a shift of the bits, we see that we still have that problem
with the additive synthesis because we are masking out bits 0 and 1
with an AND instruction and that still uses up 2 CPU cycles.
There are 2 solutions to this.
Solution 1 - Turn off the printer! (or whatever device you have plugged into the serial port) Simplebut not so elegant.
Solution 2 - This is what I have implemented in GMC... The bits 0 and 1 are programmed on powerup as
input and output on pins of the PIA chip they are connected to. Bit 0
(Cassette) is an input but this doesn't cause us any problems. We can
write to it and it goes no where. Bit 1 (RS-232) is an output. This a
problem. The solution is to reprogram the PIA so this pin is also an
input, then it too will ignore all writes. Problem solved!
And there we have a simplified explanation of how GMC creates 4 voices of sound. Clear as mud? :)
course, generating sound on the CoCo also requires setting up the 6 bit
DAC as a sound source, routing the output, initializing the interrupt
routine and more but that requires a further detailed explanation and
this is more than what I have scoped for this blog.
Coming up next
The next stage of my long adventures in game music
creation is to add some refinement to GMC and implement a few extra
functions to aid the editing process of notes. Then I can finally attempt at creating my own original music score for GUNSTAR.
Watch out world! The next Jean-Michel Jarre is coming to a CoCo near you!!