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