15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MSVC++ requires this to be set before any other includes to get M_SQRT1_2. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define _USE_MATH_DEFINES 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/channel_mixer.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cmath> 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_parameters.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/audio_bus.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/vector_math.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Default scale factor for mixing two channels together. We use a different 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// value for stereo -> mono and mono -> stereo mixes. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const float kEqualPowerScale = static_cast<float>(M_SQRT1_2); 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static void ValidateLayout(ChannelLayout layout) { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_NE(layout, CHANNEL_LAYOUT_NONE); 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_NE(layout, CHANNEL_LAYOUT_MAX); 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_NE(layout, CHANNEL_LAYOUT_UNSUPPORTED); 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CHECK_NE(layout, CHANNEL_LAYOUT_DISCRETE); 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Verify there's at least one channel. Should always be true here by virtue 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of not being one of the invalid layouts, but lets double check to be sure. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int channel_count = ChannelLayoutToChannelCount(layout); 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(channel_count, 0); 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have more than one channel, verify a symmetric layout for sanity. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The unit test will verify all possible layouts, so this can be a DCHECK. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Symmetry allows simplifying the matrix building code by allowing us to 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // assume that if one channel of a pair exists, the other will too. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (channel_count > 1) { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK((ChannelOrder(layout, LEFT) >= 0 && 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ChannelOrder(layout, RIGHT) >= 0) || 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (ChannelOrder(layout, SIDE_LEFT) >= 0 && 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ChannelOrder(layout, SIDE_RIGHT) >= 0) || 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (ChannelOrder(layout, BACK_LEFT) >= 0 && 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ChannelOrder(layout, BACK_RIGHT) >= 0) || 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (ChannelOrder(layout, LEFT_OF_CENTER) >= 0 && 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ChannelOrder(layout, RIGHT_OF_CENTER) >= 0)) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Non-symmetric channel layout encountered."; 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(layout, CHANNEL_LAYOUT_MONO); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class MatrixBuilder { 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MatrixBuilder(ChannelLayout input_layout, int input_channels, 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ChannelLayout output_layout, int output_channels) 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : input_layout_(input_layout), 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) input_channels_(input_channels), 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_layout_(output_layout), 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_channels_(output_channels) { 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Special case for 5.0, 5.1 with back channels when upmixed to 7.0, 7.1, 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // which should map the back LR to side LR. 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (input_layout_ == CHANNEL_LAYOUT_5_0_BACK && 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_layout_ == CHANNEL_LAYOUT_7_0) { 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) input_layout_ = CHANNEL_LAYOUT_5_0; 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (input_layout_ == CHANNEL_LAYOUT_5_1_BACK && 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_layout_ == CHANNEL_LAYOUT_7_1) { 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) input_layout_ = CHANNEL_LAYOUT_5_1; 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ~MatrixBuilder() { } 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Create the transformation matrix of input channels to output channels. 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Updates the empty matrix with the transformation, and returns true 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // if the transformation is just a remapping of channels (no mixing). 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool CreateTransformationMatrix(std::vector< std::vector<float> >* matrix); 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Result transformation of input channels to output channels 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector< std::vector<float> >* matrix_; 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Input and output channel layout provided during construction. 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ChannelLayout input_layout_; 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int input_channels_; 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ChannelLayout output_layout_; 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int output_channels_; 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Helper variable for tracking which inputs are currently unaccounted, 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // should be empty after construction completes. 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<Channels> unaccounted_inputs_; 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Helper methods for managing unaccounted input channels. 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void AccountFor(Channels ch); 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool IsUnaccounted(Channels ch); 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Helper methods for checking if |ch| exists in either |input_layout_| or 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // |output_layout_| respectively. 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool HasInputChannel(Channels ch); 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool HasOutputChannel(Channels ch); 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Helper methods for updating |matrix_| with the proper value for 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // mixing |input_ch| into |output_ch|. MixWithoutAccounting() does not 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // remove the channel from |unaccounted_inputs_|. 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void Mix(Channels input_ch, Channels output_ch, float scale); 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void MixWithoutAccounting(Channels input_ch, Channels output_ch, 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float scale); 111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(MatrixBuilder); 113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChannelMixer::ChannelMixer(ChannelLayout input_layout, 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChannelLayout output_layout) { 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Initialize(input_layout, 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChannelLayoutToChannelCount(input_layout), 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output_layout, 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChannelLayoutToChannelCount(output_layout)); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChannelMixer::ChannelMixer( 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AudioParameters& input, const AudioParameters& output) { 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Initialize(input.channel_layout(), 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) input.channels(), 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output.channel_layout(), 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output.channels()); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ChannelMixer::Initialize( 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChannelLayout input_layout, int input_channels, 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChannelLayout output_layout, int output_channels) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stereo down mix should never be the output layout. 135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CHECK_NE(output_layout, CHANNEL_LAYOUT_STEREO_DOWNMIX); 136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Verify that the layouts are supported 138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (input_layout != CHANNEL_LAYOUT_DISCRETE) 139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ValidateLayout(input_layout); 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (output_layout != CHANNEL_LAYOUT_DISCRETE) 141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ValidateLayout(output_layout); 142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Create the transformation matrix 144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) MatrixBuilder matrix_builder(input_layout, input_channels, 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) output_layout, output_channels); 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) remapping_ = matrix_builder.CreateTransformationMatrix(&matrix_); 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool MatrixBuilder::CreateTransformationMatrix( 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector< std::vector<float> >* matrix) { 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) matrix_ = matrix; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Size out the initial matrix. 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) matrix_->reserve(output_channels_); 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int output_ch = 0; output_ch < output_channels_; ++output_ch) 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) matrix_->push_back(std::vector<float>(input_channels_, 0)); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // First check for discrete case. 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (input_layout_ == CHANNEL_LAYOUT_DISCRETE || 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output_layout_ == CHANNEL_LAYOUT_DISCRETE) { 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the number of input channels is more than output channels, then 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // copy as many as we can then drop the remaining input channels. 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the number of input channels is less than output channels, then 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // copy them all, then zero out the remaining output channels. 165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int passthrough_channels = std::min(input_channels_, output_channels_); 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (int i = 0; i < passthrough_channels; ++i) 167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (*matrix_)[i][i] = 1; 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Route matching channels and figure out which ones aren't accounted for. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (Channels ch = LEFT; ch < CHANNELS_MAX; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ch = static_cast<Channels>(ch + 1)) { 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int input_ch_index = ChannelOrder(input_layout_, ch); 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (input_ch_index < 0) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int output_ch_index = ChannelOrder(output_layout_, ch); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (output_ch_index < 0) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unaccounted_inputs_.push_back(ch); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_LT(static_cast<size_t>(output_ch_index), matrix_->size()); 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(static_cast<size_t>(input_ch_index), 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (*matrix_)[output_ch_index].size()); 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (*matrix_)[output_ch_index][input_ch_index] = 1; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If all input channels are accounted for, there's nothing left to do. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (unaccounted_inputs_.empty()) { 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since all output channels map directly to inputs we can optimize. 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix front LR into center. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsUnaccounted(LEFT)) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When down mixing to mono from stereo, we need to be careful of full scale 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // stereo mixes. Scaling by 1 / sqrt(2) here will likely lead to clipping 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // so we use 1 / 2 instead. 2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) float scale = 203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (output_layout_ == CHANNEL_LAYOUT_MONO && input_channels_ == 2) ? 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0.5 : kEqualPowerScale; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(LEFT, CENTER, scale); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(RIGHT, CENTER, scale); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix center into front LR. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsUnaccounted(CENTER)) { 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When up mixing from mono, just do a copy to front LR. 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) float scale = 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (input_layout_ == CHANNEL_LAYOUT_MONO) ? 1 : kEqualPowerScale; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MixWithoutAccounting(CENTER, LEFT, scale); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(CENTER, RIGHT, scale); 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix back LR into: side LR || back center || front LR || front center. 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsUnaccounted(BACK_LEFT)) { 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasOutputChannel(SIDE_LEFT)) { 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have side LR, mix back LR into side LR, but instead if the input 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // doesn't have side LR (but output does) copy back LR to side LR. 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float scale = HasInputChannel(SIDE_LEFT) ? kEqualPowerScale : 1; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_LEFT, SIDE_LEFT, scale); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_RIGHT, SIDE_RIGHT, scale); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (HasOutputChannel(BACK_CENTER)) { 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix back LR into back center. 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_LEFT, BACK_CENTER, kEqualPowerScale); 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_RIGHT, BACK_CENTER, kEqualPowerScale); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (output_layout_ > CHANNEL_LAYOUT_MONO) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix back LR into front LR. 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_LEFT, LEFT, kEqualPowerScale); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_RIGHT, RIGHT, kEqualPowerScale); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix back LR into front center. 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_LEFT, CENTER, kEqualPowerScale); 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_RIGHT, CENTER, kEqualPowerScale); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix side LR into: back LR || back center || front LR || front center. 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsUnaccounted(SIDE_LEFT)) { 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasOutputChannel(BACK_LEFT)) { 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have back LR, mix side LR into back LR, but instead if the input 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // doesn't have back LR (but output does) copy side LR to back LR. 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float scale = HasInputChannel(BACK_LEFT) ? kEqualPowerScale : 1; 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(SIDE_LEFT, BACK_LEFT, scale); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(SIDE_RIGHT, BACK_RIGHT, scale); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (HasOutputChannel(BACK_CENTER)) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix side LR into back center. 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(SIDE_LEFT, BACK_CENTER, kEqualPowerScale); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(SIDE_RIGHT, BACK_CENTER, kEqualPowerScale); 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (output_layout_ > CHANNEL_LAYOUT_MONO) { 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix side LR into front LR. 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(SIDE_LEFT, LEFT, kEqualPowerScale); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(SIDE_RIGHT, RIGHT, kEqualPowerScale); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix side LR into front center. 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(SIDE_LEFT, CENTER, kEqualPowerScale); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(SIDE_RIGHT, CENTER, kEqualPowerScale); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix back center into: back LR || side LR || front LR || front center. 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsUnaccounted(BACK_CENTER)) { 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasOutputChannel(BACK_LEFT)) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix back center into back LR. 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MixWithoutAccounting(BACK_CENTER, BACK_LEFT, kEqualPowerScale); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_CENTER, BACK_RIGHT, kEqualPowerScale); 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (HasOutputChannel(SIDE_LEFT)) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix back center into side LR. 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MixWithoutAccounting(BACK_CENTER, SIDE_LEFT, kEqualPowerScale); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_CENTER, SIDE_RIGHT, kEqualPowerScale); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (output_layout_ > CHANNEL_LAYOUT_MONO) { 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix back center into front LR. 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dalecurtis): Not sure about these values? 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MixWithoutAccounting(BACK_CENTER, LEFT, kEqualPowerScale); 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_CENTER, RIGHT, kEqualPowerScale); 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix back center into front center. 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(dalecurtis): Not sure about these values? 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(BACK_CENTER, CENTER, kEqualPowerScale); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix LR of center into: front center || front LR. 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsUnaccounted(LEFT_OF_CENTER)) { 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasOutputChannel(LEFT)) { 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix LR of center into front LR. 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(LEFT_OF_CENTER, LEFT, kEqualPowerScale); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(RIGHT_OF_CENTER, RIGHT, kEqualPowerScale); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix LR of center into front center. 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(LEFT_OF_CENTER, CENTER, kEqualPowerScale); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(RIGHT_OF_CENTER, CENTER, kEqualPowerScale); 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix LFE into: front LR || front center. 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsUnaccounted(LFE)) { 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!HasOutputChannel(CENTER)) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix LFE into front LR. 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MixWithoutAccounting(LFE, LEFT, kEqualPowerScale); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(LFE, RIGHT, kEqualPowerScale); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Mix LFE into front center. 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Mix(LFE, CENTER, kEqualPowerScale); 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All channels should now be accounted for. 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(unaccounted_inputs_.empty()); 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See if the output |matrix_| is simply a remapping matrix. If each input 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // channel maps to a single output channel we can simply remap. Doing this 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // programmatically is less fragile than logic checks on channel mappings. 317c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int output_ch = 0; output_ch < output_channels_; ++output_ch) { 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int input_mappings = 0; 319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (int input_ch = 0; input_ch < input_channels_; ++input_ch) { 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can only remap if each row contains a single scale of 1. I.e., each 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // output channel is mapped from a single unscaled input channel. 322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if ((*matrix_)[output_ch][input_ch] != 1 || ++input_mappings > 1) 323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we've gotten here, |matrix_| is simply a remapping. 328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ChannelMixer::~ChannelMixer() {} 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChannelMixer::Transform(const AudioBus* input, AudioBus* output) { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(matrix_.size(), static_cast<size_t>(output->channels())); 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(matrix_[0].size(), static_cast<size_t>(input->channels())); 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(input->frames(), output->frames()); 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Zero initialize |output| so we're accumulating from zero. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output->Zero(); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we're just remapping we can simply copy the correct input to output. 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (remapping_) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int output_ch = 0; output_ch < output->channels(); ++output_ch) { 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int input_ch = 0; input_ch < input->channels(); ++input_ch) { 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float scale = matrix_[output_ch][input_ch]; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scale > 0) { 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(scale, 1.0f); 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(output->channel(output_ch), input->channel(input_ch), 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sizeof(*output->channel(output_ch)) * output->frames()); 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int output_ch = 0; output_ch < output->channels(); ++output_ch) { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int input_ch = 0; input_ch < input->channels(); ++input_ch) { 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float scale = matrix_[output_ch][input_ch]; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Scale should always be positive. Don't bother scaling by zero. 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(scale, 0); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (scale > 0) { 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vector_math::FMAC(input->channel(input_ch), scale, output->frames(), 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output->channel(output_ch)); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MatrixBuilder::AccountFor(Channels ch) { 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unaccounted_inputs_.erase(std::find( 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unaccounted_inputs_.begin(), unaccounted_inputs_.end(), ch)); 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool MatrixBuilder::IsUnaccounted(Channels ch) { 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::find(unaccounted_inputs_.begin(), unaccounted_inputs_.end(), 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ch) != unaccounted_inputs_.end(); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool MatrixBuilder::HasInputChannel(Channels ch) { 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ChannelOrder(input_layout_, ch) >= 0; 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool MatrixBuilder::HasOutputChannel(Channels ch) { 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ChannelOrder(output_layout_, ch) >= 0; 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MatrixBuilder::Mix(Channels input_ch, Channels output_ch, float scale) { 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MixWithoutAccounting(input_ch, output_ch, scale); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AccountFor(input_ch); 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void MatrixBuilder::MixWithoutAccounting(Channels input_ch, Channels output_ch, 394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) float scale) { 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int input_ch_index = ChannelOrder(input_layout_, input_ch); 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int output_ch_index = ChannelOrder(output_layout_, output_ch); 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(IsUnaccounted(input_ch)); 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(input_ch_index, 0); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(output_ch_index, 0); 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK_EQ((*matrix_)[output_ch_index][input_ch_index], 0); 403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (*matrix_)[output_ch_index][input_ch_index] = scale; 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace media 407