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
OpenMixer(NUINT & Cookie)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
GetMixerClient(NUINT Cookie)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
CloseMixer(NUINT Cookie)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
IsMixerOpen()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
MixerControlChanged(WORD wType,WORD wParameter,WORD wCh1,WORD wCh2)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
GetControlChanges(PMIXER_MULTI_NOTIFY pNotifies,NUINT MixerCookie)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
ProcessMixerFunction(PMIXER_FUNCTION pMixerFunction,INT32 & iRtnDataSz)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
ProcessMixerMultiFunction(PMIXER_MULTI_FUNCTION pMixerFunctions,INT32 & iRtnDataSz)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
GetPolledStuff(ECHO_POLLED_STUFF * pPolledStuff,NUINT MixerCookie)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
GetAudioPan(PMIXER_FUNCTION pMF)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
SetAudioPan(PMIXER_FUNCTION pMF)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
GetInputClock(WORD & wClock)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
GetOutputClock(WORD & wClock)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
SetInputClock(WORD wClock)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
SetOutputClock(WORD wClock)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
GetInputClockDetect(DWORD & dwClockDetectBits)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
SetAudioLockedSampleRate(DWORD dwSampleRate)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
GetAudioLockedSampleRate(DWORD & dwSampleRate)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
GetDigitalInAutoMute(PMIXER_FUNCTION pMixerFunction)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
SetDigitalInAutoMute(PMIXER_FUNCTION pMixerFunction)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
GetAudioLineLevel(PMIXER_FUNCTION pMF)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
CheckSetting(INT32 iValue,INT32 iMin,INT32 iMax)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
SetAudioLineLevel(PMIXER_FUNCTION pMF)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
GetAudioNominal(PMIXER_FUNCTION pMF)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
SetAudioNominal(PMIXER_FUNCTION pMF)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
SetAudioMute(PMIXER_FUNCTION pMF)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
GetAudioMute(PMIXER_FUNCTION pMF)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
GetAudioMonitor(WORD wBusIn,WORD wBusOut,INT32 & iGain)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
SetAudioMonitor(WORD wBusIn,WORD wBusOut,INT32 iGain)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
FixedMult(INT32 iNum1,INT32 iNum2)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
log2(INT32 iNum)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 //
PanToDb(INT32 iPan)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
SetAudioMonitorPan(WORD wBusIn,WORD wBusOut,INT32 iPan)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
GetAudioMonitorPan(WORD wBusIn,WORD wBusOut,INT32 & iPan)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
SetAudioMonitorMute(WORD wBusIn,WORD wBusOut,BOOL bMute)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
GetAudioMonitorMute(WORD wBusIn,WORD wBusOut,BOOL & bMute)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
SetProfessionalSpdif(BOOL bNewStatus)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
SetFlags(WORD wFlags)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
ClearFlags(WORD wFlags)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
SetDigitalMode(BYTE byDigitalMode)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
AdjustMonitorsForBusOut(WORD wBusOut)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
AdjustPipesOutForBusOut(WORD wBusOut,INT32 iBusOutGain)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
GetAudioLatency(ECHO_AUDIO_LATENCY * pLatency)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