Commit af59c273 authored by Raymond Toy's avatar Raymond Toy Committed by Commit Bot

Optimize the fast path for AudioDelayDspKernel::Process.

* The interpolation factor is constant so it can be lifted out of the
  loop.
* Computation of the read_position only needs to be done once, and
  read_index1 can just be incremented in the loop
* Cache write_index_ into a local
* Change some doubles to floats

Using spotify.github.io/web-audio-bench, without this CL we have:

TEST	                μs	MIN	Q1	MEDIAN	Q3	MAX
Baseline		397	390	397	397	397	407
Delay-default		943	882	935	943	953	980
Delay-0.1		930	913	913	930	957	967
DelayAutomation-a-rate	1007	988	993	1007	1025	1032
DelayAutomation-k-rate	925	912	918	925	962	973

With thie CL:

Baseline		393	323	383	393	393	400
Delay-default		213	210	212	213	253	278
Delay-0.1		235	232	233	235	283	343
DelayAutomation-a-rate	1043	1038	1040	1043	1043	1053
DelayAutomation-k-rate	245	238	243	245	285	313

The optimized version takes about 1/4 the time now.

Bug: 1012198
Change-Id: I0de8f0980e9006241293dc97682d812af485bba1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1861036Reviewed-by: default avatarHongchan Choi <hongchan@chromium.org>
Reviewed-by: default avatarAndrew MacPherson <andrew.macpherson@soundtrap.com>
Commit-Queue: Raymond Toy <rtoy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706595}
parent f47fae66
...@@ -121,36 +121,57 @@ void AudioDelayDSPKernel::Process(const float* source, ...@@ -121,36 +121,57 @@ void AudioDelayDSPKernel::Process(const float* source,
*destination++ = static_cast<float>(output); *destination++ = static_cast<float>(output);
} }
} else { } else {
double delay_time = this->DelayTime(sample_rate); // This is basically the same as above, but optimized for the case where the
// delay time is constant for the current render.
//
// TODO(crbug.com/1012198): There are still some further optimizations that
// could be done. interp_factor could be a float to eliminate several
// conversions between floats and doubles. It might be possible to get rid
// of the wrapping if the buffer were longer. This may aslo allow
// |write_index_| to be different from |read_index1| or |read_index2| which
// simplifies the loop a bit.
double delay_time = this->DelayTime(sample_rate);
// Make sure the delay time is in a valid range. // Make sure the delay time is in a valid range.
delay_time = clampTo(delay_time, 0.0, max_time); delay_time = clampTo(delay_time, 0.0, max_time);
double desired_delay_frames = delay_time * sample_rate;
double read_position = write_index_ + buffer_length - desired_delay_frames;
if (read_position >= buffer_length)
read_position -= buffer_length;
for (unsigned i = 0; i < frames_to_process; ++i) { // Linearly interpolate in-between delay times. |read_index1| and
double desired_delay_frames = delay_time * sample_rate; // |read_index2| are the indices of the frames to be used for
// interpolation.
double read_position = int read_index1 = static_cast<int>(read_position);
write_index_ + buffer_length - desired_delay_frames; int read_index2 = (read_index1 + 1) % buffer_length;
if (read_position >= buffer_length) double interp_factor = read_position - read_index1;
read_position -= buffer_length;
// Linearly interpolate in-between delay times.
int read_index1 = static_cast<int>(read_position);
int read_index2 = (read_index1 + 1) % buffer_length;
double interpolation_factor = read_position - read_index1;
double input = static_cast<float>(*source++);
buffer[write_index_] = static_cast<float>(input);
write_index_ = (write_index_ + 1) % buffer_length;
double sample1 = buffer[read_index1]; int w_index = write_index_;
double sample2 = buffer[read_index2];
double output = (1.0 - interpolation_factor) * sample1 + for (unsigned i = 0; i < frames_to_process; ++i) {
interpolation_factor * sample2; // Copy the latest sample into the buffer. Needed because
// w_index could be the same as read_index1 or read_index2.
*destination++ = static_cast<float>(output); buffer[w_index] = *source++;
float sample1 = buffer[read_index1];
float sample2 = buffer[read_index2];
// Update the indices and wrap them to the beginning of the buffer if
// needed.
++w_index;
++read_index1;
++read_index2;
if (w_index >= static_cast<int>(buffer_length))
w_index -= buffer_length;
if (read_index1 >= static_cast<int>(buffer_length))
read_index1 -= buffer_length;
if (read_index2 >= static_cast<int>(buffer_length))
read_index2 -= buffer_length;
// Linearly interpolate between samples.
*destination++ = (1 - interp_factor) * sample1 + interp_factor * sample2;
} }
write_index_ = w_index;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment