From 85a533faded8b76107d557dd877c06298aa61001 Mon Sep 17 00:00:00 2001 From: Matt Harding Date: Wed, 1 May 2024 08:18:01 +0100 Subject: [PATCH] Revert "Simplify logic around tones ending" and fix triangle tone popping This reverts commit 4e5085741dbc5a9347e2a7ed094c847872d42666. That change was causing tones to stop before the end of their release if an ending tick came in first. I've decided to let tones that aren't replaced with another tone to overrun the ending tick instead, to prevent sudden stops and popping. --- runtimes/native/src/apu.c | 4 ++-- runtimes/web/src/apu-worklet.ts | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) 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;