1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // MSVC++ requires this to be set before any other includes to get M_SQRT1_2. 6 #define _USE_MATH_DEFINES 7 8 #include "media/base/channel_mixer.h" 9 10 #include <algorithm> 11 #include <cmath> 12 13 #include "base/logging.h" 14 #include "media/audio/audio_parameters.h" 15 #include "media/base/audio_bus.h" 16 #include "media/base/vector_math.h" 17 18 namespace media { 19 20 // Default scale factor for mixing two channels together. We use a different 21 // value for stereo -> mono and mono -> stereo mixes. 22 static const float kEqualPowerScale = static_cast<float>(M_SQRT1_2); 23 24 static void ValidateLayout(ChannelLayout layout) { 25 CHECK_NE(layout, CHANNEL_LAYOUT_NONE); 26 CHECK_NE(layout, CHANNEL_LAYOUT_MAX); 27 CHECK_NE(layout, CHANNEL_LAYOUT_UNSUPPORTED); 28 CHECK_NE(layout, CHANNEL_LAYOUT_DISCRETE); 29 30 // Verify there's at least one channel. Should always be true here by virtue 31 // of not being one of the invalid layouts, but lets double check to be sure. 32 int channel_count = ChannelLayoutToChannelCount(layout); 33 DCHECK_GT(channel_count, 0); 34 35 // If we have more than one channel, verify a symmetric layout for sanity. 36 // The unit test will verify all possible layouts, so this can be a DCHECK. 37 // Symmetry allows simplifying the matrix building code by allowing us to 38 // assume that if one channel of a pair exists, the other will too. 39 if (channel_count > 1) { 40 DCHECK((ChannelOrder(layout, LEFT) >= 0 && 41 ChannelOrder(layout, RIGHT) >= 0) || 42 (ChannelOrder(layout, SIDE_LEFT) >= 0 && 43 ChannelOrder(layout, SIDE_RIGHT) >= 0) || 44 (ChannelOrder(layout, BACK_LEFT) >= 0 && 45 ChannelOrder(layout, BACK_RIGHT) >= 0) || 46 (ChannelOrder(layout, LEFT_OF_CENTER) >= 0 && 47 ChannelOrder(layout, RIGHT_OF_CENTER) >= 0)) 48 << "Non-symmetric channel layout encountered."; 49 } else { 50 DCHECK_EQ(layout, CHANNEL_LAYOUT_MONO); 51 } 52 53 return; 54 } 55 56 class MatrixBuilder { 57 public: 58 MatrixBuilder(ChannelLayout input_layout, int input_channels, 59 ChannelLayout output_layout, int output_channels) 60 : input_layout_(input_layout), 61 input_channels_(input_channels), 62 output_layout_(output_layout), 63 output_channels_(output_channels) { 64 // Special case for 5.0, 5.1 with back channels when upmixed to 7.0, 7.1, 65 // which should map the back LR to side LR. 66 if (input_layout_ == CHANNEL_LAYOUT_5_0_BACK && 67 output_layout_ == CHANNEL_LAYOUT_7_0) { 68 input_layout_ = CHANNEL_LAYOUT_5_0; 69 } else if (input_layout_ == CHANNEL_LAYOUT_5_1_BACK && 70 output_layout_ == CHANNEL_LAYOUT_7_1) { 71 input_layout_ = CHANNEL_LAYOUT_5_1; 72 } 73 } 74 75 ~MatrixBuilder() { } 76 77 // Create the transformation matrix of input channels to output channels. 78 // Updates the empty matrix with the transformation, and returns true 79 // if the transformation is just a remapping of channels (no mixing). 80 bool CreateTransformationMatrix(std::vector< std::vector<float> >* matrix); 81 82 private: 83 // Result transformation of input channels to output channels 84 std::vector< std::vector<float> >* matrix_; 85 86 // Input and output channel layout provided during construction. 87 ChannelLayout input_layout_; 88 int input_channels_; 89 ChannelLayout output_layout_; 90 int output_channels_; 91 92 // Helper variable for tracking which inputs are currently unaccounted, 93 // should be empty after construction completes. 94 std::vector<Channels> unaccounted_inputs_; 95 96 // Helper methods for managing unaccounted input channels. 97 void AccountFor(Channels ch); 98 bool IsUnaccounted(Channels ch); 99 100 // Helper methods for checking if |ch| exists in either |input_layout_| or 101 // |output_layout_| respectively. 102 bool HasInputChannel(Channels ch); 103 bool HasOutputChannel(Channels ch); 104 105 // Helper methods for updating |matrix_| with the proper value for 106 // mixing |input_ch| into |output_ch|. MixWithoutAccounting() does not 107 // remove the channel from |unaccounted_inputs_|. 108 void Mix(Channels input_ch, Channels output_ch, float scale); 109 void MixWithoutAccounting(Channels input_ch, Channels output_ch, 110 float scale); 111 112 DISALLOW_COPY_AND_ASSIGN(MatrixBuilder); 113 }; 114 115 ChannelMixer::ChannelMixer(ChannelLayout input_layout, 116 ChannelLayout output_layout) { 117 Initialize(input_layout, 118 ChannelLayoutToChannelCount(input_layout), 119 output_layout, 120 ChannelLayoutToChannelCount(output_layout)); 121 } 122 123 ChannelMixer::ChannelMixer( 124 const AudioParameters& input, const AudioParameters& output) { 125 Initialize(input.channel_layout(), 126 input.channels(), 127 output.channel_layout(), 128 output.channels()); 129 } 130 131 void ChannelMixer::Initialize( 132 ChannelLayout input_layout, int input_channels, 133 ChannelLayout output_layout, int output_channels) { 134 // Stereo down mix should never be the output layout. 135 CHECK_NE(output_layout, CHANNEL_LAYOUT_STEREO_DOWNMIX); 136 137 // Verify that the layouts are supported 138 if (input_layout != CHANNEL_LAYOUT_DISCRETE) 139 ValidateLayout(input_layout); 140 if (output_layout != CHANNEL_LAYOUT_DISCRETE) 141 ValidateLayout(output_layout); 142 143 // Create the transformation matrix 144 MatrixBuilder matrix_builder(input_layout, input_channels, 145 output_layout, output_channels); 146 remapping_ = matrix_builder.CreateTransformationMatrix(&matrix_); 147 } 148 149 bool MatrixBuilder::CreateTransformationMatrix( 150 std::vector< std::vector<float> >* matrix) { 151 matrix_ = matrix; 152 153 // Size out the initial matrix. 154 matrix_->reserve(output_channels_); 155 for (int output_ch = 0; output_ch < output_channels_; ++output_ch) 156 matrix_->push_back(std::vector<float>(input_channels_, 0)); 157 158 // First check for discrete case. 159 if (input_layout_ == CHANNEL_LAYOUT_DISCRETE || 160 output_layout_ == CHANNEL_LAYOUT_DISCRETE) { 161 // If the number of input channels is more than output channels, then 162 // copy as many as we can then drop the remaining input channels. 163 // If the number of input channels is less than output channels, then 164 // copy them all, then zero out the remaining output channels. 165 int passthrough_channels = std::min(input_channels_, output_channels_); 166 for (int i = 0; i < passthrough_channels; ++i) 167 (*matrix_)[i][i] = 1; 168 169 return true; 170 } 171 172 // Route matching channels and figure out which ones aren't accounted for. 173 for (Channels ch = LEFT; ch < CHANNELS_MAX; 174 ch = static_cast<Channels>(ch + 1)) { 175 int input_ch_index = ChannelOrder(input_layout_, ch); 176 if (input_ch_index < 0) 177 continue; 178 179 int output_ch_index = ChannelOrder(output_layout_, ch); 180 if (output_ch_index < 0) { 181 unaccounted_inputs_.push_back(ch); 182 continue; 183 } 184 185 DCHECK_LT(static_cast<size_t>(output_ch_index), matrix_->size()); 186 DCHECK_LT(static_cast<size_t>(input_ch_index), 187 (*matrix_)[output_ch_index].size()); 188 (*matrix_)[output_ch_index][input_ch_index] = 1; 189 } 190 191 // If all input channels are accounted for, there's nothing left to do. 192 if (unaccounted_inputs_.empty()) { 193 // Since all output channels map directly to inputs we can optimize. 194 return true; 195 } 196 197 // Mix front LR into center. 198 if (IsUnaccounted(LEFT)) { 199 // When down mixing to mono from stereo, we need to be careful of full scale 200 // stereo mixes. Scaling by 1 / sqrt(2) here will likely lead to clipping 201 // so we use 1 / 2 instead. 202 float scale = 203 (output_layout_ == CHANNEL_LAYOUT_MONO && input_channels_ == 2) ? 204 0.5 : kEqualPowerScale; 205 Mix(LEFT, CENTER, scale); 206 Mix(RIGHT, CENTER, scale); 207 } 208 209 // Mix center into front LR. 210 if (IsUnaccounted(CENTER)) { 211 // When up mixing from mono, just do a copy to front LR. 212 float scale = 213 (input_layout_ == CHANNEL_LAYOUT_MONO) ? 1 : kEqualPowerScale; 214 MixWithoutAccounting(CENTER, LEFT, scale); 215 Mix(CENTER, RIGHT, scale); 216 } 217 218 // Mix back LR into: side LR || back center || front LR || front center. 219 if (IsUnaccounted(BACK_LEFT)) { 220 if (HasOutputChannel(SIDE_LEFT)) { 221 // If we have side LR, mix back LR into side LR, but instead if the input 222 // doesn't have side LR (but output does) copy back LR to side LR. 223 float scale = HasInputChannel(SIDE_LEFT) ? kEqualPowerScale : 1; 224 Mix(BACK_LEFT, SIDE_LEFT, scale); 225 Mix(BACK_RIGHT, SIDE_RIGHT, scale); 226 } else if (HasOutputChannel(BACK_CENTER)) { 227 // Mix back LR into back center. 228 Mix(BACK_LEFT, BACK_CENTER, kEqualPowerScale); 229 Mix(BACK_RIGHT, BACK_CENTER, kEqualPowerScale); 230 } else if (output_layout_ > CHANNEL_LAYOUT_MONO) { 231 // Mix back LR into front LR. 232 Mix(BACK_LEFT, LEFT, kEqualPowerScale); 233 Mix(BACK_RIGHT, RIGHT, kEqualPowerScale); 234 } else { 235 // Mix back LR into front center. 236 Mix(BACK_LEFT, CENTER, kEqualPowerScale); 237 Mix(BACK_RIGHT, CENTER, kEqualPowerScale); 238 } 239 } 240 241 // Mix side LR into: back LR || back center || front LR || front center. 242 if (IsUnaccounted(SIDE_LEFT)) { 243 if (HasOutputChannel(BACK_LEFT)) { 244 // If we have back LR, mix side LR into back LR, but instead if the input 245 // doesn't have back LR (but output does) copy side LR to back LR. 246 float scale = HasInputChannel(BACK_LEFT) ? kEqualPowerScale : 1; 247 Mix(SIDE_LEFT, BACK_LEFT, scale); 248 Mix(SIDE_RIGHT, BACK_RIGHT, scale); 249 } else if (HasOutputChannel(BACK_CENTER)) { 250 // Mix side LR into back center. 251 Mix(SIDE_LEFT, BACK_CENTER, kEqualPowerScale); 252 Mix(SIDE_RIGHT, BACK_CENTER, kEqualPowerScale); 253 } else if (output_layout_ > CHANNEL_LAYOUT_MONO) { 254 // Mix side LR into front LR. 255 Mix(SIDE_LEFT, LEFT, kEqualPowerScale); 256 Mix(SIDE_RIGHT, RIGHT, kEqualPowerScale); 257 } else { 258 // Mix side LR into front center. 259 Mix(SIDE_LEFT, CENTER, kEqualPowerScale); 260 Mix(SIDE_RIGHT, CENTER, kEqualPowerScale); 261 } 262 } 263 264 // Mix back center into: back LR || side LR || front LR || front center. 265 if (IsUnaccounted(BACK_CENTER)) { 266 if (HasOutputChannel(BACK_LEFT)) { 267 // Mix back center into back LR. 268 MixWithoutAccounting(BACK_CENTER, BACK_LEFT, kEqualPowerScale); 269 Mix(BACK_CENTER, BACK_RIGHT, kEqualPowerScale); 270 } else if (HasOutputChannel(SIDE_LEFT)) { 271 // Mix back center into side LR. 272 MixWithoutAccounting(BACK_CENTER, SIDE_LEFT, kEqualPowerScale); 273 Mix(BACK_CENTER, SIDE_RIGHT, kEqualPowerScale); 274 } else if (output_layout_ > CHANNEL_LAYOUT_MONO) { 275 // Mix back center into front LR. 276 // TODO(dalecurtis): Not sure about these values? 277 MixWithoutAccounting(BACK_CENTER, LEFT, kEqualPowerScale); 278 Mix(BACK_CENTER, RIGHT, kEqualPowerScale); 279 } else { 280 // Mix back center into front center. 281 // TODO(dalecurtis): Not sure about these values? 282 Mix(BACK_CENTER, CENTER, kEqualPowerScale); 283 } 284 } 285 286 // Mix LR of center into: front center || front LR. 287 if (IsUnaccounted(LEFT_OF_CENTER)) { 288 if (HasOutputChannel(LEFT)) { 289 // Mix LR of center into front LR. 290 Mix(LEFT_OF_CENTER, LEFT, kEqualPowerScale); 291 Mix(RIGHT_OF_CENTER, RIGHT, kEqualPowerScale); 292 } else { 293 // Mix LR of center into front center. 294 Mix(LEFT_OF_CENTER, CENTER, kEqualPowerScale); 295 Mix(RIGHT_OF_CENTER, CENTER, kEqualPowerScale); 296 } 297 } 298 299 // Mix LFE into: front LR || front center. 300 if (IsUnaccounted(LFE)) { 301 if (!HasOutputChannel(CENTER)) { 302 // Mix LFE into front LR. 303 MixWithoutAccounting(LFE, LEFT, kEqualPowerScale); 304 Mix(LFE, RIGHT, kEqualPowerScale); 305 } else { 306 // Mix LFE into front center. 307 Mix(LFE, CENTER, kEqualPowerScale); 308 } 309 } 310 311 // All channels should now be accounted for. 312 DCHECK(unaccounted_inputs_.empty()); 313 314 // See if the output |matrix_| is simply a remapping matrix. If each input 315 // channel maps to a single output channel we can simply remap. Doing this 316 // programmatically is less fragile than logic checks on channel mappings. 317 for (int output_ch = 0; output_ch < output_channels_; ++output_ch) { 318 int input_mappings = 0; 319 for (int input_ch = 0; input_ch < input_channels_; ++input_ch) { 320 // We can only remap if each row contains a single scale of 1. I.e., each 321 // output channel is mapped from a single unscaled input channel. 322 if ((*matrix_)[output_ch][input_ch] != 1 || ++input_mappings > 1) 323 return false; 324 } 325 } 326 327 // If we've gotten here, |matrix_| is simply a remapping. 328 return true; 329 } 330 331 ChannelMixer::~ChannelMixer() {} 332 333 void ChannelMixer::Transform(const AudioBus* input, AudioBus* output) { 334 CHECK_EQ(matrix_.size(), static_cast<size_t>(output->channels())); 335 CHECK_EQ(matrix_[0].size(), static_cast<size_t>(input->channels())); 336 CHECK_EQ(input->frames(), output->frames()); 337 338 // Zero initialize |output| so we're accumulating from zero. 339 output->Zero(); 340 341 // If we're just remapping we can simply copy the correct input to output. 342 if (remapping_) { 343 for (int output_ch = 0; output_ch < output->channels(); ++output_ch) { 344 for (int input_ch = 0; input_ch < input->channels(); ++input_ch) { 345 float scale = matrix_[output_ch][input_ch]; 346 if (scale > 0) { 347 DCHECK_EQ(scale, 1.0f); 348 memcpy(output->channel(output_ch), input->channel(input_ch), 349 sizeof(*output->channel(output_ch)) * output->frames()); 350 break; 351 } 352 } 353 } 354 return; 355 } 356 357 for (int output_ch = 0; output_ch < output->channels(); ++output_ch) { 358 for (int input_ch = 0; input_ch < input->channels(); ++input_ch) { 359 float scale = matrix_[output_ch][input_ch]; 360 // Scale should always be positive. Don't bother scaling by zero. 361 DCHECK_GE(scale, 0); 362 if (scale > 0) { 363 vector_math::FMAC(input->channel(input_ch), scale, output->frames(), 364 output->channel(output_ch)); 365 } 366 } 367 } 368 } 369 370 void MatrixBuilder::AccountFor(Channels ch) { 371 unaccounted_inputs_.erase(std::find( 372 unaccounted_inputs_.begin(), unaccounted_inputs_.end(), ch)); 373 } 374 375 bool MatrixBuilder::IsUnaccounted(Channels ch) { 376 return std::find(unaccounted_inputs_.begin(), unaccounted_inputs_.end(), 377 ch) != unaccounted_inputs_.end(); 378 } 379 380 bool MatrixBuilder::HasInputChannel(Channels ch) { 381 return ChannelOrder(input_layout_, ch) >= 0; 382 } 383 384 bool MatrixBuilder::HasOutputChannel(Channels ch) { 385 return ChannelOrder(output_layout_, ch) >= 0; 386 } 387 388 void MatrixBuilder::Mix(Channels input_ch, Channels output_ch, float scale) { 389 MixWithoutAccounting(input_ch, output_ch, scale); 390 AccountFor(input_ch); 391 } 392 393 void MatrixBuilder::MixWithoutAccounting(Channels input_ch, Channels output_ch, 394 float scale) { 395 int input_ch_index = ChannelOrder(input_layout_, input_ch); 396 int output_ch_index = ChannelOrder(output_layout_, output_ch); 397 398 DCHECK(IsUnaccounted(input_ch)); 399 DCHECK_GE(input_ch_index, 0); 400 DCHECK_GE(output_ch_index, 0); 401 402 DCHECK_EQ((*matrix_)[output_ch_index][input_ch_index], 0); 403 (*matrix_)[output_ch_index][input_ch_index] = scale; 404 } 405 406 } // namespace media 407