blob: e15a5b0df682e43abc843cb87fadfbd97cb40431 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/390223051): Remove C-library calls to fix the errors.
#pragma allow_unsafe_libc_calls
#endif
#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,
int input_channels,
ChannelLayout output_layout,
int output_channels) {
Initialize(input_layout, input_channels, output_layout, output_channels);
}
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());
if (frame_count <= 0) {
return;
}
// 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_) {
const size_t frames = static_cast<size_t>(frame_count);
for (int output_ch = 0; output_ch < output->channels(); ++output_ch) {
auto output_channel = output->channel_span(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);
output_channel.first(frames).copy_from_nonoverlapping(
input->channel_span(input_ch).first(frames));
break;
}
}
}
return;
}
for (int output_ch = 0; output_ch < output->channels(); ++output_ch) {
auto output_channel = output->channel_span(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);
const size_t frames = static_cast<size_t>(frame_count);
if (scale > 0) {
vector_math::FMAC(input->channel_span(input_ch).first(frames), scale,
output_channel.first(frames));
}
}
}
}
} // namespace media