diff --git a/src/audio_core/renderer/command/effect/reverb.cpp b/src/audio_core/renderer/command/effect/reverb.cpp index 87eab1adda..ec3a82802f 100644 --- a/src/audio_core/renderer/command/effect/reverb.cpp +++ b/src/audio_core/renderer/command/effect/reverb.cpp @@ -84,6 +84,7 @@ static void UpdateReverbEffectParameter(const ReverbInfo::ParameterVersion2& par const auto pow_10 = [](f32 val) -> f32 { return (val >= 0.0f) ? 1.0f : (val <= -5.3f) ? 0.0f : std::pow(10.0f, val); }; + const auto cos = [](f32 degrees) -> f32 { return std::cos(degrees * std::numbers::pi_v / 180.0f); }; @@ -91,26 +92,39 @@ static void UpdateReverbEffectParameter(const ReverbInfo::ParameterVersion2& par static bool unk_initialized{false}; static Common::FixedPoint<50, 14> unk_value{}; - const auto sample_rate{Common::FixedPoint<50, 14>::from_base(params.sample_rate)}; - const auto pre_delay_time{Common::FixedPoint<50, 14>::from_base(params.pre_delay)}; + auto sample_rate = Common::FixedPoint<50, 14>::from_base(params.sample_rate); + if (sample_rate.to_float() < 1.0f) sample_rate = Common::FixedPoint<50, 14>(1.0f); + + auto pre_delay_time = Common::FixedPoint<50, 14>::from_base(params.pre_delay); + if (pre_delay_time.to_float() < 0.0f) pre_delay_time = Common::FixedPoint<50, 14>(0.0f); for (u32 i = 0; i < ReverbInfo::MaxDelayTaps; i++) { - auto early_delay{ - ((pre_delay_time + EarlyDelayTimes[params.early_mode][i]) * sample_rate).to_int()}; - early_delay = (std::min)(early_delay, state.pre_delay_line.sample_count_max); - state.early_delay_times[i] = early_delay + 1; - state.early_gains[i] = Common::FixedPoint<50, 14>::from_base(params.early_gain) * - EarlyDelayGains[params.early_mode][i]; + int target_delay = ((pre_delay_time + EarlyDelayTimes[params.early_mode][i]) * sample_rate).to_int(); + if (target_delay < 0) target_delay = 0; + if (target_delay > state.pre_delay_line.sample_count_max) target_delay = state.pre_delay_line.sample_count_max; + + int old_delay = state.early_delay_times[i] - 1; + int smooth_delay = old_delay + (target_delay - old_delay) / 4; + state.early_delay_times[i] = smooth_delay + 1; + + auto target_gain = Common::FixedPoint<50, 14>::from_base(params.early_gain) * EarlyDelayGains[params.early_mode][i]; + if (target_gain.to_float() < 0.0f) target_gain = Common::FixedPoint<50, 14>(0.0f); + if (target_gain.to_float() > 1.0f) target_gain = Common::FixedPoint<50, 14>(1.0f); + + state.early_gains[i] = state.early_gains[i] + (target_gain - state.early_gains[i]) / 4; } if (params.channel_count == 2) { - state.early_gains[4] * 0.5f; - state.early_gains[5] * 0.5f; + state.early_gains[4] *= Common::FixedPoint<50, 14>(0.5f); + state.early_gains[5] *= Common::FixedPoint<50, 14>(0.5f); } - auto pre_time{ - ((pre_delay_time + EarlyDelayTimes[params.early_mode][10]) * sample_rate).to_int()}; - state.pre_delay_time = (std::min)(pre_time, state.pre_delay_line.sample_count_max); + int target_pre_time = ((pre_delay_time + EarlyDelayTimes[params.early_mode][10]) * sample_rate).to_int(); + if (target_pre_time < 0) target_pre_time = 0; + if (target_pre_time > state.pre_delay_line.sample_count_max) target_pre_time = state.pre_delay_line.sample_count_max; + + int old_pre_time = state.pre_delay_time; + state.pre_delay_time = old_pre_time + (target_pre_time - old_pre_time) / 4; if (!unk_initialized) { unk_value = cos((1280.0f / sample_rate).to_float()); @@ -118,45 +132,64 @@ static void UpdateReverbEffectParameter(const ReverbInfo::ParameterVersion2& par } for (u32 i = 0; i < ReverbInfo::MaxDelayLines; i++) { - const auto fdn_delay{(FdnDelayTimes[params.late_mode][i] * sample_rate).to_int()}; - state.fdn_delay_lines[i].sample_count = - (std::min)(fdn_delay, state.fdn_delay_lines[i].sample_count_max); - state.fdn_delay_lines[i].buffer_end = - &state.fdn_delay_lines[i].buffer[state.fdn_delay_lines[i].sample_count - 1]; - - const auto decay_delay{(DecayDelayTimes[params.late_mode][i] * sample_rate).to_int()}; - state.decay_delay_lines[i].sample_count = - (std::min)(decay_delay, state.decay_delay_lines[i].sample_count_max); - state.decay_delay_lines[i].buffer_end = - &state.decay_delay_lines[i].buffer[state.decay_delay_lines[i].sample_count - 1]; - - state.decay_delay_lines[i].decay = - 0.5999755859375f * (1.0f - Common::FixedPoint<50, 14>::from_base(params.colouration)); - - auto a{(Common::FixedPoint<50, 14>(state.fdn_delay_lines[i].sample_count_max) + - state.decay_delay_lines[i].sample_count_max) * - -3}; - auto b{a / (Common::FixedPoint<50, 14>::from_base(params.decay_time) * sample_rate)}; - Common::FixedPoint<50, 14> c{0.0f}; - Common::FixedPoint<50, 14> d{0.0f}; - auto hf_decay_ratio{Common::FixedPoint<50, 14>::from_base(params.high_freq_decay_ratio)}; - - if (hf_decay_ratio > 0.99493408203125f) { + int target_fdn_delay = (FdnDelayTimes[params.late_mode][i] * sample_rate).to_int(); + if (target_fdn_delay < 0) target_fdn_delay = 0; + if (target_fdn_delay > state.fdn_delay_lines[i].sample_count_max) target_fdn_delay = state.fdn_delay_lines[i].sample_count_max; + + int old_fdn = state.fdn_delay_lines[i].sample_count; + state.fdn_delay_lines[i].sample_count = old_fdn + (target_fdn_delay - old_fdn) / 4; + state.fdn_delay_lines[i].buffer_end = &state.fdn_delay_lines[i].buffer[state.fdn_delay_lines[i].sample_count - 1]; + + int target_decay_delay = (DecayDelayTimes[params.late_mode][i] * sample_rate).to_int(); + if (target_decay_delay < 0) target_decay_delay = 0; + if (target_decay_delay > state.decay_delay_lines[i].sample_count_max) target_decay_delay = state.decay_delay_lines[i].sample_count_max; + + int old_decay = state.decay_delay_lines[i].sample_count; + state.decay_delay_lines[i].sample_count = old_decay + (target_decay_delay - old_decay) / 4; + state.decay_delay_lines[i].buffer_end = &state.decay_delay_lines[i].buffer[state.decay_delay_lines[i].sample_count - 1]; + + auto colouration = Common::FixedPoint<50, 14>::from_base(params.colouration); + if (colouration.to_float() < 0.0f) colouration = Common::FixedPoint<50, 14>(0.0f); + if (colouration.to_float() > 1.0f) colouration = Common::FixedPoint<50, 14>(1.0f); + + state.decay_delay_lines[i].decay = state.decay_delay_lines[i].decay + (0.5999755859375f * (1.0f - colouration) - state.decay_delay_lines[i].decay) / 4; + + auto decay_time_fp = Common::FixedPoint<50, 14>::from_base(params.decay_time); + if (decay_time_fp.to_float() <= 0.0f) decay_time_fp = Common::FixedPoint<50, 14>(0.0001f); + + auto a = (Common::FixedPoint<50, 14>(state.fdn_delay_lines[i].sample_count_max) + state.decay_delay_lines[i].sample_count_max) * -3; + auto b = a / (decay_time_fp * sample_rate); + + auto hf_decay_ratio = Common::FixedPoint<50, 14>::from_base(params.high_freq_decay_ratio); + if (hf_decay_ratio.to_float() < 0.001f) hf_decay_ratio = Common::FixedPoint<50, 14>(0.001f); + if (hf_decay_ratio.to_float() > 0.999f) hf_decay_ratio = Common::FixedPoint<50, 14>(0.999f); + + Common::FixedPoint<50, 14> c{0.0f}, d{0.0f}; + if (hf_decay_ratio.to_float() > 0.9949f) { c = 0.0f; d = 1.0f; } else { - const auto e{ - pow_10(((((1.0f / hf_decay_ratio) - 1.0f) * 2) / 100 * (b / 10)).to_float())}; - const auto f{1.0f - e}; - const auto g{2.0f - (unk_value * e * 2)}; - const auto h{std::sqrt(std::pow(g.to_float(), 2.0f) - (std::pow(f, 2.0f) * 4))}; + auto e = pow_10(((((1.0f / hf_decay_ratio.to_float()) - 1.0f) * 2) / 100 * (b / 10)).to_float()); + if (e < 0.0001f) e = 0.0001f; + if (e > 1.0f) e = 1.0f; + + auto f = 1.0f - e; + if (f < 0.0001f) f = 0.0001f; + + auto g = 2.0f - (unk_value.to_float() * e * 2); + + auto h_sq = g * g - f * f * 4; + if (h_sq < 0.0f) h_sq = 0.0f; + + auto h = std::sqrt(h_sq); c = (g - h) / (f * 2.0f); d = 1.0f - c; } - state.hf_decay_prev_gain[i] = c; - state.hf_decay_gain[i] = pow_10((b / 1000).to_float()) * d * 0.70709228515625f; + state.hf_decay_prev_gain[i] = state.hf_decay_prev_gain[i] + (c - state.hf_decay_prev_gain[i]) / 4; + state.hf_decay_gain[i] = state.hf_decay_gain[i] + (pow_10((b / 1000).to_float()) * d * 0.70709228515625f - state.hf_decay_gain[i]) / 4; + state.prev_feedback_output[i] = 0; } } @@ -191,6 +224,8 @@ static void InitializeReverbEffect(const ReverbInfo::ParameterVersion2& params, const auto center_delay_time{(5 * delay).to_uint_floor()}; state.center_delay_line.Initialize(center_delay_time, 1.0f); + UpdateReverbEffectParameter(params, state); + for (u32 i = 0; i < ReverbInfo::MaxDelayLines; i++) { std::ranges::fill(state.fdn_delay_lines[i].buffer, 0); std::ranges::fill(state.decay_delay_lines[i].buffer, 0); diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h index 083eb7bc27..acb7537dda 100644 --- a/src/audio_core/sink/sink_stream.h +++ b/src/audio_core/sink/sink_stream.h @@ -238,9 +238,9 @@ protected: private: /// Ring buffer of the samples waiting to be played or consumed - Common::RingBuffer samples_buffer; + Common::RingBuffer samples_buffer; /// Audio buffers queued and waiting to play - Common::SPSCQueue queue; + Common::SPSCQueue queue; /// The currently-playing audio buffer SinkBuffer playing_buffer{}; /// The last played (or received) frame of audio, used when the callback underruns