audio_core: Clear time stretcher after flushing to avoid sample bleed. (#7081)

This commit is contained in:
Steveice10 2023-10-24 17:22:10 -07:00 committed by GitHub
parent 259dbf17dc
commit 45ef11654a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 14 additions and 13 deletions

View File

@ -66,18 +66,22 @@ void DspInterface::OutputSample(std::array<s16, 2> sample) {
} }
void DspInterface::OutputCallback(s16* buffer, std::size_t num_frames) { void DspInterface::OutputCallback(s16* buffer, std::size_t num_frames) {
std::size_t frames_written; std::size_t frames_written = 0;
if (perform_time_stretching) { if (perform_time_stretching) {
const std::vector<s16> in{fifo.Pop()}; const std::vector<s16> in{fifo.Pop()};
const std::size_t num_in{in.size() / 2}; const std::size_t num_in{in.size() / 2};
frames_written = time_stretcher.Process(in.data(), num_in, buffer, num_frames); frames_written = time_stretcher.Process(in.data(), num_in, buffer, num_frames);
} else if (flushing_time_stretcher) { } else {
if (flushing_time_stretcher) {
time_stretcher.Flush(); time_stretcher.Flush();
frames_written = time_stretcher.Process(nullptr, 0, buffer, num_frames); frames_written = time_stretcher.Process(nullptr, 0, buffer, num_frames);
frames_written += fifo.Pop(buffer, num_frames - frames_written);
flushing_time_stretcher = false; flushing_time_stretcher = false;
} else {
frames_written = fifo.Pop(buffer, num_frames); // Make sure any frames that did not fit are cleared from the time stretcher,
// so that they do not bleed into the next time the stretcher is enabled.
time_stretcher.Clear();
}
frames_written += fifo.Pop(buffer, num_frames - frames_written);
} }
if (frames_written > 0) { if (frames_written > 0) {

View File

@ -18,8 +18,7 @@
namespace AudioCore { namespace AudioCore {
TimeStretcher::TimeStretcher() TimeStretcher::TimeStretcher() : sound_touch(std::make_unique<soundtouch::SoundTouch>()) {
: sample_rate(native_sample_rate), sound_touch(std::make_unique<soundtouch::SoundTouch>()) {
sound_touch->setChannels(2); sound_touch->setChannels(2);
sound_touch->setSampleRate(native_sample_rate); sound_touch->setSampleRate(native_sample_rate);
sound_touch->setPitch(1.0); sound_touch->setPitch(1.0);
@ -30,16 +29,15 @@ TimeStretcher::~TimeStretcher() = default;
void TimeStretcher::SetOutputSampleRate(unsigned int sample_rate) { void TimeStretcher::SetOutputSampleRate(unsigned int sample_rate) {
sound_touch->setSampleRate(sample_rate); sound_touch->setSampleRate(sample_rate);
sample_rate = native_sample_rate;
} }
std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out, std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
std::size_t num_out) { std::size_t num_out) {
const double time_delta = static_cast<double>(num_out) / sample_rate; // seconds const double time_delta = static_cast<double>(num_out) / native_sample_rate; // seconds
double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out); double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out);
const double max_latency = 0.25; // seconds const double max_latency = 0.25; // seconds
const double max_backlog = sample_rate * max_latency; const double max_backlog = native_sample_rate * max_latency;
const double backlog_fullness = sound_touch->numSamples() / max_backlog; const double backlog_fullness = sound_touch->numSamples() / max_backlog;
if (backlog_fullness > 4.0) { if (backlog_fullness > 4.0) {
// Too many samples in backlog: Don't push anymore on // Too many samples in backlog: Don't push anymore on

View File

@ -34,7 +34,6 @@ public:
void Flush(); void Flush();
private: private:
unsigned int sample_rate;
std::unique_ptr<soundtouch::SoundTouch> sound_touch; std::unique_ptr<soundtouch::SoundTouch> sound_touch;
double stretch_ratio = 1.0; double stretch_ratio = 1.0;
}; };