JUNE 2018

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!   :)

This 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.

Assembly 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.

I've always used 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 actual 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 approach.

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.

I must admit, I'm not all that knowledgable with music theory and so I needed something that was easier for me to understand. I also can't read music notation or know  music language. I can't even play a musical keyboard!

So 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.

Ultimately, 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 their purposes.


BASIC never looked so good!

We 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.

Operation

The 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.

You can 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.

Each 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.

The overall tempo of the song can be set to 15 different rates.

The interrupt driven sound routine generates 4 voices each made up from individual square wave tone generator routines.

Each pattern 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.

The 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

I 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.

The 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 wave sound.




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 DAC.



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 output.

ADDRESS $FF20
BIT 0
Cassette data input
BIT 1
RS-232 data output
BIT 2
DAC Bit 0
BIT 3
DAC Bit 1
BIT 4
DAC Bit 2
BIT 5
DAC Bit 3
BIT 6
DAC Bit 4
BIT 7
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 sends unwanted 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.

Problem created - 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.

For 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.

Note 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 together.

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)?

The 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.

Going 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?    :)

Of 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!!





Copyright 2017 by Nickolas Marentes