BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / audio / echo / generic / CEchoGals_mixer.cpp
blob9aef3243494d34614d7c49dec5632e760bc9364a
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
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.
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.
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
29 // ****************************************************************************
31 #include "CEchoGals.h"
33 #undef ECHO_DEBUGPRINTF
34 #define ECHO_DEBUGPRINTF(x)
36 /****************************************************************************
38 CEchoGals mixer client management
40 ****************************************************************************/
42 //===========================================================================
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.
48 // Valid cookies are non-zero. If you get a zero cookie, the open failed
49 // somehow.
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.
54 //===========================================================================
56 ECHOSTATUS CEchoGals::OpenMixer(NUINT &Cookie)
58 ECHO_MIXER_CLIENT *pTemp;
60 if (m_fMixerDisabled)
61 return ECHOSTATUS_MIXER_DISABLED;
64 // If the cookie is non-zero, then use the specified value
66 if (0 != Cookie)
68 pTemp = m_pMixerClients;
69 while (pTemp != NULL)
71 if (Cookie == pTemp->Cookie)
73 ECHO_DEBUGPRINTF(("CEchoGals::OpenMixer - cookie 0x%lx already in use\n",
74 Cookie));
75 return ECHOSTATUS_BAD_COOKIE;
78 pTemp = pTemp->pNext;
81 else
84 // Make a new cookie
86 ULONGLONG ullTime;
88 m_pOsSupport->OsGetSystemTime(&ullTime);
89 Cookie = (NUINT) ullTime;
90 if (0 == Cookie)
91 Cookie = 1;
94 // Look through the existing mixer client list to ensure that this
95 // cookie is unique.
97 pTemp = m_pMixerClients;
98 while (pTemp != NULL)
100 if (Cookie == pTemp->Cookie)
103 // Oops, someone is already using this cookie. Increment
104 // the new cookie and try again.
106 Cookie++;
107 pTemp = m_pMixerClients;
110 pTemp = pTemp->pNext;
117 // Allocate the mixer client structure
119 ECHO_MIXER_CLIENT *pClient = NULL;
120 ECHOSTATUS Status;
122 Status = OsAllocateNonPaged(sizeof(ECHO_MIXER_CLIENT),(void **) &pClient);
123 if (NULL == pClient)
125 Cookie = 0;
126 return Status;
131 // Store the new cookie and the new mixer client
133 pClient->Cookie = Cookie;
134 pClient->pNext = m_pMixerClients;
135 m_pMixerClients = pClient;
137 return ECHOSTATUS_OK;
139 } // OpenMixer
142 //===========================================================================
144 // Find a mixer client that matches a cookie
146 //===========================================================================
148 ECHO_MIXER_CLIENT *CEchoGals::GetMixerClient(NUINT Cookie)
150 ECHO_MIXER_CLIENT *pTemp;
152 pTemp = m_pMixerClients;
153 while (NULL != pTemp)
155 if (Cookie == pTemp->Cookie)
156 break;
158 pTemp = pTemp->pNext;
161 return pTemp;
163 } // GetMixerClient
166 //===========================================================================
168 // Close the mixer - free the mixer client structure
170 //===========================================================================
172 ECHOSTATUS CEchoGals::CloseMixer(NUINT Cookie)
175 // Search the linked list and remove the client that matches the cookie
177 ECHO_MIXER_CLIENT *pTemp;
179 pTemp = m_pMixerClients;
180 if (NULL == pTemp)
181 return ECHOSTATUS_BAD_COOKIE;
184 // Head of the list?
186 if (pTemp->Cookie == Cookie)
188 m_pMixerClients = pTemp->pNext;
189 OsFreeNonPaged(pTemp);
191 return ECHOSTATUS_OK;
195 // Not the head of the list; search the list
197 while (NULL != pTemp->pNext)
199 if (Cookie == pTemp->pNext->Cookie)
201 ECHO_MIXER_CLIENT *pDeadClient;
203 pDeadClient = pTemp->pNext;
204 pTemp->pNext = pDeadClient->pNext;
205 OsFreeNonPaged(pDeadClient);
207 return ECHOSTATUS_OK;
210 pTemp = pTemp->pNext;
214 // No soup for you!
216 return ECHOSTATUS_BAD_COOKIE;
218 } // CloseMixer
221 //===========================================================================
223 // IsMixerOpen - returns true if at least one client has the mixer open
225 //===========================================================================
227 BOOL CEchoGals::IsMixerOpen()
229 if (NULL == m_pMixerClients)
230 return FALSE;
232 return TRUE;
234 } // IsMixerOpen
237 //===========================================================================
239 // This function is called when a mixer control changes; add the change
240 // to the queue for each client.
242 // Here's what the wCh1 and wCh2 parameters represent, based on the wType
243 // parameter:
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
252 // ECHO_PIPE_IN is not used right now.
254 //===========================================================================
256 ECHOSTATUS CEchoGals::MixerControlChanged
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
264 ECHO_MIXER_CLIENT *pClient = m_pMixerClients;
265 PMIXER_NOTIFY pNotify;
267 if (m_fMixerDisabled)
268 return ECHOSTATUS_MIXER_DISABLED;
271 // Go through all the clients and store this control change
273 while (NULL != pClient)
276 // Search the circular buffer for this client and see if
277 // this control change is already stored
279 DWORD dwIndex,dwCount;
280 BOOL fFound;
282 dwCount = pClient->dwCount;
283 dwIndex = pClient->dwTail;
284 fFound = FALSE;
285 while (dwCount > 0)
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))
294 // Found this notify already in the circular buffer
296 fFound = TRUE;
297 break;
299 dwIndex++;
300 dwIndex &= MAX_MIXER_NOTIFIES - 1;
301 dwCount--;
305 // If the notify was not found, add this notify to the circular buffer if
306 // there is enough room.
308 if ( (FALSE == fFound) &&
309 (pClient->dwCount != MAX_MIXER_NOTIFIES))
311 pNotify = pClient->Notifies + pClient->dwHead;
313 pNotify->wType = wType;
314 pNotify->wParameter = wParameter;
316 if (ECHO_BUS_OUT == wType)
318 pNotify->u.wPipeOut = ECHO_CHANNEL_UNUSED;
319 pNotify->wBusOut = wCh1;
321 else
323 pNotify->u.wPipeOut = wCh1; // can use any union member here also
324 pNotify->wBusOut = wCh2;
327 pClient->dwCount += 1;
328 pClient->dwHead = (pClient->dwHead + 1) & (MAX_MIXER_NOTIFIES - 1);
331 pClient = pClient->pNext;
334 return ECHOSTATUS_OK;
336 } // MixerControlChanged
339 //===========================================================================
341 // This method is called when a client wants to know what controls have
342 // changed.
344 //===========================================================================
346 ECHOSTATUS CEchoGals::GetControlChanges
348 PMIXER_MULTI_NOTIFY pNotifies,
349 NUINT MixerCookie
353 // Match the cookie
355 ECHO_MIXER_CLIENT *pClient = GetMixerClient(MixerCookie);
357 if (NULL == pClient)
359 pNotifies->dwCount = 0;
360 return ECHOSTATUS_BAD_COOKIE;
364 // Copy mixer notifies
366 PMIXER_NOTIFY pDest,pSrc;
367 DWORD dwNumClientNotifies,dwNumReturned;
369 dwNumClientNotifies = pNotifies->dwCount;
370 pDest = pNotifies->Notifies;
371 dwNumReturned = 0;
372 while ( (dwNumClientNotifies > 0) && (pClient->dwCount > 0))
374 pSrc = pClient->Notifies + pClient->dwTail;
376 OsCopyMemory(pDest,pSrc,sizeof(MIXER_NOTIFY));
378 pDest++;
380 pClient->dwTail = (pClient->dwTail + 1) & (MAX_MIXER_NOTIFIES - 1);
381 pClient->dwCount -= 1;
383 dwNumClientNotifies--;
385 dwNumReturned++;
388 pNotifies->dwCount = dwNumReturned;
390 return ECHOSTATUS_OK;
392 } // GetControlChanges
397 /****************************************************************************
399 CEchoGals mixer control
401 ****************************************************************************/
403 //===========================================================================
405 // Process mixer function - service a single mixer function
407 //===========================================================================
409 ECHOSTATUS CEchoGals::ProcessMixerFunction
411 PMIXER_FUNCTION pMixerFunction,
412 INT32 & iRtnDataSz
415 ECHOSTATUS Status = ECHOSTATUS_OK;
417 if (m_fMixerDisabled)
418 return ECHOSTATUS_MIXER_DISABLED;
420 switch ( pMixerFunction->iFunction )
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;
428 case MXF_GET_LEVEL :
429 Status = GetAudioLineLevel( pMixerFunction);
431 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
432 "MXF_GET_LEVEL Status %ld\n", Status) );
434 break;
436 case MXF_SET_LEVEL :
437 Status = SetAudioLineLevel( pMixerFunction);
438 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
439 "MXF_SET_LEVEL Status %ld\n", Status) );
440 break;
442 case MXF_GET_NOMINAL :
443 Status = GetAudioNominal( pMixerFunction);
445 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
446 "MXF_GET_NOMINAL Status %ld\n", Status) );
448 break;
450 case MXF_SET_NOMINAL :
451 Status = SetAudioNominal( pMixerFunction);
452 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
453 "MXF_SET_NOMINAL Status %ld\n", Status) );
454 break;
456 case MXF_GET_MONITOR :
457 Status = GetAudioMonitor( pMixerFunction->Channel.wChannel,
458 pMixerFunction->Data.Monitor.wBusOut,
459 pMixerFunction->Data.Monitor.Data.iLevel );
461 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
462 "MXF_GET_MONITOR Status %ld\n", Status) );
464 break;
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;
474 case MXF_GET_CLOCK_DETECT :
475 Status = GetInputClockDetect( pMixerFunction->Data.dwClockDetectBits );
476 break;
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;
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;
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;
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;
504 case MXF_GET_METERS :
506 if (NULL != GetDspCommObject())
508 Status = GetDspCommObject()->
509 GetAudioMeters( &pMixerFunction->Data.Meters );
511 else
513 Status = ECHOSTATUS_DSP_DEAD;
516 //ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
517 // "MXF_GET_METERS Status %ld\n", Status) );
518 break;
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;
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;
532 case MXF_GET_PROF_SPDIF :
533 if ( ECHOSTATUS_DSP_DEAD == IsProfessionalSpdif() )
535 Status = ECHOSTATUS_DSP_DEAD;
537 else
539 pMixerFunction->Data.bProfSpdif = IsProfessionalSpdif();
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;
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;
555 case MXF_GET_MUTE :
556 Status = GetAudioMute(pMixerFunction);
558 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
559 "MXF_GET_MUTE Status %ld\n", Status) );
561 break;
563 case MXF_SET_MUTE :
564 Status = SetAudioMute(pMixerFunction);
565 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
566 "MXF_SET_MUTE Status %ld\n", Status) );
567 break;
569 case MXF_GET_MONITOR_MUTE :
570 Status =
571 GetAudioMonitorMute( pMixerFunction->Channel.wChannel,
572 pMixerFunction->Data.Monitor.wBusOut,
573 pMixerFunction->Data.Monitor.Data.bMuteOn );
575 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
576 "MXF_GET_MONITOR_MUTE Status %ld\n", Status) );
578 break;
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;
589 case MXF_GET_MONITOR_PAN :
590 Status =
591 GetAudioMonitorPan( pMixerFunction->Channel.wChannel,
592 pMixerFunction->Data.Monitor.wBusOut,
593 pMixerFunction->Data.Monitor.Data.iPan);
596 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
597 "MXF_GET_MONITOR_PAN Status %ld\n", Status) );
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;
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;
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;
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;
648 case MXF_GET_SAMPLERATE :
650 GetAudioSampleRate( &pMixerFunction->Data.dwSampleRate );
652 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
653 "MXF_GET_SAMPLERATE 0x%lx Status %ld\n",
654 pMixerFunction->Data.dwSampleRate,
655 Status) );
656 break;
658 #ifdef MIDI_SUPPORT
660 case MXF_GET_MIDI_IN_ACTIVITY :
661 pMixerFunction->Data.bMidiActive = m_MidiIn.IsActive();
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;
672 case MXF_GET_MIDI_OUT_ACTIVITY :
673 pMixerFunction->Data.bMidiActive =
674 GetDspCommObject()->IsMidiOutActive();
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;
684 #endif // MIDI_SUPPORT
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;
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;
718 case MXF_GET_PAN :
719 Status = GetAudioPan( pMixerFunction);
720 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
721 "MXF_GET_PAN Status %ld\n", Status) );
722 break;
724 case MXF_SET_PAN :
725 Status = SetAudioPan( pMixerFunction);
726 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
727 "MXF_SET_PAN Status %ld\n", Status) );
728 break;
730 #ifdef DIGITAL_INPUT_AUTO_MUTE_SUPPORT
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;
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;
745 #endif // DIGITAL_INPUT_AUTO_MUTE_SUPPORT
747 case MXF_GET_AUDIO_LATENCY :
748 GetAudioLatency( &(pMixerFunction->Data.Latency) );
749 break;
751 #ifdef PHANTOM_POWER_CONTROL
753 case MXF_GET_PHANTOM_POWER :
754 GetPhantomPower( &(pMixerFunction->Data.fPhantomPower) );
755 break;
757 case MXF_SET_PHANTOM_POWER :
758 SetPhantomPower( pMixerFunction->Data.fPhantomPower );
759 break;
761 #endif
763 default :
764 iRtnDataSz = 0;
765 ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
766 "Function %ld not supported\n",
767 pMixerFunction->iFunction) );
768 return ECHOSTATUS_NOT_SUPPORTED;
771 pMixerFunction->RtnStatus = Status;
772 iRtnDataSz = sizeof( MIXER_FUNCTION );
774 return Status;
776 } // ECHOSTATUS CEchoGals::ProcessMixerFunction
781 //===========================================================================
783 // Process multiple mixer functions
785 //===========================================================================
787 ECHOSTATUS CEchoGals::ProcessMixerMultiFunction
789 PMIXER_MULTI_FUNCTION pMixerFunctions, // Request from mixer
790 INT32 & iRtnDataSz // # bytes returned (if any)
793 ECHOSTATUS Status = ECHOSTATUS_NOT_SUPPORTED;
794 PMIXER_FUNCTION pMixerFunction;
795 INT32 iRtn, nCard, i;
797 if (m_fMixerDisabled)
798 return ECHOSTATUS_MIXER_DISABLED;
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++ )
805 pMixerFunction = &pMixerFunctions->MixerFunction[ i ];
806 if ( nCard != pMixerFunction->Channel.wCardId )
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;
816 Status = ProcessMixerFunction(pMixerFunction,iRtn);
817 iRtnDataSz += iRtn;
820 return Status;
822 } // ECHOSTATUS CEchoGals::ProcessMixerMultiFunction
827 //===========================================================================
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.
834 //===========================================================================
836 ECHOSTATUS CEchoGals::GetPolledStuff
838 ECHO_POLLED_STUFF *pPolledStuff,
839 NUINT MixerCookie
842 ECHO_MIXER_CLIENT *pClient;
843 CDspCommObject *pDCO = GetDspCommObject();
845 if (m_fMixerDisabled)
846 return ECHOSTATUS_MIXER_DISABLED;
848 if (NULL == pDCO)
849 return ECHOSTATUS_DSP_DEAD;
852 // Fill out the non-client-specific portions of the struct
854 pDCO->GetAudioMeters(&(pPolledStuff->Meters));
855 GetInputClockDetect(pPolledStuff->dwClockDetectBits);
858 // If there is a matching client, fill out the number
859 // of notifies
861 pClient = GetMixerClient(MixerCookie);
862 if (NULL == pClient)
863 pPolledStuff->dwNumPendingNotifies = 0;
864 else
865 pPolledStuff->dwNumPendingNotifies = pClient->dwCount;
867 return ECHOSTATUS_OK;
869 } // GetPolledStuff
872 //===========================================================================
874 // Get the pan setting for an output pipe (virtual outputs only)
876 //===========================================================================
878 ECHOSTATUS CEchoGals::GetAudioPan
880 PMIXER_FUNCTION pMF
883 WORD wPipe;
884 WORD wBus;
885 ECHOSTATUS Status;
887 if ( (pMF->Channel.dwType != ECHO_PIPE_OUT) ||
888 ( !HasVmixer() ) )
889 return ECHOSTATUS_INVALID_CHANNEL;
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);
897 return Status;
899 } // ECHOSTATUS CEchoGals::GetAudioPan
902 //===========================================================================
904 // Set the pan for an output pipe (virtual outputs only)
906 //===========================================================================
908 ECHOSTATUS CEchoGals::SetAudioPan
910 PMIXER_FUNCTION pMF
913 WORD wPipe;
914 WORD wBus;
915 ECHOSTATUS Status;
917 if ( (pMF->Channel.dwType != ECHO_PIPE_OUT) ||
918 ( !HasVmixer() ) )
919 return ECHOSTATUS_INVALID_CHANNEL;
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);
927 return Status;
929 } // ECHOSTATUS CEchoGals::SetAudioPan
934 /****************************************************************************
936 CEchoGals clock control
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.
941 Output clock is only supported on Layla20 - Layla20 can transmit either
942 word or super clock.
944 ****************************************************************************/
946 //===========================================================================
948 // Get input and output clocks - just return the stored value
950 //===========================================================================
952 ECHOSTATUS CEchoGals::GetInputClock(WORD &wClock)
954 if ( NULL == GetDspCommObject() )
955 return ECHOSTATUS_DSP_DEAD;
957 wClock = GetDspCommObject()->GetInputClock();
959 return ECHOSTATUS_OK;
963 ECHOSTATUS CEchoGals::GetOutputClock(WORD &wClock)
965 if ( NULL == GetDspCommObject() )
966 return ECHOSTATUS_DSP_DEAD;
968 wClock = GetDspCommObject()->GetOutputClock();
970 return ECHOSTATUS_OK;
974 //===========================================================================
976 // Set input and output clocks - pass it down to the comm page and
977 // store the control change.
979 //===========================================================================
981 ECHOSTATUS CEchoGals::SetInputClock(WORD wClock)
983 ECHOSTATUS Status;
985 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
986 return ECHOSTATUS_DSP_DEAD;
988 ECHO_DEBUGPRINTF( ("CEchoGals::SetInputClock: ") );
990 Status = GetDspCommObject()->SetInputClock( wClock );
992 if (ECHOSTATUS_OK == Status)
994 MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
995 MXN_INPUT_CLOCK);
997 return Status;
999 } // SetInputClock
1002 ECHOSTATUS CEchoGals::SetOutputClock(WORD wClock)
1004 ECHOSTATUS Status;
1006 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
1007 return ECHOSTATUS_DSP_DEAD;
1009 ECHO_DEBUGPRINTF( ("CEchoGals::SetOutputClock: ") );
1011 Status = GetDspCommObject()->SetOutputClock( wClock );
1013 if (ECHOSTATUS_OK == Status)
1015 MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
1016 MXN_OUTPUT_CLOCK);
1018 return Status;
1023 //===========================================================================
1025 // Get the currently detected clock bits - default method. Overridden by
1026 // derived card classes.
1028 //===========================================================================
1030 ECHOSTATUS CEchoGals::GetInputClockDetect(DWORD &dwClockDetectBits)
1032 dwClockDetectBits = ECHO_CLOCK_INTERNAL;
1034 return ECHOSTATUS_OK;
1038 //===========================================================================
1040 // Set the locked sample rate
1042 //===========================================================================
1044 ECHOSTATUS CEchoGals::SetAudioLockedSampleRate
1046 DWORD dwSampleRate
1049 ECHOSTATUS Status;
1051 Status = QueryAudioSampleRate( dwSampleRate );
1052 if ( ECHOSTATUS_OK != Status )
1053 return Status;
1055 if (0 != (ECHOGALS_FLAG_SAMPLE_RATE_LOCKED & GetFlags()))
1057 GetDspCommObject()->SetSampleRate( dwSampleRate );
1058 m_dwSampleRate = dwSampleRate;
1061 m_dwLockedSampleRate = dwSampleRate;
1063 return ECHOSTATUS_OK;
1065 } // ECHOSTATUS CEchoGals::SetAudioLockedSampleRate
1068 //===========================================================================
1070 // Get the locked sample rate
1072 //===========================================================================
1074 ECHOSTATUS CEchoGals::GetAudioLockedSampleRate
1076 DWORD &dwSampleRate
1079 dwSampleRate = m_dwLockedSampleRate;
1081 return ECHOSTATUS_OK;
1083 } // ECHOSTATUS CEchoGals::GetAudioLockedSampleRate
1087 #ifdef DIGITAL_INPUT_AUTO_MUTE_SUPPORT
1089 //===========================================================================
1091 // Get the digital input auto mute flag from the comm page
1093 //===========================================================================
1095 ECHOSTATUS CEchoGals::GetDigitalInAutoMute(PMIXER_FUNCTION pMixerFunction)
1097 BOOL fAutoMute;
1099 if (0 == (m_wFlags & ECHOGALS_ROFLAG_DIGITAL_IN_AUTOMUTE))
1101 pMixerFunction->Data.fDigitalInAutoMute = FALSE;
1102 return ECHOSTATUS_NOT_SUPPORTED;
1105 GetDspCommObject()->GetDigitalInputAutoMute( fAutoMute );
1106 pMixerFunction->Data.fDigitalInAutoMute = fAutoMute;
1108 return ECHOSTATUS_OK;
1110 } // GetDigitalInAutoMute
1113 //===========================================================================
1115 // Set the digital input auto mute flag
1117 //===========================================================================
1119 ECHOSTATUS CEchoGals::SetDigitalInAutoMute(PMIXER_FUNCTION pMixerFunction)
1121 BOOL fAutoMute;
1123 if (0 == (m_wFlags & ECHOGALS_ROFLAG_DIGITAL_IN_AUTOMUTE))
1124 return ECHOSTATUS_NOT_SUPPORTED;
1126 fAutoMute = pMixerFunction->Data.fDigitalInAutoMute;
1127 GetDspCommObject()->SetDigitalInputAutoMute( fAutoMute );
1129 return ECHOSTATUS_OK;
1131 } // SetDigitalInAutoMute
1133 #endif // DIGITAL_INPUT_AUTO_MUTE_SUPPORT
1136 //===========================================================================
1138 // Get the gain for an output bus, input bus, or output pipe.
1140 // Gain levels are in units of dB * 256.
1142 //===========================================================================
1144 ECHOSTATUS CEchoGals::GetAudioLineLevel
1146 PMIXER_FUNCTION pMF
1149 WORD wPipe;
1150 WORD wBus;
1151 ECHOSTATUS Status;
1153 switch (pMF->Channel.dwType)
1155 case ECHO_BUS_OUT :
1157 wBus = pMF->Channel.wChannel;
1159 if (wBus < GetNumBussesOut())
1161 pMF->Data.iLevel = m_BusOutLineLevels[wBus].GetGain();
1162 Status = ECHOSTATUS_OK;
1164 else
1166 Status = ECHOSTATUS_INVALID_CHANNEL;
1169 break;
1171 case ECHO_BUS_IN :
1173 wBus = pMF->Channel.wChannel;
1174 if (wBus < GetNumBussesIn())
1176 pMF->Data.iLevel = m_BusInLineLevels[wBus].GetGain();
1177 Status = ECHOSTATUS_OK;
1179 else
1181 Status = ECHOSTATUS_INVALID_CHANNEL;
1183 break;
1185 case ECHO_PIPE_OUT :
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;
1194 default:
1195 Status = ECHOSTATUS_INVALID_PARAM;
1196 break;
1199 return Status;
1201 } // ECHOSTATUS CEchoGals::GetAudioLineLevel
1204 //===========================================================================
1206 // Utility function to check that a setting is within the correct range.
1208 //===========================================================================
1210 ECHOSTATUS CheckSetting(INT32 iValue,INT32 iMin,INT32 iMax)
1212 if ( (iValue > iMax) || (iValue < iMin))
1213 return ECHOSTATUS_INVALID_PARAM;
1215 return ECHOSTATUS_OK;
1217 } // CheckSetting
1220 //===========================================================================
1222 // Set the gain for an output bus, input bus, or output pipe.
1224 // Gain levels are in units of dB * 256.
1226 //===========================================================================
1228 ECHOSTATUS CEchoGals::SetAudioLineLevel
1230 PMIXER_FUNCTION pMF
1233 WORD wPipe;
1234 WORD wBus;
1235 ECHOSTATUS Status;
1236 INT32 iLevel;
1238 switch (pMF->Channel.dwType)
1240 case ECHO_BUS_OUT :
1242 wBus = pMF->Channel.wChannel;
1243 iLevel = pMF->Data.iLevel;
1245 Status = CheckSetting(iLevel,ECHOGAIN_MINOUT,ECHOGAIN_MAXOUT);
1246 if (ECHOSTATUS_OK != Status)
1247 break;
1249 Status = m_BusOutLineLevels[wBus].SetGain(iLevel);
1250 break;
1252 case ECHO_BUS_IN :
1254 wBus = pMF->Channel.wChannel;
1255 iLevel = pMF->Data.iLevel;
1257 Status = CheckSetting(iLevel,ECHOGAIN_MININP,ECHOGAIN_MAXINP);
1258 if (ECHOSTATUS_OK != Status)
1259 break;
1261 Status = m_BusInLineLevels[wBus].SetGain(iLevel);
1262 break;
1264 case ECHO_PIPE_OUT :
1266 wPipe = pMF->Channel.wChannel;
1267 wBus = pMF->Data.PipeOut.wBusOut;
1268 iLevel = pMF->Data.PipeOut.Data.iLevel;
1270 Status = CheckSetting(iLevel,ECHOGAIN_MINOUT,ECHOGAIN_MAXOUT);
1271 if (ECHOSTATUS_OK != Status)
1272 break;
1274 Status = m_PipeOutCtrl.SetGain( wPipe,
1275 wBus,
1276 iLevel);
1277 break;
1279 default:
1280 Status = ECHOSTATUS_INVALID_PARAM;
1281 break;
1284 return Status;
1286 } // ECHOSTATUS CEchoGals::SetAudioLineLevel
1289 //===========================================================================
1291 // Get the nominal level for an output or input bus. The nominal level is
1292 // also referred to as the +4/-10 switch.
1294 //===========================================================================
1296 ECHOSTATUS CEchoGals::GetAudioNominal
1298 PMIXER_FUNCTION pMF
1301 BYTE byNominal;
1302 ECHOSTATUS Status;
1303 CDspCommObject * pDspCommObj = GetDspCommObject();
1304 WORD wCh;
1306 if ( NULL == pDspCommObj || pDspCommObj->IsBoardBad() )
1307 return ECHOSTATUS_DSP_DEAD;
1309 switch (pMF->Channel.dwType)
1311 case ECHO_BUS_OUT :
1312 wCh = pMF->Channel.wChannel;
1313 break;
1315 case ECHO_BUS_IN :
1316 wCh = pMF->Channel.wChannel + GetNumBussesOut();
1317 break;
1319 default :
1320 return ECHOSTATUS_INVALID_CHANNEL;
1323 Status = pDspCommObj->GetNominalLevel( wCh, &byNominal );
1325 if ( ECHOSTATUS_OK != Status )
1326 return Status;
1328 pMF->Data.iNominal = ( byNominal ) ? -10 : 4;
1330 return ECHOSTATUS_OK;
1331 } // ECHOSTATUS CEchoGals::GetAudioNominal
1334 //===========================================================================
1336 // Set the nominal level for an output or input bus. The nominal level is
1337 // also referred to as the +4/-10 switch.
1339 //===========================================================================
1341 ECHOSTATUS CEchoGals::SetAudioNominal
1343 PMIXER_FUNCTION pMF
1346 ECHOSTATUS Status;
1347 WORD wCh;
1348 INT32 iNominal;
1350 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
1351 return ECHOSTATUS_DSP_DEAD;
1353 switch (pMF->Channel.dwType)
1355 case ECHO_BUS_OUT :
1356 wCh = pMF->Channel.wChannel;
1357 break;
1359 case ECHO_BUS_IN :
1360 wCh = pMF->Channel.wChannel + GetNumBussesOut();
1361 break;
1363 default :
1364 return ECHOSTATUS_INVALID_CHANNEL;
1367 iNominal = pMF->Data.iNominal;
1369 if ((iNominal!= -10) && (iNominal != 4))
1370 return ECHOSTATUS_INVALID_PARAM;
1372 Status =
1373 GetDspCommObject()->SetNominalLevel( wCh,
1374 ( iNominal == -10 ) );
1376 if ( ECHOSTATUS_OK != Status )
1377 return Status;
1379 Status = MixerControlChanged( (WORD) pMF->Channel.dwType,
1380 MXN_NOMINAL,
1381 pMF->Channel.wChannel);
1382 return Status;
1384 } // ECHOSTATUS CEchoGals::SetAudioNominal
1387 //===========================================================================
1389 // Set the mute for an output bus, input bus, or output pipe.
1391 //===========================================================================
1393 ECHOSTATUS CEchoGals::SetAudioMute
1395 PMIXER_FUNCTION pMF
1398 WORD wPipe;
1399 WORD wBus;
1400 ECHOSTATUS Status;
1401 BOOL bMute;
1403 switch (pMF->Channel.dwType)
1405 case ECHO_BUS_OUT :
1407 wBus = pMF->Channel.wChannel;
1408 bMute = pMF->Data.bMuteOn;
1409 Status = m_BusOutLineLevels[wBus].SetMute(bMute);
1410 break;
1412 case ECHO_BUS_IN :
1414 wBus = pMF->Channel.wChannel;
1415 bMute = pMF->Data.bMuteOn;
1416 Status = m_BusInLineLevels[wBus].SetMute(bMute);
1417 break;
1419 case ECHO_PIPE_OUT :
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;
1429 default:
1430 Status = ECHOSTATUS_INVALID_PARAM;
1431 break;
1434 return Status;
1435 } // ECHOSTATUS CEchoGals::SetAudioMute
1438 //===========================================================================
1440 // Get the mute for an output bus, input bus, or output pipe.
1442 //===========================================================================
1444 ECHOSTATUS CEchoGals::GetAudioMute
1446 PMIXER_FUNCTION pMF
1449 WORD wPipe;
1450 WORD wBus;
1451 ECHOSTATUS Status;
1453 switch (pMF->Channel.dwType)
1455 case ECHO_BUS_OUT :
1457 wBus = pMF->Channel.wChannel;
1459 if (wBus < GetNumBussesOut())
1461 pMF->Data.bMuteOn = m_BusOutLineLevels[wBus].IsMuteOn();
1462 Status = ECHOSTATUS_OK;
1464 else
1466 Status = ECHOSTATUS_INVALID_CHANNEL;
1469 break;
1471 case ECHO_BUS_IN :
1473 wBus = pMF->Channel.wChannel;
1475 if (wBus < GetNumBussesIn())
1477 pMF->Data.bMuteOn = m_BusInLineLevels[wBus].IsMuteOn();
1478 Status = ECHOSTATUS_OK;
1480 else
1482 Status = ECHOSTATUS_INVALID_CHANNEL;
1484 break;
1486 case ECHO_PIPE_OUT :
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;
1495 default:
1496 Status = ECHOSTATUS_INVALID_PARAM;
1497 break;
1500 return Status;
1502 } // ECHOSTATUS CEchoGals::GetAudioMute
1505 //===========================================================================
1507 // Get the monitor gain for a single input bus mixed to a single output bus.
1509 //===========================================================================
1511 ECHOSTATUS CEchoGals::GetAudioMonitor
1513 WORD wBusIn,
1514 WORD wBusOut,
1515 INT32 & iGain
1518 if ( wBusIn >= GetNumBussesIn() ||
1519 wBusOut >= GetNumBussesOut() )
1521 return ECHOSTATUS_INVALID_INDEX;
1525 // Get the monitor value
1527 m_MonitorCtrl.GetGain(wBusIn,wBusOut,iGain);
1529 return ECHOSTATUS_OK;
1531 } // ECHOSTATUS CEchoGals::GetAudioMonitor
1534 //===========================================================================
1536 // Set the monitor gain for a single input bus mixed to a single output bus.
1538 //===========================================================================
1540 ECHOSTATUS CEchoGals::SetAudioMonitor
1542 WORD wBusIn,
1543 WORD wBusOut,
1544 INT32 iGain
1547 ECHOSTATUS Status;
1549 if ( wBusIn >= GetNumBussesIn() ||
1550 wBusOut >= GetNumBussesOut() )
1552 return ECHOSTATUS_INVALID_INDEX;
1555 Status = CheckSetting(iGain,ECHOGAIN_MINOUT,ECHOGAIN_MAXOUT);
1556 if (ECHOSTATUS_OK == Status)
1559 // Set the monitor gain
1561 m_MonitorCtrl.SetGain(wBusIn,wBusOut,iGain);
1564 return Status;
1566 } // ECHOSTATUS CEchoGals::SetAudioMonitor
1569 //===========================================================================
1571 // Helper functions for doing log conversions on pan values
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
1577 // Valid range for iNum is from +1.0 (0x10000) to 0.
1579 //===========================================================================
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
1587 #define DB_CONVERT 0x60546 // 6.02... in 16.16
1589 // Note use of double precision here to prevent overflow
1590 static INT32 FixedMult( INT32 iNum1, INT32 iNum2 )
1592 LONGLONG llNum;
1594 llNum = (LONGLONG) iNum1 * (LONGLONG) iNum2;
1596 return (INT32) (llNum >> FIXED_BASE);
1597 } // INT32 FixedMult( INT32 iNum1, INT32 iNum2 )
1600 static INT32 log2( INT32 iNum )
1602 INT32 iNumShifts;
1603 INT32 iTemp;
1605 // log2 is undefined for zero, so return -infinity (or close enough)
1606 if ( 0 == iNum )
1607 return ECHOGAIN_MUTED;
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 )
1614 iNumShifts++;
1615 iNum <<= 1;
1618 // Step 2 - Calculate LOG2 by polynomial approximation. 8 bit accuracy.
1620 // LOG2(x) = 4.0* (-.3372223 x*x + .9981958 x - .6626105)
1621 // a2 a1 a0
1622 // where 0.5 <= x < 1.0
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;
1631 // Multiply by four
1632 iTemp <<= 2;
1634 // Account for the normalize shifts
1635 iTemp -= ( iNumShifts << FIXED_BASE );
1637 return( iTemp );
1638 } // INT32 log2( INT32 iNum )
1642 // Convert pan value to Db X 256
1643 // Pan value is 0 - MAX_MIXER_PAN
1645 INT32 PanToDb( INT32 iPan )
1647 if ( iPan >= ( MAX_MIXER_PAN - 1 ) )
1648 return( 0 );
1649 if ( iPan <= 1 )
1650 return( ECHOGAIN_MUTED );
1652 // Convert pan to 16.16
1654 iPan = ( iPan << 16 ) / MAX_MIXER_PAN;
1656 // Take the log
1658 iPan = log2( iPan );
1660 // To convert to decibels*256, just multiply by the conversion factor
1662 iPan = FixedMult( iPan << 8, DB_CONVERT );
1664 // To round, add one half and then mask off the fractional bits
1666 iPan = ( iPan + FIXED_ONE_HALF ) >> FIXED_BASE;
1667 return( iPan );
1668 } // INT32 PanToDb( INT32 iPan )
1671 //===========================================================================
1673 // Set the monitor pan
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.
1680 // iPan ranges from 0 (hard left) to MAX_MIXER_PAN (hard right)
1682 //===========================================================================
1684 ECHOSTATUS CEchoGals::SetAudioMonitorPan
1686 WORD wBusIn,
1687 WORD wBusOut,
1688 INT32 iPan // New pan
1691 ECHOSTATUS Status;
1693 if ( wBusIn >= GetNumBussesIn() ||
1694 wBusOut >= GetNumBussesOut() )
1696 return ECHOSTATUS_INVALID_INDEX;
1699 Status = CheckSetting(iPan,0,MAX_MIXER_PAN);
1700 if (ECHOSTATUS_OK == Status)
1703 // Set the pan
1705 m_MonitorCtrl.SetPan(wBusIn,wBusOut,iPan);
1708 return Status;
1710 } // ECHOSTATUS CEchoGals::SetAudioMonitorPan
1713 //===========================================================================
1715 // Get the monitor pan
1717 //===========================================================================
1719 ECHOSTATUS CEchoGals::GetAudioMonitorPan
1721 WORD wBusIn,
1722 WORD wBusOut,
1723 INT32 & iPan // Returns current pan (0 - MAX_MIXER_PAN)
1726 if ( wBusIn >= GetNumBussesIn() ||
1727 wBusOut >= GetNumBussesOut() )
1729 return ECHOSTATUS_INVALID_INDEX;
1733 // Get the pan
1735 m_MonitorCtrl.GetPan(wBusIn,wBusOut,iPan);
1737 return ECHOSTATUS_OK;
1739 } // ECHOSTATUS CEchoGals::GetAudioMonitorPan
1742 //===========================================================================
1744 // Set the monitor mute
1746 //===========================================================================
1748 ECHOSTATUS CEchoGals::SetAudioMonitorMute
1750 WORD wBusIn,
1751 WORD wBusOut,
1752 BOOL bMute // New state
1755 if ( wBusIn >= GetNumBussesIn() ||
1756 wBusOut >= GetNumBussesOut() )
1758 return ECHOSTATUS_INVALID_INDEX;
1762 // Set the mute
1764 m_MonitorCtrl.SetMute(wBusIn,wBusOut,bMute);
1766 return ECHOSTATUS_OK;
1768 } // ECHOSTATUS CEchoGals::SetAudioMonitorMute
1771 //===========================================================================
1773 // Get the monitor mute
1775 //===========================================================================
1777 ECHOSTATUS CEchoGals::GetAudioMonitorMute
1779 WORD wBusIn,
1780 WORD wBusOut,
1781 BOOL &bMute // Returns current state
1784 if ( wBusIn >= GetNumBussesIn() ||
1785 wBusOut >= GetNumBussesOut() )
1787 return ECHOSTATUS_INVALID_INDEX;
1791 // Get the mute
1793 m_MonitorCtrl.GetMute(wBusIn,wBusOut,bMute);
1795 return ECHOSTATUS_OK;
1797 } // ECHOSTATUS CEchoGals::GetAudioMonitorMute
1800 //===========================================================================
1802 // Set the S/PDIF output format to professional or consumer
1804 //===========================================================================
1806 void CEchoGals::SetProfessionalSpdif( BOOL bNewStatus )
1808 ECHO_DEBUGPRINTF(("CEchoGals::SetProfessionalSpdif %d\n",bNewStatus));
1810 if ( NULL != GetDspCommObject() )
1812 GetDspCommObject()->SetProfessionalSpdif( bNewStatus );
1813 MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
1814 MXN_SPDIF );
1816 } // void CEchoGals::SetProfessionalSpdif( BOOL bNewStatus )
1819 //===========================================================================
1821 // Set driver flags
1823 // See ECHOGALS_FLAG_??? definitions in EchoGalsXface.h
1825 //===========================================================================
1827 ECHOSTATUS CEchoGals::SetFlags
1829 WORD wFlags
1833 // Mask off the read-only flags so they don't change
1835 wFlags &= ECHOGALS_FLAG_WRITABLE_MASK;
1838 // Set the flags & mark the flags as changed
1840 m_wFlags |= wFlags;
1842 MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
1843 MXN_FLAGS );
1845 return ECHOSTATUS_OK;
1847 } // ECHOSTATUS CEchoGals::SetFlags
1850 //===========================================================================
1852 // Clear driver flags
1854 // See ECHOGALS_FLAG_??? definitions in EchoGalsXface.h
1856 //===========================================================================
1858 ECHOSTATUS CEchoGals::ClearFlags
1860 WORD wFlags
1864 // Mask off the read-only flags so they don't change
1866 wFlags &= ECHOGALS_FLAG_WRITABLE_MASK;
1869 // Clear the flags & mark the flags as changed
1871 m_wFlags &= ~wFlags;
1873 MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
1874 MXN_FLAGS );
1876 return ECHOSTATUS_OK;
1878 } // ECHOSTATUS CEchoGals::ClearFlags
1881 //===========================================================================
1883 // Set the digital mode - currently for Gina24, Layla24, and Mona
1885 //===========================================================================
1887 ECHOSTATUS CEchoGals::SetDigitalMode
1889 BYTE byDigitalMode
1892 ECHOSTATUS Status;
1893 BYTE byPreviousDigitalMode;
1895 if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
1896 return ECHOSTATUS_DSP_DEAD;
1898 if ( 0 == GetDspCommObject()->GetDigitalModes() )
1899 return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED;
1901 if ( TRUE == GetDspCommObject()->IsTransportActive() )
1903 ECHO_DEBUGPRINTF( ( "CEchoGals::SetDigitalMode() Cannot set the digital "
1904 "mode while transport is running\n"));
1905 return ECHOSTATUS_BUSY;
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 );
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.
1919 if ( ECHOSTATUS_OK == Status &&
1920 byPreviousDigitalMode != byDigitalMode &&
1921 ( DIGITAL_MODE_ADAT == byPreviousDigitalMode ||
1922 DIGITAL_MODE_ADAT == byDigitalMode ) )
1924 WORD i, j,wBus,wPipe;
1926 for ( i = 0; i < GetNumBussesIn(); i++ )
1928 for ( j = 0; j < GetNumBussesOut(); j += 2 )
1930 m_MonitorCtrl.SetGain(i,j,ECHOGAIN_UPDATE,FALSE);
1934 for ( wBus = 0; wBus < GetNumBussesOut(); wBus++)
1936 for ( wPipe = 0; wPipe < GetNumPipesOut(); wPipe++)
1938 m_PipeOutCtrl.SetGain(wPipe,wBus,ECHOGAIN_UPDATE,FALSE);
1942 for ( i = 0; i < GetNumBussesOut(); i++ )
1944 m_BusOutLineLevels[ i ].SetGain(ECHOGAIN_UPDATE,FALSE);
1947 for ( i = 0; i < GetNumBussesIn(); i++ )
1949 m_BusInLineLevels[ i ].SetGain( ECHOGAIN_UPDATE );
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.
1957 m_BusOutLineLevels[0].SetGain(ECHOGAIN_UPDATE,TRUE);
1958 m_PipeOutCtrl.SetGain(0,0,ECHOGAIN_UPDATE,TRUE);
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.
1966 if ( (DIGITAL_MODE_ADAT == byDigitalMode) &&
1967 (m_wFlags & ECHOGALS_FLAG_SAMPLE_RATE_LOCKED) &&
1968 (m_dwLockedSampleRate > 48000) )
1970 m_dwLockedSampleRate = 48000;
1973 return Status;
1975 } // ECHOSTATUS CEchoGals::SetDigitalMode( ... )
1980 The output bus gain controls aren't actually implemented in the hardware;
1981 insted they are virtual controls created by the generic code.
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.
1990 //===========================================================================
1992 // Adjust all the monitor levels for a particular output bus
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.
1998 //===========================================================================
2000 ECHOSTATUS CEchoGals::AdjustMonitorsForBusOut(WORD wBusOut)
2002 WORD wBusIn;
2005 // Poke the monitors
2007 for (wBusIn = 0; wBusIn < GetNumBussesIn(); wBusIn++)
2009 m_MonitorCtrl.SetGain(wBusIn,wBusOut,ECHOGAIN_UPDATE,FALSE);
2012 return ECHOSTATUS_OK;
2014 } // AdjustMonitorsForBusOut
2017 //===========================================================================
2019 // Adjust all the pipe out levels for a particular output bus
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.
2025 //===========================================================================
2027 ECHOSTATUS CEchoGals::AdjustPipesOutForBusOut(WORD wBusOut,INT32 iBusOutGain)
2029 ECHO_DEBUGPRINTF(("CEchoGals::AdjustPipesOutForBusOut wBusOut %d iBusOutGain %ld\n",
2030 wBusOut,
2031 iBusOutGain));
2034 // Round down to the nearest even bus
2036 wBusOut &= 0xfffe;
2038 m_PipeOutCtrl.SetGain(wBusOut,wBusOut,ECHOGAIN_UPDATE,FALSE);
2039 wBusOut++;
2040 m_PipeOutCtrl.SetGain(wBusOut,wBusOut,ECHOGAIN_UPDATE,TRUE);
2042 return ECHOSTATUS_OK;
2044 } // AdjustPipesOutForBusOut
2048 //===========================================================================
2050 // GetAudioLatency - returns the latency for a single pipe
2052 //===========================================================================
2054 void CEchoGals::GetAudioLatency(ECHO_AUDIO_LATENCY *pLatency)
2056 DWORD dwLatency;
2058 if (FALSE == pLatency->wIsInput)
2060 if (pLatency->wPipe >= GetFirstDigitalBusOut())
2061 dwLatency = m_wDigitalOutputLatency;
2062 else
2063 dwLatency = m_wAnalogOutputLatency;
2065 else
2067 if (pLatency->wPipe >= GetFirstDigitalBusIn())
2068 dwLatency = m_wDigitalInputLatency;
2069 else
2070 dwLatency = m_wAnalogInputLatency;
2073 pLatency->dwLatency = dwLatency;
2075 } // GetAudioLatency