diff --git a/runtimes/native/src/apu.c b/runtimes/native/src/apu.c index d756bbbb..41037b23 100644 --- a/runtimes/native/src/apu.c +++ b/runtimes/native/src/apu.c @@ -158,7 +158,7 @@ void w4_apuTone (int frequency, int duration, int volume, int flags) { // Restart the phase if the channel isn't already playing, but be // careful to keep the phase if the channel is already playing to allow // for continuous tones and smooth transitions to or from a glide etc. - if (ticks > channel->endTick) { + if (time > channel->releaseTime && ticks > channel->endTick) { channel->phase = (channelIdx == 2) ? 0.25 : 0; } if (noteMode) { @@ -220,7 +220,7 @@ void w4_apuWriteSamples (int16_t* output, unsigned long frames) { for (int channelIdx = 0; channelIdx < 4; ++channelIdx) { Channel* channel = &channels[channelIdx]; - if (ticks <= channel->endTick) { + if (time < channel->releaseTime || ticks <= channel->endTick) { float freq = getCurrentFrequency(channel); int16_t volume = getCurrentVolume(channel); int16_t sample; diff --git a/runtimes/web/src/apu-worklet.ts b/runtimes/web/src/apu-worklet.ts index fd06f77b..2660d19b 100644 --- a/runtimes/web/src/apu-worklet.ts +++ b/runtimes/web/src/apu-worklet.ts @@ -5,7 +5,8 @@ const SAMPLE_RATE = 44100; const MAX_VOLUME = 0.15; // The triangle channel sounds a bit quieter than the others, so give it higher amplitude const MAX_VOLUME_TRIANGLE = 0.25; -// Also the triangle channel prevent popping on hard stops by adding a 1 ms release +// Also the triangle channel has a short release by default to reduce popping. Popping isn't +// as noticable on the other channels. const RELEASE_TIME_TRIANGLE = Math.floor(SAMPLE_RATE / 1000); class Channel { @@ -113,7 +114,7 @@ class APUProcessor extends AudioWorkletProcessor { getCurrentVolume (channel: Channel) { const time = this.time; - if (time >= channel.sustainTime && (channel.releaseTime - channel.sustainTime) > RELEASE_TIME_TRIANGLE) { + if (time >= channel.sustainTime) { // Release return this.ramp(channel.sustainVolume, 0, channel.sustainTime, channel.releaseTime); } else if (time >= channel.decayTime) { @@ -158,7 +159,7 @@ class APUProcessor extends AudioWorkletProcessor { // Restart the phase if the channel isn't already playing, but be // careful to keep the phase if the channel is already playing to allow // for continuous tones and smooth transitions to or from a glide etc. - if (this.ticks > channel.endTick) { + if (this.time > channel.releaseTime && this.ticks > channel.endTick) { channel.phase = (channelIdx == 2) ? 0.25 : 0; } if (noteMode) { @@ -209,7 +210,7 @@ class APUProcessor extends AudioWorkletProcessor { for (let channelIdx = 0; channelIdx < 4; ++channelIdx) { const channel = this.channels[channelIdx]; - if (this.ticks <= channel.endTick) { + if (this.time < channel.releaseTime || this.ticks <= channel.endTick) { const freq = this.getCurrentFrequency(channel); const volume = this.getCurrentVolume(channel); let sample;