1 // **************************************************************************** 2 // 3 // CEchoGals_mixer.cpp 4 // 5 // Implementation file for the CEchoGals driver class (mixer functions). 6 // Set editor tabs to 3 for your viewing pleasure. 7 // 8 // Copyright Echo Digital Audio Corporation (c) 1998 - 2002 9 // All rights reserved 10 // www.echoaudio.com 11 // 12 // Permission is hereby granted, free of charge, to any person obtaining a 13 // copy of this software and associated documentation files (the 14 // "Software"), to deal with the Software without restriction, including 15 // without limitation the rights to use, copy, modify, merge, publish, 16 // distribute, sublicense, and/or sell copies of the Software, and to 17 // permit persons to whom the Software is furnished to do so, subject to 18 // the following conditions: 19 // 20 // - Redistributions of source code must retain the above copyright 21 // notice, this list of conditions and the following disclaimers. 22 // 23 // - Redistributions in binary form must reproduce the above copyright 24 // notice, this list of conditions and the following disclaimers in the 25 // documentation and/or other materials provided with the distribution. 26 // 27 // - Neither the name of Echo Digital Audio, nor the names of its 28 // contributors may be used to endorse or promote products derived from 29 // this Software without specific prior written permission. 30 // 31 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 32 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 33 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 34 // IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR 35 // ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 36 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 37 // SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. 38 // 39 // **************************************************************************** 40 41 #include "CEchoGals.h" 42 43 44 /**************************************************************************** 45 46 CEchoGals mixer client management 47 48 ****************************************************************************/ 49 50 //=========================================================================== 51 // 52 // Open the mixer - create a mixer client structure for this client and 53 // return the cookie. The cookie uniquely identifies this client to the 54 // mixer driver. 55 // 56 // Valid cookies are non-zero. If you get a zero cookie, the open failed 57 // somehow. 58 // 59 // Clients can change mixer controls without calling OpenMixer first; it just 60 // means that they can't track control changes made by other clients. 61 // 62 //=========================================================================== 63 64 ECHOSTATUS CEchoGals::OpenMixer(DWORD &dwCookie) 65 { 66 if (m_fMixerDisabled) 67 return ECHOSTATUS_MIXER_DISABLED; 68 69 // 70 // Allocate the mixer client structure 71 // 72 ECHO_MIXER_CLIENT *pClient = NULL; 73 ECHOSTATUS Status; 74 75 Status = OsAllocateNonPaged(sizeof(ECHO_MIXER_CLIENT),(void **) &pClient); 76 if (NULL == pClient) 77 { 78 dwCookie = 0; 79 return Status; 80 } 81 82 83 // 84 // Make the cookie 85 // 86 ULONGLONG ullTime; 87 88 m_pOsSupport->OsGetSystemTime(&ullTime); 89 dwCookie = (DWORD) ullTime; 90 if (0 == dwCookie) 91 dwCookie = 1; 92 93 // 94 // Look through the existing mixer client list to ensure that this 95 // cookie is unique. 96 // 97 ECHO_MIXER_CLIENT *pTemp; 98 99 pTemp = m_pMixerClients; 100 while (pTemp != NULL) 101 { 102 if (dwCookie == pTemp->dwCookie) 103 { 104 // 105 // Oops, someone is already using this cookie. Increment 106 // the new cookie and try again. 107 // 108 dwCookie++; 109 pTemp = m_pMixerClients; 110 } 111 112 pTemp = pTemp->pNext; 113 } 114 115 // 116 // Store the new cookie and the new mixer client 117 // 118 pClient->dwCookie = dwCookie; 119 pClient->pNext = m_pMixerClients; 120 m_pMixerClients = pClient; 121 122 return ECHOSTATUS_OK; 123 124 } // OpenMixer 125 126 127 //=========================================================================== 128 // 129 // Find a mixer client that matches a cookie 130 // 131 //=========================================================================== 132 133 ECHO_MIXER_CLIENT *CEchoGals::GetMixerClient(DWORD dwCookie) 134 { 135 ECHO_MIXER_CLIENT *pTemp; 136 137 pTemp = m_pMixerClients; 138 while (NULL != pTemp) 139 { 140 if (dwCookie == pTemp->dwCookie) 141 break; 142 143 pTemp = pTemp->pNext; 144 } 145 146 return pTemp; 147 148 } // GetMixerClient 149 150 151 //=========================================================================== 152 // 153 // Close the mixer - free the mixer client structure 154 // 155 //=========================================================================== 156 157 ECHOSTATUS CEchoGals::CloseMixer(DWORD dwCookie) 158 { 159 // 160 // Search the linked list and remove the client that matches the cookie 161 // 162 ECHO_MIXER_CLIENT *pTemp; 163 164 pTemp = m_pMixerClients; 165 if (NULL == pTemp) 166 return ECHOSTATUS_BAD_COOKIE; 167 168 // 169 // Head of the list? 170 // 171 if (pTemp->dwCookie == dwCookie) 172 { 173 m_pMixerClients = pTemp->pNext; 174 OsFreeNonPaged(pTemp); 175 176 return ECHOSTATUS_OK; 177 } 178 179 // 180 // Not the head of the list; search the list 181 // 182 while (NULL != pTemp->pNext) 183 { 184 if (dwCookie == pTemp->pNext->dwCookie) 185 { 186 ECHO_MIXER_CLIENT *pDeadClient; 187 188 pDeadClient = pTemp->pNext; 189 pTemp->pNext = pDeadClient->pNext; 190 OsFreeNonPaged(pDeadClient); 191 192 return ECHOSTATUS_OK; 193 } 194 195 pTemp = pTemp->pNext; 196 } 197 198 // 199 // No soup for you! 200 // 201 return ECHOSTATUS_BAD_COOKIE; 202 203 } // CloseMixer 204 205 206 //=========================================================================== 207 // 208 // IsMixerOpen - returns true if at least one client has the mixer open 209 // 210 //=========================================================================== 211 212 BOOL CEchoGals::IsMixerOpen() 213 { 214 if (NULL == m_pMixerClients) 215 return FALSE; 216 217 return TRUE; 218 219 } // IsMixerOpen 220 221 222 //=========================================================================== 223 // 224 // This function is called when a mixer control changes; add the change 225 // to the queue for each client. 226 // 227 // Here's what the wCh1 and wCh2 parameters represent, based on the wType 228 // parameter: 229 // 230 // wType wCh1 wCh2 231 // ----- ---- ---- 232 // ECHO_BUS_OUT Output bus Ignored 233 // ECHO_BUS_IN Input bus Ignored 234 // ECHO_PIPE_OUT Output pipe Output bus 235 // ECHO_MONITOR Input bus Output bus 236 // 237 // ECHO_PIPE_IN is not used right now. 238 // 239 //=========================================================================== 240 241 ECHOSTATUS CEchoGals::MixerControlChanged 242 ( 243 WORD wType, // One of the ECHO_CHANNEL_TYPES 244 WORD wParameter, // One of the MXN_* values 245 WORD wCh1, // Depends on the wType value 246 WORD wCh2 // Also depends on wType value 247 ) 248 { 249 ECHO_MIXER_CLIENT *pClient = m_pMixerClients; 250 PMIXER_NOTIFY pNotify; 251 252 if (m_fMixerDisabled) 253 return ECHOSTATUS_MIXER_DISABLED; 254 255 // 256 // Go through all the clients and store this control change 257 // 258 while (NULL != pClient) 259 { 260 // 261 // Search the circular buffer for this client and see if 262 // this control change is already stored 263 // 264 DWORD dwIndex,dwCount; 265 BOOL fFound; 266 267 dwCount = pClient->dwCount; 268 dwIndex = pClient->dwTail; 269 fFound = FALSE; 270 while (dwCount > 0) 271 { 272 pNotify = pClient->Notifies + dwIndex; 273 if ( (pNotify->wType == wType) && 274 (pNotify->wParameter == wParameter) && 275 (pNotify->u.wPipeOut == wCh1) && // can use any union member her 276 (pNotify->wBusOut == wCh2)) 277 { 278 // 279 // Found this notify already in the circular buffer 280 // 281 fFound = TRUE; 282 break; 283 } 284 dwIndex++; 285 dwIndex &= MAX_MIXER_NOTIFIES - 1; 286 dwCount--; 287 } 288 289 // 290 // If the notify was not found, add this notify to the circular buffer if 291 // there is enough room. 292 // 293 if ( (FALSE == fFound) && 294 (pClient->dwCount != MAX_MIXER_NOTIFIES)) 295 { 296 pNotify = pClient->Notifies + pClient->dwHead; 297 298 pNotify->wType = wType; 299 pNotify->wParameter = wParameter; 300 301 if (ECHO_BUS_OUT == wType) 302 { 303 pNotify->u.wPipeOut = ECHO_CHANNEL_UNUSED; 304 pNotify->wBusOut = wCh1; 305 } 306 else 307 { 308 pNotify->u.wPipeOut = wCh1; // can use any union member here also 309 pNotify->wBusOut = wCh2; 310 } 311 312 pClient->dwCount += 1; 313 pClient->dwHead = (pClient->dwHead + 1) & (MAX_MIXER_NOTIFIES - 1); 314 } 315 316 pClient = pClient->pNext; 317 } 318 319 return ECHOSTATUS_OK; 320 321 } // MixerControlChanged 322 323 324 //=========================================================================== 325 // 326 // This method is called when a client wants to know what controls have 327 // changed. 328 // 329 //=========================================================================== 330 331 ECHOSTATUS CEchoGals::GetControlChanges 332 ( 333 PMIXER_MULTI_NOTIFY pNotifies 334 ) 335 { 336 // 337 // Match the cookie 338 // 339 ECHO_MIXER_CLIENT *pClient = GetMixerClient(pNotifies->dwCookie); 340 341 if (NULL == pClient) 342 { 343 pNotifies->dwCount = 0; 344 return ECHOSTATUS_BAD_COOKIE; 345 } 346 347 // 348 // Copy mixer notifies 349 // 350 PMIXER_NOTIFY pDest,pSrc; 351 DWORD dwNumClientNotifies,dwNumReturned; 352 353 dwNumClientNotifies = pNotifies->dwCount; 354 pDest = pNotifies->Notifies; 355 dwNumReturned = 0; 356 while ( (dwNumClientNotifies > 0) && (pClient->dwCount > 0)) 357 { 358 pSrc = pClient->Notifies + pClient->dwTail; 359 360 OsCopyMemory(pDest,pSrc,sizeof(MIXER_NOTIFY)); 361 362 pDest++; 363 364 pClient->dwTail = (pClient->dwTail + 1) & (MAX_MIXER_NOTIFIES - 1); 365 pClient->dwCount -= 1; 366 367 dwNumClientNotifies--; 368 369 dwNumReturned++; 370 } 371 372 pNotifies->dwCount = dwNumReturned; 373 374 return ECHOSTATUS_OK; 375 376 } // GetControlChanges 377 378 379 380 381 /**************************************************************************** 382 383 CEchoGals mixer control 384 385 ****************************************************************************/ 386 387 //=========================================================================== 388 // 389 // Process mixer function - service a single mixer function 390 // 391 //=========================================================================== 392 393 ECHOSTATUS CEchoGals::ProcessMixerFunction 394 ( 395 PMIXER_FUNCTION pMixerFunction, 396 INT32 & iRtnDataSz 397 ) 398 { 399 ECHOSTATUS Status = ECHOSTATUS_OK; 400 401 if (m_fMixerDisabled) 402 return ECHOSTATUS_MIXER_DISABLED; 403 404 switch ( pMixerFunction->iFunction ) 405 { 406 case MXF_GET_CAPS : 407 Status = GetCapabilities( &pMixerFunction->Data.Capabilities ); 408 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 409 "MXF_GET_CAPS Status %ld\n", Status) ); 410 break; 411 412 case MXF_GET_LEVEL : 413 Status = GetAudioLineLevel( pMixerFunction); 414 /* 415 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 416 "MXF_GET_LEVEL Status %ld\n", Status) ); 417 */ 418 break; 419 420 case MXF_SET_LEVEL : 421 Status = SetAudioLineLevel( pMixerFunction); 422 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 423 "MXF_SET_LEVEL Status %ld\n", Status) ); 424 break; 425 426 case MXF_GET_NOMINAL : 427 Status = GetAudioNominal( pMixerFunction); 428 /* 429 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 430 "MXF_GET_NOMINAL Status %ld\n", Status) ); 431 */ 432 break; 433 434 case MXF_SET_NOMINAL : 435 Status = SetAudioNominal( pMixerFunction); 436 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 437 "MXF_SET_NOMINAL Status %ld\n", Status) ); 438 break; 439 440 case MXF_GET_MONITOR : 441 Status = GetAudioMonitor( pMixerFunction->Channel.wChannel, 442 pMixerFunction->Data.Monitor.wBusOut, 443 pMixerFunction->Data.Monitor.Data.iLevel ); 444 /* 445 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 446 "MXF_GET_MONITOR Status %ld\n", Status) ); 447 */ 448 break; 449 450 case MXF_SET_MONITOR : 451 Status = SetAudioMonitor( pMixerFunction->Channel.wChannel, 452 pMixerFunction->Data.Monitor.wBusOut, 453 pMixerFunction->Data.Monitor.Data.iLevel ); 454 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 455 "MXF_SET_MONITOR Status %ld\n", Status) ); 456 break; 457 458 case MXF_GET_CLOCK_DETECT : 459 Status = GetInputClockDetect( pMixerFunction->Data.dwClockDetectBits ); 460 break; 461 462 case MXF_GET_INPUT_CLOCK : 463 Status = GetInputClock( pMixerFunction->Data.wClock ); 464 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 465 "MXF_GET_INPUT_CLOCK Status %ld\n", Status) ); 466 break; 467 468 case MXF_SET_INPUT_CLOCK : 469 Status = SetInputClock( pMixerFunction->Data.wClock ); 470 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 471 "MXF_SET_INPUT_CLOCK Status %ld\n", Status) ); 472 break; 473 474 475 case MXF_GET_OUTPUT_CLOCK : 476 Status = GetOutputClock( pMixerFunction->Data.wClock ); 477 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 478 "MXF_GET_OUTPUT_CLOCK Status %ld\n", Status) ); 479 break; 480 481 case MXF_SET_OUTPUT_CLOCK : 482 Status = SetOutputClock( pMixerFunction->Data.wClock ); 483 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 484 "MXF_SET_OUTPUT_CLOCK Status %ld\n", Status) ); 485 break; 486 487 488 case MXF_GET_METERS : 489 490 if (NULL != GetDspCommObject()) 491 { 492 Status = GetDspCommObject()-> 493 GetAudioMeters( &pMixerFunction->Data.Meters ); 494 } 495 else 496 { 497 Status = ECHOSTATUS_DSP_DEAD; 498 } 499 500 //ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 501 // "MXF_GET_METERS Status %ld\n", Status) ); 502 break; 503 504 case MXF_GET_METERS_ON : 505 Status = GetMetersOn( pMixerFunction->Data.bMetersOn ); 506 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 507 "MXF_SET_METERS Status %ld\n", Status) ); 508 break; 509 510 case MXF_SET_METERS_ON : 511 Status = SetMetersOn( pMixerFunction->Data.bMetersOn ); 512 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 513 "MXF_SET_METERS_ON Status %ld\n", Status) ); 514 break; 515 516 case MXF_GET_PROF_SPDIF : 517 if ( ECHOSTATUS_DSP_DEAD == IsProfessionalSpdif() ) 518 { 519 Status = ECHOSTATUS_DSP_DEAD; 520 } 521 else 522 { 523 pMixerFunction->Data.bProfSpdif = IsProfessionalSpdif(); 524 } 525 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 526 "MXF_GET_PROF_SPDIF Pro S/PDIF: 0x%x Status %ld\n", 527 pMixerFunction->Data.bProfSpdif, 528 Status) ); 529 break; 530 531 case MXF_SET_PROF_SPDIF : 532 SetProfessionalSpdif( pMixerFunction->Data.bProfSpdif ); 533 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 534 "MXF_SET_PROF_SPDIF Pro S/PDIF: 0x%x Status %ld\n", 535 pMixerFunction->Data.bProfSpdif, 536 Status) ); 537 break; 538 539 case MXF_GET_MUTE : 540 Status = GetAudioMute(pMixerFunction); 541 /* 542 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 543 "MXF_GET_MUTE Status %ld\n", Status) ); 544 */ 545 break; 546 547 case MXF_SET_MUTE : 548 Status = SetAudioMute(pMixerFunction); 549 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 550 "MXF_SET_MUTE Status %ld\n", Status) ); 551 break; 552 553 case MXF_GET_MONITOR_MUTE : 554 Status = 555 GetAudioMonitorMute( pMixerFunction->Channel.wChannel, 556 pMixerFunction->Data.Monitor.wBusOut, 557 pMixerFunction->Data.Monitor.Data.bMuteOn ); 558 /* 559 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 560 "MXF_GET_MONITOR_MUTE Status %ld\n", Status) ); 561 */ 562 break; 563 564 case MXF_SET_MONITOR_MUTE : 565 Status = 566 SetAudioMonitorMute( pMixerFunction->Channel.wChannel, 567 pMixerFunction->Data.Monitor.wBusOut, 568 pMixerFunction->Data.Monitor.Data.bMuteOn ); 569 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 570 "MXF_SET_MONITOR_MUTE Status %ld\n", Status) ); 571 break; 572 573 case MXF_GET_MONITOR_PAN : 574 Status = 575 GetAudioMonitorPan( pMixerFunction->Channel.wChannel, 576 pMixerFunction->Data.Monitor.wBusOut, 577 pMixerFunction->Data.Monitor.Data.iPan); 578 /* 579 580 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 581 "MXF_GET_MONITOR_PAN Status %ld\n", Status) ); 582 */ 583 584 break; 585 case MXF_SET_MONITOR_PAN : 586 Status = 587 SetAudioMonitorPan( pMixerFunction->Channel.wChannel, 588 pMixerFunction->Data.Monitor.wBusOut, 589 pMixerFunction->Data.Monitor.Data.iPan ); 590 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 591 "MXF_SET_MONITOR_PAN Status %ld\n", Status) ); 592 break; 593 594 case MXF_GET_FLAGS : 595 pMixerFunction->Data.wFlags = GetFlags(); 596 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 597 "MXF_GET_FLAGS 0x%x Status %ld\n", 598 pMixerFunction->Data.wFlags, 599 Status) ); 600 break; 601 case MXF_SET_FLAGS : 602 SetFlags( pMixerFunction->Data.wFlags ); 603 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 604 "MXF_SET_FLAGS 0x%x Status %ld\n", 605 pMixerFunction->Data.wFlags, 606 Status) ); 607 break; 608 case MXF_CLEAR_FLAGS : 609 ClearFlags( pMixerFunction->Data.wFlags ); 610 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 611 "MXF_CLEAR_FLAGS 0x%x Status %ld\n", 612 pMixerFunction->Data.wFlags, 613 Status) ); 614 break; 615 616 case MXF_GET_SAMPLERATE_LOCK : 617 GetAudioLockedSampleRate( pMixerFunction->Data.dwLockedSampleRate ); 618 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 619 "MXF_GET_SAMPLERATE_LOCK 0x%lx Status %ld\n", 620 pMixerFunction->Data.dwLockedSampleRate, 621 Status) ); 622 break; 623 624 case MXF_SET_SAMPLERATE_LOCK : 625 SetAudioLockedSampleRate( pMixerFunction->Data.dwLockedSampleRate ); 626 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 627 "MXF_SET_SAMPLERATE_LOCK 0x%lx Status %ld\n", 628 pMixerFunction->Data.dwLockedSampleRate, 629 Status) ); 630 break; 631 632 case MXF_GET_SAMPLERATE : 633 634 GetAudioSampleRate( &pMixerFunction->Data.dwSampleRate ); 635 636 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 637 "MXF_GET_SAMPLERATE 0x%lx Status %ld\n", 638 pMixerFunction->Data.dwSampleRate, 639 Status) ); 640 break; 641 642 #ifdef MIDI_SUPPORT 643 644 case MXF_GET_MIDI_IN_ACTIVITY : 645 pMixerFunction->Data.bMidiActive = m_MidiIn.IsActive(); 646 647 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 648 "MXF_GET_MIDI_IN_ACTIVITY %s " 649 "Status %ld\n", 650 ( pMixerFunction->Data.bMidiActive ) 651 ? "ACTIVE" : "INACTIVE", 652 Status) ); 653 break; 654 655 656 case MXF_GET_MIDI_OUT_ACTIVITY : 657 pMixerFunction->Data.bMidiActive = 658 GetDspCommObject()->IsMidiOutActive(); 659 660 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 661 "MXF_GET_MIDI_OUT_ACTIVITY %s " 662 "Status %ld\n", 663 ( pMixerFunction->Data.bMidiActive ) 664 ? "ACTIVE" : "INACTIVE", 665 Status) ); 666 break; 667 668 #endif // MIDI_SUPPORT 669 670 671 case MXF_GET_DIGITAL_MODE : 672 Status = ECHOSTATUS_OK; 673 pMixerFunction->Data.iDigMode = GetDigitalMode(); 674 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 675 "MXF_GET_DIGITAL_MODE %s " 676 "Status %ld\n", 677 ( DIGITAL_MODE_SPDIF_RCA == 678 pMixerFunction->Data.iDigMode ) 679 ? "S/PDIF RCA" 680 : ( DIGITAL_MODE_SPDIF_OPTICAL == 681 pMixerFunction->Data.iDigMode ) 682 ? "S/PDIF Optical" : "ADAT", 683 Status) ); 684 break; 685 686 687 case MXF_SET_DIGITAL_MODE : 688 Status = SetDigitalMode( (BYTE) pMixerFunction->Data.iDigMode ); 689 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 690 "MXF_SET_DIGITAL_MODE %s " 691 "Status %ld\n", 692 ( DIGITAL_MODE_SPDIF_RCA == 693 pMixerFunction->Data.iDigMode ) 694 ? "S/PDIF RCA" 695 : ( DIGITAL_MODE_SPDIF_OPTICAL == 696 pMixerFunction->Data.iDigMode ) 697 ? "S/PDIF Optical" : "ADAT", 698 Status) ); 699 break; 700 701 702 case MXF_GET_PAN : 703 Status = GetAudioPan( pMixerFunction); 704 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 705 "MXF_GET_PAN Status %ld\n", Status) ); 706 break; 707 708 case MXF_SET_PAN : 709 Status = SetAudioPan( pMixerFunction); 710 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 711 "MXF_SET_PAN Status %ld\n", Status) ); 712 break; 713 714 #ifdef DIGITAL_INPUT_AUTO_MUTE_SUPPORT 715 716 case MXF_GET_DIG_IN_AUTO_MUTE : 717 Status = GetDigitalInAutoMute( pMixerFunction ); 718 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 719 "MXF_GET_DIG_IN_AUTO_MUTE Status %ld\n", Status) ); 720 break; 721 722 723 case MXF_SET_DIG_IN_AUTO_MUTE : 724 Status = SetDigitalInAutoMute( pMixerFunction ); 725 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 726 "MXF_SET_DIG_IN_AUTO_MUTE Status %ld\n", Status) ); 727 break; 728 729 #endif // DIGITAL_INPUT_AUTO_MUTE_SUPPORT 730 731 732 default : 733 iRtnDataSz = 0; 734 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: " 735 "Function %ld not supported\n", 736 pMixerFunction->iFunction) ); 737 return ECHOSTATUS_NOT_SUPPORTED; 738 } 739 740 pMixerFunction->RtnStatus = Status; 741 iRtnDataSz = sizeof( MIXER_FUNCTION ); 742 743 return Status; 744 745 } // ECHOSTATUS CEchoGals::ProcessMixerFunction 746 747 748 749 750 //=========================================================================== 751 // 752 // Process multiple mixer functions 753 // 754 //=========================================================================== 755 756 ECHOSTATUS CEchoGals::ProcessMixerMultiFunction 757 ( 758 PMIXER_MULTI_FUNCTION pMixerFunctions, // Request from mixer 759 INT32 & iRtnDataSz // # bytes returned (if any) 760 ) 761 { 762 ECHOSTATUS Status = ECHOSTATUS_NOT_SUPPORTED; 763 PMIXER_FUNCTION pMixerFunction; 764 INT32 iRtn, nCard, i; 765 766 if (m_fMixerDisabled) 767 return ECHOSTATUS_MIXER_DISABLED; 768 769 iRtnDataSz = sizeof( MIXER_MULTI_FUNCTION ) - sizeof( MIXER_FUNCTION ); 770 pMixerFunction = &pMixerFunctions->MixerFunction[ 0 ]; 771 nCard = pMixerFunction->Channel.wCardId; 772 for ( i = 0; i < pMixerFunctions->iCount; i++ ) 773 { 774 pMixerFunction = &pMixerFunctions->MixerFunction[ i ]; 775 if ( nCard != pMixerFunction->Channel.wCardId ) 776 { 777 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerMultiFunction: " 778 "All functions MUST be for the same card " 779 "exp %ld act %d!\n", 780 nCard, 781 pMixerFunction->Channel.wCardId) ); 782 return ECHOSTATUS_NOT_SUPPORTED; 783 } 784 785 Status = ProcessMixerFunction(pMixerFunction,iRtn); 786 iRtnDataSz += iRtn; 787 } 788 789 return Status; 790 791 } // ECHOSTATUS CEchoGals::ProcessMixerMultiFunction 792 793 794 795 796 //=========================================================================== 797 // 798 // Typically, if you are writing a console, you will be polling the driver 799 // to get the current peak and VU meters, clock detect bits, and 800 // control changes. GetPolledStuff will fill out an ECHO_POLLED_STUFF 801 // structure with all of those things. 802 // 803 //=========================================================================== 804 805 ECHOSTATUS CEchoGals::GetPolledStuff(ECHO_POLLED_STUFF *pPolledStuff) 806 { 807 CDspCommObject *pDCO = GetDspCommObject(); 808 809 if (m_fMixerDisabled) 810 return ECHOSTATUS_MIXER_DISABLED; 811 812 if (NULL == pDCO) 813 return ECHOSTATUS_DSP_DEAD; 814 815 // 816 // Match the client to the cookie 817 // 818 ECHO_MIXER_CLIENT *pClient = GetMixerClient(pPolledStuff->dwCookie); 819 820 if (NULL == pClient) 821 return ECHOSTATUS_BAD_COOKIE; 822 823 // 824 // Fill out the struct 825 // 826 pDCO->GetAudioMeters(&(pPolledStuff->Meters)); 827 GetInputClockDetect(pPolledStuff->dwClockDetectBits); 828 pPolledStuff->dwNumPendingNotifies = pClient->dwCount; 829 830 return ECHOSTATUS_OK; 831 832 } // GetPolledStuff 833 834 835 //=========================================================================== 836 // 837 // Get the pan setting for an output pipe (virtual outputs only) 838 // 839 //=========================================================================== 840 841 ECHOSTATUS CEchoGals::GetAudioPan 842 ( 843 PMIXER_FUNCTION pMF 844 ) 845 { 846 WORD wPipe; 847 WORD wBus; 848 ECHOSTATUS Status; 849 850 if ( (pMF->Channel.dwType != ECHO_PIPE_OUT) || 851 ( !HasVmixer() ) ) 852 return ECHOSTATUS_INVALID_CHANNEL; 853 854 wPipe = pMF->Channel.wChannel; 855 wBus = pMF->Data.PipeOut.wBusOut; 856 Status = m_PipeOutCtrl.GetPan(wPipe, 857 wBus, 858 pMF->Data.PipeOut.Data.iPan); 859 860 return Status; 861 862 } // ECHOSTATUS CEchoGals::GetAudioPan 863 864 865 //=========================================================================== 866 // 867 // Set the pan for an output pipe (virtual outputs only) 868 // 869 //=========================================================================== 870 871 ECHOSTATUS CEchoGals::SetAudioPan 872 ( 873 PMIXER_FUNCTION pMF 874 ) 875 { 876 WORD wPipe; 877 WORD wBus; 878 ECHOSTATUS Status; 879 880 if ( (pMF->Channel.dwType != ECHO_PIPE_OUT) || 881 ( !HasVmixer() ) ) 882 return ECHOSTATUS_INVALID_CHANNEL; 883 884 wPipe = pMF->Channel.wChannel; 885 wBus = pMF->Data.PipeOut.wBusOut; 886 Status = m_PipeOutCtrl.SetPan(wPipe, 887 wBus, 888 pMF->Data.PipeOut.Data.iPan); 889 890 return Status; 891 892 } // ECHOSTATUS CEchoGals::SetAudioPan 893 894 895 896 897 /**************************************************************************** 898 899 CEchoGals clock control 900 901 The input clock is the sync source - is the audio for this card running 902 off of the internal clock, synced to word clock, etc. 903 904 Output clock is only supported on Layla20 - Layla20 can transmit either 905 word or super clock. 906 907 ****************************************************************************/ 908 909 //=========================================================================== 910 // 911 // Get input and output clocks - just return the stored value 912 // 913 //=========================================================================== 914 915 ECHOSTATUS CEchoGals::GetInputClock(WORD &wClock) 916 { 917 if ( NULL == GetDspCommObject() ) 918 return ECHOSTATUS_DSP_DEAD; 919 920 wClock = GetDspCommObject()->GetInputClock(); 921 922 return ECHOSTATUS_OK; 923 } 924 925 926 ECHOSTATUS CEchoGals::GetOutputClock(WORD &wClock) 927 { 928 if ( NULL == GetDspCommObject() ) 929 return ECHOSTATUS_DSP_DEAD; 930 931 wClock = GetDspCommObject()->GetOutputClock(); 932 933 return ECHOSTATUS_OK; 934 } 935 936 937 //=========================================================================== 938 // 939 // Set input and output clocks - pass it down to the comm page and 940 // store the control change. 941 // 942 //=========================================================================== 943 944 ECHOSTATUS CEchoGals::SetInputClock(WORD wClock) 945 { 946 ECHOSTATUS Status; 947 948 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 949 return ECHOSTATUS_DSP_DEAD; 950 951 ECHO_DEBUGPRINTF( ("CEchoGals::SetInputClock: ") ); 952 953 Status = GetDspCommObject()->SetInputClock( wClock ); 954 955 if (ECHOSTATUS_OK == Status) 956 { 957 MixerControlChanged( ECHO_NO_CHANNEL_TYPE, 958 MXN_INPUT_CLOCK); 959 } 960 return Status; 961 962 } // SetInputClock 963 964 965 ECHOSTATUS CEchoGals::SetOutputClock(WORD wClock) 966 { 967 ECHOSTATUS Status; 968 969 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 970 return ECHOSTATUS_DSP_DEAD; 971 972 ECHO_DEBUGPRINTF( ("CEchoGals::SetOutputClock: ") ); 973 974 Status = GetDspCommObject()->SetOutputClock( wClock ); 975 976 if (ECHOSTATUS_OK == Status) 977 { 978 MixerControlChanged( ECHO_NO_CHANNEL_TYPE, 979 MXN_OUTPUT_CLOCK); 980 } 981 return Status; 982 983 } 984 985 986 //=========================================================================== 987 // 988 // Get the currently detected clock bits - default method. Overridden by 989 // derived card classes. 990 // 991 //=========================================================================== 992 993 ECHOSTATUS CEchoGals::GetInputClockDetect(DWORD &dwClockDetectBits) 994 { 995 dwClockDetectBits = ECHO_CLOCK_INTERNAL; 996 997 return ECHOSTATUS_OK; 998 } 999 1000 1001 //=========================================================================== 1002 // 1003 // Set the locked sample rate 1004 // 1005 //=========================================================================== 1006 1007 ECHOSTATUS CEchoGals::SetAudioLockedSampleRate 1008 ( 1009 DWORD dwSampleRate 1010 ) 1011 { 1012 ECHOSTATUS Status; 1013 1014 Status = QueryAudioSampleRate( dwSampleRate ); 1015 if ( ECHOSTATUS_OK != Status ) 1016 return Status; 1017 1018 if (0 != (ECHOGALS_FLAG_SAMPLE_RATE_LOCKED & GetFlags())) 1019 { 1020 GetDspCommObject()->SetSampleRate( dwSampleRate ); 1021 } 1022 1023 m_dwLockedSampleRate = dwSampleRate; 1024 1025 return ECHOSTATUS_OK; 1026 1027 } // ECHOSTATUS CEchoGals::SetAudioLockedSampleRate 1028 1029 1030 //=========================================================================== 1031 // 1032 // Get the locked sample rate 1033 // 1034 //=========================================================================== 1035 1036 ECHOSTATUS CEchoGals::GetAudioLockedSampleRate 1037 ( 1038 DWORD &dwSampleRate 1039 ) 1040 { 1041 dwSampleRate = m_dwLockedSampleRate; 1042 1043 return ECHOSTATUS_OK; 1044 1045 } // ECHOSTATUS CEchoGals::GetAudioLockedSampleRate 1046 1047 1048 1049 #ifdef DIGITAL_INPUT_AUTO_MUTE_SUPPORT 1050 1051 //=========================================================================== 1052 // 1053 // Get the digital input auto mute flag from the comm page 1054 // 1055 //=========================================================================== 1056 1057 ECHOSTATUS CEchoGals::GetDigitalInAutoMute(PMIXER_FUNCTION pMixerFunction) 1058 { 1059 BOOL fAutoMute; 1060 1061 if (0 == (m_wFlags & ECHOGALS_ROFLAG_DIGITAL_IN_AUTOMUTE)) 1062 { 1063 pMixerFunction->Data.fDigitalInAutoMute = FALSE; 1064 return ECHOSTATUS_NOT_SUPPORTED; 1065 } 1066 1067 GetDspCommObject()->GetDigitalInputAutoMute( fAutoMute ); 1068 pMixerFunction->Data.fDigitalInAutoMute = fAutoMute; 1069 1070 return ECHOSTATUS_OK; 1071 1072 } // GetDigitalInAutoMute 1073 1074 1075 //=========================================================================== 1076 // 1077 // Set the digital input auto mute flag 1078 // 1079 //=========================================================================== 1080 1081 ECHOSTATUS CEchoGals::SetDigitalInAutoMute(PMIXER_FUNCTION pMixerFunction) 1082 { 1083 BOOL fAutoMute; 1084 1085 if (0 == (m_wFlags & ECHOGALS_ROFLAG_DIGITAL_IN_AUTOMUTE)) 1086 return ECHOSTATUS_NOT_SUPPORTED; 1087 1088 fAutoMute = pMixerFunction->Data.fDigitalInAutoMute; 1089 GetDspCommObject()->SetDigitalInputAutoMute( fAutoMute ); 1090 1091 return ECHOSTATUS_OK; 1092 1093 } // SetDigitalInAutoMute 1094 1095 #endif // DIGITAL_INPUT_AUTO_MUTE_SUPPORT 1096 1097 1098 //=========================================================================== 1099 // 1100 // Get the gain for an output bus, input bus, or output pipe. 1101 // 1102 // Gain levels are in units of dB * 256. 1103 // 1104 //=========================================================================== 1105 1106 ECHOSTATUS CEchoGals::GetAudioLineLevel 1107 ( 1108 PMIXER_FUNCTION pMF 1109 ) 1110 { 1111 WORD wPipe; 1112 WORD wBus; 1113 ECHOSTATUS Status; 1114 1115 switch (pMF->Channel.dwType) 1116 { 1117 case ECHO_BUS_OUT : 1118 1119 wBus = pMF->Channel.wChannel; 1120 1121 if (wBus < GetNumBussesOut()) 1122 { 1123 pMF->Data.iLevel = m_BusOutLineLevels[wBus].GetGain(); 1124 Status = ECHOSTATUS_OK; 1125 } 1126 else 1127 { 1128 Status = ECHOSTATUS_INVALID_CHANNEL; 1129 } 1130 1131 break; 1132 1133 case ECHO_BUS_IN : 1134 1135 wBus = pMF->Channel.wChannel; 1136 if (wBus < GetNumBussesIn()) 1137 { 1138 pMF->Data.iLevel = m_BusInLineLevels[wBus].GetGain(); 1139 Status = ECHOSTATUS_OK; 1140 } 1141 else 1142 { 1143 Status = ECHOSTATUS_INVALID_CHANNEL; 1144 } 1145 break; 1146 1147 case ECHO_PIPE_OUT : 1148 1149 wPipe = pMF->Channel.wChannel; 1150 wBus = pMF->Data.PipeOut.wBusOut; 1151 Status = m_PipeOutCtrl.GetGain( wPipe, 1152 wBus, 1153 pMF->Data.PipeOut.Data.iLevel); 1154 break; 1155 1156 default: 1157 Status = ECHOSTATUS_INVALID_PARAM; 1158 break; 1159 } 1160 1161 return Status; 1162 1163 } // ECHOSTATUS CEchoGals::GetAudioLineLevel 1164 1165 1166 //=========================================================================== 1167 // 1168 // Utility function to check that a setting is within the correct range. 1169 // 1170 //=========================================================================== 1171 1172 ECHOSTATUS CheckSetting(INT32 iValue,INT32 iMin,INT32 iMax) 1173 { 1174 if ( (iValue > iMax) || (iValue < iMin)) 1175 return ECHOSTATUS_INVALID_PARAM; 1176 1177 return ECHOSTATUS_OK; 1178 1179 } // CheckSetting 1180 1181 1182 //=========================================================================== 1183 // 1184 // Set the gain for an output bus, input bus, or output pipe. 1185 // 1186 // Gain levels are in units of dB * 256. 1187 // 1188 //=========================================================================== 1189 1190 ECHOSTATUS CEchoGals::SetAudioLineLevel 1191 ( 1192 PMIXER_FUNCTION pMF 1193 ) 1194 { 1195 WORD wPipe; 1196 WORD wBus; 1197 ECHOSTATUS Status; 1198 INT32 iLevel; 1199 1200 switch (pMF->Channel.dwType) 1201 { 1202 case ECHO_BUS_OUT : 1203 1204 wBus = pMF->Channel.wChannel; 1205 iLevel = pMF->Data.iLevel; 1206 1207 Status = CheckSetting(iLevel,ECHOGAIN_MINOUT,ECHOGAIN_MAXOUT); 1208 if (ECHOSTATUS_OK != Status) 1209 break; 1210 1211 Status = m_BusOutLineLevels[wBus].SetGain(iLevel); 1212 break; 1213 1214 case ECHO_BUS_IN : 1215 1216 wBus = pMF->Channel.wChannel; 1217 iLevel = pMF->Data.iLevel; 1218 1219 Status = CheckSetting(iLevel,ECHOGAIN_MININP,ECHOGAIN_MAXINP); 1220 if (ECHOSTATUS_OK != Status) 1221 break; 1222 1223 Status = m_BusInLineLevels[wBus].SetGain(iLevel); 1224 break; 1225 1226 case ECHO_PIPE_OUT : 1227 1228 wPipe = pMF->Channel.wChannel; 1229 wBus = pMF->Data.PipeOut.wBusOut; 1230 iLevel = pMF->Data.PipeOut.Data.iLevel; 1231 1232 Status = CheckSetting(iLevel,ECHOGAIN_MINOUT,ECHOGAIN_MAXOUT); 1233 if (ECHOSTATUS_OK != Status) 1234 break; 1235 1236 Status = m_PipeOutCtrl.SetGain( wPipe, 1237 wBus, 1238 iLevel); 1239 break; 1240 1241 default: 1242 Status = ECHOSTATUS_INVALID_PARAM; 1243 break; 1244 } 1245 1246 return Status; 1247 1248 } // ECHOSTATUS CEchoGals::SetAudioLineLevel 1249 1250 1251 //=========================================================================== 1252 // 1253 // Get the nominal level for an output or input bus. The nominal level is 1254 // also referred to as the +4/-10 switch. 1255 // 1256 //=========================================================================== 1257 1258 ECHOSTATUS CEchoGals::GetAudioNominal 1259 ( 1260 PMIXER_FUNCTION pMF 1261 ) 1262 { 1263 BYTE byNominal; 1264 ECHOSTATUS Status; 1265 CDspCommObject * pDspCommObj = GetDspCommObject(); 1266 WORD wCh; 1267 1268 if ( NULL == pDspCommObj || pDspCommObj->IsBoardBad() ) 1269 return ECHOSTATUS_DSP_DEAD; 1270 1271 switch (pMF->Channel.dwType) 1272 { 1273 case ECHO_BUS_OUT : 1274 wCh = pMF->Channel.wChannel; 1275 break; 1276 1277 case ECHO_BUS_IN : 1278 wCh = pMF->Channel.wChannel + GetNumBussesOut(); 1279 break; 1280 1281 default : 1282 return ECHOSTATUS_INVALID_CHANNEL; 1283 } 1284 1285 Status = pDspCommObj->GetNominalLevel( wCh, &byNominal ); 1286 1287 if ( ECHOSTATUS_OK != Status ) 1288 return Status; 1289 1290 pMF->Data.iNominal = ( byNominal ) ? -10 : 4; 1291 1292 return ECHOSTATUS_OK; 1293 } // ECHOSTATUS CEchoGals::GetAudioNominal 1294 1295 1296 //=========================================================================== 1297 // 1298 // Set the nominal level for an output or input bus. The nominal level is 1299 // also referred to as the +4/-10 switch. 1300 // 1301 //=========================================================================== 1302 1303 ECHOSTATUS CEchoGals::SetAudioNominal 1304 ( 1305 PMIXER_FUNCTION pMF 1306 ) 1307 { 1308 ECHOSTATUS Status; 1309 WORD wCh; 1310 int iNominal; 1311 1312 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 1313 return ECHOSTATUS_DSP_DEAD; 1314 1315 switch (pMF->Channel.dwType) 1316 { 1317 case ECHO_BUS_OUT : 1318 wCh = pMF->Channel.wChannel; 1319 break; 1320 1321 case ECHO_BUS_IN : 1322 wCh = pMF->Channel.wChannel + GetNumBussesOut(); 1323 break; 1324 1325 default : 1326 return ECHOSTATUS_INVALID_CHANNEL; 1327 } 1328 1329 iNominal = pMF->Data.iNominal; 1330 1331 if ((iNominal!= -10) && (iNominal != 4)) 1332 return ECHOSTATUS_INVALID_PARAM; 1333 1334 Status = 1335 GetDspCommObject()->SetNominalLevel( wCh, 1336 ( iNominal == -10 ) ); 1337 1338 if ( ECHOSTATUS_OK != Status ) 1339 return Status; 1340 1341 Status = MixerControlChanged( (WORD) pMF->Channel.dwType, 1342 MXN_NOMINAL, 1343 pMF->Channel.wChannel); 1344 return Status; 1345 1346 } // ECHOSTATUS CEchoGals::SetAudioNominal 1347 1348 1349 //=========================================================================== 1350 // 1351 // Set the mute for an output bus, input bus, or output pipe. 1352 // 1353 //=========================================================================== 1354 1355 ECHOSTATUS CEchoGals::SetAudioMute 1356 ( 1357 PMIXER_FUNCTION pMF 1358 ) 1359 { 1360 WORD wPipe; 1361 WORD wBus; 1362 ECHOSTATUS Status; 1363 BOOL bMute; 1364 1365 switch (pMF->Channel.dwType) 1366 { 1367 case ECHO_BUS_OUT : 1368 1369 wBus = pMF->Channel.wChannel; 1370 bMute = pMF->Data.bMuteOn; 1371 Status = m_BusOutLineLevels[wBus].SetMute(bMute); 1372 break; 1373 1374 case ECHO_BUS_IN : 1375 1376 wBus = pMF->Channel.wChannel; 1377 bMute = pMF->Data.bMuteOn; 1378 Status = m_BusInLineLevels[wBus].SetMute(bMute); 1379 break; 1380 1381 case ECHO_PIPE_OUT : 1382 1383 wPipe = pMF->Channel.wChannel; 1384 wBus = pMF->Data.PipeOut.wBusOut; 1385 bMute = pMF->Data.PipeOut.Data.bMuteOn; 1386 Status = m_PipeOutCtrl.SetMute( wPipe, 1387 wBus, 1388 bMute); 1389 break; 1390 1391 default: 1392 Status = ECHOSTATUS_INVALID_PARAM; 1393 break; 1394 } 1395 1396 return Status; 1397 } // ECHOSTATUS CEchoGals::SetAudioMute 1398 1399 1400 //=========================================================================== 1401 // 1402 // Get the mute for an output bus, input bus, or output pipe. 1403 // 1404 //=========================================================================== 1405 1406 ECHOSTATUS CEchoGals::GetAudioMute 1407 ( 1408 PMIXER_FUNCTION pMF 1409 ) 1410 { 1411 WORD wPipe; 1412 WORD wBus; 1413 ECHOSTATUS Status; 1414 1415 switch (pMF->Channel.dwType) 1416 { 1417 case ECHO_BUS_OUT : 1418 1419 wBus = pMF->Channel.wChannel; 1420 1421 if (wBus < GetNumBussesOut()) 1422 { 1423 pMF->Data.bMuteOn = m_BusOutLineLevels[wBus].IsMuteOn(); 1424 Status = ECHOSTATUS_OK; 1425 } 1426 else 1427 { 1428 Status = ECHOSTATUS_INVALID_CHANNEL; 1429 } 1430 1431 break; 1432 1433 case ECHO_BUS_IN : 1434 1435 wBus = pMF->Channel.wChannel; 1436 1437 if (wBus < GetNumBussesIn()) 1438 { 1439 pMF->Data.bMuteOn = m_BusInLineLevels[wBus].IsMuteOn(); 1440 Status = ECHOSTATUS_OK; 1441 } 1442 else 1443 { 1444 Status = ECHOSTATUS_INVALID_CHANNEL; 1445 } 1446 break; 1447 1448 case ECHO_PIPE_OUT : 1449 1450 wPipe = pMF->Channel.wChannel; 1451 wBus = pMF->Data.PipeOut.wBusOut; 1452 Status = m_PipeOutCtrl.GetMute( wPipe, 1453 wBus, 1454 pMF->Data.PipeOut.Data.bMuteOn); 1455 break; 1456 1457 default: 1458 Status = ECHOSTATUS_INVALID_PARAM; 1459 break; 1460 } 1461 1462 return Status; 1463 1464 } // ECHOSTATUS CEchoGals::GetAudioMute 1465 1466 1467 //=========================================================================== 1468 // 1469 // Get the monitor gain for a single input bus mixed to a single output bus. 1470 // 1471 //=========================================================================== 1472 1473 ECHOSTATUS CEchoGals::GetAudioMonitor 1474 ( 1475 WORD wBusIn, 1476 WORD wBusOut, 1477 INT32 & iGain 1478 ) 1479 { 1480 if ( wBusIn >= GetNumBussesIn() || 1481 wBusOut >= GetNumBussesOut() ) 1482 { 1483 return ECHOSTATUS_INVALID_INDEX; 1484 } 1485 1486 // 1487 // Get the monitor value 1488 // 1489 m_MonitorCtrl.GetGain(wBusIn,wBusOut,iGain); 1490 1491 return ECHOSTATUS_OK; 1492 1493 } // ECHOSTATUS CEchoGals::GetAudioMonitor 1494 1495 1496 //=========================================================================== 1497 // 1498 // Set the monitor gain for a single input bus mixed to a single output bus. 1499 // 1500 //=========================================================================== 1501 1502 ECHOSTATUS CEchoGals::SetAudioMonitor 1503 ( 1504 WORD wBusIn, 1505 WORD wBusOut, 1506 INT32 iGain 1507 ) 1508 { 1509 ECHOSTATUS Status; 1510 1511 if ( wBusIn >= GetNumBussesIn() || 1512 wBusOut >= GetNumBussesOut() ) 1513 { 1514 return ECHOSTATUS_INVALID_INDEX; 1515 } 1516 1517 Status = CheckSetting(iGain,ECHOGAIN_MINOUT,ECHOGAIN_MAXOUT); 1518 if (ECHOSTATUS_OK == Status) 1519 { 1520 // 1521 // Set the monitor gain 1522 // 1523 m_MonitorCtrl.SetGain(wBusIn,wBusOut,iGain); 1524 } 1525 1526 return Status; 1527 1528 } // ECHOSTATUS CEchoGals::SetAudioMonitor 1529 1530 1531 //=========================================================================== 1532 // 1533 // Helper functions for doing log conversions on pan values 1534 // 1535 // The parameter iNum is a fixed point 32 bit number in 16.16 format; 1536 // that is, 16 bits of integer and 16 bits of decimal 1537 // To convert a float number to fixed point, simply multiply by 2^16 and round 1538 // 1539 // Valid range for iNum is from +1.0 (0x10000) to 0. 1540 // 1541 //=========================================================================== 1542 1543 #define FIXED_BASE 16 // 16 bits of fraction 1544 #define FIXED_ONE_HALF ((int) 0x00008000) // 0.5 in 16.16 format 1545 #define COEFF_A2 ((int) 0xffffa9ac) // -.3372223 1546 #define COEFF_A1 ((int) 0x0000ff8a) // .9981958 1547 #define COEFF_A0 ((int) 0xffff5661) // -.6626105 1548 1549 #define DB_CONVERT 0x60546 // 6.02... in 16.16 1550 1551 // Note use of double precision here to prevent overflow 1552 static int FixedMult( int iNum1, int iNum2 ) 1553 { 1554 LONGLONG llNum; 1555 1556 llNum = (LONGLONG) iNum1 * (LONGLONG) iNum2; 1557 1558 return (int) (llNum >> FIXED_BASE); 1559 } // int FixedMult( int iNum1, int iNum2 ) 1560 1561 1562 static int log2( int iNum ) 1563 { 1564 int iNumShifts; 1565 int iTemp; 1566 1567 // log2 is undefined for zero, so return -infinity (or close enough) 1568 if ( 0 == iNum ) 1569 return ECHOGAIN_MUTED; 1570 1571 // Step 1 - Normalize and save the number of shifts 1572 // Keep shifting iNum up until iNum > 0.5 1573 iNumShifts = 0; 1574 while ( iNum < FIXED_ONE_HALF ) 1575 { 1576 iNumShifts++; 1577 iNum <<= 1; 1578 } 1579 1580 // Step 2 - Calculate LOG2 by polynomial approximation. 8 bit accuracy. 1581 // 1582 // LOG2(x) = 4.0* (-.3372223 x*x + .9981958 x - .6626105) 1583 // a2 a1 a0 1584 // where 0.5 <= x < 1.0 1585 // 1586 1587 // Compute polynomial sum 1588 iTemp = FixedMult( iNum, iNum ); // iTemp now has iNum squared 1589 iTemp = FixedMult( iTemp, COEFF_A2 ); 1590 iTemp += FixedMult( iNum, COEFF_A1 ); 1591 iTemp += COEFF_A0; 1592 1593 // Multiply by four 1594 iTemp <<= 2; 1595 1596 // Account for the normalize shifts 1597 iTemp -= ( iNumShifts << FIXED_BASE ); 1598 1599 return( iTemp ); 1600 } // int log2( int iNum ) 1601 1602 1603 // 1604 // Convert pan value to Db X 256 1605 // Pan value is 0 - MAX_MIXER_PAN 1606 // 1607 INT32 PanToDb( INT32 iPan ) 1608 { 1609 if ( iPan >= ( MAX_MIXER_PAN - 1 ) ) 1610 return( 0 ); 1611 if ( iPan <= 1 ) 1612 return( ECHOGAIN_MUTED ); 1613 // 1614 // Convert pan to 16.16 1615 // 1616 iPan = ( iPan << 16 ) / MAX_MIXER_PAN; 1617 // 1618 // Take the log 1619 // 1620 iPan = log2( iPan ); 1621 // 1622 // To convert to decibels*256, just multiply by the conversion factor 1623 // 1624 iPan = FixedMult( iPan << 8, DB_CONVERT ); 1625 // 1626 // To round, add one half and then mask off the fractional bits 1627 // 1628 iPan = ( iPan + FIXED_ONE_HALF ) >> FIXED_BASE; 1629 return( iPan ); 1630 } // INT32 PanToDb( INT32 iPan ) 1631 1632 1633 //=========================================================================== 1634 // 1635 // Set the monitor pan 1636 // 1637 // For this to work effectively, both the input and output channels must 1638 // both either be odd or even. Thus even channel numbers are for the 1639 // left channel and odd channel numbers are for the right channel. 1640 // Pan values will be computed for both channels. 1641 // 1642 // iPan ranges from 0 (hard left) to MAX_MIXER_PAN (hard right) 1643 // 1644 //=========================================================================== 1645 1646 ECHOSTATUS CEchoGals::SetAudioMonitorPan 1647 ( 1648 WORD wBusIn, 1649 WORD wBusOut, 1650 INT32 iPan // New pan 1651 ) 1652 { 1653 ECHOSTATUS Status; 1654 1655 if ( wBusIn >= GetNumBussesIn() || 1656 wBusOut >= GetNumBussesOut() ) 1657 { 1658 return ECHOSTATUS_INVALID_INDEX; 1659 } 1660 1661 Status = CheckSetting(iPan,0,MAX_MIXER_PAN); 1662 if (ECHOSTATUS_OK == Status) 1663 { 1664 // 1665 // Set the pan 1666 // 1667 m_MonitorCtrl.SetPan(wBusIn,wBusOut,iPan); 1668 } 1669 1670 return Status; 1671 1672 } // ECHOSTATUS CEchoGals::SetAudioMonitorPan 1673 1674 1675 //=========================================================================== 1676 // 1677 // Get the monitor pan 1678 // 1679 //=========================================================================== 1680 1681 ECHOSTATUS CEchoGals::GetAudioMonitorPan 1682 ( 1683 WORD wBusIn, 1684 WORD wBusOut, 1685 INT32 & iPan // Returns current pan (0 - MAX_MIXER_PAN) 1686 ) 1687 { 1688 if ( wBusIn >= GetNumBussesIn() || 1689 wBusOut >= GetNumBussesOut() ) 1690 { 1691 return ECHOSTATUS_INVALID_INDEX; 1692 } 1693 1694 // 1695 // Get the pan 1696 // 1697 m_MonitorCtrl.GetPan(wBusIn,wBusOut,iPan); 1698 1699 return ECHOSTATUS_OK; 1700 1701 } // ECHOSTATUS CEchoGals::GetAudioMonitorPan 1702 1703 1704 //=========================================================================== 1705 // 1706 // Set the monitor mute 1707 // 1708 //=========================================================================== 1709 1710 ECHOSTATUS CEchoGals::SetAudioMonitorMute 1711 ( 1712 WORD wBusIn, 1713 WORD wBusOut, 1714 BOOL bMute // New state 1715 ) 1716 { 1717 if ( wBusIn >= GetNumBussesIn() || 1718 wBusOut >= GetNumBussesOut() ) 1719 { 1720 return ECHOSTATUS_INVALID_INDEX; 1721 } 1722 1723 // 1724 // Set the mute 1725 // 1726 m_MonitorCtrl.SetMute(wBusIn,wBusOut,bMute); 1727 1728 return ECHOSTATUS_OK; 1729 1730 } // ECHOSTATUS CEchoGals::SetAudioMonitorMute 1731 1732 1733 //=========================================================================== 1734 // 1735 // Get the monitor mute 1736 // 1737 //=========================================================================== 1738 1739 ECHOSTATUS CEchoGals::GetAudioMonitorMute 1740 ( 1741 WORD wBusIn, 1742 WORD wBusOut, 1743 BOOL &bMute // Returns current state 1744 ) 1745 { 1746 if ( wBusIn >= GetNumBussesIn() || 1747 wBusOut >= GetNumBussesOut() ) 1748 { 1749 return ECHOSTATUS_INVALID_INDEX; 1750 } 1751 1752 // 1753 // Get the mute 1754 // 1755 m_MonitorCtrl.GetMute(wBusIn,wBusOut,bMute); 1756 1757 return ECHOSTATUS_OK; 1758 1759 } // ECHOSTATUS CEchoGals::GetAudioMonitorMute 1760 1761 1762 //=========================================================================== 1763 // 1764 // Set the S/PDIF output format to professional or consumer 1765 // 1766 //=========================================================================== 1767 1768 void CEchoGals::SetProfessionalSpdif( BOOL bNewStatus ) 1769 { 1770 ECHO_DEBUGPRINTF(("CEchoGals::SetProfessionalSpdif %d\n",bNewStatus)); 1771 1772 if ( NULL != GetDspCommObject() ) 1773 { 1774 GetDspCommObject()->SetProfessionalSpdif( bNewStatus ); 1775 MixerControlChanged( ECHO_NO_CHANNEL_TYPE, 1776 MXN_SPDIF ); 1777 } 1778 } // void CEchoGals::SetProfessionalSpdif( BOOL bNewStatus ) 1779 1780 1781 //=========================================================================== 1782 // 1783 // Set driver flags 1784 // 1785 // See ECHOGALS_FLAG_??? definitions in EchoGalsXface.h 1786 // 1787 //=========================================================================== 1788 1789 ECHOSTATUS CEchoGals::SetFlags 1790 ( 1791 WORD wFlags 1792 ) 1793 { 1794 // 1795 // Mask off the read-only flags so they don't change 1796 // 1797 wFlags &= ECHOGALS_FLAG_WRITABLE_MASK; 1798 1799 // 1800 // Set the flags & mark the flags as changed 1801 // 1802 m_wFlags |= wFlags; 1803 1804 MixerControlChanged( ECHO_NO_CHANNEL_TYPE, 1805 MXN_FLAGS ); 1806 1807 return ECHOSTATUS_OK; 1808 1809 } // ECHOSTATUS CEchoGals::SetFlags 1810 1811 1812 //=========================================================================== 1813 // 1814 // Clear driver flags 1815 // 1816 // See ECHOGALS_FLAG_??? definitions in EchoGalsXface.h 1817 // 1818 //=========================================================================== 1819 1820 ECHOSTATUS CEchoGals::ClearFlags 1821 ( 1822 WORD wFlags 1823 ) 1824 { 1825 // 1826 // Mask off the read-only flags so they don't change 1827 // 1828 wFlags &= ECHOGALS_FLAG_WRITABLE_MASK; 1829 1830 // 1831 // Clear the flags & mark the flags as changed 1832 // 1833 m_wFlags &= ~wFlags; 1834 1835 MixerControlChanged( ECHO_NO_CHANNEL_TYPE, 1836 MXN_FLAGS ); 1837 1838 return ECHOSTATUS_OK; 1839 1840 } // ECHOSTATUS CEchoGals::ClearFlags 1841 1842 1843 //=========================================================================== 1844 // 1845 // Set the digital mode - currently for Gina24, Layla24, and Mona 1846 // 1847 //=========================================================================== 1848 1849 ECHOSTATUS CEchoGals::SetDigitalMode 1850 ( 1851 BYTE byDigitalMode 1852 ) 1853 { 1854 ECHOSTATUS Status; 1855 BYTE byPreviousDigitalMode; 1856 1857 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() ) 1858 return ECHOSTATUS_DSP_DEAD; 1859 1860 if ( 0 == GetDspCommObject()->GetDigitalModes() ) 1861 return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED; 1862 1863 if ( !m_cmAudioOpen.IsEmpty() ) 1864 { 1865 ECHO_DEBUGPRINTF( ( "CEchoGals::SetDigitalMode() All audio channels " 1866 "must be closed before changing the digital " 1867 "mode\n" ) ); 1868 return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED; 1869 } 1870 byPreviousDigitalMode = GetDspCommObject()->GetDigitalMode(); 1871 Status = GetDspCommObject()->SetDigitalMode( byDigitalMode ); 1872 MixerControlChanged( ECHO_NO_CHANNEL_TYPE, 1873 MXN_DIGITAL_MODE ); 1874 // 1875 // If we successfully changed the digital mode from or to ADAT, then 1876 // make sure all output, input and monitor levels are updated by the 1877 // DSP comm object. 1878 // 1879 if ( ECHOSTATUS_OK == Status && 1880 byPreviousDigitalMode != byDigitalMode && 1881 ( DIGITAL_MODE_ADAT == byPreviousDigitalMode || 1882 DIGITAL_MODE_ADAT == byDigitalMode ) ) 1883 { 1884 WORD i, j,wBus,wPipe; 1885 1886 for ( i = 0; i < GetNumBussesIn(); i++ ) 1887 { 1888 for ( j = 0; j < GetNumBussesOut(); j += 2 ) 1889 { 1890 m_MonitorCtrl.SetGain(i,j,ECHOGAIN_UPDATE,FALSE); 1891 } 1892 } 1893 1894 for ( wBus = 0; wBus < GetNumBussesOut(); wBus++) 1895 { 1896 for ( wPipe = 0; wPipe < GetNumPipesOut(); wPipe++) 1897 { 1898 m_PipeOutCtrl.SetGain(wPipe,wBus,ECHOGAIN_UPDATE,FALSE); 1899 } 1900 } 1901 1902 for ( i = 0; i < GetNumBussesOut(); i++ ) 1903 { 1904 m_BusOutLineLevels[ i ].SetGain(ECHOGAIN_UPDATE,FALSE); 1905 } 1906 1907 for ( i = 0; i < GetNumBussesIn(); i++ ) 1908 { 1909 m_BusInLineLevels[ i ].SetGain( ECHOGAIN_UPDATE ); 1910 } 1911 1912 // 1913 // Now set them all at once, since all the 1914 // fImmediate parameters were set to FALSE. Do the output 1915 // bus _and_ the output pipe in case this is a vmixer card. 1916 // 1917 m_BusOutLineLevels[0].SetGain(ECHOGAIN_UPDATE,TRUE); 1918 m_PipeOutCtrl.SetGain(0,0,ECHOGAIN_UPDATE,TRUE); 1919 } 1920 1921 // 1922 // If the card has just been put in ADAT mode, it is possible 1923 // that the locked sample rate is greater than 48KHz, which is not allowed 1924 // in ADAT mode. If this happens, change the locked rate to 48. 1925 // 1926 if ( (DIGITAL_MODE_ADAT == byDigitalMode) && 1927 (m_wFlags & ECHOGALS_FLAG_SAMPLE_RATE_LOCKED) && 1928 (m_dwLockedSampleRate > 48000) ) 1929 { 1930 m_dwLockedSampleRate = 48000; 1931 } 1932 1933 return Status; 1934 1935 } // ECHOSTATUS CEchoGals::SetDigitalMode( ... ) 1936 1937 1938 /* 1939 1940 The output bus gain controls aren't actually implemented in the hardware; 1941 insted they are virtual controls created by the generic code. 1942 1943 The signal sent to an output bus is a mix of the monitors and output pipes 1944 routed to that bus; the output bus gain is therefore implemented by tweaking 1945 each appropriate monitor and output pipe gain. 1946 1947 */ 1948 1949 1950 //=========================================================================== 1951 // 1952 // Adjust all the monitor levels for a particular output bus 1953 // 1954 // For efficiency, fImmediate is set to FALSE in the call 1955 // to SetGain; all the monitor and pipe out gains are 1956 // sent to the DSP at once by AdjustPipesOutForBusOut. 1957 // 1958 //=========================================================================== 1959 1960 ECHOSTATUS CEchoGals::AdjustMonitorsForBusOut(WORD wBusOut) 1961 { 1962 WORD wBusIn; 1963 1964 // 1965 // Round down to the nearest even bus so the pans work right 1966 // 1967 wBusOut &= 0xfffe; 1968 1969 // 1970 // Poke the monitors 1971 // 1972 for (wBusIn = 0; wBusIn < GetNumBussesIn(); wBusIn++) 1973 { 1974 m_MonitorCtrl.SetGain(wBusIn,wBusOut,ECHOGAIN_UPDATE,FALSE); 1975 } 1976 1977 return ECHOSTATUS_OK; 1978 1979 } // AdjustMonitorsForBusOut 1980 1981 1982 //=========================================================================== 1983 // 1984 // Adjust all the monitor levels for a particular output bus 1985 // 1986 // For efficiency, fImmediate is set to FALSE in the call 1987 // to SetGain; all the monitor and pipe out gains are 1988 // sent to the DSP at once by AdjustPipesOutForBusOut. 1989 // 1990 //=========================================================================== 1991 1992 ECHOSTATUS CEchoGals::AdjustPipesOutForBusOut(WORD wBusOut,int iBusOutGain) 1993 { 1994 ECHO_DEBUGPRINTF(("CEchoGals::AdjustPipesOutForBusOut wBusOut %d iBusOutGain %d\n", 1995 wBusOut, 1996 iBusOutGain)); 1997 1998 // 1999 // Round down to the nearest even bus 2000 // 2001 wBusOut &= 0xfffe; 2002 2003 m_PipeOutCtrl.SetGain(wBusOut,wBusOut,ECHOGAIN_UPDATE,FALSE); 2004 wBusOut++; 2005 m_PipeOutCtrl.SetGain(wBusOut,wBusOut,ECHOGAIN_UPDATE,TRUE); 2006 2007 return ECHOSTATUS_OK; 2008 2009 } // AdjustPipesOutForBusOut 2010 2011 2012