1 /* 2 * Copyright 2002 David Shipman, 3 * Copyright 2003-2007 Marcus Overhagen 4 * Copyright 2007-2011 Haiku Inc. All rights reserved. 5 * 6 * Distributed under the terms of the MIT License. 7 */ 8 9 10 #include "AudioMixer.h" 11 12 #include <math.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include <Buffer.h> 18 #include <Catalog.h> 19 #include <FindDirectory.h> 20 #include <MediaDefs.h> 21 #include <MediaRoster.h> 22 #include <ParameterWeb.h> 23 #include <Path.h> 24 #include <RealtimeAlloc.h> 25 #include <TimeSource.h> 26 27 #include "MixerCore.h" 28 #include "MixerInput.h" 29 #include "MixerOutput.h" 30 #include "MixerUtils.h" 31 32 33 #undef B_TRANSLATION_CONTEXT 34 #define B_TRANSLATION_CONTEXT "AudioMixer" 35 36 37 // the range of the gain sliders (in dB) 38 #define DB_MAX 18.0 39 #define DB_MIN -60.0 40 // when using non linear sliders, we use a power function with 41 #define DB_EXPONENT_POSITIVE 1.4 // for dB values > 0 42 #define DB_EXPONENT_NEGATIVE 1.8 // for dB values < 0 43 44 #define USE_MEDIA_FORMAT_WORKAROUND 1 45 46 #define DB_TO_GAIN(db) dB_to_Gain((db)) 47 #define GAIN_TO_DB(gain) Gain_to_dB((gain)) 48 #define PERCENT_TO_GAIN(pct) ((pct) / 100.0) 49 #define GAIN_TO_PERCENT(gain) ((gain) * 100.0) 50 51 // the id is encoded with 16 bits 52 // then chan and src (or dst) are encoded with 6 bits 53 // the unique number with 4 bits 54 // the PARAM_ETC etc is encoded with 26 bits 55 #define PARAM_SRC_ENABLE(id, chan, src) (((id) << 16) | ((chan) << 10) | ((src) << 4) | 0x1) 56 #define PARAM_SRC_GAIN(id, chan, src) (((id) << 16) | ((chan) << 10) | ((src) << 4) | 0x2) 57 #define PARAM_DST_ENABLE(id, chan, dst) (((id) << 16) | ((chan) << 10) | ((dst) << 4) | 0x3) 58 #define PARAM_ETC(etc) (((etc) << 16) | 0x4) 59 #define PARAM_SRC_STR(id, chan) (((id) << 16) | ((chan) << 10) | 0x5) 60 #define PARAM_DST_STR(id, chan) (((id) << 16) | ((chan) << 10) | 0x6) 61 #define PARAM_MUTE(id) (((id) << 16) | 0x7) 62 #define PARAM_GAIN(id) (((id) << 16) | 0x8) 63 #define PARAM_BALANCE(id) (((id) << 16) | 0x9) 64 #define PARAM_STR1(id) (((id) << 16) | ((1) << 10) | 0xa) 65 #define PARAM_STR2(id) (((id) << 16) | ((2) << 10) | 0xa) 66 #define PARAM_STR3(id) (((id) << 16) | ((3) << 10) | 0xa) 67 #define PARAM_STR4(id) (((id) << 16) | ((4) << 10) | 0xa) 68 #define PARAM_STR5(id) (((id) << 16) | ((5) << 10) | 0xa) 69 #define PARAM_STR6(id) (((id) << 16) | ((6) << 10) | 0xa) 70 #define PARAM_STR7(id) (((id) << 16) | ((7) << 10) | 0xa) 71 72 #define PARAM(id) ((id) >> 16) 73 #define ETC(id) ((id) >> 16) 74 #define PARAM_CHAN(id) (((id) >> 10) & 0x3f) 75 #define PARAM_SRC(id) (((id) >> 4) & 0x3f) 76 #define PARAM_DST(id) (((id) >> 4) & 0x3f) 77 #define PARAM_IS_SRC_ENABLE(id) (((id) & 0xf) == 0x1) 78 #define PARAM_IS_SRC_GAIN(id) (((id) & 0xf) == 0x2) 79 #define PARAM_IS_DST_ENABLE(id) (((id) & 0xf) == 0x3) 80 #define PARAM_IS_ETC(id) (((id) & 0xf) == 0x4) 81 #define PARAM_IS_MUTE(id) (((id) & 0xf) == 0x7) 82 #define PARAM_IS_GAIN(id) (((id) & 0xf) == 0x8) 83 #define PARAM_IS_BALANCE(id) (((id) & 0xf) == 0x9) 84 85 #if USE_MEDIA_FORMAT_WORKAROUND 86 static void 87 multi_audio_format_specialize(media_multi_audio_format *format, 88 const media_multi_audio_format *other); 89 #endif 90 91 #define FORMAT_USER_DATA_TYPE 0x7294a8f3 92 #define FORMAT_USER_DATA_MAGIC_1 0xc84173bd 93 #define FORMAT_USER_DATA_MAGIC_2 0x4af62b7d 94 95 96 const static bigtime_t kMaxLatency = 150000; 97 // 150 ms is the maximum latency we publish 98 99 const bigtime_t kMinMixingTime = 3500; 100 const bigtime_t kMaxJitter = 1500; 101 102 103 AudioMixer::AudioMixer(BMediaAddOn *addOn, bool isSystemMixer) 104 : 105 BMediaNode("Audio Mixer"), 106 BBufferConsumer(B_MEDIA_RAW_AUDIO), 107 BBufferProducer(B_MEDIA_RAW_AUDIO), 108 BControllable(), 109 BMediaEventLooper(), 110 fAddOn(addOn), 111 fCore(new MixerCore(this)), 112 fWeb(NULL), 113 fBufferGroup(NULL), 114 fDownstreamLatency(1), 115 fInternalLatency(1), 116 fDisableStop(false), 117 fLastLateNotification(0), 118 fLastLateness(0) 119 { 120 BMediaNode::AddNodeKind(B_SYSTEM_MIXER); 121 122 // this is the default format used for all wildcard format SpecializeTo()s 123 fDefaultFormat.type = B_MEDIA_RAW_AUDIO; 124 fDefaultFormat.u.raw_audio.frame_rate = 96000; 125 fDefaultFormat.u.raw_audio.channel_count = 2; 126 fDefaultFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; 127 fDefaultFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; 128 fDefaultFormat.u.raw_audio.buffer_size = 4096; 129 fDefaultFormat.u.raw_audio.channel_mask = 0; 130 fDefaultFormat.u.raw_audio.valid_bits = 0; 131 fDefaultFormat.u.raw_audio.matrix_mask = 0; 132 133 if (isSystemMixer) { 134 // to get persistent settings, assign a settings file 135 BPath path; 136 if (B_OK != find_directory (B_USER_SETTINGS_DIRECTORY, &path)) 137 path.SetTo("/boot/home/config/settings/"); 138 path.Append("System Audio Mixer"); 139 fCore->Settings()->SetSettingsFile(path.Path()); 140 141 // disable stop on the auto started (system) mixer 142 DisableNodeStop(); 143 } 144 145 ApplySettings(); 146 } 147 148 149 AudioMixer::~AudioMixer() 150 { 151 BMediaEventLooper::Quit(); 152 SetParameterWeb(NULL); 153 154 // stop the mixer 155 fCore->Lock(); 156 fCore->Stop(); 157 fCore->Unlock(); 158 159 // disconnect all nodes from the mixer 160 // XXX todo 161 162 delete fCore; 163 delete fBufferGroup; 164 165 DEBUG_ONLY(fCore = 0; fBufferGroup = 0; fWeb = 0); 166 } 167 168 169 void 170 AudioMixer::ApplySettings() 171 { 172 fCore->Lock(); 173 fCore->SetOutputAttenuation(fCore->Settings()->AttenuateOutput() ? 0.708 : 1.0); 174 fCore->Unlock(); 175 } 176 177 178 void 179 AudioMixer::DisableNodeStop() 180 { 181 fDisableStop = true; 182 } 183 184 185 // #pragma mark - BMediaNode methods 186 187 188 void 189 AudioMixer::Stop(bigtime_t performance_time, bool immediate) 190 { 191 if (fDisableStop) { 192 TRACE("AudioMixer STOP is disabled\n"); 193 return; 194 } else { 195 BMediaEventLooper::Stop(performance_time, immediate); 196 } 197 } 198 199 200 BMediaAddOn* 201 AudioMixer::AddOn(int32 *internal_id) const 202 { 203 *internal_id = 0; 204 return fAddOn; 205 } 206 207 208 // #pragma mark - BBufferConsumer methods 209 210 211 status_t 212 AudioMixer::HandleMessage(int32 message, const void *data, size_t size) 213 { 214 // since we're using a mediaeventlooper, there shouldn't be any messages 215 // except the message we are using to schedule output events for the 216 // process thread. 217 218 if (message == MIXER_SCHEDULE_EVENT) { 219 RealTimeQueue()->AddEvent(*(const media_timed_event*)data); 220 return B_OK; 221 } 222 223 return B_ERROR; 224 } 225 226 227 status_t 228 AudioMixer::AcceptFormat(const media_destination &dest, media_format *ioFormat) 229 { 230 PRINT_FORMAT("AudioMixer::AcceptFormat: ", *ioFormat); 231 232 // check that the specified format is reasonable for the specified destination, and 233 // fill in any wildcard fields for which our BBufferConsumer has specific requirements. 234 235 // we have multiple inputs with different IDs, but 236 // the port number must match our ControlPort() 237 if (dest.port != ControlPort()) 238 return B_MEDIA_BAD_DESTINATION; 239 240 // specialize to raw audio format if necessary 241 if (ioFormat->type == B_MEDIA_UNKNOWN_TYPE) 242 ioFormat->type = B_MEDIA_RAW_AUDIO; 243 244 // we require a raw audio format 245 if (ioFormat->type != B_MEDIA_RAW_AUDIO) 246 return B_MEDIA_BAD_FORMAT; 247 248 // We do not have special requirements, but just in case 249 // another mixer is connecting to us and may need a hint 250 // to create a connection at optimal frame rate and 251 // channel count, we place this information in the user_data 252 fCore->Lock(); 253 MixerOutput *output = fCore->Output(); 254 uint32 channel_count = output ? output->MediaOutput().format.u.raw_audio.channel_count : 0; 255 float frame_rate = output ? output->MediaOutput().format.u.raw_audio.frame_rate : 0.0; 256 fCore->Unlock(); 257 ioFormat->user_data_type = FORMAT_USER_DATA_TYPE; 258 *(uint32 *)&ioFormat->user_data[0] = FORMAT_USER_DATA_MAGIC_1; 259 *(uint32 *)&ioFormat->user_data[4] = channel_count; 260 *(float *)&ioFormat->user_data[20] = frame_rate; 261 *(uint32 *)&ioFormat->user_data[44] = FORMAT_USER_DATA_MAGIC_2; 262 263 return B_OK; 264 } 265 266 267 status_t 268 AudioMixer::GetNextInput(int32 *cookie, media_input *out_input) 269 { 270 TRACE("AudioMixer::GetNextInput\n"); 271 272 // our 0th input is always a wildcard and free one 273 if (*cookie == 0) { 274 out_input->node = Node(); 275 out_input->source = media_source::null; 276 out_input->destination.port = ControlPort(); 277 out_input->destination.id = 0; 278 memset(&out_input->format, 0, sizeof(out_input->format)); 279 out_input->format.type = B_MEDIA_RAW_AUDIO; 280 strcpy(out_input->name, "Free Input"); 281 *cookie += 1; 282 return B_OK; 283 } 284 285 // the other inputs are the currently connected ones 286 fCore->Lock(); 287 MixerInput *input; 288 input = fCore->Input(*cookie - 1); 289 if (!input) { 290 fCore->Unlock(); 291 return B_BAD_INDEX; 292 } 293 *out_input = input->MediaInput(); 294 *cookie += 1; 295 fCore->Unlock(); 296 return B_OK; 297 } 298 299 300 void 301 AudioMixer::DisposeInputCookie(int32 cookie) 302 { 303 // nothing to do 304 } 305 306 307 void 308 AudioMixer::BufferReceived(BBuffer *buffer) 309 { 310 311 if (buffer->Header()->type == B_MEDIA_PARAMETERS) { 312 TRACE("Control Buffer Received\n"); 313 ApplyParameterData(buffer->Data(), buffer->SizeUsed()); 314 buffer->Recycle(); 315 return; 316 } 317 318 //PRINT(4, "buffer received at %12Ld, should arrive at %12Ld, delta %12Ld\n", TimeSource()->Now(), buffer->Header()->start_time, TimeSource()->Now() - buffer->Header()->start_time); 319 320 // to receive the buffer at the right time, 321 // push it through the event looper 322 media_timed_event event(buffer->Header()->start_time, 323 BTimedEventQueue::B_HANDLE_BUFFER, buffer, 324 BTimedEventQueue::B_RECYCLE_BUFFER); 325 EventQueue()->AddEvent(event); 326 } 327 328 329 void 330 AudioMixer::HandleInputBuffer(BBuffer* buffer, bigtime_t lateness) 331 { 332 bigtime_t variation = 0; 333 if (lateness > fLastLateness) 334 variation = lateness-fLastLateness; 335 336 if (variation > kMaxJitter) { 337 TRACE("AudioMixer: Dequeued input buffer %" B_PRIdBIGTIME 338 " usec late\n", lateness); 339 if (RunMode() == B_DROP_DATA || RunMode() == B_DECREASE_PRECISION 340 || RunMode() == B_INCREASE_LATENCY) { 341 TRACE("AudioMixer: sending notify\n"); 342 343 // Build a media_source out of the header data 344 media_source source = media_source::null; 345 source.port = buffer->Header()->source_port; 346 source.id = buffer->Header()->source; 347 348 NotifyLateProducer(source, variation, TimeSource()->Now()); 349 350 if (RunMode() == B_DROP_DATA) { 351 TRACE("AudioMixer: dropping buffer\n"); 352 return; 353 } 354 } 355 } 356 357 fLastLateness = lateness; 358 359 fCore->Lock(); 360 fCore->BufferReceived(buffer, lateness); 361 fCore->Unlock(); 362 } 363 364 365 void 366 AudioMixer::ProducerDataStatus(const media_destination& for_whom, 367 int32 status, bigtime_t at_performance_time) 368 { 369 /* 370 if (IsValidDest(for_whom)) 371 { 372 media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS, 373 (void *)(&for_whom), BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL); 374 EventQueue()->AddEvent(event); 375 376 // FIX_THIS 377 // the for_whom destination is not being sent correctly - verify in HandleEvent loop 378 379 } 380 */ 381 } 382 383 384 status_t 385 AudioMixer::GetLatencyFor(const media_destination &for_whom, 386 bigtime_t *out_latency, media_node_id *out_timesource) 387 { 388 // we have multiple inputs with different IDs, but 389 // the port number must match our ControlPort() 390 if (for_whom.port != ControlPort()) 391 return B_MEDIA_BAD_DESTINATION; 392 393 // return our event latency - this includes our internal + downstream 394 // latency, but _not_ the scheduling latency 395 *out_latency = EventLatency(); 396 *out_timesource = TimeSource()->ID(); 397 398 printf("AudioMixer::GetLatencyFor %" B_PRIdBIGTIME ", timesource is %" 399 B_PRId32 "\n", *out_latency, *out_timesource); 400 401 return B_OK; 402 } 403 404 405 status_t 406 AudioMixer::Connected(const media_source &producer, 407 const media_destination &where, const media_format &with_format, 408 media_input *out_input) 409 { 410 PRINT_FORMAT("AudioMixer::Connected: ", with_format); 411 412 // workaround for a crashing bug in RealPlayer. to be proper, RealPlayer's 413 // BBufferProducer::PrepareToConnect() should have removed all wildcards. 414 if (out_input->format.u.raw_audio.frame_rate == 0) { 415 fprintf(stderr, "Audio Mixer Warning: " 416 "Producer (port %" B_PRId32 ", id %" B_PRId32 ") connected with " 417 "frame_rate=0\n", producer.port, producer.id); 418 MixerOutput *output = fCore->Output(); 419 float frame_rate = output 420 ? output->MediaOutput().format.u.raw_audio.frame_rate : 44100.0f; 421 out_input->format.u.raw_audio.frame_rate = frame_rate; 422 } 423 424 // a BBufferProducer is connecting to our BBufferConsumer 425 426 // incoming connections should always have an incoming ID=0, 427 // and the port number must match our ControlPort() 428 if (where.id != 0 || where.port != ControlPort()) 429 return B_MEDIA_BAD_DESTINATION; 430 431 fCore->Lock(); 432 433 // we assign a new id (!= 0) to the newly created input 434 out_input->destination.id = fCore->CreateInputID(); 435 436 // We need to make sure that the outInput's name field contains a valid 437 // name, the name given the connection by the producer may still be an 438 // empty string. 439 // if the input has no name, assign one 440 if (strlen(out_input->name) == 0) { 441 sprintf(out_input->name, "Input %" B_PRId32, 442 out_input->destination.id); 443 } 444 445 // add a new input to the mixer engine 446 MixerInput *input; 447 input = fCore->AddInput(*out_input); 448 449 fCore->Settings()->LoadConnectionSettings(input); 450 451 fCore->Unlock(); 452 453 // If we want the producer to use a specific BBufferGroup, we now need 454 // to call BMediaRoster::SetOutputBuffersFor() here to set the producer's 455 // buffer group. 456 // But we have no special buffer requirements anyway... 457 458 UpdateParameterWeb(); 459 460 return B_OK; 461 } 462 463 464 void 465 AudioMixer::Disconnected(const media_source &producer, 466 const media_destination &where) 467 { 468 // One of our inputs has been disconnected 469 470 // check if it is really belongs to us 471 if (where.port != ControlPort()) { 472 TRACE("AudioMixer::Disconnected wrong input port\n"); 473 return; 474 } 475 476 fCore->Lock(); 477 478 if (!fCore->RemoveInput(where.id)) { 479 TRACE("AudioMixer::Disconnected can't remove input\n"); 480 } 481 482 fCore->Unlock(); 483 UpdateParameterWeb(); 484 } 485 486 487 status_t 488 AudioMixer::FormatChanged(const media_source &producer, 489 const media_destination &consumer, int32 change_tag, 490 const media_format &format) 491 { 492 // at some point in the future (indicated by change_tag and RequestCompleted()), 493 // we will receive buffers in a different format 494 495 TRACE("AudioMixer::FormatChanged\n"); 496 497 if (consumer.port != ControlPort() || consumer.id == 0) 498 return B_MEDIA_BAD_DESTINATION; 499 500 if (fCore->Settings()->RefuseInputFormatChange()) { 501 TRACE("AudioMixer::FormatChanged: input format change refused\n"); 502 return B_NOT_ALLOWED; 503 } 504 505 // TODO: We should not apply the format change at this point 506 // TODO: At the moment, this is not implemented at the moment and will just 507 // crash the media_server. 508 return B_NOT_SUPPORTED; 509 510 // tell core about format change 511 fCore->Lock(); 512 fCore->InputFormatChanged(consumer.id, format.u.raw_audio); 513 fCore->Unlock(); 514 515 return B_OK; 516 } 517 518 519 // #pragma mark - BBufferProducer methods 520 521 522 status_t 523 AudioMixer::FormatSuggestionRequested(media_type type, int32 quality, 524 media_format *format) 525 { 526 TRACE("AudioMixer::FormatSuggestionRequested\n"); 527 528 // BBufferProducer function, a downstream consumer 529 // is asking for our output format 530 531 if (type != B_MEDIA_RAW_AUDIO && type != B_MEDIA_UNKNOWN_TYPE) 532 return B_MEDIA_BAD_FORMAT; 533 534 // we can produce any (wildcard) raw audio format 535 memset(format, 0, sizeof(*format)); 536 format->type = B_MEDIA_RAW_AUDIO; 537 return B_OK; 538 } 539 540 541 status_t 542 AudioMixer::FormatProposal(const media_source &output, media_format *ioFormat) 543 { 544 // BBufferProducer function, we implement this function to verify that the 545 // proposed media_format is suitable for the specified output. If any fields 546 // in the format are wildcards, and we have a specific requirement, adjust 547 // those fields to match our requirements before returning. 548 549 TRACE("AudioMixer::FormatProposal\n"); 550 551 // we only have one output (id=0, port=ControlPort()) 552 if (output.id != 0 || output.port != ControlPort()) 553 return B_MEDIA_BAD_SOURCE; 554 555 // specialize to raw audio format if necessary 556 if (ioFormat->type == B_MEDIA_UNKNOWN_TYPE) 557 ioFormat->type = B_MEDIA_RAW_AUDIO; 558 559 // we require a raw audio format 560 if (ioFormat->type != B_MEDIA_RAW_AUDIO) 561 return B_MEDIA_BAD_FORMAT; 562 563 return B_OK; 564 } 565 566 /*! If the format isn't good, put a good format into *io_format and return error 567 If format has wildcard, specialize to what you can do (and change). 568 If you can change the format, return OK. 569 The request comes from your destination sychronously, so you cannot ask it 570 whether it likes it -- you should assume it will since it asked. 571 */ 572 status_t 573 AudioMixer::FormatChangeRequested(const media_source &source, 574 const media_destination &destination, media_format *io_format, 575 int32 *_deprecated_) 576 { 577 // the downstream consumer node (soundcard) requested that we produce 578 // another format, we need to check if the format is acceptable and 579 // remove any wildcards before returning OK. 580 581 TRACE("AudioMixer::FormatChangeRequested\n"); 582 583 if (fCore->Settings()->RefuseOutputFormatChange()) { 584 TRACE("AudioMixer::FormatChangeRequested: output format change refused\n"); 585 return B_ERROR; 586 } 587 588 fCore->Lock(); 589 590 status_t status = B_OK; 591 BBufferGroup *group = NULL; 592 MixerOutput *output = fCore->Output(); 593 if (!output) { 594 ERROR("AudioMixer::FormatChangeRequested: no output\n"); 595 goto err; 596 } 597 if (source != output->MediaOutput().source) { 598 ERROR("AudioMixer::FormatChangeRequested: wrong output source\n"); 599 goto err; 600 } 601 if (destination != output->MediaOutput().destination) { 602 ERROR("AudioMixer::FormatChangeRequested: wrong output destination " 603 "(port %ld, id %ld), our is (port %ld, id %ld)\n", destination.port, 604 destination.id, output->MediaOutput().destination.port, 605 output->MediaOutput().destination.id); 606 if (destination.port == output->MediaOutput().destination.port 607 && destination.id == output->MediaOutput().destination.id + 1) { 608 ERROR("AudioMixer::FormatChangeRequested: this might be the broken " 609 "R5 multi audio add-on\n"); 610 } 611 goto err; 612 } 613 if (io_format->type != B_MEDIA_RAW_AUDIO 614 && io_format->type != B_MEDIA_UNKNOWN_TYPE) { 615 ERROR("AudioMixer::FormatChangeRequested: wrong format type\n"); 616 goto err; 617 } 618 619 /* remove wildcards */ 620 #if USE_MEDIA_FORMAT_WORKAROUND 621 multi_audio_format_specialize(&io_format->u.raw_audio, 622 &fDefaultFormat.u.raw_audio); 623 #else 624 io_format->SpecializeTo(&fDefaultFormat); 625 #endif 626 627 media_node_id id; 628 FindLatencyFor(destination, &fDownstreamLatency, &id); 629 TRACE("AudioMixer: Downstream Latency is %" B_PRIdBIGTIME " usecs\n", 630 fDownstreamLatency); 631 632 // SetDuration of one buffer 633 SetBufferDuration(buffer_duration(io_format->u.raw_audio)); 634 TRACE("AudioMixer: buffer duration is %" B_PRIdBIGTIME " usecs\n", 635 BufferDuration()); 636 637 // Our internal latency is at least the length of a full output buffer 638 fInternalLatency = BufferDuration() 639 + max((bigtime_t)4500, bigtime_t(0.5 * BufferDuration())); 640 TRACE("AudioMixer: Internal latency is %" B_PRIdBIGTIME " usecs\n", 641 fInternalLatency); 642 643 SetEventLatency(fDownstreamLatency + fInternalLatency); 644 645 // we need to inform all connected *inputs* about *our* change in latency 646 PublishEventLatencyChange(); 647 648 // TODO: we might need to create more buffers, to span a larger downstream 649 // latency 650 651 // apply latency change 652 fCore->SetTimingInfo(TimeSource(), fDownstreamLatency); 653 654 // apply format change 655 fCore->OutputFormatChanged(io_format->u.raw_audio); 656 657 status = CreateBufferGroup(&group); 658 if (status != B_OK) 659 return status; 660 else { 661 delete fBufferGroup; 662 fBufferGroup = group; 663 fCore->SetOutputBufferGroup(fBufferGroup); 664 } 665 666 err: 667 fCore->Unlock(); 668 return status; 669 } 670 671 672 status_t 673 AudioMixer::GetNextOutput(int32 *cookie, media_output *out_output) 674 { 675 TRACE("AudioMixer::GetNextOutput\n"); 676 677 if (*cookie != 0) 678 return B_BAD_INDEX; 679 680 fCore->Lock(); 681 MixerOutput *output = fCore->Output(); 682 if (output) { 683 *out_output = output->MediaOutput(); 684 } else { 685 out_output->node = Node(); 686 out_output->source.port = ControlPort(); 687 out_output->source.id = 0; 688 out_output->destination = media_destination::null; 689 memset(&out_output->format, 0, sizeof(out_output->format)); 690 out_output->format.type = B_MEDIA_RAW_AUDIO; 691 strcpy(out_output->name, "Mixer Output"); 692 } 693 fCore->Unlock(); 694 695 *cookie += 1; 696 return B_OK; 697 } 698 699 700 status_t 701 AudioMixer::DisposeOutputCookie(int32 cookie) 702 { 703 // nothing to do 704 return B_OK; 705 } 706 707 708 status_t 709 AudioMixer::SetBufferGroup(const media_source &for_source, 710 BBufferGroup *newGroup) 711 { 712 TRACE("AudioMixer::SetBufferGroup\n"); 713 // the downstream consumer (soundcard) node asks us to use another 714 // BBufferGroup (might be NULL). We only have one output (id 0) 715 if (for_source.port != ControlPort() || for_source.id != 0) 716 return B_MEDIA_BAD_SOURCE; 717 718 if (newGroup == fBufferGroup) { 719 // we're already using this buffergroup 720 return B_OK; 721 } 722 723 fCore->Lock(); 724 if (!newGroup) { 725 status_t status = CreateBufferGroup(&newGroup); 726 if (status != B_OK) 727 return status; 728 } 729 fCore->SetOutputBufferGroup(newGroup); 730 delete fBufferGroup; 731 fBufferGroup = newGroup; 732 fCore->Unlock(); 733 734 return B_OK; 735 } 736 737 738 status_t 739 AudioMixer::GetLatency(bigtime_t *out_latency) 740 { 741 // report our *total* latency: internal plus downstream plus scheduling 742 *out_latency = EventLatency() + SchedulingLatency(); 743 744 TRACE("AudioMixer::GetLatency %Ld\n", *out_latency); 745 746 return B_OK; 747 } 748 749 750 void 751 AudioMixer::LatencyChanged(const media_source& source, 752 const media_destination& destination, bigtime_t new_latency, uint32 flags) 753 { 754 if (source.port != ControlPort() || source.id != 0) { 755 ERROR("AudioMixer::LatencyChanged: received but has wrong source " 756 "%ld/%ld\n", source.port, source.id); 757 return; 758 } 759 760 TRACE("AudioMixer::LatencyChanged: downstream latency from %ld/%ld to " 761 "%ld/%ld changed from %Ld to %Ld\n", source.port, source.id, 762 destination.port, destination.id, fDownstreamLatency, new_latency); 763 764 #if DEBUG 765 { 766 media_node_id id; 767 bigtime_t l; 768 FindLatencyFor(destination, &l, &id); 769 TRACE("AudioMixer: Reported downstream Latency is %Ld usecs\n", l); 770 } 771 #endif 772 773 fDownstreamLatency = new_latency; 774 SetEventLatency(fDownstreamLatency + fInternalLatency); 775 776 // XXX we might need to create more buffers, to span a larger downstream 777 // latency 778 779 fCore->Lock(); 780 fCore->SetTimingInfo(TimeSource(), fDownstreamLatency); 781 PublishEventLatencyChange(); 782 fCore->Unlock(); 783 } 784 785 status_t 786 AudioMixer::PrepareToConnect(const media_source &what, 787 const media_destination &where, media_format *format, 788 media_source *out_source, char *out_name) 789 { 790 TRACE("AudioMixer::PrepareToConnect\n"); 791 // PrepareToConnect() is the second stage of format negotiations that 792 // happens inside BMediaRoster::Connect(). At this point, the consumer's 793 // AcceptFormat() method has been called, and that node has potentially 794 // changed the proposed format. 795 // It may also have left wildcards in the format. PrepareToConnect() 796 // *must* fully specialize the format before returning! 797 // we also create the new output connection and return it in out_source. 798 799 PRINT_FORMAT("AudioMixer::PrepareToConnect: suggested format", *format); 800 801 // avoid loop connections 802 if (where.port == ControlPort()) 803 return B_MEDIA_BAD_SOURCE; 804 805 // is the source valid? 806 if (what.port != ControlPort() || what.id != 0) 807 return B_MEDIA_BAD_SOURCE; 808 809 // is the format acceptable? 810 if (format->type != B_MEDIA_RAW_AUDIO 811 && format->type != B_MEDIA_UNKNOWN_TYPE) { 812 PRINT_FORMAT("AudioMixer::PrepareToConnect: bad format", *format); 813 return B_MEDIA_BAD_FORMAT; 814 } 815 816 fCore->Lock(); 817 818 // are we already connected? 819 if (fCore->Output() != 0) { 820 fCore->Unlock(); 821 ERROR("AudioMixer::PrepareToConnect: already connected\n"); 822 return B_MEDIA_ALREADY_CONNECTED; 823 } 824 825 // It is possible that another mixer is connecting. 826 // To avoid using the default format, we use one of 827 // a) the format that it indicated as hint in the user_data, 828 // b) the output format of the system audio mixer 829 // c) the input format of the system DAC device 830 // d) if everything failes, keep the wildcard 831 if (format->u.raw_audio.channel_count == 0 832 && format->u.raw_audio.frame_rate < 1 833 && format->user_data_type == FORMAT_USER_DATA_TYPE 834 && *(uint32 *)&format->user_data[0] == FORMAT_USER_DATA_MAGIC_1 835 && *(uint32 *)&format->user_data[44] == FORMAT_USER_DATA_MAGIC_2) { 836 // ok, a mixer is connecting 837 uint32 channel_count = *(uint32 *)&format->user_data[4]; 838 float frame_rate = *(float *)&format->user_data[20]; 839 if (channel_count > 0 && frame_rate > 0) { 840 // format is good, use it 841 format->u.raw_audio.channel_count = channel_count; 842 format->u.raw_audio.frame_rate = frame_rate; 843 } else { 844 // other mixer's output is probably not connected 845 media_node node; 846 BMediaRoster *roster = BMediaRoster::Roster(); 847 media_output out; 848 media_input in; 849 int32 count; 850 if (roster->GetAudioMixer(&node) == B_OK 851 && roster->GetConnectedOutputsFor(node, &out, 1, &count) 852 == B_OK 853 && count == 1) { 854 // use mixer output format 855 format->u.raw_audio.channel_count 856 = out.format.u.raw_audio.channel_count; 857 format->u.raw_audio.frame_rate 858 = out.format.u.raw_audio.frame_rate; 859 } else if (roster->GetAudioOutput(&node) == B_OK 860 && roster->GetAllInputsFor(node, &in, 1, &count) == B_OK 861 && count == 1) { 862 // use DAC input format 863 format->u.raw_audio.channel_count 864 = in.format.u.raw_audio.channel_count; 865 format->u.raw_audio.frame_rate 866 = in.format.u.raw_audio.frame_rate; 867 } 868 } 869 } 870 871 /* set source and suggest a name */ 872 *out_source = what; 873 strcpy(out_name, "Mixer Output"); 874 875 /* remove wildcards */ 876 #if USE_MEDIA_FORMAT_WORKAROUND 877 multi_audio_format_specialize(&format->u.raw_audio, 878 &fDefaultFormat.u.raw_audio); 879 #else 880 format->SpecializeTo(&fDefaultFormat); 881 #endif 882 883 PRINT_FORMAT("AudioMixer::PrepareToConnect: final format", *format); 884 885 /* add output to core */ 886 media_output output; 887 output.node = Node(); 888 output.source = *out_source; 889 output.destination = where; 890 output.format = *format; 891 strcpy(output.name, out_name); 892 893 fCore->EnableOutput(false); 894 fCore->AddOutput(output); 895 896 fCore->Unlock(); 897 return B_OK; 898 } 899 900 901 void 902 AudioMixer::Connect(status_t error, const media_source &source, 903 const media_destination &dest, const media_format &format, char *io_name) 904 { 905 TRACE("AudioMixer::Connect\n"); 906 907 fCore->Lock(); 908 // are we still connected? 909 if (fCore->Output() == 0) { 910 fCore->Unlock(); 911 ERROR("AudioMixer::Connect: no longer connected\n"); 912 return; 913 } 914 fCore->Unlock(); 915 916 if (error != B_OK) { 917 // if an error occured, remove output from core 918 ERROR("AudioMixer::Connect failed with error 0x%08lX, removing " 919 "connection\n", error); 920 fCore->Lock(); 921 fCore->RemoveOutput(); 922 fCore->Unlock(); 923 return; 924 } 925 926 // Switch our prefered format to have the same 927 // frame_rate and channel count as the output. 928 fDefaultFormat.u.raw_audio.frame_rate = format.u.raw_audio.frame_rate; 929 fDefaultFormat.u.raw_audio.channel_count = format.u.raw_audio.channel_count; 930 931 // if the connection has no name, we set it now 932 if (strlen(io_name) == 0) 933 strcpy(io_name, "Mixer Output"); 934 935 // Now that we're connected, we can determine our downstream latency. 936 media_node_id id; 937 FindLatencyFor(dest, &fDownstreamLatency, &id); 938 TRACE("AudioMixer: Downstream Latency is %Ld usecs\n", fDownstreamLatency); 939 940 // SetDuration of one buffer 941 SetBufferDuration(buffer_duration(format.u.raw_audio)); 942 TRACE("AudioMixer: buffer duration is %Ld usecs\n", BufferDuration()); 943 944 // Our internal latency is at least the length of a full output buffer 945 // plus mixing time, plus jitter 946 fInternalLatency = BufferDuration() 947 + max(kMinMixingTime, bigtime_t(0.5 * BufferDuration())) + kMaxJitter; 948 TRACE("AudioMixer: Internal latency is %Ld usecs\n", fInternalLatency); 949 950 SetEventLatency(fDownstreamLatency + fInternalLatency); 951 952 // we need to inform all connected *inputs* about *our* change in latency 953 PublishEventLatencyChange(); 954 955 fCore->Lock(); 956 957 // Set up the buffer group for our connection, as long as nobody handed 958 // us a buffer group (via SetBufferGroup()) prior to this. That can 959 // happen, for example, if the consumer calls SetOutputBuffersFor() on 960 // us from within its Connected() method. 961 if (!fBufferGroup) { 962 BBufferGroup *group = NULL; 963 if (CreateBufferGroup(&group) != B_OK) 964 return; 965 fBufferGroup = group; 966 } 967 968 ASSERT(fCore->Output() != 0); 969 970 // our source should still be valid, too 971 ASSERT(fCore->Output()->MediaOutput().source.id == 0); 972 ASSERT(fCore->Output()->MediaOutput().source.port == ControlPort()); 973 974 // BBufferConsumer::Connected() may return a different input for the 975 // newly created connection. The destination can have changed since 976 // AudioMixer::PrepareToConnect() and we need to update it. 977 fCore->Output()->MediaOutput().destination = dest; 978 979 fCore->EnableOutput(true); 980 fCore->SetTimingInfo(TimeSource(), fDownstreamLatency); 981 fCore->SetOutputBufferGroup(fBufferGroup); 982 983 fCore->Settings()->LoadConnectionSettings(fCore->Output()); 984 985 fCore->Unlock(); 986 UpdateParameterWeb(); 987 } 988 989 990 void 991 AudioMixer::Disconnect(const media_source& what, const media_destination& where) 992 { 993 TRACE("AudioMixer::Disconnect\n"); 994 fCore->Lock(); 995 996 // Make sure that our connection is the one being disconnected 997 MixerOutput* output = fCore->Output(); 998 if (!output 999 || output->MediaOutput().node != Node() 1000 || output->MediaOutput().source != what 1001 || output->MediaOutput().destination != where) { 1002 ERROR("AudioMixer::Disconnect can't disconnect (wrong connection)\n"); 1003 fCore->Unlock(); 1004 return; 1005 } 1006 1007 // Switch our prefered format back to default 1008 // frame rate and channel count. 1009 fDefaultFormat.u.raw_audio.frame_rate = 96000; 1010 fDefaultFormat.u.raw_audio.channel_count = 2; 1011 1012 // force a stop 1013 fCore->Stop(); 1014 1015 fCore->RemoveOutput(); 1016 1017 // destroy buffer group 1018 delete fBufferGroup; 1019 fBufferGroup = NULL; 1020 fCore->SetOutputBufferGroup(0); 1021 1022 fCore->Unlock(); 1023 UpdateParameterWeb(); 1024 } 1025 1026 1027 void 1028 AudioMixer::LateNoticeReceived(const media_source& what, bigtime_t howMuch, 1029 bigtime_t performanceTime) 1030 { 1031 // We've produced some late buffers... Increase Latency 1032 // is the only runmode in which we can do anything about this 1033 // TODO: quality could be decreased, too 1034 1035 ERROR("AudioMixer::LateNoticeReceived, %Ld too late at %Ld\n", howMuch, 1036 performanceTime); 1037 1038 if (what == fCore->Output()->MediaOutput().source 1039 && RunMode() == B_INCREASE_LATENCY) { 1040 // We need to ignore subsequent notices whose arrival time here 1041 // lies within the last lateness, because queued-up buffers will all be 'late' 1042 if (performanceTime < fLastLateNotification) 1043 return; 1044 1045 fInternalLatency += howMuch; 1046 1047 // At some point a too large latency can get annoying 1048 // (actually more than annoying, as there won't be enough buffers long before this!) 1049 if (fInternalLatency > kMaxLatency) 1050 fInternalLatency = kMaxLatency; 1051 1052 fLastLateNotification = TimeSource()->Now() + howMuch; 1053 1054 TRACE("AudioMixer: increasing internal latency to %" 1055 B_PRIdBIGTIME " usec\n", fInternalLatency); 1056 SetEventLatency(fDownstreamLatency + fInternalLatency); 1057 1058 PublishEventLatencyChange(); 1059 } 1060 } 1061 1062 1063 void 1064 AudioMixer::EnableOutput(const media_source& what, bool enabled, 1065 int32 */*deprecated*/) 1066 { 1067 // we only have one output 1068 if (what.id != 0 || what.port != ControlPort()) 1069 return; 1070 1071 fCore->Lock(); 1072 fCore->EnableOutput(enabled); 1073 fCore->Unlock(); 1074 } 1075 1076 1077 // #pragma mark - BMediaEventLooper methods 1078 1079 1080 void 1081 AudioMixer::NodeRegistered() 1082 { 1083 UpdateParameterWeb(); 1084 SetPriority(B_REAL_TIME_PRIORITY); 1085 Run(); 1086 } 1087 1088 1089 void 1090 AudioMixer::SetTimeSource(BTimeSource* timeSource) 1091 { 1092 TRACE("AudioMixer::SetTimeSource: timesource is now %ld\n", 1093 timeSource->ID()); 1094 fCore->Lock(); 1095 fCore->SetTimingInfo(timeSource, fDownstreamLatency); 1096 fCore->Unlock(); 1097 } 1098 1099 1100 void 1101 AudioMixer::HandleEvent(const media_timed_event *event, bigtime_t lateness, 1102 bool realTimeEvent) 1103 { 1104 switch (event->type) { 1105 case BTimedEventQueue::B_HANDLE_BUFFER: 1106 { 1107 HandleInputBuffer((BBuffer *)event->pointer, lateness); 1108 ((BBuffer *)event->pointer)->Recycle(); 1109 break; 1110 } 1111 1112 case BTimedEventQueue::B_START: 1113 { 1114 TRACE("AudioMixer::HandleEvent: B_START\n"); 1115 if (RunState() != B_STARTED) { 1116 fCore->Lock(); 1117 fCore->Start(); 1118 fCore->Unlock(); 1119 } 1120 break; 1121 } 1122 1123 case BTimedEventQueue::B_STOP: 1124 { 1125 TRACE("AudioMixer::HandleEvent: B_STOP\n"); 1126 // stopped - don't process any more buffers, flush all buffers 1127 // from event queue 1128 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, 1129 BTimedEventQueue::B_HANDLE_BUFFER); 1130 fCore->Lock(); 1131 fCore->Stop(); 1132 fCore->Unlock(); 1133 break; 1134 } 1135 1136 case BTimedEventQueue::B_DATA_STATUS: 1137 { 1138 ERROR("DataStatus message\n"); 1139 break; 1140 } 1141 1142 case MIXER_PROCESS_EVENT: 1143 fCore->Process(); 1144 break; 1145 1146 default: 1147 break; 1148 } 1149 } 1150 1151 1152 // #pragma mark - AudioMixer methods 1153 1154 1155 void 1156 AudioMixer::PublishEventLatencyChange() 1157 { 1158 // our event (processing + downstream) latency has changed, 1159 // and we need tell all inputs about this 1160 1161 TRACE("AudioMixer::PublishEventLatencyChange\n"); 1162 1163 fCore->Lock(); 1164 1165 MixerInput *input; 1166 for (int i = 0; (input = fCore->Input(i)) != 0; i++) { 1167 TRACE("AudioMixer::PublishEventLatencyChange: SendLatencyChange, " 1168 "connection %ld/%ld to %ld/%ld event latency is now %Ld\n", 1169 input->MediaInput().source.port, input->MediaInput().source.id, 1170 input->MediaInput().destination.port, 1171 input->MediaInput().destination.id, EventLatency()); 1172 SendLatencyChange(input->MediaInput().source, 1173 input->MediaInput().destination, EventLatency()); 1174 } 1175 1176 fCore->Unlock(); 1177 } 1178 1179 1180 status_t 1181 AudioMixer::CreateBufferGroup(BBufferGroup** buffer) const 1182 { 1183 // allocate enough buffers to span our downstream latency 1184 // (plus one for rounding up), plus one extra 1185 int32 count = int32(fDownstreamLatency / BufferDuration()) + 2; 1186 1187 TRACE("AudioMixer::CreateBufferGroup: fDownstreamLatency %Ld, " 1188 "BufferDuration %Ld, buffer count = %ld\n", fDownstreamLatency, 1189 BufferDuration(), count); 1190 1191 if (count < 3) 1192 count = 3; 1193 1194 fCore->Lock(); 1195 uint32 size = fCore->Output()->MediaOutput().format.u.raw_audio.buffer_size; 1196 fCore->Unlock(); 1197 1198 TRACE("AudioMixer: allocating %ld buffers of %ld bytes each\n", 1199 count, size); 1200 1201 BBufferGroup* buf = new BBufferGroup(size, count); 1202 if (buf == NULL) 1203 return B_NO_MEMORY; 1204 1205 status_t status = buf->InitCheck(); 1206 if (status != B_OK) 1207 delete buf; 1208 else 1209 *buffer = buf; 1210 1211 return status; 1212 } 1213 1214 1215 status_t 1216 AudioMixer::SendBuffer(BBuffer* buffer, MixerOutput* output) 1217 { 1218 return BBufferProducer::SendBuffer(buffer, output->MediaOutput().source, 1219 output->MediaOutput().destination); 1220 } 1221 1222 1223 float 1224 AudioMixer::dB_to_Gain(float db) 1225 { 1226 TRACE("dB_to_Gain: dB in: %01.2f ", db); 1227 if (fCore->Settings()->NonLinearGainSlider()) { 1228 if (db > 0) { 1229 db = db * (pow(abs(DB_MAX), (1.0 / DB_EXPONENT_POSITIVE)) 1230 / abs(DB_MAX)); 1231 db = pow(db, DB_EXPONENT_POSITIVE); 1232 } else { 1233 db = -db; 1234 db = db * (pow(abs(DB_MIN), (1.0 / DB_EXPONENT_NEGATIVE)) 1235 / abs(DB_MIN)); 1236 db = pow(db, DB_EXPONENT_NEGATIVE); 1237 db = -db; 1238 } 1239 } 1240 TRACE("dB out: %01.2f\n", db); 1241 return pow(10.0, db / 20.0); 1242 } 1243 1244 1245 float 1246 AudioMixer::Gain_to_dB(float gain) 1247 { 1248 float db; 1249 db = 20.0 * log10(gain); 1250 if (fCore->Settings()->NonLinearGainSlider()) { 1251 if (db > 0) { 1252 db = pow(db, (1.0 / DB_EXPONENT_POSITIVE)); 1253 db = db * (abs(DB_MAX) / pow(abs(DB_MAX), 1254 (1.0 / DB_EXPONENT_POSITIVE))); 1255 } else { 1256 db = -db; 1257 db = pow(db, (1.0 / DB_EXPONENT_NEGATIVE)); 1258 db = db * (abs(DB_MIN) / pow(abs(DB_MIN), 1259 (1.0 / DB_EXPONENT_NEGATIVE))); 1260 db = -db; 1261 } 1262 } 1263 return db; 1264 } 1265 1266 1267 // #pragma mark - BControllable methods 1268 1269 1270 status_t 1271 AudioMixer::GetParameterValue(int32 id, bigtime_t *last_change, void *value, 1272 size_t *ioSize) 1273 { 1274 TRACE("GetParameterValue: id 0x%08lx, ioSize %ld\n", id, *ioSize); 1275 int param = PARAM(id); 1276 fCore->Lock(); 1277 if (PARAM_IS_ETC(id)) { 1278 switch (ETC(id)) { 1279 case 10: // Attenuate mixer output by 3dB 1280 *ioSize = sizeof(int32); 1281 static_cast<int32 *>(value)[0] = fCore->Settings()->AttenuateOutput(); 1282 break; 1283 case 20: // Use non linear gain sliders 1284 *ioSize = sizeof(int32); 1285 static_cast<int32 *>(value)[0] = fCore->Settings()->NonLinearGainSlider(); 1286 break; 1287 case 30: // Display balance control for stereo connections 1288 *ioSize = sizeof(int32); 1289 static_cast<int32 *>(value)[0] = fCore->Settings()->UseBalanceControl(); 1290 break; 1291 case 40: // Allow output channel remapping 1292 *ioSize = sizeof(int32); 1293 static_cast<int32 *>(value)[0] = fCore->Settings()->AllowOutputChannelRemapping(); 1294 break; 1295 case 50: // Allow input channel remapping 1296 *ioSize = sizeof(int32); 1297 static_cast<int32 *>(value)[0] = fCore->Settings()->AllowInputChannelRemapping(); 1298 break; 1299 case 60: // Input gain controls 1300 *ioSize = sizeof(int32); 1301 static_cast<int32 *>(value)[0] = fCore->Settings()->InputGainControls(); 1302 break; 1303 case 70: // Resampling algorithm 1304 *ioSize = sizeof(int32); 1305 static_cast<int32 *>(value)[0] = fCore->Settings()->ResamplingAlgorithm(); 1306 break; 1307 case 80: // Refuse output format changes 1308 *ioSize = sizeof(int32); 1309 static_cast<int32 *>(value)[0] = fCore->Settings()->RefuseOutputFormatChange(); 1310 break; 1311 case 90: // Refuse input format changes 1312 *ioSize = sizeof(int32); 1313 static_cast<int32 *>(value)[0] = fCore->Settings()->RefuseInputFormatChange(); 1314 break; 1315 default: 1316 ERROR("unhandled ETC 0x%08lx\n", id); 1317 break; 1318 } 1319 } else if (param == 0) { 1320 MixerOutput *output = fCore->Output(); 1321 if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id) && !PARAM_IS_BALANCE(id))) 1322 goto err; 1323 if (PARAM_IS_MUTE(id)) { 1324 // output mute control 1325 if (*ioSize < sizeof(int32)) 1326 goto err; 1327 *ioSize = sizeof(int32); 1328 static_cast<int32 *>(value)[0] = output->IsMuted(); 1329 } 1330 if (PARAM_IS_GAIN(id)) { 1331 // output gain control 1332 if (fCore->Settings()->UseBalanceControl() && output->GetOutputChannelCount() == 2 && 1 /*channel mask is stereo */) { 1333 // single channel control + balance 1334 if (*ioSize < sizeof(float)) 1335 goto err; 1336 *ioSize = sizeof(float); 1337 static_cast<float *>(value)[0] = GAIN_TO_DB((output->GetOutputChannelGain(0) + output->GetOutputChannelGain(1)) / 2); 1338 } else { 1339 // multi channel control 1340 if (*ioSize == sizeof(float)) { 1341 // get combined gain for all controls 1342 float gain = 0; 1343 for (int channel = 0; 1344 channel < output->GetOutputChannelCount(); 1345 channel++) { 1346 gain += GAIN_TO_DB( 1347 output->GetOutputChannelGain(channel)); 1348 } 1349 static_cast<float *>(value)[0] = gain 1350 / output->GetOutputChannelCount(); 1351 } else { 1352 if (*ioSize < output->GetOutputChannelCount() 1353 * sizeof(float)) 1354 goto err; 1355 1356 *ioSize = output->GetOutputChannelCount() * sizeof(float); 1357 1358 for (int channel = 0; 1359 channel < output->GetOutputChannelCount(); 1360 channel++) { 1361 static_cast<float *>(value)[channel] 1362 = GAIN_TO_DB(output->GetOutputChannelGain(channel)); 1363 } 1364 } 1365 } 1366 } 1367 if (PARAM_IS_BALANCE(id)) { 1368 float l = output->GetOutputChannelGain(0); 1369 float r = output->GetOutputChannelGain(1); 1370 float v = r / (l+r); 1371 TRACE("balance l %1.3f, r %1.3f, v %1.3f\n",l,r,v); 1372 if (*ioSize < sizeof(float)) 1373 goto err; 1374 *ioSize = sizeof(float); 1375 static_cast<float *>(value)[0] = v * 100; 1376 } 1377 if (PARAM_IS_SRC_ENABLE(id)) { 1378 if (*ioSize < sizeof(int32)) 1379 goto err; 1380 *ioSize = sizeof(int32); 1381 static_cast<int32 *>(value)[0] = output->HasOutputChannelSource(PARAM_CHAN(id), PARAM_SRC(id)); 1382 } 1383 if (PARAM_IS_SRC_GAIN(id)) { 1384 if (*ioSize < sizeof(float)) 1385 goto err; 1386 *ioSize = sizeof(float); 1387 static_cast<float *>(value)[0] = GAIN_TO_PERCENT(output->GetOutputChannelSourceGain(PARAM_CHAN(id), PARAM_SRC(id))); 1388 } 1389 } else { 1390 MixerInput *input; 1391 for (int i = 0; (input = fCore->Input(i)); i++) 1392 if (input->ID() == param) 1393 break; 1394 if (!input || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_DST_ENABLE(id) && !PARAM_IS_BALANCE(id))) 1395 goto err; 1396 if (PARAM_IS_MUTE(id)) { 1397 // input mute control 1398 if (*ioSize < sizeof(int32)) 1399 goto err; 1400 *ioSize = sizeof(int32); 1401 static_cast<int32 *>(value)[0] = !input->IsEnabled(); 1402 } 1403 if (PARAM_IS_GAIN(id)) { 1404 // input gain control 1405 if (fCore->Settings()->InputGainControls() == 0) { 1406 // Physical input channels 1407 if (fCore->Settings()->UseBalanceControl() && input->GetInputChannelCount() == 2 && 1 /*channel mask is stereo */) { 1408 // single channel control + balance 1409 if (*ioSize < sizeof(float)) 1410 goto err; 1411 *ioSize = sizeof(float); 1412 static_cast<float *>(value)[0] = GAIN_TO_DB((input->GetInputChannelGain(0) + input->GetInputChannelGain(1)) / 2); 1413 } else { 1414 // multi channel control 1415 if (*ioSize < input->GetInputChannelCount() * sizeof(float)) 1416 goto err; 1417 *ioSize = input->GetInputChannelCount() * sizeof(float); 1418 for (int chan = 0; chan < input->GetInputChannelCount(); chan++) 1419 static_cast<float *>(value)[chan] = GAIN_TO_DB(input->GetInputChannelGain(chan)); 1420 } 1421 } else { 1422 // Virtual output channels 1423 if (fCore->Settings()->UseBalanceControl() && input->GetMixerChannelCount() == 2 && 1 /*channel mask is stereo */) { 1424 // single channel control + balance 1425 if (*ioSize < sizeof(float)) 1426 goto err; 1427 *ioSize = sizeof(float); 1428 static_cast<float *>(value)[0] = GAIN_TO_DB((input->GetMixerChannelGain(0) + input->GetMixerChannelGain(1)) / 2); 1429 } else { 1430 // multi channel control 1431 if (*ioSize < input->GetMixerChannelCount() * sizeof(float)) 1432 goto err; 1433 *ioSize = input->GetMixerChannelCount() * sizeof(float); 1434 for (int chan = 0; chan < input->GetMixerChannelCount(); chan++) 1435 static_cast<float *>(value)[chan] = GAIN_TO_DB(input->GetMixerChannelGain(chan)); 1436 } 1437 } 1438 } 1439 if (PARAM_IS_BALANCE(id)) { 1440 if (fCore->Settings()->InputGainControls() == 0) { 1441 // Physical input channels 1442 float l = input->GetInputChannelGain(0); 1443 float r = input->GetInputChannelGain(1); 1444 float v = r / (l+r); 1445 TRACE("balance l %1.3f, r %1.3f, v %1.3f\n",l,r,v); 1446 if (*ioSize < sizeof(float)) 1447 goto err; 1448 *ioSize = sizeof(float); 1449 static_cast<float *>(value)[0] = v * 100; 1450 } else { 1451 // Virtual output channels 1452 float l = input->GetMixerChannelGain(0); 1453 float r = input->GetMixerChannelGain(1); 1454 float v = r / (l+r); 1455 TRACE("balance l %1.3f, r %1.3f, v %1.3f\n",l,r,v); 1456 if (*ioSize < sizeof(float)) 1457 goto err; 1458 *ioSize = sizeof(float); 1459 static_cast<float *>(value)[0] = v * 100; 1460 } 1461 } 1462 if (PARAM_IS_DST_ENABLE(id)) { 1463 if (*ioSize < sizeof(int32)) 1464 goto err; 1465 *ioSize = sizeof(int32); 1466 static_cast<int32 *>(value)[0] = input->HasInputChannelDestination(PARAM_CHAN(id), PARAM_DST(id)); 1467 } 1468 } 1469 *last_change = TimeSource()->Now(); // XXX we could do better 1470 fCore->Unlock(); 1471 return B_OK; 1472 err: 1473 fCore->Unlock(); 1474 return B_ERROR; 1475 } 1476 1477 1478 void 1479 AudioMixer::SetParameterValue(int32 id, bigtime_t when, const void *value, 1480 size_t size) 1481 { 1482 TRACE("SetParameterValue: id 0x%08lx, size %ld\n", id, size); 1483 bool update = false; 1484 int param = PARAM(id); 1485 fCore->Lock(); 1486 if (PARAM_IS_ETC(id)) { 1487 switch (ETC(id)) { 1488 case 10: // Attenuate mixer output by 3dB 1489 if (size != sizeof(int32)) 1490 goto err; 1491 fCore->Settings()->SetAttenuateOutput(static_cast<const int32 *>(value)[0]); 1492 // this value is special (see MixerCore.h) and we need to notify the core 1493 fCore->SetOutputAttenuation((static_cast<const int32 *>(value)[0]) ? 0.708 : 1.0); 1494 break; 1495 case 20: // Use non linear gain sliders 1496 if (size != sizeof(int32)) 1497 goto err; 1498 fCore->Settings()->SetNonLinearGainSlider(static_cast<const int32 *>(value)[0]); 1499 update = true; // XXX should use BroadcastChangedParameter() 1500 break; 1501 case 30: // Display balance control for stereo connections 1502 if (size != sizeof(int32)) 1503 goto err; 1504 fCore->Settings()->SetUseBalanceControl(static_cast<const int32 *>(value)[0]); 1505 update = true; 1506 break; 1507 case 40: // Allow output channel remapping 1508 if (size != sizeof(int32)) 1509 goto err; 1510 fCore->Settings()->SetAllowOutputChannelRemapping(static_cast<const int32 *>(value)[0]); 1511 update = true; 1512 break; 1513 case 50: // Allow input channel remapping 1514 if (size != sizeof(int32)) 1515 goto err; 1516 fCore->Settings()->SetAllowInputChannelRemapping(static_cast<const int32 *>(value)[0]); 1517 update = true; 1518 break; 1519 case 60: // Input gain controls represent 1520 // (0, "Physical input channels") 1521 // (1, "Virtual output channels") 1522 if (size != sizeof(int32)) 1523 goto err; 1524 fCore->Settings()->SetInputGainControls(static_cast<const int32 *>(value)[0]); 1525 update = true; // XXX should use BroadcastChangedParameter() 1526 break; 1527 case 70: // Resampling algorithm 1528 if (size != sizeof(int32)) 1529 goto err; 1530 fCore->Settings()->SetResamplingAlgorithm(static_cast<const int32 *>(value)[0]); 1531 fCore->UpdateResamplingAlgorithm(); 1532 break; 1533 case 80: // Refuse output format changes 1534 if (size != sizeof(int32)) 1535 goto err; 1536 fCore->Settings()->SetRefuseOutputFormatChange(static_cast<const int32 *>(value)[0]); 1537 break; 1538 case 90: // Refuse input format changes 1539 if (size != sizeof(int32)) 1540 goto err; 1541 fCore->Settings()->SetRefuseInputFormatChange(static_cast<const int32 *>(value)[0]); 1542 break; 1543 default: 1544 ERROR("unhandled ETC 0x%08lx\n", id); 1545 break; 1546 } 1547 } else if (param == 0) { 1548 MixerOutput *output = fCore->Output(); 1549 if (!output || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_SRC_ENABLE(id) && !PARAM_IS_SRC_GAIN(id) && !PARAM_IS_BALANCE(id))) 1550 goto err; 1551 if (PARAM_IS_MUTE(id)) { 1552 // output mute control 1553 if (size != sizeof(int32)) 1554 goto err; 1555 output->SetMuted(static_cast<const int32 *>(value)[0]); 1556 } 1557 if (PARAM_IS_GAIN(id)) { 1558 // output gain control 1559 if (fCore->Settings()->UseBalanceControl() 1560 && output->GetOutputChannelCount() == 2 && 1 /*channel mask is stereo */) { 1561 // single channel control + balance 1562 float l = output->GetOutputChannelGain(0); 1563 float r = output->GetOutputChannelGain(1); 1564 float m = (l + r) / 2; // master volume 1565 float v = DB_TO_GAIN(static_cast<const float *>(value)[0]); 1566 float f = v / m; // factor for both channels 1567 TRACE("gain set l %1.3f, r %1.3f, m %1.3f, v %1.3f, f %1.3f\n",l,r,m,v,f); 1568 output->SetOutputChannelGain(0, output->GetOutputChannelGain(0) * f); 1569 output->SetOutputChannelGain(1, output->GetOutputChannelGain(1) * f); 1570 } else { 1571 // multi channel control 1572 if (size == sizeof(float)) { 1573 // set same volume for all channels 1574 float gain = static_cast<const float *>(value)[0]; 1575 for (int channel = 0; 1576 channel < output->GetOutputChannelCount(); 1577 channel++) { 1578 output->SetOutputChannelGain(channel, 1579 DB_TO_GAIN(gain)); 1580 } 1581 } else { 1582 if (size < output->GetOutputChannelCount() * sizeof(float)) 1583 goto err; 1584 for (int channel = 0; 1585 channel < output->GetOutputChannelCount(); 1586 channel++) { 1587 output->SetOutputChannelGain(channel, 1588 DB_TO_GAIN(static_cast<const float *>( 1589 value)[channel])); 1590 } 1591 } 1592 } 1593 } 1594 if (PARAM_IS_BALANCE(id)) { 1595 float l = output->GetOutputChannelGain(0); 1596 float r = output->GetOutputChannelGain(1); 1597 float m = (l + r) / 2; // master volume 1598 float v = static_cast<const float *>(value)[0] / 100; // current balance value 1599 float fl = 2 * (1 - v); // left channel factor of master volume 1600 float fr = 2 * v; // right channel factor of master volume 1601 TRACE("balance set l %1.3f, r %1.3f, m %1.3f, v %1.3f, fl %1.3f, fr %1.3f\n",l,r,m,v,fl,fr); 1602 output->SetOutputChannelGain(0, m * fl); 1603 output->SetOutputChannelGain(1, m * fr); 1604 } 1605 if (PARAM_IS_SRC_ENABLE(id)) { 1606 if (size != sizeof(int32)) 1607 goto err; 1608 if (static_cast<const int32 *>(value)[0]) { 1609 output->AddOutputChannelSource(PARAM_CHAN(id), PARAM_SRC(id)); 1610 } else { 1611 output->RemoveOutputChannelSource(PARAM_CHAN(id), PARAM_SRC(id)); 1612 } 1613 } 1614 if (PARAM_IS_SRC_GAIN(id)) { 1615 if (size != sizeof(float)) 1616 goto err; 1617 output->SetOutputChannelSourceGain(PARAM_CHAN(id), PARAM_SRC(id), PERCENT_TO_GAIN(static_cast<const float *>(value)[0])); 1618 } 1619 fCore->Settings()->SaveConnectionSettings(output); 1620 } else { 1621 MixerInput *input; 1622 for (int i = 0; (input = fCore->Input(i)); i++) 1623 if (input->ID() == param) 1624 break; 1625 if (!input || (!PARAM_IS_MUTE(id) && !PARAM_IS_GAIN(id) && !PARAM_IS_DST_ENABLE(id) && !PARAM_IS_BALANCE(id))) 1626 goto err; 1627 if (PARAM_IS_MUTE(id)) { 1628 // input mute control 1629 if (size != sizeof(int32)) 1630 goto err; 1631 input->SetEnabled(!static_cast<const int32 *>(value)[0]); 1632 } 1633 if (PARAM_IS_GAIN(id)) { 1634 // input gain control 1635 if (fCore->Settings()->InputGainControls() == 0) { 1636 // Physical input channels 1637 if (fCore->Settings()->UseBalanceControl() && input->GetInputChannelCount() == 2 && 1 /*channel mask is stereo */) { 1638 // single channel control + balance 1639 float l = input->GetInputChannelGain(0); 1640 float r = input->GetInputChannelGain(1); 1641 float m = (l + r) / 2; // master volume 1642 float v = DB_TO_GAIN(static_cast<const float *>(value)[0]); 1643 float f = v / m; // factor for both channels 1644 TRACE("gain set l %1.3f, r %1.3f, m %1.3f, v %1.3f, f %1.3f\n",l,r,m,v,f); 1645 input->SetInputChannelGain(0, input->GetInputChannelGain(0) * f); 1646 input->SetInputChannelGain(1, input->GetInputChannelGain(1) * f); 1647 } else { 1648 // multi channel control 1649 if (size < input->GetInputChannelCount() * sizeof(float)) 1650 goto err; 1651 for (int chan = 0; chan < input->GetInputChannelCount(); chan++) 1652 input->SetInputChannelGain(chan, DB_TO_GAIN(static_cast<const float *>(value)[chan])); 1653 } 1654 } else { 1655 // Virtual output channels 1656 if (fCore->Settings()->UseBalanceControl() && input->GetMixerChannelCount() == 2 && 1 /*channel mask is stereo */) { 1657 // single channel control + balance 1658 float l = input->GetMixerChannelGain(0); 1659 float r = input->GetMixerChannelGain(1); 1660 float m = (l + r) / 2; // master volume 1661 float v = DB_TO_GAIN(static_cast<const float *>(value)[0]); 1662 float f = v / m; // factor for both channels 1663 TRACE("gain set l %1.3f, r %1.3f, m %1.3f, v %1.3f, f %1.3f\n",l,r,m,v,f); 1664 input->SetMixerChannelGain(0, input->GetMixerChannelGain(0) * f); 1665 input->SetMixerChannelGain(1, input->GetMixerChannelGain(1) * f); 1666 } else { 1667 // multi channel control 1668 if (size < input->GetMixerChannelCount() * sizeof(float)) 1669 goto err; 1670 for (int chan = 0; chan < input->GetMixerChannelCount(); chan++) 1671 input->SetMixerChannelGain(chan, DB_TO_GAIN(static_cast<const float *>(value)[chan])); 1672 } 1673 } 1674 } 1675 if (PARAM_IS_BALANCE(id)) { 1676 if (fCore->Settings()->InputGainControls() == 0) { 1677 // Physical input channels 1678 float l = input->GetInputChannelGain(0); 1679 float r = input->GetInputChannelGain(1); 1680 float m = (l + r) / 2; // master volume 1681 float v = static_cast<const float *>(value)[0] / 100; // current balance value 1682 float fl = 2 * (1 - v); // left channel factor of master volume 1683 float fr = 2 * v; // right channel factor of master volume 1684 TRACE("balance set l %1.3f, r %1.3f, m %1.3f, v %1.3f, fl %1.3f, fr %1.3f\n",l,r,m,v,fl,fr); 1685 input->SetInputChannelGain(0, m * fl); 1686 input->SetInputChannelGain(1, m * fr); 1687 } else { 1688 // Virtual output channels 1689 float l = input->GetMixerChannelGain(0); 1690 float r = input->GetMixerChannelGain(1); 1691 float m = (l + r) / 2; // master volume 1692 float v = static_cast<const float *>(value)[0] / 100; // current balance value 1693 float fl = 2 * (1 - v); // left channel factor of master volume 1694 float fr = 2 * v; // right channel factor of master volume 1695 TRACE("balance set l %1.3f, r %1.3f, m %1.3f, v %1.3f, fl %1.3f, fr %1.3f\n",l,r,m,v,fl,fr); 1696 input->SetMixerChannelGain(0, m * fl); 1697 input->SetMixerChannelGain(1, m * fr); 1698 } 1699 } 1700 if (PARAM_IS_DST_ENABLE(id)) { 1701 if (size != sizeof(int32)) 1702 goto err; 1703 if (static_cast<const int32 *>(value)[0]) { 1704 int oldchan = input->GetInputChannelForDestination(PARAM_DST(id)); 1705 if (oldchan != -1) { 1706 input->RemoveInputChannelDestination(oldchan, PARAM_DST(id)); 1707 int32 null = 0; 1708 BroadcastNewParameterValue(when, PARAM_DST_ENABLE(PARAM(id), oldchan, PARAM_DST(id)), &null, sizeof(null)); 1709 } 1710 input->AddInputChannelDestination(PARAM_CHAN(id), PARAM_DST(id)); 1711 } else { 1712 input->RemoveInputChannelDestination(PARAM_CHAN(id), PARAM_DST(id)); 1713 } 1714 // TODO: this is really annoying 1715 // The slider count of the gain control needs to be changed, 1716 // but calling SetChannelCount(input->GetMixerChannelCount()) 1717 // on it has no effect on remote BParameterWebs in other apps. 1718 // BroadcastChangedParameter() should be correct, but doesn't work 1719 BroadcastChangedParameter(PARAM_GAIN(PARAM(id))); 1720 // We trigger a complete ParameterWeb update as workaround 1721 // but it will change the focus from tab 3 to tab 1 1722 update = true; 1723 } 1724 fCore->Settings()->SaveConnectionSettings(input); 1725 } 1726 1727 BroadcastNewParameterValue(when, id, const_cast<void *>(value), size); 1728 1729 err: 1730 fCore->Unlock(); 1731 if (update) 1732 UpdateParameterWeb(); 1733 } 1734 1735 1736 void 1737 AudioMixer::UpdateParameterWeb() 1738 { 1739 fCore->Lock(); 1740 BParameterWeb *web = new BParameterWeb(); 1741 BParameterGroup *top; 1742 BParameterGroup *outputchannels; 1743 BParameterGroup *inputchannels; 1744 BParameterGroup *group; 1745 BParameterGroup *subgroup; 1746 BParameterGroup *subsubgroup; 1747 BDiscreteParameter *dp; 1748 MixerInput *in; 1749 MixerOutput *out; 1750 char buf[50]; 1751 1752 top = web->MakeGroup(B_TRANSLATE("Gain controls")); 1753 1754 out = fCore->Output(); 1755 group = top->MakeGroup(""); 1756 group->MakeNullParameter(PARAM_STR1(0), B_MEDIA_RAW_AUDIO, 1757 B_TRANSLATE("Master output"), B_WEB_BUFFER_INPUT); 1758 if (!out) { 1759 group->MakeNullParameter(PARAM_STR2(0), B_MEDIA_RAW_AUDIO, 1760 B_TRANSLATE("not connected"), B_GENERIC); 1761 } else { 1762 group->MakeNullParameter(PARAM_STR2(0), B_MEDIA_RAW_AUDIO, 1763 StringForFormat(buf, out), B_GENERIC); 1764 group->MakeDiscreteParameter(PARAM_MUTE(0), B_MEDIA_RAW_AUDIO, 1765 B_TRANSLATE("Mute"), B_MUTE); 1766 if (fCore->Settings()->UseBalanceControl() 1767 && out->GetOutputChannelCount() == 2 && 1 1768 /*channel mask is stereo */) { 1769 // single channel control + balance 1770 group->MakeContinuousParameter(PARAM_GAIN(0), B_MEDIA_RAW_AUDIO, 1771 B_TRANSLATE("Gain"), B_MASTER_GAIN, B_TRANSLATE("dB"), 1772 DB_MIN, DB_MAX, 0.1); 1773 group->MakeContinuousParameter(PARAM_BALANCE(0), B_MEDIA_RAW_AUDIO, 1774 "", B_BALANCE, "", 0, 100, 1); 1775 } else { 1776 // multi channel control 1777 group->MakeContinuousParameter(PARAM_GAIN(0), B_MEDIA_RAW_AUDIO, 1778 B_TRANSLATE("Gain"), B_MASTER_GAIN, B_TRANSLATE("dB"), 1779 DB_MIN, DB_MAX, 0.1) 1780 ->SetChannelCount(out->GetOutputChannelCount()); 1781 } 1782 group->MakeNullParameter(PARAM_STR3(0), B_MEDIA_RAW_AUDIO, 1783 B_TRANSLATE("To output"), B_WEB_BUFFER_OUTPUT); 1784 } 1785 1786 for (int i = 0; (in = fCore->Input(i)); i++) { 1787 group = top->MakeGroup(""); 1788 group->MakeNullParameter(PARAM_STR1(in->ID()), B_MEDIA_RAW_AUDIO, 1789 in->MediaInput().name, B_WEB_BUFFER_INPUT); 1790 group->MakeNullParameter(PARAM_STR2(in->ID()), B_MEDIA_RAW_AUDIO, 1791 StringForFormat(buf, in), B_GENERIC); 1792 group->MakeDiscreteParameter(PARAM_MUTE(in->ID()), B_MEDIA_RAW_AUDIO, 1793 B_TRANSLATE("Mute"), B_MUTE); 1794 // XXX the gain control is ugly once you have more than two channels, 1795 // as you don't know what channel each slider controls. Tooltips might help... 1796 if (fCore->Settings()->InputGainControls() == 0) { 1797 // Physical input channels 1798 if (fCore->Settings()->UseBalanceControl() 1799 && in->GetInputChannelCount() == 2 && 1 1800 /*channel mask is stereo */) { 1801 // single channel control + balance 1802 group->MakeContinuousParameter(PARAM_GAIN(in->ID()), 1803 B_MEDIA_RAW_AUDIO, B_TRANSLATE("Gain"), B_GAIN, 1804 B_TRANSLATE("dB"), DB_MIN, DB_MAX, 0.1); 1805 group->MakeContinuousParameter(PARAM_BALANCE(in->ID()), 1806 B_MEDIA_RAW_AUDIO, "", B_BALANCE, "", 0, 100, 1); 1807 } else { 1808 // multi channel control 1809 group->MakeContinuousParameter(PARAM_GAIN(in->ID()), 1810 B_MEDIA_RAW_AUDIO, B_TRANSLATE("Gain"), B_GAIN, 1811 B_TRANSLATE("dB"), DB_MIN, DB_MAX, 0.1) 1812 ->SetChannelCount(in->GetInputChannelCount()); 1813 } 1814 } else { 1815 // Virtual output channels 1816 if (fCore->Settings()->UseBalanceControl() 1817 && in->GetMixerChannelCount() == 2 && 1 1818 /*channel mask is stereo */) { 1819 // single channel control + balance 1820 group->MakeContinuousParameter(PARAM_GAIN(in->ID()), 1821 B_MEDIA_RAW_AUDIO, B_TRANSLATE("Gain"), B_GAIN, 1822 B_TRANSLATE("dB"), DB_MIN, DB_MAX, 0.1); 1823 group->MakeContinuousParameter(PARAM_BALANCE(in->ID()), 1824 B_MEDIA_RAW_AUDIO, "", B_BALANCE, "", 0, 100, 1); 1825 } else { 1826 // multi channel control 1827 group->MakeContinuousParameter(PARAM_GAIN(in->ID()), 1828 B_MEDIA_RAW_AUDIO, B_TRANSLATE("Gain"), B_GAIN, 1829 B_TRANSLATE("dB"), DB_MIN, DB_MAX, 0.1) 1830 ->SetChannelCount(in->GetMixerChannelCount()); 1831 } 1832 } 1833 group->MakeNullParameter(PARAM_STR3(in->ID()), B_MEDIA_RAW_AUDIO, 1834 B_TRANSLATE("To master"), B_WEB_BUFFER_OUTPUT); 1835 } 1836 1837 if (fCore->Settings()->AllowOutputChannelRemapping()) { 1838 top = web->MakeGroup(B_TRANSLATE("Output mapping")); // top level group 1839 outputchannels = top->MakeGroup(""); 1840 outputchannels->MakeNullParameter(PARAM_STR4(0), B_MEDIA_RAW_AUDIO, 1841 B_TRANSLATE("Output channel sources"), B_GENERIC); 1842 1843 group = outputchannels->MakeGroup(""); 1844 group->MakeNullParameter(PARAM_STR5(0), B_MEDIA_RAW_AUDIO, 1845 B_TRANSLATE("Master output"), B_GENERIC); 1846 group = group->MakeGroup(""); 1847 if (!out) { 1848 group->MakeNullParameter(PARAM_STR6(0), B_MEDIA_RAW_AUDIO, 1849 B_TRANSLATE("not connected"), B_GENERIC); 1850 } else { 1851 for (int chan = 0; chan < out->GetOutputChannelCount(); chan++) { 1852 subgroup = group->MakeGroup(""); 1853 subgroup->MakeNullParameter(PARAM_SRC_STR(0, chan), 1854 B_MEDIA_RAW_AUDIO, StringForChannelType(buf, 1855 out->GetOutputChannelType(chan)), B_GENERIC); 1856 for (int src = 0; src < MAX_CHANNEL_TYPES; src++) { 1857 subsubgroup = subgroup->MakeGroup(""); 1858 subsubgroup->MakeDiscreteParameter( 1859 PARAM_SRC_ENABLE(0, chan, src), B_MEDIA_RAW_AUDIO, "", 1860 B_ENABLE); 1861 subsubgroup->MakeContinuousParameter( 1862 PARAM_SRC_GAIN(0, chan, src), B_MEDIA_RAW_AUDIO, 1863 StringForChannelType(buf, src), B_GAIN, "%", 0.0, 1864 100.0, 0.1); 1865 } 1866 } 1867 } 1868 } 1869 1870 if (fCore->Settings()->AllowInputChannelRemapping()) { 1871 top = web->MakeGroup(B_TRANSLATE("Input mapping")); // top level group 1872 inputchannels = top->MakeGroup(""); 1873 inputchannels->MakeNullParameter(PARAM_STR7(0), B_MEDIA_RAW_AUDIO, 1874 B_TRANSLATE("Input channel destinations"), B_GENERIC); 1875 1876 for (int i = 0; (in = fCore->Input(i)); i++) { 1877 group = inputchannels->MakeGroup(""); 1878 group->MakeNullParameter(PARAM_STR4(in->ID()), B_MEDIA_RAW_AUDIO, 1879 in->MediaInput().name, B_GENERIC); 1880 group = group->MakeGroup(""); 1881 1882 for (int chan = 0; chan < in->GetInputChannelCount(); chan++) { 1883 subgroup = group->MakeGroup(""); 1884 subgroup->MakeNullParameter(PARAM_DST_STR(in->ID(), chan), 1885 B_MEDIA_RAW_AUDIO, StringForChannelType(buf, 1886 in->GetInputChannelType(chan)), B_GENERIC); 1887 for (int dst = 0; dst < MAX_CHANNEL_TYPES; dst++) { 1888 subgroup->MakeDiscreteParameter(PARAM_DST_ENABLE(in->ID(), 1889 chan, dst), B_MEDIA_RAW_AUDIO, StringForChannelType(buf, dst), 1890 B_ENABLE); 1891 } 1892 } 1893 } 1894 } 1895 1896 top = web->MakeGroup(B_TRANSLATE("Setup")); // top level group 1897 group = top->MakeGroup(""); 1898 1899 group->MakeDiscreteParameter(PARAM_ETC(10), B_MEDIA_RAW_AUDIO, 1900 B_TRANSLATE("Attenuate mixer output by 3dB (like BeOS R5)"), B_ENABLE); 1901 group->MakeDiscreteParameter(PARAM_ETC(20), B_MEDIA_RAW_AUDIO, 1902 B_TRANSLATE("Use non linear gain sliders (like BeOS R5)"), B_ENABLE); 1903 group->MakeDiscreteParameter(PARAM_ETC(30), B_MEDIA_RAW_AUDIO, 1904 B_TRANSLATE("Display balance control for stereo connections"), 1905 B_ENABLE); 1906 1907 group->MakeDiscreteParameter(PARAM_ETC(40), B_MEDIA_RAW_AUDIO, 1908 B_TRANSLATE("Allow output channel remapping"), B_ENABLE); 1909 group->MakeDiscreteParameter(PARAM_ETC(50), B_MEDIA_RAW_AUDIO, 1910 B_TRANSLATE("Allow input channel remapping"), B_ENABLE); 1911 1912 dp = group->MakeDiscreteParameter(PARAM_ETC(60), B_MEDIA_RAW_AUDIO, 1913 B_TRANSLATE("Input gain controls represent"), B_INPUT_MUX); 1914 dp->AddItem(0, B_TRANSLATE("Physical input channels")); 1915 dp->AddItem(1, B_TRANSLATE("Virtual output channels")); 1916 1917 dp = group->MakeDiscreteParameter(PARAM_ETC(70), B_MEDIA_RAW_AUDIO, 1918 B_TRANSLATE("Resampling algorithm"), B_INPUT_MUX); 1919 dp->AddItem(0, B_TRANSLATE("Drop/repeat samples")); 1920 dp->AddItem(2, B_TRANSLATE("Linear interpolation")); 1921 1922 // Note: The following code is outcommented on purpose 1923 // and is about to be modified at a later point 1924 /* 1925 dp->AddItem(1, B_TRANSLATE("Drop/repeat samples (template based)")); 1926 dp->AddItem(3, B_TRANSLATE("17th order filtering")); 1927 */ 1928 group->MakeDiscreteParameter(PARAM_ETC(80), B_MEDIA_RAW_AUDIO, 1929 B_TRANSLATE("Refuse output format changes"), B_ENABLE); 1930 group->MakeDiscreteParameter(PARAM_ETC(90), B_MEDIA_RAW_AUDIO, 1931 B_TRANSLATE("Refuse input format changes"), B_ENABLE); 1932 1933 fCore->Unlock(); 1934 SetParameterWeb(web); 1935 } 1936 1937 1938 #if USE_MEDIA_FORMAT_WORKAROUND 1939 static void 1940 raw_audio_format_specialize(media_raw_audio_format *format, 1941 const media_raw_audio_format *other) 1942 { 1943 if (format->frame_rate == 0) 1944 format->frame_rate = other->frame_rate; 1945 if (format->channel_count == 0) 1946 format->channel_count = other->channel_count; 1947 if (format->format == 0) 1948 format->format = other->format; 1949 if (format->byte_order == 0) 1950 format->byte_order = other->byte_order; 1951 if (format->buffer_size == 0) 1952 format->buffer_size = other->buffer_size; 1953 if (format->frame_rate == 0) 1954 format->frame_rate = other->frame_rate; 1955 } 1956 1957 1958 static void 1959 multi_audio_info_specialize(media_multi_audio_info *format, 1960 const media_multi_audio_info *other) 1961 { 1962 if (format->channel_mask == 0) 1963 format->channel_mask = other->channel_mask; 1964 if (format->valid_bits == 0) 1965 format->valid_bits = other->valid_bits; 1966 if (format->matrix_mask == 0) 1967 format->matrix_mask = other->matrix_mask; 1968 } 1969 1970 1971 static void 1972 multi_audio_format_specialize(media_multi_audio_format *format, 1973 const media_multi_audio_format *other) 1974 { 1975 raw_audio_format_specialize(format, other); 1976 multi_audio_info_specialize(format, other); 1977 } 1978 #endif 1979