My next article is on ADSR, it's been in draft form for a long time though due to work commitments
Just in case it's of any use to you:
Welcome to the second article in the Megadrive Sound series! I've been hard at work on my PSG sequencer, making a few improvements, adding new features, and messing with different sounds. The first addition is software envelopes, which allow for individual notes to fade in and out over time. The second is white noise, which allows for some basic percussion sounds. As usual, I'll be starting off with a little theory behind the things I've implemented.
ADSR Envelopes
An envelope is a predefined volume curve applied to each note, which can be tweaked to provide softer sounding notes compared to just hammering them on or off at full volume. With a little creativity, they can be adjusted to create different sounding instruments, or can even be used to create very short notes to simulate percussion, especially when applied to white noise rather than a wave. I've been implementing a specific kind of envelope - ADSR. These envelopes comprise four parts - Attack, Decay, Sustain and Release. Attack is a curve from full attenuation up to an initial "on" volume. The volume then dips down a Decay curve, settling on the Sustain volume. When the sustain time has expired, the volume fades down over the Release curve.
If you're not familiar with the concept, it's easier to imagine how a piano note behaves - it begins with the player pressing down on the key which hits the string with the mallet and immediately recoils, creating the attack sound. This very quickly (over a couple of milliseconds) decays down to a softer sustain volume. Once the player lifts their finger off they key, a dampener covers the string to force the sound to die down sharply, which is the release. Technically, there's a lot more to it than that, but this is all we need to know in order to approximate the sound electronically.
Software ADSR on the PSG
Many dedicated audio processors implement ADSR envelopes on the hardware, but the PSG is very simple and does no such thing. We need to manually ramp the volume up and down to approximate the curves. In the image above, I've demonstrated linear changes, but in the real world these would likely be curves. The PSG's attenuation values from 0xF to 0x0 step up the volume exponentially, so by incrementing the attenuation register linearly we get a curve for free. Unfortunately, with only 16 possible values, the difference between the top few values are quite steep, which can result in some undesired artefacts. It seems the PSG applies all register changes immediately, rather than waiting for the next square wave polarity flip, which means we can potentially alter the attenuation in the middle of a zero crossover point causing pops and clicks. There's no real solution to this, and after some discussions with a few wiser brains on the SpritesMind forum, it seems the best thing to do is avoid these top attenuation values completely. I've also been told the PSG's volume is far louder than the FM chip, so losing the ability to play the PSG at full blast is no real loss. With this in mind, I've chosen a minimum attenuation value of 0x5 to avoid these large, quick jumps in volume. So, how do we define the envelope? We need the following information: attack time, attack height, decay time, sustain height, and release time. We already have the sustain time, that's defined in the data for each note.