blob: 87e6c4590db7a2eb53e4c4e438725041335ecdec [file] [log] [blame]
// 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 <stddef.h>
#include <string.h>
#include "base/check_op.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_parameters.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() = default;
void ChannelMixer::Transform(const AudioBus* input, AudioBus* output) {
CHECK_EQ(input->frames(), output->frames());
TransformPartial(input, input->frames(), output);
}
void ChannelMixer::TransformPartial(const AudioBus* input,
int frame_count,
AudioBus* output) {
CHECK_EQ(matrix_.size(), static_cast<size_t>(output->channels()));
CHECK_EQ(matrix_[0].size(), static_cast<size_t>(input->channels()));
CHECK_LE(frame_count, input->frames());
CHECK_LE(frame_count, output->frames());
// Zero initialize |output| so we're accumulating from zero.
output->ZeroFrames(frame_count);
// 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)) * frame_count);
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, frame_count,
output->channel(output_ch));
}
}
}
}
} // namespace media