| Index: media/filters/audio_renderer_algorithm.cc
|
| diff --git a/media/filters/audio_renderer_algorithm.cc b/media/filters/audio_renderer_algorithm.cc
|
| index ebe334a0f1a0c76c1063ed1c79512cc36fd4c6bb..275f939f55caac0c187f48f9aab7356f99ca8839 100644
|
| --- a/media/filters/audio_renderer_algorithm.cc
|
| +++ b/media/filters/audio_renderer_algorithm.cc
|
| @@ -82,9 +82,11 @@ AudioRendererAlgorithm::AudioRendererAlgorithm()
|
|
|
| AudioRendererAlgorithm::~AudioRendererAlgorithm() {}
|
|
|
| -void AudioRendererAlgorithm::Initialize(const AudioParameters& params) {
|
| +void AudioRendererAlgorithm::Initialize(const AudioParameters& params,
|
| + std::vector<bool> channel_mask) {
|
| CHECK(params.IsValid());
|
|
|
| + channel_mask_ = std::move(channel_mask);
|
| channels_ = params.channels();
|
| samples_per_second_ = params.sample_rate();
|
| initial_capacity_ = capacity_ =
|
| @@ -137,6 +139,27 @@ void AudioRendererAlgorithm::Initialize(const AudioParameters& params) {
|
| search_block_ = AudioBus::Create(
|
| channels_, num_candidate_blocks_ + (ola_window_size_ - 1));
|
| target_block_ = AudioBus::Create(channels_, ola_window_size_);
|
| +
|
| + // If no mask is provided, assume all channels are valid.
|
| + if (channel_mask_.empty())
|
| + channel_mask_ = std::vector<bool>(channels_, true);
|
| + DCHECK_EQ(channel_mask_.size(), static_cast<size_t>(channels_));
|
| +
|
| + // WSOLA is quite expensive to run, so if a channel mask exists, use it to
|
| + // reduce the size of our search space.
|
| + std::vector<float*> active_target_channels;
|
| + std::vector<float*> active_search_channels;
|
| + for (int ch = 0; ch < channels_; ++ch) {
|
| + if (channel_mask_[ch]) {
|
| + active_target_channels.push_back(target_block_->channel(ch));
|
| + active_search_channels.push_back(search_block_->channel(ch));
|
| + }
|
| + }
|
| +
|
| + target_block_wrapper_ =
|
| + AudioBus::WrapVector(target_block_->frames(), active_target_channels);
|
| + search_block_wrapper_ =
|
| + AudioBus::WrapVector(search_block_->frames(), active_search_channels);
|
| }
|
|
|
| int AudioRendererAlgorithm::FillBuffer(AudioBus* dest,
|
| @@ -254,11 +277,14 @@ bool AudioRendererAlgorithm::RunOneWsolaIteration(double playback_rate) {
|
|
|
| // Overlap-and-add.
|
| for (int k = 0; k < channels_; ++k) {
|
| + if (!channel_mask_[k])
|
| + continue;
|
| +
|
| const float* const ch_opt_frame = optimal_block_->channel(k);
|
| float* ch_output = wsola_output_->channel(k) + num_complete_frames_;
|
| for (int n = 0; n < ola_hop_size_; ++n) {
|
| ch_output[n] = ch_output[n] * ola_window_[ola_hop_size_ + n] +
|
| - ch_opt_frame[n] * ola_window_[n];
|
| + ch_opt_frame[n] * ola_window_[n];
|
| }
|
|
|
| // Copy the second half to the output.
|
| @@ -310,6 +336,8 @@ int AudioRendererAlgorithm::WriteCompletedFramesTo(
|
| // Remove the frames which are read.
|
| int frames_to_move = wsola_output_->frames() - rendered_frames;
|
| for (int k = 0; k < channels_; ++k) {
|
| + if (!channel_mask_[k])
|
| + continue;
|
| float* ch = wsola_output_->channel(k);
|
| memmove(ch, &ch[rendered_frames], sizeof(*ch) * frames_to_move);
|
| }
|
| @@ -338,16 +366,17 @@ void AudioRendererAlgorithm::GetOptimalBlock() {
|
| } else {
|
| PeekAudioWithZeroPrepend(target_block_index_, target_block_.get());
|
| PeekAudioWithZeroPrepend(search_block_index_, search_block_.get());
|
| - int last_optimal = target_block_index_ - ola_hop_size_ -
|
| - search_block_index_;
|
| - internal::Interval exclude_iterval = std::make_pair(
|
| - last_optimal - kExcludeIntervalLengthFrames / 2,
|
| - last_optimal + kExcludeIntervalLengthFrames / 2);
|
| + int last_optimal =
|
| + target_block_index_ - ola_hop_size_ - search_block_index_;
|
| + internal::Interval exclude_interval =
|
| + std::make_pair(last_optimal - kExcludeIntervalLengthFrames / 2,
|
| + last_optimal + kExcludeIntervalLengthFrames / 2);
|
|
|
| // |optimal_index| is in frames and it is relative to the beginning of the
|
| // |search_block_|.
|
| - optimal_index = internal::OptimalIndex(
|
| - search_block_.get(), target_block_.get(), exclude_iterval);
|
| + optimal_index =
|
| + internal::OptimalIndex(search_block_wrapper_.get(),
|
| + target_block_wrapper_.get(), exclude_interval);
|
|
|
| // Translate |index| w.r.t. the beginning of |audio_buffer_| and extract the
|
| // optimal block.
|
| @@ -363,11 +392,13 @@ void AudioRendererAlgorithm::GetOptimalBlock() {
|
| // where target-block has higher weight close to zero (weight of 1 at index
|
| // 0) and lower weight close the end.
|
| for (int k = 0; k < channels_; ++k) {
|
| + if (!channel_mask_[k])
|
| + continue;
|
| float* ch_opt = optimal_block_->channel(k);
|
| const float* const ch_target = target_block_->channel(k);
|
| for (int n = 0; n < ola_window_size_; ++n) {
|
| - ch_opt[n] = ch_opt[n] * transition_window_[n] + ch_target[n] *
|
| - transition_window_[ola_window_size_ + n];
|
| + ch_opt[n] = ch_opt[n] * transition_window_[n] +
|
| + ch_target[n] * transition_window_[ola_window_size_ + n];
|
| }
|
| }
|
| }
|
|
|