⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ac97mixer.cpp

📁 EP931X系列的WinCE声卡驱动源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
        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 + -