📄 ac97mixer.cpp
字号:
pQuery->dwComponentType = pFound->dwComponentType;
pQuery->dwLineID = pFound->usLineID;
pQuery->dwDestination = pFound->ucDstIndex;
pQuery->dwSource = pFound->ucDstIndex;
pQuery->fdwLine = pFound->ucFlags;
pQuery->Target.dwDeviceID = 0;
pQuery->Target.dwType = pFound->dwTargetType;
pQuery->Target.vDriverVersion = 1;
pQuery->Target.wMid = MM_CRYSTAL;
pQuery->Target.wPid = MM_CRYSTAL_EP9312_MIXER;
wcscpy(pQuery->szName, pFound->szName);
wcscpy(pQuery->szShortName, pFound->szShortName);
wsprintf (pQuery->Target.szPname, TEXT("EP9312 Audio (%hs)"), __DATE__);
mmRet = MMSYSERR_NOERROR;
DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerLineInfo: \"%s\" %08x\r\n"), pFound->szName, pFound->ucFlags));
}
return mmRet;
}
// mixerGetLineControls
MMRESULT
AC97Mixer::GetMixerLineControls ( PMIXERLINECONTROLS pQuery, DWORD dwFlags)
{ int i;
PMIXERCONTROL pDstControl = pQuery->pamxctrl;
USHORT usLineID = (USHORT) pQuery->dwLineID;
DWORD dwCount = pQuery->cControls;
switch (dwFlags & MIXER_GETLINECONTROLSF_QUERYMASK) {
case MIXER_GETLINECONTROLSF_ALL:
DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerLineControls: ALL %x\r\n"), usLineID));
// retrieve all controls for the line pQuery->dwLineID
{
PMXLINEDESC pFound = LookupMxLine(usLineID);
if (pFound == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineControls: invalid line ID %04x\r\n"), usLineID));
return MIXERR_INVALLINE;
}
if (pFound->ucControls != dwCount) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineControls: incorrect number of controls. Expect %d, found %d.\r\n"),dwCount,pFound->ucControls));
return MMSYSERR_INVALPARAM;
}
for (i = 0; i < ncontrols && dwCount > 0; i++) {
PMXCONTROLDESC pSrcControl = &g_controls[i];
if (pSrcControl->usLineID == usLineID) {
CopyMixerControl(pDstControl, pSrcControl, i);
pDstControl++;
dwCount--;
}
}
}
break;
case MIXER_GETLINECONTROLSF_ONEBYID:
DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerLineControls: ONEBYID %x\r\n"), pQuery->dwControlID));
// retrieve the control specified by pQuery->dwControlID
if (pQuery->dwControlID >= ncontrols) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineControls: invalid control ID %d (max %d)\r\n"), pQuery->dwControlID, ncontrols));
return MIXERR_INVALCONTROL;
}
if (dwCount < 1) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineControls: control count must be nonzero\r\n")));
return MMSYSERR_INVALPARAM;
}
CopyMixerControl(pDstControl, &g_controls[pQuery->dwControlID], pQuery->dwControlID);
pQuery->dwLineID = g_controls[pQuery->dwControlID].usLineID;
break;
case MIXER_GETLINECONTROLSF_ONEBYTYPE:
// retrieve the control specified by pQuery->dwLineID and pQuery->dwControlType
{
PMXLINEDESC pFound = LookupMxLine(usLineID);
if (pFound == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineControls: invalid line ID %04x\r\n"), usLineID));
return MIXERR_INVALLINE;
}
DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerLineControls: ONEBYTYPE %x \"%s\"\r\n"), usLineID, pFound->szName));
if (dwCount < 1) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineControls: control count must be non zero\r\n")));
return MMSYSERR_INVALPARAM;
}
int index = LookupMxControl(usLineID, pQuery->dwControlType);
if (index >= ncontrols) {
// not to be alarmed: SndVol32 queries for LOTS of control types we don't have
DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerLineControls: line %04x (%s) has no control of type %s (%08x)\r\n"), usLineID, pFound->szName, COMPTYPE(pQuery->dwControlType), pQuery->dwControlType));
return MMSYSERR_INVALPARAM;
}
CopyMixerControl(pDstControl, &g_controls[index], index);
return MMSYSERR_NOERROR;
// if we fall out of the search loop, we return failure
}
break;
default:
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineControls: invalid query %08x\r\n"), dwFlags & MIXER_GETLINECONTROLSF_QUERYMASK));
break;
}
return MMSYSERR_NOERROR;
}
// mixerGetControlDetails
MMRESULT
AC97Mixer::GetMixerControlDetails( PMIXERCONTROLDETAILS pQuery, DWORD dwFlags)
{
// API guarantees that pQuery points to accessible, aligned, properly sized MIXERCONTROLDETAILS structure
DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerControlDetails(%d)\r\n"), pQuery->dwControlID));
if (pQuery->dwControlID >= ncontrols) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerControlDetails: invalid control %d (max %d)\r\n"), pQuery->dwControlID, ncontrols));
return MIXERR_INVALCONTROL;
}
PMXCONTROLDESC pSrcControlDesc = &g_controls[pQuery->dwControlID];
PMXCONTROLSTATE pSrcControlState = &m_pMxControlState[pQuery->dwControlID];
PMXLINEDESC pLine = LookupMxLine(pSrcControlDesc->usLineID);
if (pLine == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerControlDetails: inconsistent internal mixer line table\r\n")));
return MMSYSERR_ERROR;
}
switch (dwFlags & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
case MIXER_GETCONTROLDETAILSF_LISTTEXT:
// only support this for the Record Select mux
if (pSrcControlDesc->usLineID != MXLINEID(PCM_IN,NOLINE)) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerControlDetails: invalid line ID %04x\r\n"), pSrcControlDesc->usLineID));
return MMSYSERR_INVALPARAM;
}
{
if (pQuery->cMultipleItems != pLine->ucConnections) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerControlDetails: incorrect cMultipleItems. Expected %d, found\r\n"),
pLine->ucConnections, pQuery->cMultipleItems));
return MMSYSERR_INVALPARAM;
}
MIXERCONTROLDETAILS_LISTTEXT * pValue = (MIXERCONTROLDETAILS_LISTTEXT * ) pQuery->paDetails;
for (int i = 0; i < pLine->ucConnections; i++) {
PMXLINEDESC pl = LookupMxLine(pLine->pSources[i]);
if (pl == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerControlDetails - inconsistent internal mixer line table\r\n")));
return MMSYSERR_ERROR;
}
pValue[i].dwParam1 = pl->usLineID;
pValue[i].dwParam2 = pl->dwComponentType;
wcscpy(pValue[i].szName, pl->szShortName);
}
}
break;
case MIXER_GETCONTROLDETAILSF_VALUE:
switch(pSrcControlDesc->dwType) {
case MIXERCONTROL_CONTROLTYPE_VOLUME:
{
MIXERCONTROLDETAILS_UNSIGNED * pValue = (MIXERCONTROLDETAILS_UNSIGNED * ) pQuery->paDetails;
ULONG ulVolR, ulVolL;
ulVolR = pSrcControlState->uSetting.dw & 0xffff;
if (pLine->ucChannels == 2) {
ulVolL = (pSrcControlState->uSetting.dw >> 16) & 0xffff;
}
else {
ulVolL = ulVolR;
}
if (pQuery->cChannels == 1) {
pValue[0].dwValue = (ulVolR + ulVolL)/2;
}
else {
pValue[0].dwValue = ulVolL;
pValue[1].dwValue = ulVolR;
}
}
break;
case MIXERCONTROL_CONTROLTYPE_ONOFF:
case MIXERCONTROL_CONTROLTYPE_MUTE:
{
MIXERCONTROLDETAILS_BOOLEAN * pValue = (MIXERCONTROLDETAILS_BOOLEAN *) pQuery->paDetails;
pValue[0].fValue = pSrcControlState->uSetting.b;
}
break;
case MIXERCONTROL_CONTROLTYPE_MUX:
{
MIXERCONTROLDETAILS_BOOLEAN * pValue = (MIXERCONTROLDETAILS_BOOLEAN *) pQuery->paDetails;
memset(pValue, 0, sizeof(pValue[0]) * pSrcControlDesc->usMask); // set all entries to FALSE
ASSERT((pSrcControlState->uSetting.dw & 0xF) < NELEMS(MuxIndexToLine));
USHORT usSelectedLine = MuxIndexToLine[pSrcControlState->uSetting.us];
PMXLINEDESC pl = LookupMxLine(usSelectedLine);
if (pl == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerControlDetails: inconsistent internal mixer line table\r\n")));
return MMSYSERR_ERROR;
}
pValue[pl->ucSrcIndex].fValue = TRUE;
}
break;
default:
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerControlDetails: unexpected control type %08x\r\n"), pSrcControlDesc->dwType));
ASSERT(0);
break;
}
break;
default:
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerControlDetails: invalid query %08x\r\n"), dwFlags & MIXER_GETCONTROLDETAILSF_QUERYMASK));
break;
}
return MMSYSERR_NOERROR;
}
// mixerSetControlDetails
MMRESULT
AC97Mixer::SetMixerControlDetails( PMIXERCONTROLDETAILS pDetail, DWORD dwFlags)
{
// API guarantees that pDetail points to accessible, aligned, properly siezd MIXERCONTROLDETAILS structure
DEBUGMSG(ZONE_PARAMS, (TEXT("SetMixerControlDetails(%d)\r\n"), pDetail->dwControlID));
if (pDetail->dwControlID >= ncontrols) {
DEBUGMSG(ZONE_ERROR, (TEXT("SetMixerControlDetails: invalid control %d (max %d)\r\n"), pDetail->dwControlID, ncontrols));
return MIXERR_INVALCONTROL;
}
PMXCONTROLDESC pSrcControlDesc = &g_controls[pDetail->dwControlID];
PMXCONTROLSTATE pSrcControlState = &m_pMxControlState[pDetail->dwControlID];
PMXLINEDESC pLine = LookupMxLine(pSrcControlDesc->usLineID);
if (pLine == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("SetMixerControlDetails: inconsistent internal mixer line table\r\n")));
return MMSYSERR_ERROR;
}
switch(pSrcControlDesc->dwType) {
case MIXERCONTROL_CONTROLTYPE_VOLUME:
{
MIXERCONTROLDETAILS_UNSIGNED * pValue = (MIXERCONTROLDETAILS_UNSIGNED * ) pDetail->paDetails;
DWORD dwSettingL, dwSettingR;
dwSettingL = pValue[0].dwValue;
// setting might be mono or stereo. For mono, apply same volume to both channels
if (pDetail->cChannels == 2) {
dwSettingR = pValue[1].dwValue;
}
else {
dwSettingR = dwSettingL;
}
USHORT settingL, settingR;
if (pLine->ucChannels == 1) {
pSrcControlState->uSetting.dw = (dwSettingL + dwSettingR) / 2;
settingR = settingL = VolToReg(pSrcControlState->uSetting.dw & 0xffff, pSrcControlDesc->usMask);
}
else {
pSrcControlState->uSetting.dw = (dwSettingL << 16) | dwSettingR;
settingR = VolToReg(dwSettingR & 0xffff, pSrcControlDesc->usMask);
settingL = VolToReg(dwSettingL & 0xffff, pSrcControlDesc->usMask);
}
if (pSrcControlDesc->ucCodecRegister == AC97_RECORD_GAIN) {
// sigh. The record register is biased the other way
settingR = 0xf - settingR;
settingL = 0xf - settingL;
}
if (! (pSrcControlState->fVirtualized)) {
DEBUGMSG(ZONE_MXDM, (TEXT("AC97Mixer::SetMixerControlDetailsX: %08x %08x %04x %04x\r\n"), dwSettingL, dwSettingR, pSrcControlDesc->ucCodecRegister, (settingL << 8) | settingR));
RMWCodecRegister(pSrcControlDesc->ucCodecRegister, MUTE_BIT, (settingL << 8) | settingR);
}
}
break;
case MIXERCONTROL_CONTROLTYPE_ONOFF:
case MIXERCONTROL_CONTROLTYPE_MUTE:
{
MIXERCONTROLDETAILS_BOOLEAN * pValue = (MIXERCONTROLDETAILS_BOOLEAN *) pDetail->paDetails;
pSrcControlState->uSetting.b = pValue[0].fValue;
USHORT setting = (pValue[0].fValue) ? pSrcControlDesc->usMask : 0;
if (! (pSrcControlState->fVirtualized))
{
RMWCodecRegister(pSrcControlDesc->ucCodecRegister, ~pSrcControlDesc->usMask, setting);
}
}
break;
case MIXERCONTROL_CONTROLTYPE_MUX:
{
if (pDetail->cMultipleItems != pLine->ucConnections) {
DEBUGMSG(ZONE_ERROR, (TEXT("SetMixerControlDetails: incorrect cMultipleItems. Expect %d, found %d\r\n"),
pLine->ucConnections, pDetail->cMultipleItems));
return MMSYSERR_INVALPARAM;
}
MIXERCONTROLDETAILS_BOOLEAN * pValue = (MIXERCONTROLDETAILS_BOOLEAN *) pDetail->paDetails;
for (USHORT i = 0; i < pLine->ucConnections; i++) {
// find the entry that's set.
if (pValue[i].fValue) {
USHORT usSelectedLine = pLine->pSources[i];
// Do a reverse look up for the selected line in the MuxIndexToLine table
// This gives us the desired new setting for the mux register.
for (USHORT j = 0; j < NELEMS(MuxIndexToLine); j++) {
if (usSelectedLine == MuxIndexToLine[j]) {
int index;
// set mux to j
// But first, the "Virtual Volume" trick:
// All of the PCM_IN source line volume controls have, in fact, no underlying codec register.
// Instead, when the Record Select MUX changes values, we copy the selected line's
// volume setting to the Record Gain register.
// first, re-virtualize the current source line
index = LookupMxControl(MuxIndexToLine[pSrcControlState->uSetting.us], MIXERCONTROL_CONTROLTYPE_VOLUME);
ASSERT(index < ncontrols);
ASSERT( ! m_pMxControlState[index].fVirtualized);
m_pMxControlState[index].fVirtualized = TRUE;
// now, switch the mux to the new source
// note that the mux has separate Left/Right settings, but for simplicity,
// we expose the mux as uniform
pSrcControlState->uSetting.us = j;
DEBUGMSG(ZONE_MXDM, (TEXT("AC97Mixer::SetMixerControlDetailsA: %04x %04x)\r\n"), pSrcControlDesc->ucCodecRegister, j | (j << 8)));
m_pAC97Codec->PokeAC97(pSrcControlDesc->ucCodecRegister, j | (j << 8));
// finally, un-virtualize the new source and copy the volume/mute settings
// into the AC97_RECORD_GAIN register.
index = LookupMxControl(MuxIndexToLine[j], MIXERCONTROL_CONTROLTYPE_VOLUME);
ASSERT(index < ncontrols);
ASSERT (m_pMxControlState[index].fVirtualized);
m_pMxControlState[index].fVirtualized = FALSE;
// Recording level is actually a true gain, so reverse-bias this.
USHORT r = (USHORT) ((m_pMxControlState[index].uSetting.dw >> 8 ) & 0xf);
USHORT l = (USHORT) ((m_pMxControlState[index].uSetting.dw >> 24 ) & 0xf);
DEBUGMSG(ZONE_MXDM, (TEXT("AC97Mixer::SetMixerControlDetailsB: %04x %04x)\r\n"), pSrcControlDesc->ucCodecRegister, l | (r << 8)));
m_pAC97Codec->PokeAC97(g_controls[index].ucCodecRegister, r | (l << 8));
break;
} // if selected
} // for j
break; // found the first TRUE entry - break out.
} // if fValue
} // for i
}
break;
default:
DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerControlDetails: unexpected control type %08x\r\n"), pSrcControlDesc->dwType));
ASSERT(0);
break;
}
PerformMixerCallbacks (MM_MIXM_CONTROL_CHANGE, GET_MXCONTROL_ID(pSrcControlDesc));
return MMSYSERR_NOERROR;
}
// mixerGetDevCaps
MMRESULT
AC97Mixer::GetMixerCaps(PMIXERCAPS pCaps)
{
pCaps->wMid = MM_CRYSTAL;
pCaps->wPid = MM_CRYSTAL_EP9312_MIXER;
wsprintf (pCaps->szPname, TEXT("EP9312 Audio (%hs)"), __DATE__);
pCaps->vDriverVersion = 1;
pCaps->cDestinations = NELEMS(g_dst_lines);
pCaps->fdwSupport = 0;
return MMSYSERR_NOERROR;
}
void AC97Mixer::RMWCodecRegister(UCHAR Reg, USHORT Mask, USHORT Value)
{
ULONG Old,New;
m_pAC97Codec->PeekAC97(Reg, &Old);
New = (Old & Mask) | Value;
m_pAC97Codec->PokeAC97(Reg, New);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -