1 /* 2 * Copyright 2007 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * probably Marcus Overhagen 7 */ 8 #include "MixerCore.h" 9 #include "MixerDebug.h" 10 #include "MixerOutput.h" 11 #include "MixerUtils.h" 12 13 #include <MediaNode.h> 14 15 MixerOutput::MixerOutput(MixerCore *core, const media_output &output) 16 : fCore(core), 17 fOutput(output), 18 fOutputChannelCount(0), 19 fOutputChannelInfo(0), 20 fOutputByteSwap(0), 21 fMuted(false) 22 { 23 fix_multiaudio_format(&fOutput.format.u.raw_audio); 24 PRINT_OUTPUT("MixerOutput::MixerOutput", fOutput); 25 PRINT_CHANNEL_MASK(fOutput.format); 26 27 UpdateOutputChannels(); 28 UpdateByteOrderSwap(); 29 } 30 31 MixerOutput::~MixerOutput() 32 { 33 delete fOutputChannelInfo; 34 delete fOutputByteSwap; 35 } 36 37 media_output & 38 MixerOutput::MediaOutput() 39 { 40 return fOutput; 41 } 42 43 void 44 MixerOutput::ChangeFormat(const media_multi_audio_format &format) 45 { 46 fOutput.format.u.raw_audio = format; 47 fix_multiaudio_format(&fOutput.format.u.raw_audio); 48 49 PRINT_OUTPUT("MixerOutput::ChangeFormat", fOutput); 50 PRINT_CHANNEL_MASK(fOutput.format); 51 52 UpdateOutputChannels(); 53 UpdateByteOrderSwap(); 54 } 55 56 void 57 MixerOutput::UpdateByteOrderSwap() 58 { 59 delete fOutputByteSwap; 60 fOutputByteSwap = 0; 61 62 // perhaps we need byte swapping 63 if (fOutput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) { 64 if ( fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT 65 || fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_INT 66 || fOutput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) { 67 fOutputByteSwap = new ByteSwap(fOutput.format.u.raw_audio.format); 68 } 69 } 70 } 71 72 void 73 MixerOutput::UpdateOutputChannels() 74 { 75 output_chan_info *oldInfo = fOutputChannelInfo; 76 int oldCount = fOutputChannelCount; 77 78 fOutputChannelCount = fOutput.format.u.raw_audio.channel_count; 79 fOutputChannelInfo = new output_chan_info[fOutputChannelCount]; 80 for (int i = 0; i < fOutputChannelCount; i++) { 81 fOutputChannelInfo[i].channel_type = GetChannelType(i, fOutput.format.u.raw_audio.channel_mask); 82 fOutputChannelInfo[i].channel_gain = 1.0; 83 fOutputChannelInfo[i].source_count = 1; 84 fOutputChannelInfo[i].source_gain[0] = 1.0; 85 fOutputChannelInfo[i].source_type[0] = fOutputChannelInfo[i].channel_type; 86 // all the cached values are 0.0 for a new channel 87 for (int j = 0; j < MAX_CHANNEL_TYPES; j++) 88 fOutputChannelInfo[i].source_gain_cache[j] = 0.0; 89 } 90 91 AssignDefaultSources(); 92 93 // apply old gains and sources, overriding the 1.0 gain defaults for the old channels 94 if (oldInfo != 0 && oldCount != 0) { 95 for (int i = 0; i < fOutputChannelCount; i++) { 96 for (int j = 0; j < oldCount; j++) { 97 if (fOutputChannelInfo[i].channel_type == oldInfo[j].channel_type) { 98 fOutputChannelInfo[i].channel_gain = oldInfo[j].channel_gain; 99 fOutputChannelInfo[i].source_count = oldInfo[j].source_count; 100 for (int k = 0; k < fOutputChannelInfo[i].source_count; k++) { 101 fOutputChannelInfo[i].source_gain[k] = oldInfo[j].source_gain[k]; 102 fOutputChannelInfo[i].source_type[k] = oldInfo[j].source_type[k]; 103 } 104 // also copy the old gain cache 105 for (int k = 0; k < MAX_CHANNEL_TYPES; k++) 106 fOutputChannelInfo[i].source_gain_cache[k] = oldInfo[j].source_gain_cache[k]; 107 break; 108 } 109 } 110 } 111 // also delete the old info array 112 delete [] oldInfo; 113 } 114 for (int i = 0; i < fOutputChannelCount; i++) 115 TRACE("UpdateOutputChannels: output channel %d, type %2d, gain %.3f\n", i, fOutputChannelInfo[i].channel_type, fOutputChannelInfo[i].channel_gain); 116 } 117 118 void 119 MixerOutput::AssignDefaultSources() 120 { 121 uint32 mask = fOutput.format.u.raw_audio.channel_mask; 122 int count = fOutputChannelCount; 123 124 // assign default sources for a few known setups, 125 // everything else is left unchanged (it already is 1:1) 126 if (count == 1 && mask & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) { 127 // we have only one phycial output channel, and use it as a mix of 128 // left, right, rear-left, rear-right, center and sub 129 TRACE("AssignDefaultSources: 1 channel setup\n"); 130 fOutputChannelInfo[0].source_count = 9; 131 fOutputChannelInfo[0].source_gain[0] = 1.0; 132 fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT); 133 fOutputChannelInfo[0].source_gain[1] = 1.0; 134 fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_RIGHT); 135 fOutputChannelInfo[0].source_gain[2] = 0.8; 136 fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT); 137 fOutputChannelInfo[0].source_gain[3] = 0.8; 138 fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT); 139 fOutputChannelInfo[0].source_gain[4] = 0.7; 140 fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_CENTER); 141 fOutputChannelInfo[0].source_gain[5] = 0.6; 142 fOutputChannelInfo[0].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SUB); 143 fOutputChannelInfo[0].source_gain[6] = 1.0; 144 fOutputChannelInfo[0].source_type[6] = ChannelMaskToChannelType(B_CHANNEL_MONO); 145 fOutputChannelInfo[0].source_gain[7] = 0.7; 146 fOutputChannelInfo[0].source_type[7] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT); 147 fOutputChannelInfo[0].source_gain[8] = 0.7; 148 fOutputChannelInfo[0].source_type[8] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT); 149 } else if (count == 2 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT)) { 150 // we have have two phycial output channels 151 TRACE("AssignDefaultSources: 2 channel setup\n"); 152 // left channel: 153 fOutputChannelInfo[0].source_count = 6; 154 fOutputChannelInfo[0].source_gain[0] = 1.0; 155 fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT); 156 fOutputChannelInfo[0].source_gain[1] = 0.8; 157 fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT); 158 fOutputChannelInfo[0].source_gain[2] = 0.7; 159 fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_CENTER); 160 fOutputChannelInfo[0].source_gain[3] = 0.6; 161 fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SUB); 162 fOutputChannelInfo[0].source_gain[4] = 1.0; 163 fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_MONO); 164 fOutputChannelInfo[0].source_gain[5] = 0.7; 165 fOutputChannelInfo[0].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT); 166 // right channel: 167 fOutputChannelInfo[1].source_count = 6; 168 fOutputChannelInfo[1].source_gain[0] = 1.0; 169 fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT); 170 fOutputChannelInfo[1].source_gain[1] = 0.8; 171 fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT); 172 fOutputChannelInfo[1].source_gain[2] = 0.7; 173 fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_CENTER); 174 fOutputChannelInfo[1].source_gain[3] = 0.6; 175 fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SUB); 176 fOutputChannelInfo[1].source_gain[4] = 1.0; 177 fOutputChannelInfo[1].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_MONO); 178 fOutputChannelInfo[1].source_gain[5] = 0.7; 179 fOutputChannelInfo[1].source_type[5] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT); 180 } else if (count == 4 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT)) { 181 TRACE("AssignDefaultSources: 4 channel setup\n"); 182 // left channel: 183 fOutputChannelInfo[0].source_count = 5; 184 fOutputChannelInfo[0].source_gain[0] = 1.0; 185 fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT); 186 fOutputChannelInfo[0].source_gain[1] = 0.7; 187 fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_CENTER); 188 fOutputChannelInfo[0].source_gain[2] = 0.6; 189 fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_SUB); 190 fOutputChannelInfo[0].source_gain[3] = 1.0; 191 fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_MONO); 192 fOutputChannelInfo[0].source_gain[4] = 0.6; 193 fOutputChannelInfo[0].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT); 194 // right channel: 195 fOutputChannelInfo[1].source_count = 5; 196 fOutputChannelInfo[1].source_gain[0] = 1.0; 197 fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT); 198 fOutputChannelInfo[1].source_gain[1] = 0.7; 199 fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_CENTER); 200 fOutputChannelInfo[1].source_gain[2] = 0.6; 201 fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_SUB); 202 fOutputChannelInfo[1].source_gain[3] = 1.0; 203 fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_MONO); 204 fOutputChannelInfo[1].source_gain[4] = 0.6; 205 fOutputChannelInfo[1].source_type[4] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT); 206 // rear-left channel: 207 fOutputChannelInfo[2].source_count = 4; 208 fOutputChannelInfo[2].source_gain[0] = 1.0; 209 fOutputChannelInfo[2].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT); 210 fOutputChannelInfo[2].source_gain[1] = 0.6; 211 fOutputChannelInfo[2].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB); 212 fOutputChannelInfo[2].source_gain[2] = 0.9; 213 fOutputChannelInfo[2].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO); 214 fOutputChannelInfo[2].source_gain[3] = 0.6; 215 fOutputChannelInfo[2].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT); 216 // rear-right channel: 217 fOutputChannelInfo[3].source_count = 4; 218 fOutputChannelInfo[3].source_gain[0] = 1.0; 219 fOutputChannelInfo[3].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT); 220 fOutputChannelInfo[3].source_gain[1] = 0.6; 221 fOutputChannelInfo[3].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB); 222 fOutputChannelInfo[3].source_gain[2] = 0.9; 223 fOutputChannelInfo[3].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO); 224 fOutputChannelInfo[3].source_gain[3] = 0.6; 225 fOutputChannelInfo[3].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT); 226 } else if (count == 5 && mask == (B_CHANNEL_LEFT | B_CHANNEL_RIGHT | B_CHANNEL_REARLEFT | B_CHANNEL_REARRIGHT | B_CHANNEL_CENTER)) { 227 TRACE("AssignDefaultSources: 5 channel setup\n"); 228 // left channel: 229 fOutputChannelInfo[0].source_count = 4; 230 fOutputChannelInfo[0].source_gain[0] = 1.0; 231 fOutputChannelInfo[0].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_LEFT); 232 fOutputChannelInfo[0].source_gain[1] = 0.6; 233 fOutputChannelInfo[0].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB); 234 fOutputChannelInfo[0].source_gain[2] = 1.0; 235 fOutputChannelInfo[0].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO); 236 fOutputChannelInfo[0].source_gain[3] = 0.6; 237 fOutputChannelInfo[0].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT); 238 // right channel: 239 fOutputChannelInfo[1].source_count = 4; 240 fOutputChannelInfo[1].source_gain[0] = 1.0; 241 fOutputChannelInfo[1].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_RIGHT); 242 fOutputChannelInfo[1].source_gain[1] = 0.6; 243 fOutputChannelInfo[1].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB); 244 fOutputChannelInfo[1].source_gain[2] = 1.0; 245 fOutputChannelInfo[1].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO); 246 fOutputChannelInfo[1].source_gain[3] = 0.6; 247 fOutputChannelInfo[1].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT); 248 // rear-left channel: 249 fOutputChannelInfo[2].source_count = 4; 250 fOutputChannelInfo[2].source_gain[0] = 1.0; 251 fOutputChannelInfo[2].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARLEFT); 252 fOutputChannelInfo[2].source_gain[1] = 0.6; 253 fOutputChannelInfo[2].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB); 254 fOutputChannelInfo[2].source_gain[2] = 0.9; 255 fOutputChannelInfo[2].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO); 256 fOutputChannelInfo[2].source_gain[3] = 0.6; 257 fOutputChannelInfo[2].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_LEFT); 258 // rear-right channel: 259 fOutputChannelInfo[3].source_count = 4; 260 fOutputChannelInfo[3].source_gain[0] = 1.0; 261 fOutputChannelInfo[3].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_REARRIGHT); 262 fOutputChannelInfo[3].source_gain[1] = 0.6; 263 fOutputChannelInfo[3].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB); 264 fOutputChannelInfo[3].source_gain[2] = 0.9; 265 fOutputChannelInfo[3].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO); 266 fOutputChannelInfo[3].source_gain[3] = 0.6; 267 fOutputChannelInfo[3].source_type[3] = ChannelMaskToChannelType(B_CHANNEL_SIDE_RIGHT); 268 // center channel: 269 fOutputChannelInfo[4].source_count = 3; 270 fOutputChannelInfo[4].source_gain[0] = 1.0; 271 fOutputChannelInfo[4].source_type[0] = ChannelMaskToChannelType(B_CHANNEL_CENTER); 272 fOutputChannelInfo[4].source_gain[1] = 0.5; 273 fOutputChannelInfo[4].source_type[1] = ChannelMaskToChannelType(B_CHANNEL_SUB); 274 fOutputChannelInfo[4].source_gain[2] = 0.8; 275 fOutputChannelInfo[4].source_type[2] = ChannelMaskToChannelType(B_CHANNEL_MONO); 276 } else { 277 TRACE("AssignDefaultSources: no default setup, adding mono channel to first two channels\n"); 278 if (count >= 1) { 279 // this is not a left channel, but we add the mono channel anyway 280 fOutputChannelInfo[0].source_gain[fOutputChannelInfo[0].source_count] = 1.0; 281 fOutputChannelInfo[0].source_type[fOutputChannelInfo[0].source_count] = ChannelMaskToChannelType(B_CHANNEL_MONO); 282 fOutputChannelInfo[0].source_count++; 283 } 284 if (count >= 2) { 285 // this is not a right channel, but we add the mono channel anyway 286 fOutputChannelInfo[1].source_gain[fOutputChannelInfo[1].source_count] = 1.0; 287 fOutputChannelInfo[1].source_type[fOutputChannelInfo[1].source_count] = ChannelMaskToChannelType(B_CHANNEL_MONO); 288 fOutputChannelInfo[1].source_count++; 289 } 290 } 291 292 for (int i = 0; i < fOutputChannelCount; i++) { 293 for (int j = 0; j < fOutputChannelInfo[i].source_count; j++) { 294 TRACE("AssignDefaultSources: output channel %d, source index %d: source_type %2d, source_gain %.3f\n", i, j, fOutputChannelInfo[i].source_type[j], fOutputChannelInfo[i].source_gain[j]); 295 } 296 } 297 } 298 299 int 300 MixerOutput::GetOutputChannelType(int channel) 301 { 302 if (channel < 0 || channel >= fOutputChannelCount) 303 return 0; 304 return fOutputChannelInfo[channel].channel_type; 305 } 306 307 void 308 MixerOutput::SetOutputChannelGain(int channel, float gain) 309 { 310 TRACE("SetOutputChannelGain chan %d, gain %.5f\n", channel, gain); 311 if (channel < 0 || channel >= fOutputChannelCount) 312 return; 313 fOutputChannelInfo[channel].channel_gain = gain; 314 } 315 316 void 317 MixerOutput::AddOutputChannelSource(int channel, int source_type) 318 { 319 if (channel < 0 || channel >= fOutputChannelCount) 320 return; 321 if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES) 322 return; 323 if (fOutputChannelInfo[channel].source_count == MAX_SOURCE_ENTRIES) 324 return; 325 for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) { 326 if (fOutputChannelInfo[channel].source_type[i] == source_type) 327 return; 328 } 329 // when adding a new source, use the current gain value from cache 330 float source_gain = fOutputChannelInfo[channel].source_gain_cache[source_type]; 331 fOutputChannelInfo[channel].source_type[fOutputChannelInfo[channel].source_count] = source_type; 332 fOutputChannelInfo[channel].source_gain[fOutputChannelInfo[channel].source_count] = source_gain; 333 fOutputChannelInfo[channel].source_count++; 334 } 335 336 void 337 MixerOutput::RemoveOutputChannelSource(int channel, int source_type) 338 { 339 if (channel < 0 || channel >= fOutputChannelCount) 340 return; 341 for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) { 342 if (fOutputChannelInfo[channel].source_type[i] == source_type) { 343 // when removing a source, save the current gain value into the cache 344 fOutputChannelInfo[channel].source_gain_cache[source_type] = fOutputChannelInfo[channel].source_gain[i]; 345 // remove the entry 346 fOutputChannelInfo[channel].source_type[i] = fOutputChannelInfo[channel].source_type[fOutputChannelInfo[channel].source_count - 1]; 347 fOutputChannelInfo[channel].source_gain[i] = fOutputChannelInfo[channel].source_gain[fOutputChannelInfo[channel].source_count - 1]; 348 fOutputChannelInfo[channel].source_count--; 349 return; 350 } 351 } 352 } 353 354 void 355 MixerOutput::SetOutputChannelSourceGain(int channel, int source_type, float source_gain) 356 { 357 if (channel < 0 || channel >= fOutputChannelCount) 358 return; 359 // set gain for active source 360 for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) { 361 if (fOutputChannelInfo[channel].source_type[i] == source_type) { 362 fOutputChannelInfo[channel].source_gain[i] = source_gain; 363 return; 364 } 365 } 366 // we don't have an active source of that type, save gain in cache 367 if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES) 368 return; 369 fOutputChannelInfo[channel].source_gain_cache[source_type] = source_gain; 370 } 371 372 float 373 MixerOutput::GetOutputChannelSourceGain(int channel, int source_type) 374 { 375 if (channel < 0 || channel >= fOutputChannelCount) 376 return 0.0; 377 // get gain for active source 378 for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) { 379 if (fOutputChannelInfo[channel].source_type[i] == source_type) { 380 return fOutputChannelInfo[channel].source_gain[i]; 381 } 382 } 383 // we don't have an active source of that type, get gain from cache 384 if (source_type < 0 || source_type >= MAX_CHANNEL_TYPES) 385 return 0.0; 386 return fOutputChannelInfo[channel].source_gain_cache[source_type]; 387 } 388 389 bool 390 MixerOutput::HasOutputChannelSource(int channel, int source_type) 391 { 392 if (channel < 0 || channel >= fOutputChannelCount) 393 return false; 394 for (int i = 0; i < fOutputChannelInfo[channel].source_count; i++) { 395 if (fOutputChannelInfo[channel].source_type[i] == source_type) { 396 return true; 397 } 398 } 399 return false; 400 } 401 402 void 403 MixerOutput::SetMuted(bool yesno) 404 { 405 fMuted = yesno; 406 } 407