Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/audio/mixer.c
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,10 @@ static void mixer_ch_sync_freq(int ch, int64_t tick)
mixer_channel_t *c = &Mixer.channels[ch];
if (c->flags & CH_FLAGS_STEREO_SUB)
return;
// A stopped channel keeps its last frequency, which may exceed limits set
// since; its step is not used until it plays again, and play sets it.
if (!c->ptr)
return;
float f = mixer_ramp_at(&Mixer.freq_ramp[ch], Mixer.freq[ch], tick);
mixer_ramp_active(&Mixer.freq_ramp[ch], tick);
mixer_ch_apply_freq(ch, f);
Expand Down
48 changes: 48 additions & 0 deletions tests/test_wav64.c
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,49 @@ static bool test_mixer_stream_pcm8(float freq, int startsample)
return true;
}

// Lowering the limit of a stopped channel, which is what xm64player_close does
// on each of its channels (mixer_ch_stop, then mixer_ch_set_limits back to the
// defaults). mixer_ch_stop keeps the last frequency of the channel, and each mix
// round syncs the frequency of every channel below the highest one ever used,
// playing or not: a stopped note faster than the new limit used to trip the
// limit assertion of mixer_ch_apply_freq on the next poll.
static bool test_mixer_stop_lower_limit(void)
{
float rate = audio_get_frequency();
mixer_ch_stop(SP_CHANNEL);
sv_mix(2048);

mixer_ch_set_limits(SP_CHANNEL, 8, rate * 2, 0);
mixer_ch_play(SP_CHANNEL, &sp_wave);
mixer_ch_set_freq(SP_CHANNEL, rate * 1.5f);
sv_mix(2048);

mixer_ch_stop(SP_CHANNEL);
mixer_ch_set_limits(SP_CHANNEL, 0, 0, 0);
// Used to assert here, though nothing is playing above the limit.
sv_mix(2048);

// The channel is usable again within its new limit.
mixer_ch_play(SP_CHANNEL, &sp_wave);
mixer_ch_set_freq(SP_CHANNEL, rate);
mixer_ch_set_vol(SP_CHANNEL, 0.5f, 0.5f);
sv_mix(2048);
sv_mix(4096);
int peak = 0;
for (int j = 0; j < 4096 * 2; j++) {
int a = sv_out[j] < 0 ? -sv_out[j] : sv_out[j];
if (a > peak) peak = a;
}
mixer_ch_stop(SP_CHANNEL);
sv_mix(2048);

if (peak < 256) {
printf("FAILED mixer stop lower limit: silent after replay (peak %d)\n", peak);
return false;
}
return true;
}

//////////////////////////////////////////////////////////////////////////////
// Block codec at a loop point
//
Expand Down Expand Up @@ -3664,6 +3707,11 @@ int main(void)
total++; if (!test_mixer_vadpcm_large_loop_seek(&ll_wave_8x, 44100.f * 16)) failed++;
total++; if (!test_mixer_vadpcm_large_loop_seek(&ll_wave, 16000)) failed++;

// Last: a regression fails on an assertion, which stops the ROM.
printf("Stopped channel, lower limit\n");
fflush(stdout);
total++; if (!test_mixer_stop_lower_limit()) failed++;

sv_silence();
mixer_ch_set_limits(SV_CHANNEL, 0, 48000, 0);

Expand Down