audio_core: Clear time stretcher after flushing to avoid sample bleed. (#7081)
This commit is contained in:
parent
259dbf17dc
commit
45ef11654a
|
@ -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) {
|
|
||||||
time_stretcher.Flush();
|
|
||||||
frames_written = time_stretcher.Process(nullptr, 0, buffer, num_frames);
|
|
||||||
frames_written += fifo.Pop(buffer, num_frames - frames_written);
|
|
||||||
flushing_time_stretcher = false;
|
|
||||||
} else {
|
} else {
|
||||||
frames_written = fifo.Pop(buffer, num_frames);
|
if (flushing_time_stretcher) {
|
||||||
|
time_stretcher.Flush();
|
||||||
|
frames_written = time_stretcher.Process(nullptr, 0, buffer, num_frames);
|
||||||
|
flushing_time_stretcher = false;
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
Reference in New Issue