Delay between key off and key on

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Delay between key off and key on
by on (#150947)
I'm porting my NES music engine to the Super NES, and I'm trying to determine whether to delay all key-on events for one "frame" of the music engine. Fullsnes states that keying off a channel causes its envelope volume to decrease at 8 units per sample. Full scale is 2047 units, so a fade from full scale would take 256 samples, or 256 / 32 = 8 ms, or 256 * 32 = 8192 CPU cycles. Can undefined or undesirable behavior happen if I prepare the channel for the next note (volume, frequency, sample ID, and envelope) before this fade completes? Do any commercial games' music engines suffer from artifacts related to this, or is there some common workaround that they use?
Re: Delay between key off and key on
by on (#150970)
It seems like it's a really quick fade-out (like, so quick as to be imperceivable) as a means of preventing clicking or popping when you want to silence the note, which would happen sometimes if the note were just clamped off (similar to what happens if you silence the NES's triangle channel by setting the period to 0 instead of properly halting it).

I don't think anything bad would happen if you didn't have a delay between key-off and key-on, but you'd risk the aforementioned popping as one waveform suddenly ends and jumps to another waveform. I think that's why so many music engines add a small space between each note.
Re: Delay between key off and key on
by on (#150994)
Here's my understanding from here:

http://problemkaputt.de/fullsnes.htm#sn ... lregisters

The interesting thing is that you're most likely not going to get any artifacts because the envelopes go to zero regardless of ADSR and gain settings.

The SPC700 is more prone to your usual clicks and pops than usual because of a 5 sample delay between when a sample gets cut (and thus zeroed out) and when a sample starts playing again after calling KON. If you forget to turn off your KOFF and write to KON, you have 63 cycles to get rid of the KOFF for that channel.

An alternative to KOFF is to use gain to zero out the sample. When ADSR is set to use gain and the gain is set to linear decrease and its setting is maxed out at 31, you get a 64 sample fade-out (that's 2048 CPU cycles, in comparison to 8192 CPU cycles with key off).

I know SNESMod takes advantage of a 5 sample headstart after KON (that's 160 cycles) to set up volume and gain and doesn't set KOFF beforehand.

Actually, maybe you should try some other kind of magic for your NES to SNES engine. Those lovely square waveforms and triangle waves should only simply need their pitch values (and gain if you're manipulating volume) changed (unless you're emulating phase reset). When changing pulse widths, with the right kind of BRR magic, you can simply change the sample ID without keying on and off and with a small delay (mainly because the loop point has to actually trigger), you'll change the waveform without bothering with key on and off (unless your waveform was never keyed on in the first place). This works well thanks to the fact you're using chip waveforms.
Re: Delay between key off and key on
by on (#150995)
KungFuFurby wrote:
When changing pulse widths, with the right kind of BRR magic, you can simply change the sample ID without keying on and off and with a small delay (mainly because the loop point has to actually trigger), you'll change the waveform without bothering with key on and off (unless your waveform was never keyed on in the first place). This works well thanks to the fact you're using chip waveforms.

Interesting idea. I have already 32-sample 1/8, 1/4, and 1/2 duty pulse and 64-sample triangle wave loops as default samples usable by instruments and sound effects. But to make it sound less like a TurboGrafx or Virtual Boy and more like a Super NES, I'm also planning to support actual sampled (or pre-synthesized) BRRs, for which the 8 ms fadeout will be far more critical. So I guess the way to do it is to run the music engine, trigger KOFF immediately for any channel needing it, and wait until the next time I run the music engine before poking in the new values and triggering KON.

Does stopping a wave by setting its playback rate to 0 Hz ($x2 = 0 and $x3 = 0) work? If so, that'd be the direct S-DSP equivalent to shutting off an NES APU triangle wave.
Re: Delay between key off and key on
by on (#150996)
Alright, that will do the trick then.

Yeah, I think that would work for the triangle wave by setting the pitch to zero.