#include "CEchoGals.h"
#undef ECHO_DEBUGPRINTF
#define ECHO_DEBUGPRINTF(x)
CEchoGals mixer client management
****************************************************************************/
ECHOSTATUS CEchoGals::OpenMixer(NUINT &Cookie)
{
ECHO_MIXER_CLIENT *pTemp;
if (m_fMixerDisabled)
return ECHOSTATUS_MIXER_DISABLED;
if (0 != Cookie)
{
pTemp = m_pMixerClients;
while (pTemp != NULL)
{
if (Cookie == pTemp->Cookie)
{
ECHO_DEBUGPRINTF(("CEchoGals::OpenMixer - cookie 0x%lx already in use\n",
Cookie));
return ECHOSTATUS_BAD_COOKIE;
}
pTemp = pTemp->pNext;
}
}
else
{
ULONGLONG ullTime;
m_pOsSupport->OsGetSystemTime(&ullTime);
Cookie = (NUINT) ullTime;
if (0 == Cookie)
Cookie = 1;
pTemp = m_pMixerClients;
while (pTemp != NULL)
{
if (Cookie == pTemp->Cookie)
{
Cookie++;
pTemp = m_pMixerClients;
}
pTemp = pTemp->pNext;
}
}
ECHO_MIXER_CLIENT *pClient = NULL;
ECHOSTATUS Status;
Status = OsAllocateNonPaged(sizeof(ECHO_MIXER_CLIENT),(void **) &pClient);
if (NULL == pClient)
{
Cookie = 0;
return Status;
}
pClient->Cookie = Cookie;
pClient->pNext = m_pMixerClients;
m_pMixerClients = pClient;
return ECHOSTATUS_OK;
}
ECHO_MIXER_CLIENT *CEchoGals::GetMixerClient(NUINT Cookie)
{
ECHO_MIXER_CLIENT *pTemp;
pTemp = m_pMixerClients;
while (NULL != pTemp)
{
if (Cookie == pTemp->Cookie)
break;
pTemp = pTemp->pNext;
}
return pTemp;
}
ECHOSTATUS CEchoGals::CloseMixer(NUINT Cookie)
{
ECHO_MIXER_CLIENT *pTemp;
pTemp = m_pMixerClients;
if (NULL == pTemp)
return ECHOSTATUS_BAD_COOKIE;
if (pTemp->Cookie == Cookie)
{
m_pMixerClients = pTemp->pNext;
OsFreeNonPaged(pTemp);
return ECHOSTATUS_OK;
}
while (NULL != pTemp->pNext)
{
if (Cookie == pTemp->pNext->Cookie)
{
ECHO_MIXER_CLIENT *pDeadClient;
pDeadClient = pTemp->pNext;
pTemp->pNext = pDeadClient->pNext;
OsFreeNonPaged(pDeadClient);
return ECHOSTATUS_OK;
}
pTemp = pTemp->pNext;
}
return ECHOSTATUS_BAD_COOKIE;
}
BOOL CEchoGals::IsMixerOpen()
{
if (NULL == m_pMixerClients)
return FALSE;
return TRUE;
}
ECHOSTATUS CEchoGals::MixerControlChanged
(
WORD wType,
WORD wParameter,
WORD wCh1,
WORD wCh2
)
{
ECHO_MIXER_CLIENT *pClient = m_pMixerClients;
PMIXER_NOTIFY pNotify;
if (m_fMixerDisabled)
return ECHOSTATUS_MIXER_DISABLED;
while (NULL != pClient)
{
DWORD dwIndex,dwCount;
BOOL fFound;
dwCount = pClient->dwCount;
dwIndex = pClient->dwTail;
fFound = FALSE;
while (dwCount > 0)
{
pNotify = pClient->Notifies + dwIndex;
if ( (pNotify->wType == wType) &&
(pNotify->wParameter == wParameter) &&
(pNotify->u.wPipeOut == wCh1) &&
(pNotify->wBusOut == wCh2))
{
fFound = TRUE;
break;
}
dwIndex++;
dwIndex &= MAX_MIXER_NOTIFIES - 1;
dwCount--;
}
if ( (FALSE == fFound) &&
(pClient->dwCount != MAX_MIXER_NOTIFIES))
{
pNotify = pClient->Notifies + pClient->dwHead;
pNotify->wType = wType;
pNotify->wParameter = wParameter;
if (ECHO_BUS_OUT == wType)
{
pNotify->u.wPipeOut = ECHO_CHANNEL_UNUSED;
pNotify->wBusOut = wCh1;
}
else
{
pNotify->u.wPipeOut = wCh1;
pNotify->wBusOut = wCh2;
}
pClient->dwCount += 1;
pClient->dwHead = (pClient->dwHead + 1) & (MAX_MIXER_NOTIFIES - 1);
}
pClient = pClient->pNext;
}
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::GetControlChanges
(
PMIXER_MULTI_NOTIFY pNotifies,
NUINT MixerCookie
)
{
ECHO_MIXER_CLIENT *pClient = GetMixerClient(MixerCookie);
if (NULL == pClient)
{
pNotifies->dwCount = 0;
return ECHOSTATUS_BAD_COOKIE;
}
PMIXER_NOTIFY pDest,pSrc;
DWORD dwNumClientNotifies,dwNumReturned;
dwNumClientNotifies = pNotifies->dwCount;
pDest = pNotifies->Notifies;
dwNumReturned = 0;
while ( (dwNumClientNotifies > 0) && (pClient->dwCount > 0))
{
pSrc = pClient->Notifies + pClient->dwTail;
OsCopyMemory(pDest,pSrc,sizeof(MIXER_NOTIFY));
pDest++;
pClient->dwTail = (pClient->dwTail + 1) & (MAX_MIXER_NOTIFIES - 1);
pClient->dwCount -= 1;
dwNumClientNotifies--;
dwNumReturned++;
}
pNotifies->dwCount = dwNumReturned;
return ECHOSTATUS_OK;
}
CEchoGals mixer control
****************************************************************************/
ECHOSTATUS CEchoGals::ProcessMixerFunction
(
PMIXER_FUNCTION pMixerFunction,
INT32 & iRtnDataSz
)
{
ECHOSTATUS Status = ECHOSTATUS_OK;
if (m_fMixerDisabled)
return ECHOSTATUS_MIXER_DISABLED;
switch ( pMixerFunction->iFunction )
{
case MXF_GET_CAPS :
Status = GetCapabilities( &pMixerFunction->Data.Capabilities );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_CAPS Status %ld\n", Status) );
break;
case MXF_GET_LEVEL :
Status = GetAudioLineLevel( pMixerFunction);
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_LEVEL Status %ld\n", Status) );
*/
break;
case MXF_SET_LEVEL :
Status = SetAudioLineLevel( pMixerFunction);
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_LEVEL Status %ld\n", Status) );
break;
case MXF_GET_NOMINAL :
Status = GetAudioNominal( pMixerFunction);
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_NOMINAL Status %ld\n", Status) );
*/
break;
case MXF_SET_NOMINAL :
Status = SetAudioNominal( pMixerFunction);
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_NOMINAL Status %ld\n", Status) );
break;
case MXF_GET_MONITOR :
Status = GetAudioMonitor( pMixerFunction->Channel.wChannel,
pMixerFunction->Data.Monitor.wBusOut,
pMixerFunction->Data.Monitor.Data.iLevel );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_MONITOR Status %ld\n", Status) );
*/
break;
case MXF_SET_MONITOR :
Status = SetAudioMonitor( pMixerFunction->Channel.wChannel,
pMixerFunction->Data.Monitor.wBusOut,
pMixerFunction->Data.Monitor.Data.iLevel );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_MONITOR Status %ld\n", Status) );
break;
case MXF_GET_CLOCK_DETECT :
Status = GetInputClockDetect( pMixerFunction->Data.dwClockDetectBits );
break;
case MXF_GET_INPUT_CLOCK :
Status = GetInputClock( pMixerFunction->Data.wClock );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_INPUT_CLOCK Status %ld\n", Status) );
break;
case MXF_SET_INPUT_CLOCK :
Status = SetInputClock( pMixerFunction->Data.wClock );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_INPUT_CLOCK Status %ld\n", Status) );
break;
case MXF_GET_OUTPUT_CLOCK :
Status = GetOutputClock( pMixerFunction->Data.wClock );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_OUTPUT_CLOCK Status %ld\n", Status) );
break;
case MXF_SET_OUTPUT_CLOCK :
Status = SetOutputClock( pMixerFunction->Data.wClock );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_OUTPUT_CLOCK Status %ld\n", Status) );
break;
case MXF_GET_METERS :
if (NULL != GetDspCommObject())
{
Status = GetDspCommObject()->
GetAudioMeters( &pMixerFunction->Data.Meters );
}
else
{
Status = ECHOSTATUS_DSP_DEAD;
}
break;
case MXF_GET_METERS_ON :
Status = GetMetersOn( pMixerFunction->Data.bMetersOn );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_METERS Status %ld\n", Status) );
break;
case MXF_SET_METERS_ON :
Status = SetMetersOn( pMixerFunction->Data.bMetersOn );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_METERS_ON Status %ld\n", Status) );
break;
case MXF_GET_PROF_SPDIF :
if ( NULL == GetDspCommObject() )
{
Status = ECHOSTATUS_DSP_DEAD;
}
else
{
pMixerFunction->Data.bProfSpdif = IsProfessionalSpdif();
}
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_PROF_SPDIF Pro S/PDIF: 0x%x Status %ld\n",
pMixerFunction->Data.bProfSpdif,
Status) );
break;
case MXF_SET_PROF_SPDIF :
SetProfessionalSpdif( pMixerFunction->Data.bProfSpdif );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_PROF_SPDIF Pro S/PDIF: 0x%x Status %ld\n",
pMixerFunction->Data.bProfSpdif,
Status) );
break;
case MXF_GET_MUTE :
Status = GetAudioMute(pMixerFunction);
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_MUTE Status %ld\n", Status) );
*/
break;
case MXF_SET_MUTE :
Status = SetAudioMute(pMixerFunction);
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_MUTE Status %ld\n", Status) );
break;
case MXF_GET_MONITOR_MUTE :
Status =
GetAudioMonitorMute( pMixerFunction->Channel.wChannel,
pMixerFunction->Data.Monitor.wBusOut,
pMixerFunction->Data.Monitor.Data.bMuteOn );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_MONITOR_MUTE Status %ld\n", Status) );
*/
break;
case MXF_SET_MONITOR_MUTE :
Status =
SetAudioMonitorMute( pMixerFunction->Channel.wChannel,
pMixerFunction->Data.Monitor.wBusOut,
pMixerFunction->Data.Monitor.Data.bMuteOn );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_MONITOR_MUTE Status %ld\n", Status) );
break;
case MXF_GET_MONITOR_PAN :
Status =
GetAudioMonitorPan( pMixerFunction->Channel.wChannel,
pMixerFunction->Data.Monitor.wBusOut,
pMixerFunction->Data.Monitor.Data.iPan);
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_MONITOR_PAN Status %ld\n", Status) );
*/
break;
case MXF_SET_MONITOR_PAN :
Status =
SetAudioMonitorPan( pMixerFunction->Channel.wChannel,
pMixerFunction->Data.Monitor.wBusOut,
pMixerFunction->Data.Monitor.Data.iPan );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_MONITOR_PAN Status %ld\n", Status) );
break;
case MXF_GET_FLAGS :
pMixerFunction->Data.wFlags = GetFlags();
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_FLAGS 0x%x Status %ld\n",
pMixerFunction->Data.wFlags,
Status) );
break;
case MXF_SET_FLAGS :
SetFlags( pMixerFunction->Data.wFlags );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_FLAGS 0x%x Status %ld\n",
pMixerFunction->Data.wFlags,
Status) );
break;
case MXF_CLEAR_FLAGS :
ClearFlags( pMixerFunction->Data.wFlags );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_CLEAR_FLAGS 0x%x Status %ld\n",
pMixerFunction->Data.wFlags,
Status) );
break;
case MXF_GET_SAMPLERATE_LOCK :
GetAudioLockedSampleRate( pMixerFunction->Data.dwLockedSampleRate );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_SAMPLERATE_LOCK 0x%lx Status %ld\n",
pMixerFunction->Data.dwLockedSampleRate,
Status) );
break;
case MXF_SET_SAMPLERATE_LOCK :
SetAudioLockedSampleRate( pMixerFunction->Data.dwLockedSampleRate );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_SAMPLERATE_LOCK 0x%lx Status %ld\n",
pMixerFunction->Data.dwLockedSampleRate,
Status) );
break;
case MXF_GET_SAMPLERATE :
GetAudioSampleRate( &pMixerFunction->Data.dwSampleRate );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_SAMPLERATE 0x%lx Status %ld\n",
pMixerFunction->Data.dwSampleRate,
Status) );
break;
#ifdef MIDI_SUPPORT
case MXF_GET_MIDI_IN_ACTIVITY :
pMixerFunction->Data.bMidiActive = m_MidiIn.IsActive();
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_MIDI_IN_ACTIVITY %s "
"Status %ld\n",
( pMixerFunction->Data.bMidiActive )
? "ACTIVE" : "INACTIVE",
Status) );
break;
case MXF_GET_MIDI_OUT_ACTIVITY :
pMixerFunction->Data.bMidiActive =
GetDspCommObject()->IsMidiOutActive();
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_MIDI_OUT_ACTIVITY %s "
"Status %ld\n",
( pMixerFunction->Data.bMidiActive )
? "ACTIVE" : "INACTIVE",
Status) );
break;
#endif
case MXF_GET_DIGITAL_MODE :
Status = ECHOSTATUS_OK;
pMixerFunction->Data.iDigMode = GetDigitalMode();
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_DIGITAL_MODE %s "
"Status %ld\n",
( DIGITAL_MODE_SPDIF_RCA ==
pMixerFunction->Data.iDigMode )
? "S/PDIF RCA"
: ( DIGITAL_MODE_SPDIF_OPTICAL ==
pMixerFunction->Data.iDigMode )
? "S/PDIF Optical" : "ADAT",
Status) );
break;
case MXF_SET_DIGITAL_MODE :
Status = SetDigitalMode( (BYTE) pMixerFunction->Data.iDigMode );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_DIGITAL_MODE %s "
"Status %ld\n",
( DIGITAL_MODE_SPDIF_RCA ==
pMixerFunction->Data.iDigMode )
? "S/PDIF RCA"
: ( DIGITAL_MODE_SPDIF_OPTICAL ==
pMixerFunction->Data.iDigMode )
? "S/PDIF Optical" : "ADAT",
Status) );
break;
case MXF_GET_PAN :
Status = GetAudioPan( pMixerFunction);
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_PAN Status %ld\n", Status) );
break;
case MXF_SET_PAN :
Status = SetAudioPan( pMixerFunction);
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_PAN Status %ld\n", Status) );
break;
#ifdef DIGITAL_INPUT_AUTO_MUTE_SUPPORT
case MXF_GET_DIG_IN_AUTO_MUTE :
Status = GetDigitalInAutoMute( pMixerFunction );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_GET_DIG_IN_AUTO_MUTE Status %ld\n", Status) );
break;
case MXF_SET_DIG_IN_AUTO_MUTE :
Status = SetDigitalInAutoMute( pMixerFunction );
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"MXF_SET_DIG_IN_AUTO_MUTE Status %ld\n", Status) );
break;
#endif
case MXF_GET_AUDIO_LATENCY :
GetAudioLatency( &(pMixerFunction->Data.Latency) );
break;
#ifdef PHANTOM_POWER_CONTROL
case MXF_GET_PHANTOM_POWER :
GetPhantomPower( &(pMixerFunction->Data.fPhantomPower) );
break;
case MXF_SET_PHANTOM_POWER :
SetPhantomPower( pMixerFunction->Data.fPhantomPower );
break;
#endif
default :
iRtnDataSz = 0;
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerFunction: "
"Function %ld not supported\n",
pMixerFunction->iFunction) );
return ECHOSTATUS_NOT_SUPPORTED;
}
pMixerFunction->RtnStatus = Status;
iRtnDataSz = sizeof( MIXER_FUNCTION );
return Status;
}
ECHOSTATUS CEchoGals::ProcessMixerMultiFunction
(
PMIXER_MULTI_FUNCTION pMixerFunctions,
INT32 & iRtnDataSz
)
{
ECHOSTATUS Status = ECHOSTATUS_NOT_SUPPORTED;
PMIXER_FUNCTION pMixerFunction;
INT32 iRtn, nCard, i;
if (m_fMixerDisabled)
return ECHOSTATUS_MIXER_DISABLED;
iRtnDataSz = sizeof( MIXER_MULTI_FUNCTION ) - sizeof( MIXER_FUNCTION );
pMixerFunction = &pMixerFunctions->MixerFunction[ 0 ];
nCard = pMixerFunction->Channel.wCardId;
for ( i = 0; i < pMixerFunctions->iCount; i++ )
{
pMixerFunction = &pMixerFunctions->MixerFunction[ i ];
if ( nCard != pMixerFunction->Channel.wCardId )
{
ECHO_DEBUGPRINTF( ("CEchoGals::ProcessMixerMultiFunction: "
"All functions MUST be for the same card "
"exp %ld act %d!\n",
nCard,
pMixerFunction->Channel.wCardId) );
return ECHOSTATUS_NOT_SUPPORTED;
}
Status = ProcessMixerFunction(pMixerFunction,iRtn);
iRtnDataSz += iRtn;
}
return Status;
}
ECHOSTATUS CEchoGals::GetPolledStuff
(
ECHO_POLLED_STUFF *pPolledStuff,
NUINT MixerCookie
)
{
ECHO_MIXER_CLIENT *pClient;
CDspCommObject *pDCO = GetDspCommObject();
if (m_fMixerDisabled)
return ECHOSTATUS_MIXER_DISABLED;
if (NULL == pDCO)
return ECHOSTATUS_DSP_DEAD;
pDCO->GetAudioMeters(&(pPolledStuff->Meters));
GetInputClockDetect(pPolledStuff->dwClockDetectBits);
pClient = GetMixerClient(MixerCookie);
if (NULL == pClient)
pPolledStuff->dwNumPendingNotifies = 0;
else
pPolledStuff->dwNumPendingNotifies = pClient->dwCount;
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::GetAudioPan
(
PMIXER_FUNCTION pMF
)
{
WORD wPipe;
WORD wBus;
ECHOSTATUS Status;
if ( (pMF->Channel.dwType != ECHO_PIPE_OUT) ||
( !HasVmixer() ) )
return ECHOSTATUS_INVALID_CHANNEL;
wPipe = pMF->Channel.wChannel;
wBus = pMF->Data.PipeOut.wBusOut;
Status = m_PipeOutCtrl.GetPan(wPipe,
wBus,
pMF->Data.PipeOut.Data.iPan);
return Status;
}
ECHOSTATUS CEchoGals::SetAudioPan
(
PMIXER_FUNCTION pMF
)
{
WORD wPipe;
WORD wBus;
ECHOSTATUS Status;
if ( (pMF->Channel.dwType != ECHO_PIPE_OUT) ||
( !HasVmixer() ) )
return ECHOSTATUS_INVALID_CHANNEL;
wPipe = pMF->Channel.wChannel;
wBus = pMF->Data.PipeOut.wBusOut;
Status = m_PipeOutCtrl.SetPan(wPipe,
wBus,
pMF->Data.PipeOut.Data.iPan);
return Status;
}
CEchoGals clock control
The input clock is the sync source - is the audio for this card running
off of the internal clock, synced to word clock, etc.
Output clock is only supported on Layla20 - Layla20 can transmit either
word or super clock.
****************************************************************************/
ECHOSTATUS CEchoGals::GetInputClock(WORD &wClock)
{
if ( NULL == GetDspCommObject() )
return ECHOSTATUS_DSP_DEAD;
wClock = GetDspCommObject()->GetInputClock();
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::GetOutputClock(WORD &wClock)
{
if ( NULL == GetDspCommObject() )
return ECHOSTATUS_DSP_DEAD;
wClock = GetDspCommObject()->GetOutputClock();
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::SetInputClock(WORD wClock)
{
ECHOSTATUS Status;
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
ECHO_DEBUGPRINTF( ("CEchoGals::SetInputClock: ") );
Status = GetDspCommObject()->SetInputClock( wClock );
if (ECHOSTATUS_OK == Status)
{
MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
MXN_INPUT_CLOCK);
}
return Status;
}
ECHOSTATUS CEchoGals::SetOutputClock(WORD wClock)
{
ECHOSTATUS Status;
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
ECHO_DEBUGPRINTF( ("CEchoGals::SetOutputClock: ") );
Status = GetDspCommObject()->SetOutputClock( wClock );
if (ECHOSTATUS_OK == Status)
{
MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
MXN_OUTPUT_CLOCK);
}
return Status;
}
ECHOSTATUS CEchoGals::GetInputClockDetect(DWORD &dwClockDetectBits)
{
dwClockDetectBits = ECHO_CLOCK_INTERNAL;
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::SetAudioLockedSampleRate
(
DWORD dwSampleRate
)
{
ECHOSTATUS Status;
Status = QueryAudioSampleRate( dwSampleRate );
if ( ECHOSTATUS_OK != Status )
return Status;
if (0 != (ECHOGALS_FLAG_SAMPLE_RATE_LOCKED & GetFlags()))
{
GetDspCommObject()->SetSampleRate( dwSampleRate );
m_dwSampleRate = dwSampleRate;
}
m_dwLockedSampleRate = dwSampleRate;
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::GetAudioLockedSampleRate
(
DWORD &dwSampleRate
)
{
dwSampleRate = m_dwLockedSampleRate;
return ECHOSTATUS_OK;
}
#ifdef DIGITAL_INPUT_AUTO_MUTE_SUPPORT
ECHOSTATUS CEchoGals::GetDigitalInAutoMute(PMIXER_FUNCTION pMixerFunction)
{
BOOL fAutoMute;
if (0 == (m_wFlags & ECHOGALS_ROFLAG_DIGITAL_IN_AUTOMUTE))
{
pMixerFunction->Data.fDigitalInAutoMute = FALSE;
return ECHOSTATUS_NOT_SUPPORTED;
}
GetDspCommObject()->GetDigitalInputAutoMute( fAutoMute );
pMixerFunction->Data.fDigitalInAutoMute = fAutoMute;
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::SetDigitalInAutoMute(PMIXER_FUNCTION pMixerFunction)
{
BOOL fAutoMute;
if (0 == (m_wFlags & ECHOGALS_ROFLAG_DIGITAL_IN_AUTOMUTE))
return ECHOSTATUS_NOT_SUPPORTED;
fAutoMute = pMixerFunction->Data.fDigitalInAutoMute;
GetDspCommObject()->SetDigitalInputAutoMute( fAutoMute );
return ECHOSTATUS_OK;
}
#endif
ECHOSTATUS CEchoGals::GetAudioLineLevel
(
PMIXER_FUNCTION pMF
)
{
WORD wPipe;
WORD wBus;
ECHOSTATUS Status;
switch (pMF->Channel.dwType)
{
case ECHO_BUS_OUT :
wBus = pMF->Channel.wChannel;
if (wBus < GetNumBussesOut())
{
pMF->Data.iLevel = m_BusOutLineLevels[wBus].GetGain();
Status = ECHOSTATUS_OK;
}
else
{
Status = ECHOSTATUS_INVALID_CHANNEL;
}
break;
case ECHO_BUS_IN :
wBus = pMF->Channel.wChannel;
if (wBus < GetNumBussesIn())
{
pMF->Data.iLevel = m_BusInLineLevels[wBus].GetGain();
Status = ECHOSTATUS_OK;
}
else
{
Status = ECHOSTATUS_INVALID_CHANNEL;
}
break;
case ECHO_PIPE_OUT :
wPipe = pMF->Channel.wChannel;
wBus = pMF->Data.PipeOut.wBusOut;
Status = m_PipeOutCtrl.GetGain( wPipe,
wBus,
pMF->Data.PipeOut.Data.iLevel);
break;
default:
Status = ECHOSTATUS_INVALID_PARAM;
break;
}
return Status;
}
ECHOSTATUS CheckSetting(INT32 iValue,INT32 iMin,INT32 iMax)
{
if ( (iValue > iMax) || (iValue < iMin))
return ECHOSTATUS_INVALID_PARAM;
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::SetAudioLineLevel
(
PMIXER_FUNCTION pMF
)
{
WORD wPipe;
WORD wBus;
ECHOSTATUS Status;
INT32 iLevel;
switch (pMF->Channel.dwType)
{
case ECHO_BUS_OUT :
wBus = pMF->Channel.wChannel;
iLevel = pMF->Data.iLevel;
Status = CheckSetting(iLevel,ECHOGAIN_MINOUT,ECHOGAIN_MAXOUT);
if (ECHOSTATUS_OK != Status)
break;
Status = m_BusOutLineLevels[wBus].SetGain(iLevel);
break;
case ECHO_BUS_IN :
wBus = pMF->Channel.wChannel;
iLevel = pMF->Data.iLevel;
Status = CheckSetting(iLevel,ECHOGAIN_MININP,ECHOGAIN_MAXINP);
if (ECHOSTATUS_OK != Status)
break;
Status = m_BusInLineLevels[wBus].SetGain(iLevel);
break;
case ECHO_PIPE_OUT :
wPipe = pMF->Channel.wChannel;
wBus = pMF->Data.PipeOut.wBusOut;
iLevel = pMF->Data.PipeOut.Data.iLevel;
Status = CheckSetting(iLevel,ECHOGAIN_MINOUT,ECHOGAIN_MAXOUT);
if (ECHOSTATUS_OK != Status)
break;
Status = m_PipeOutCtrl.SetGain( wPipe,
wBus,
iLevel);
break;
default:
Status = ECHOSTATUS_INVALID_PARAM;
break;
}
return Status;
}
ECHOSTATUS CEchoGals::GetAudioNominal
(
PMIXER_FUNCTION pMF
)
{
BYTE byNominal;
ECHOSTATUS Status;
CDspCommObject * pDspCommObj = GetDspCommObject();
WORD wCh;
if ( NULL == pDspCommObj || pDspCommObj->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
switch (pMF->Channel.dwType)
{
case ECHO_BUS_OUT :
wCh = pMF->Channel.wChannel;
break;
case ECHO_BUS_IN :
wCh = pMF->Channel.wChannel + GetNumBussesOut();
break;
default :
return ECHOSTATUS_INVALID_CHANNEL;
}
Status = pDspCommObj->GetNominalLevel( wCh, &byNominal );
if ( ECHOSTATUS_OK != Status )
return Status;
pMF->Data.iNominal = ( byNominal ) ? -10 : 4;
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::SetAudioNominal
(
PMIXER_FUNCTION pMF
)
{
ECHOSTATUS Status;
WORD wCh;
INT32 iNominal;
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
switch (pMF->Channel.dwType)
{
case ECHO_BUS_OUT :
wCh = pMF->Channel.wChannel;
break;
case ECHO_BUS_IN :
wCh = pMF->Channel.wChannel + GetNumBussesOut();
break;
default :
return ECHOSTATUS_INVALID_CHANNEL;
}
iNominal = pMF->Data.iNominal;
if ((iNominal!= -10) && (iNominal != 4))
return ECHOSTATUS_INVALID_PARAM;
Status =
GetDspCommObject()->SetNominalLevel( wCh,
( iNominal == -10 ) );
if ( ECHOSTATUS_OK != Status )
return Status;
Status = MixerControlChanged( (WORD) pMF->Channel.dwType,
MXN_NOMINAL,
pMF->Channel.wChannel);
return Status;
}
ECHOSTATUS CEchoGals::SetAudioMute
(
PMIXER_FUNCTION pMF
)
{
WORD wPipe;
WORD wBus;
ECHOSTATUS Status;
BOOL bMute;
switch (pMF->Channel.dwType)
{
case ECHO_BUS_OUT :
wBus = pMF->Channel.wChannel;
bMute = pMF->Data.bMuteOn;
Status = m_BusOutLineLevels[wBus].SetMute(bMute);
break;
case ECHO_BUS_IN :
wBus = pMF->Channel.wChannel;
bMute = pMF->Data.bMuteOn;
Status = m_BusInLineLevels[wBus].SetMute(bMute);
break;
case ECHO_PIPE_OUT :
wPipe = pMF->Channel.wChannel;
wBus = pMF->Data.PipeOut.wBusOut;
bMute = pMF->Data.PipeOut.Data.bMuteOn;
Status = m_PipeOutCtrl.SetMute( wPipe,
wBus,
bMute);
break;
default:
Status = ECHOSTATUS_INVALID_PARAM;
break;
}
return Status;
}
ECHOSTATUS CEchoGals::GetAudioMute
(
PMIXER_FUNCTION pMF
)
{
WORD wPipe;
WORD wBus;
ECHOSTATUS Status;
switch (pMF->Channel.dwType)
{
case ECHO_BUS_OUT :
wBus = pMF->Channel.wChannel;
if (wBus < GetNumBussesOut())
{
pMF->Data.bMuteOn = m_BusOutLineLevels[wBus].IsMuteOn();
Status = ECHOSTATUS_OK;
}
else
{
Status = ECHOSTATUS_INVALID_CHANNEL;
}
break;
case ECHO_BUS_IN :
wBus = pMF->Channel.wChannel;
if (wBus < GetNumBussesIn())
{
pMF->Data.bMuteOn = m_BusInLineLevels[wBus].IsMuteOn();
Status = ECHOSTATUS_OK;
}
else
{
Status = ECHOSTATUS_INVALID_CHANNEL;
}
break;
case ECHO_PIPE_OUT :
wPipe = pMF->Channel.wChannel;
wBus = pMF->Data.PipeOut.wBusOut;
Status = m_PipeOutCtrl.GetMute( wPipe,
wBus,
pMF->Data.PipeOut.Data.bMuteOn);
break;
default:
Status = ECHOSTATUS_INVALID_PARAM;
break;
}
return Status;
}
ECHOSTATUS CEchoGals::GetAudioMonitor
(
WORD wBusIn,
WORD wBusOut,
INT32 & iGain
)
{
if ( wBusIn >= GetNumBussesIn() ||
wBusOut >= GetNumBussesOut() )
{
return ECHOSTATUS_INVALID_INDEX;
}
m_MonitorCtrl.GetGain(wBusIn,wBusOut,iGain);
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::SetAudioMonitor
(
WORD wBusIn,
WORD wBusOut,
INT32 iGain
)
{
ECHOSTATUS Status;
if ( wBusIn >= GetNumBussesIn() ||
wBusOut >= GetNumBussesOut() )
{
return ECHOSTATUS_INVALID_INDEX;
}
Status = CheckSetting(iGain,ECHOGAIN_MINOUT,ECHOGAIN_MAXOUT);
if (ECHOSTATUS_OK == Status)
{
m_MonitorCtrl.SetGain(wBusIn,wBusOut,iGain);
}
return Status;
}
#define FIXED_BASE 16 // 16 bits of fraction
#define FIXED_ONE_HALF ((INT32) 0x00008000) // 0.5 in 16.16 format
#define COEFF_A2 ((INT32) 0xffffa9ac) // -.3372223
#define COEFF_A1 ((INT32) 0x0000ff8a) // .9981958
#define COEFF_A0 ((INT32) 0xffff5661) // -.6626105
#define DB_CONVERT 0x60546 // 6.02... in 16.16
static INT32 FixedMult( INT32 iNum1, INT32 iNum2 )
{
LONGLONG llNum;
llNum = (LONGLONG) iNum1 * (LONGLONG) iNum2;
return (INT32) (llNum >> FIXED_BASE);
}
static INT32 log2( INT32 iNum )
{
INT32 iNumShifts;
INT32 iTemp;
if ( 0 == iNum )
return ECHOGAIN_MUTED;
iNumShifts = 0;
while ( iNum < FIXED_ONE_HALF )
{
iNumShifts++;
iNum <<= 1;
}
iTemp = FixedMult( iNum, iNum );
iTemp = FixedMult( iTemp, COEFF_A2 );
iTemp += FixedMult( iNum, COEFF_A1 );
iTemp += COEFF_A0;
iTemp <<= 2;
iTemp -= ( iNumShifts << FIXED_BASE );
return( iTemp );
}
INT32 PanToDb( INT32 iPan )
{
if ( iPan >= ( MAX_MIXER_PAN - 1 ) )
return( 0 );
if ( iPan <= 1 )
return( ECHOGAIN_MUTED );
iPan = ( iPan << 16 ) / MAX_MIXER_PAN;
iPan = log2( iPan );
iPan = FixedMult( iPan << 8, DB_CONVERT );
iPan = ( iPan + FIXED_ONE_HALF ) >> FIXED_BASE;
return( iPan );
}
ECHOSTATUS CEchoGals::SetAudioMonitorPan
(
WORD wBusIn,
WORD wBusOut,
INT32 iPan
)
{
ECHOSTATUS Status;
if ( wBusIn >= GetNumBussesIn() ||
wBusOut >= GetNumBussesOut() )
{
return ECHOSTATUS_INVALID_INDEX;
}
Status = CheckSetting(iPan,0,MAX_MIXER_PAN);
if (ECHOSTATUS_OK == Status)
{
m_MonitorCtrl.SetPan(wBusIn,wBusOut,iPan);
}
return Status;
}
ECHOSTATUS CEchoGals::GetAudioMonitorPan
(
WORD wBusIn,
WORD wBusOut,
INT32 & iPan
)
{
if ( wBusIn >= GetNumBussesIn() ||
wBusOut >= GetNumBussesOut() )
{
return ECHOSTATUS_INVALID_INDEX;
}
m_MonitorCtrl.GetPan(wBusIn,wBusOut,iPan);
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::SetAudioMonitorMute
(
WORD wBusIn,
WORD wBusOut,
BOOL bMute
)
{
if ( wBusIn >= GetNumBussesIn() ||
wBusOut >= GetNumBussesOut() )
{
return ECHOSTATUS_INVALID_INDEX;
}
m_MonitorCtrl.SetMute(wBusIn,wBusOut,bMute);
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::GetAudioMonitorMute
(
WORD wBusIn,
WORD wBusOut,
BOOL &bMute
)
{
if ( wBusIn >= GetNumBussesIn() ||
wBusOut >= GetNumBussesOut() )
{
return ECHOSTATUS_INVALID_INDEX;
}
m_MonitorCtrl.GetMute(wBusIn,wBusOut,bMute);
return ECHOSTATUS_OK;
}
void CEchoGals::SetProfessionalSpdif( BOOL bNewStatus )
{
ECHO_DEBUGPRINTF(("CEchoGals::SetProfessionalSpdif %d\n",bNewStatus));
if ( NULL != GetDspCommObject() )
{
GetDspCommObject()->SetProfessionalSpdif( bNewStatus );
MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
MXN_SPDIF );
}
}
ECHOSTATUS CEchoGals::SetFlags
(
WORD wFlags
)
{
wFlags &= ECHOGALS_FLAG_WRITABLE_MASK;
m_wFlags |= wFlags;
MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
MXN_FLAGS );
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::ClearFlags
(
WORD wFlags
)
{
wFlags &= ECHOGALS_FLAG_WRITABLE_MASK;
m_wFlags &= ~wFlags;
MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
MXN_FLAGS );
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::SetDigitalMode
(
BYTE byDigitalMode
)
{
ECHOSTATUS Status;
BYTE byPreviousDigitalMode;
if ( NULL == GetDspCommObject() || GetDspCommObject()->IsBoardBad() )
return ECHOSTATUS_DSP_DEAD;
if ( 0 == GetDspCommObject()->GetDigitalModes() )
return ECHOSTATUS_DIGITAL_MODE_NOT_SUPPORTED;
if ( TRUE == GetDspCommObject()->IsTransportActive() )
{
ECHO_DEBUGPRINTF( ( "CEchoGals::SetDigitalMode() Cannot set the digital "
"mode while transport is running\n"));
return ECHOSTATUS_BUSY;
}
byPreviousDigitalMode = GetDspCommObject()->GetDigitalMode();
Status = GetDspCommObject()->SetDigitalMode( byDigitalMode );
MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
MXN_DIGITAL_MODE );
MixerControlChanged( ECHO_NO_CHANNEL_TYPE,
MXN_INPUT_CLOCK );
if ( ECHOSTATUS_OK == Status &&
byPreviousDigitalMode != byDigitalMode &&
( DIGITAL_MODE_ADAT == byPreviousDigitalMode ||
DIGITAL_MODE_ADAT == byDigitalMode ) )
{
WORD i, j,wBus,wPipe;
for ( i = 0; i < GetNumBussesIn(); i++ )
{
for ( j = 0; j < GetNumBussesOut(); j += 2 )
{
m_MonitorCtrl.SetGain(i,j,ECHOGAIN_UPDATE,FALSE);
}
}
for ( wBus = 0; wBus < GetNumBussesOut(); wBus++)
{
for ( wPipe = 0; wPipe < GetNumPipesOut(); wPipe++)
{
m_PipeOutCtrl.SetGain(wPipe,wBus,ECHOGAIN_UPDATE,FALSE);
}
}
for ( i = 0; i < GetNumBussesOut(); i++ )
{
m_BusOutLineLevels[ i ].SetGain(ECHOGAIN_UPDATE,FALSE);
}
for ( i = 0; i < GetNumBussesIn(); i++ )
{
m_BusInLineLevels[ i ].SetGain( ECHOGAIN_UPDATE );
}
m_BusOutLineLevels[0].SetGain(ECHOGAIN_UPDATE,TRUE);
m_PipeOutCtrl.SetGain(0,0,ECHOGAIN_UPDATE,TRUE);
}
if ( (DIGITAL_MODE_ADAT == byDigitalMode) &&
(m_wFlags & ECHOGALS_FLAG_SAMPLE_RATE_LOCKED) &&
(m_dwLockedSampleRate > 48000) )
{
m_dwLockedSampleRate = 48000;
}
return Status;
}
The output bus gain controls aren't actually implemented in the hardware;
insted they are virtual controls created by the generic code.
The signal sent to an output bus is a mix of the monitors and output pipes
routed to that bus; the output bus gain is therefore implemented by tweaking
each appropriate monitor and output pipe gain.
*/
ECHOSTATUS CEchoGals::AdjustMonitorsForBusOut(WORD wBusOut)
{
WORD wBusIn;
for (wBusIn = 0; wBusIn < GetNumBussesIn(); wBusIn++)
{
m_MonitorCtrl.SetGain(wBusIn,wBusOut,ECHOGAIN_UPDATE,FALSE);
}
return ECHOSTATUS_OK;
}
ECHOSTATUS CEchoGals::AdjustPipesOutForBusOut(WORD wBusOut,INT32 iBusOutGain)
{
ECHO_DEBUGPRINTF(("CEchoGals::AdjustPipesOutForBusOut wBusOut %d iBusOutGain %ld\n",
wBusOut,
iBusOutGain));
wBusOut &= 0xfffe;
m_PipeOutCtrl.SetGain(wBusOut,wBusOut,ECHOGAIN_UPDATE,FALSE);
wBusOut++;
m_PipeOutCtrl.SetGain(wBusOut,wBusOut,ECHOGAIN_UPDATE,TRUE);
return ECHOSTATUS_OK;
}
void CEchoGals::GetAudioLatency(ECHO_AUDIO_LATENCY *pLatency)
{
DWORD dwLatency;
if (FALSE == pLatency->wIsInput)
{
if (pLatency->wPipe >= GetFirstDigitalBusOut())
dwLatency = m_wDigitalOutputLatency;
else
dwLatency = m_wAnalogOutputLatency;
}
else
{
if (pLatency->wPipe >= GetFirstDigitalBusIn())
dwLatency = m_wDigitalInputLatency;
else
dwLatency = m_wAnalogInputLatency;
}
pLatency->dwLatency = dwLatency;
}