// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "media/base/channel_mixer.h" #include "base/logging.h" #include "media/audio/audio_parameters.h" #include "media/base/audio_bus.h" #include "media/base/channel_mixing_matrix.h" #include "media/base/vector_math.h" namespace media { ChannelMixer::ChannelMixer(ChannelLayout input_layout, ChannelLayout output_layout) { Initialize(input_layout, ChannelLayoutToChannelCount(input_layout), output_layout, ChannelLayoutToChannelCount(output_layout)); } ChannelMixer::ChannelMixer( const AudioParameters& input, const AudioParameters& output) { Initialize(input.channel_layout(), input.channels(), output.channel_layout(), output.channels()); } void ChannelMixer::Initialize( ChannelLayout input_layout, int input_channels, ChannelLayout output_layout, int output_channels) { // Create the transformation matrix ChannelMixingMatrix matrix_builder(input_layout, input_channels, output_layout, output_channels); remapping_ = matrix_builder.CreateTransformationMatrix(&matrix_); } ChannelMixer::~ChannelMixer() {} void ChannelMixer::Transform(const AudioBus* input, AudioBus* output) { CHECK_EQ(matrix_.size(), static_cast(output->channels())); CHECK_EQ(matrix_[0].size(), static_cast(input->channels())); CHECK_EQ(input->frames(), output->frames()); // Zero initialize |output| so we're accumulating from zero. output->Zero(); // If we're just remapping we can simply copy the correct input to output. if (remapping_) { for (int output_ch = 0; output_ch < output->channels(); ++output_ch) { for (int input_ch = 0; input_ch < input->channels(); ++input_ch) { float scale = matrix_[output_ch][input_ch]; if (scale > 0) { DCHECK_EQ(scale, 1.0f); memcpy(output->channel(output_ch), input->channel(input_ch), sizeof(*output->channel(output_ch)) * output->frames()); break; } } } return; } for (int output_ch = 0; output_ch < output->channels(); ++output_ch) { for (int input_ch = 0; input_ch < input->channels(); ++input_ch) { float scale = matrix_[output_ch][input_ch]; // Scale should always be positive. Don't bother scaling by zero. DCHECK_GE(scale, 0); if (scale > 0) { vector_math::FMAC(input->channel(input_ch), scale, output->frames(), output->channel(output_ch)); } } } } } // namespace media