Saturday, 10 March 2018

$11 times the charm

My entry for the competition. (short version, before I realised there was a 2 minute minimum limit)
I don't write a lot of SID music these days, the only times I do it is when I've got something new on the code side. (or at least new to me)  I can't really see myself writing SID music now just for the sake of writing it, I guess the motivation isn't there.  Weirdly my favourite release on the SID is Mini Melodies   This is the least tech-driven thing I've done but it reminds me of my favourite type of SID tracks: the super basic players, pure noise drums, usually by people who only write a couple of tracks and move onto something else.  I love this kind of stuff above all else on there.

Currently (as I type) there's a competition going on to write music using only the triangle wave and filter.  This is turning into quite a tech-heavy competition and you can hear the entries at this link.   (I've dotted some videos through the article)

LMan - "Mellowhouse"
So I thought it'd be nice to contribute something, but if I just load up GoatTracker and start making a track I know I won't come up with anything.  Plus as it's on CSDB you know the standard is going to be super high and my instrument design skills aren't on any kind of parity with those other guys. :)   So then, what to do.  I need some tech idea within the limits of the competition, but without having to suddenly learn a great deal of sid craft in a couple of weeks.

A 4th channel

The 4th channel idea actually came out of writing the previous article on here.   While writing up Patchwork's fx list I was thinking that the filter allocation ($d417) is an on/off state on each channel.  On/Off states are good in sound because they can be used as a basic oscillator for audio.  The question then becomes, does allocating a channel to the filter create enough of an audible change that it's useful?

As with playing samples, sound generation is a cpu-intensive process because you have to send rapid updates to a sound buffer.  To test out the extra channel I first made an infinite loop that would rapidly toggle the channel allocation between full and zero without waiting for a frame to pass. (so it's running as fast as the CPU can manage) This produced a high-pitched whirr, which showed there was maybe something useful.  By adding some delay into the loop the pitch lowered, as the toggle is being updated at a slower rate.   So it was kind of like generating a square wave sample but playing it through the filter.

My next task was to get the sound under control by setting up a timer system.  This is nearly the same as running it in the infinite loop but the update speed of the loop can be controlled from a timer, and hence it's pitch can be controlled.  You're also able to run the loop alongside a normal frame-based music engine so it can be controlled from a constant beat source, like any other music channel.

Progress of the player. The border colours show which bits in $d417 are being set.
So now we have the timer system in place, we need a friendly way to control it while writing our music.   I opted to use an existing music editor (because there's no point re-inventing the wheel on the SID channel side) and look for a way to put some control data in that I could read from my code.

Well most music editors only use 3 channels so that's not good, but what about the ones that can use multiple SIDs?  I opted to use GoatTracker Stereo as the editor, with the '4th' channel in there being used to control our generated sound.   I wrote some code to take the exported song and patch it at runtime, so all writes to the sidchips are sent to a different part of memory instead.  From there I can write back the first 3 channels to the SID and use the information being sent to the 4th channel to control our generated channel instead. Any filter writes in GoatTracker's driver are ignored too as we're controlling the filter directly from our code.  

The first three channels write the SID data directly, but the 4th one reads the currently played note number from inside Goat Tracker's driver.   I have a table of timer speeds matched to the frequencies that would be sent to the SID pitches and set our timer to the relevant one.  I could get 4 octaves of useful pitch directly, and then this could be doubled by stepping through the $d417 changes at double the speed.  (though in my song this is only used in the fast bass sections)  I also do a check to see if  the note is a 'rest' command, and disable the 4th channel in that case.

Working this way there are going to be some compromises on the composing side though.  Without rewriting a bunch of the editor we won't be able to hear our music in exactly the same way it sounds on the machine.  But we'll be able to write the music and use dummy instruments for the 4th channel to create the structure.   That way only the sound design of the 4th channel needs to be done in code, that seems a good enough trade-off.

Wiklund - "Club Eleven"

More advanced sounds

So now we have a 1-bit oscillator we can control.  But thinking about it the filter allocation isn't really a 1-bit value, it's a 3-bit value: a bit-wise toggle for each SID channel:
  • Channel 1 : $01 toggle
  • Channel 2 : $02 toggle
  • Channel 3 : $04 toggle
Do we get any differences by toggling with different values?  The answer is: yes!   Combined channels = larger volume.  This means we have some kind of stepped range for our generated sound.

The other thing with a generated sound is you can shape the timbre of it. If you've used the Gameboy you'll remember the 3rd pitch channel allowed you to make custom 4-bit waveforms with multiple steps.  The hardware then cycles through this waveform on a loop with the different permutations in the waveform creating an individual timbre to the instrument.   So we can do something similar here, I opted for an 8 step waveform which gives enough variety in the sounds.   By dropping 'on' toggles at fixed steps you can also add harmonics to the sound in a similar way to a drawbar organ.   Some examples:
  • 01,00,00,00,00,00,00,00 - Straight tone
  • 01,00,00,00,01,00,00,00 - Octaver effect
  • 01,00,00,00,01,00,01,00 - Double octaver effect
The symmetry between the on and off states will change the 'duty' of the sound, if you've used a NES you'll know this kind of setup:
  • 01,00,00,00,00,00,00,00 - 12.5%
  • 01,01,00,00,00,00,00,00 - 25%
  • 01,01,01,01,00,00,00,00 - 50% (full 'square wave' sound)

JT & LMan - "Skypeople"
So now we can shape our sounds enough that they'll sound different to each other.  But hang on, as we're using the filter to do this the 4th channel is also affected by the filter's settings.  Is there anything more we can add?  

Well for a start the $d417 register has two jobs: channel allocation and setting the resonance.  So we can have difference resonance values in each instrument, or change it per cycle.   We also have the cutoff frequency which we can apply a sweep value to, and finally the type of filter being used. (between low,band,high-pass or the combinations)   So yes,  there is more!

But there's also one more software thing we can do:  switch the waveform over time.   I added the option to cycle through a set of waveforms with a time delay while playing a note, kind of like using a wavetable in a traditional sid player.  This let me produce the echo effect and octaver bass sounds used in the song.

Generated sound and the sid channels

So we now have 4 channels playing, but if we're setting the sid channels to use the filter too what does it do to the SID channels?   Well it kind of gives the set channels a ring-modulation effect.  To quote the very knowledgeable lft on my original upload:

"The reason for the apparent ring modulation is that the filter is inverting. So when flipping the filter routing at some frequency, that's similar to applying ring modulation at that frequency to the waveform."
The timbre of the 4th channel is also affected by the SID waveforms used, I haven't dug into how useful this is but amusingly using waveforms other than $11 gives better resolution at least. :)

A funny thing is this modulation effect would have been super useful when making the ST musicdisk.  It's a nearly spot-on simultation of the Buzz bass sound and would have freed up a channel on the SID in the process.

No comments:

Post a Comment