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

📄 ac97mixer.cpp

📁 EP931X系列的WinCE声卡驱动源代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
        "Aux Volume","Aux Volume",
        MIXERLINE_TARGETTYPE_UNDEFINED
        ),
    // src line 4 - Stereo Mix
    MXSLE(MXLINEID(PCM_IN, STEREO_MIX), 1, 4,
        MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE, // flags
        MIXERLINE_COMPONENTTYPE_SRC_ANALOG,
        2,1,
        "Stereo Mix", "Stereo Mix",
        MIXERLINE_TARGETTYPE_UNDEFINED
        ),

};
const int nlines = NELEMS(g_mixerline);


DWORD
RegToVol(DWORD dwSetting, DWORD dwMax)
{
    return (dwMax - (dwSetting & dwMax)) * (LOGICAL_VOLUME_MAX-1) / dwMax;
}

USHORT
VolToReg(DWORD dwVolume, DWORD dwMax)
{

    return (USHORT) (dwMax - dwVolume * dwMax / (LOGICAL_VOLUME_MAX-1));
}

PMXLINEDESC
LookupMxLine(USHORT usLineID)
{
    // scan for mixer line
    for (int i = 0; i < nlines; i++) {
        if (g_mixerline[i].usLineID == usLineID) {
            return &g_mixerline[i];
        }
    }
    return NULL;
}

int
LookupMxControl (USHORT usLineID, DWORD dwControlType)
{
    for (int i = 0; i < ncontrols; i++) {
        PMXCONTROLDESC pSrcControl = &g_controls[i];
        if (    pSrcControl->usLineID == usLineID 
            &&  pSrcControl->dwType == dwControlType) {
            break;
        }
    }
    return i;
}

void
CopyMixerControl(PMIXERCONTROL pDst, PMXCONTROLDESC pSrc, DWORD dwIndex)
{
    // all of our lines have a volume and a mute.
    // in addition, the PCM_IN has a MUX control
    // fill in the volume:
    pDst->cbStruct = sizeof(MIXERCONTROL);
    pDst->dwControlID = dwIndex;

    wcscpy(pDst->szName, pSrc->szName);
    wcscpy(pDst->szShortName, pSrc->szName);

    pDst->dwControlType = pSrc->dwType;
    pDst->cMultipleItems = 0;

    switch(pSrc->dwType) {
    case MIXERCONTROL_CONTROLTYPE_VOLUME:
        pDst->fdwControl = 0;
        pDst->Metrics.cSteps = pSrc->usMask;
        pDst->Bounds.lMaximum = LOGICAL_VOLUME_MAX;
        pDst->Bounds.lMinimum = LOGICAL_VOLUME_MIN;
        break;
    case MIXERCONTROL_CONTROLTYPE_ONOFF:
    case MIXERCONTROL_CONTROLTYPE_MUTE:
        pDst->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM;
        pDst->Metrics.cSteps = 0;
        pDst->Bounds.lMaximum = 1;
        pDst->Bounds.lMinimum = 0;
        break;
    case MIXERCONTROL_CONTROLTYPE_MUX:
        // this better be Record Select...
        pDst->cMultipleItems = 5;
        pDst->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM | MIXERCONTROL_CONTROLF_MULTIPLE;
        pDst->Metrics.cSteps = 5;
        pDst->Bounds.lMaximum = 5;
        pDst->Bounds.lMinimum = 0;
        break;
    default:
        DEBUGMSG(ZONE_ERROR, (TEXT("Unexpected control type %08x\r\n"), pSrc->dwType));
        ASSERT(0);
    }
}

//#########################################################################
// Mixer Driver Entries
//#########################################################################

MMRESULT AC97Mixer::Initialize (AC97Codec *pAC97Codec)
{ 
    int i;
    USHORT mux_setting;

    m_pAC97Codec = pAC97Codec;

    // The mixer lines and controls are represented with two separate structures:
    // a 'description' structure, which is constant and global,
    // and a 'state' structure, which is modifiable and device-specific
    // At initialization time, we allocate the line and control state objects
    // and associate them with the corresponding description objects.
    // There is a one-to-one correspondence between entries in the global
    // line and control description tables (g_mixerline and g_controls) and
    // the instance-specific state arrays.
    m_pMxLineState = new MXLINESTATE [nlines];
    if (m_pMxLineState == NULL) 
    {
        return MMSYSERR_ERROR;
    }
    m_pMxControlState = new MXCONTROLSTATE [ncontrols];
    if (m_pMxControlState == NULL) 
    {
        return MMSYSERR_ERROR;
    }
    // this function assumes that the audio device has been initialized and that it's 
    // safe to go read the startup settings from the device
    for (i = 0; i < nlines; i++) {
        m_pMxLineState[i].dwState = 0;
    }
    for (i = 0; i < ncontrols; i++) {
        // figure out which kind of control
        ULONG regval;

        
        m_pAC97Codec->PeekAC97(g_controls[i].ucCodecRegister, &regval);

        if (g_controls[i].ucCodecRegister == AC97_RECORD_GAIN) {
            m_pMxControlState[i].fVirtualized = TRUE;
        }
        else {
            m_pMxControlState[i].fVirtualized = FALSE;
        }
        switch (g_controls[i].dwType) {
        case MIXERCONTROL_CONTROLTYPE_VOLUME:
            { 
                DWORD l = RegToVol(regval & g_controls[i].usMask, g_controls[i].usMask);
                DWORD r = RegToVol((regval >> 8) & g_controls[i].usMask, g_controls[i].usMask);
                m_pMxControlState[i].uSetting.dw = l | (r << 16);
            }
            break;
        case MIXERCONTROL_CONTROLTYPE_ONOFF:
        case MIXERCONTROL_CONTROLTYPE_MUTE:
            m_pMxControlState[i].uSetting.b = !!(regval & g_controls[i].usMask);
            break;
        case MIXERCONTROL_CONTROLTYPE_MUX:
            mux_setting =  (USHORT)(regval & 0xff); 
            m_pMxControlState[i].uSetting.us = mux_setting;
            break;
        default:
            // should never get here!
            DEBUGCHK(0);
            break;
        }
    }
    // special case handling for the record-select muxed inputs
    // figure out which line is selected and un-virtualize it's control
    int index = LookupMxControl(MuxIndexToLine[mux_setting], MIXERCONTROL_CONTROLTYPE_VOLUME);
    ASSERT(index < ncontrols);
    m_pMxControlState[index].fVirtualized = FALSE;

    return MMSYSERR_NOERROR;
}

typedef DWORD (* PFNDRIVERCALL) 
    (
    DWORD  hmx,
    UINT   uMsg,
    DWORD  dwInstance,
    DWORD  dwParam1,
    DWORD  dwParam2
    );


struct _tagMCB
{
    DWORD           hmx;
    PFNDRIVERCALL   pfnCallback;
    PMIXER_CALLBACK pNext;
};

void
AC97Mixer::PerformMixerCallbacks(DWORD dwMessage, DWORD dwId)
{

    PMIXER_CALLBACK pCurr;
    for (pCurr = m_pHead; pCurr != NULL; pCurr = pCurr->pNext) {
        if (pCurr->pfnCallback != NULL) {
            DEBUGMSG(ZONE_IOCTL, (TEXT("MixerCallback(%d)\r\n"), dwId));
            pCurr->pfnCallback(pCurr->hmx, dwMessage, 0, dwId, 0);
        }
    }
}


MMRESULT  
AC97Mixer::OpenMixerHandle(PDWORD phMixer, PMIXEROPENDESC pMOD, DWORD dwFlags)
{
    PMIXER_CALLBACK pNew = new MIXER_CALLBACK;
    if (pNew == NULL) {
        DEBUGMSG(ZONE_ERROR, (TEXT("OpenMixerHandle: out of memory\r\n")));
        return MMSYSERR_NOMEM;
    }

    pNew->hmx = (DWORD) pMOD->hmx;
    if (dwFlags & CALLBACK_FUNCTION) {
        pNew->pfnCallback = (PFNDRIVERCALL) pMOD->dwCallback;
    }
    else {
        pNew->pfnCallback = NULL;
    }
    pNew->pNext = m_pHead;
    m_pHead = pNew;
    *phMixer = (DWORD) pNew;
 
    return MMSYSERR_NOERROR;
}

MMRESULT  
AC97Mixer::CloseMixerHandle( MIXHANDLE mxh)
{
    PMIXER_CALLBACK pCurr, pPrev;
    pPrev = NULL;
    for (pCurr = m_pHead; pCurr != NULL; pCurr = pCurr->pNext) {
        if (pCurr == (PMIXER_CALLBACK) mxh) {
            if (pPrev == NULL) {
                // we're deleting the first item
                m_pHead = pCurr->pNext;
            }
            else {
                pPrev->pNext = pCurr->pNext;
            }
            delete pCurr;
            break;
        }
        pPrev = pCurr;
    }

    return MMSYSERR_NOERROR;
}

/*
- mixerGetLineInfo

MIXER_GETLINEINFOF_COMPONENTTYPE - first line whose type matches dwComponentType member of the MIXERLINE structure.
MIXER_GETLINEINFOF_DESTINATION  - line specified by dwDestination
MIXER_GETLINEINFOF_LINEID - line specified by the dwLineID member
MIXER_GETLINEINFOF_SOURCE - line specified by the dwDestination and dwSource
MIXER_GETLINEINFOF_TARGETTYPE - line that is for the dwType member of the Target structure

*/

MMRESULT  
AC97Mixer::GetMixerLineInfo( PMIXERLINE pQuery, DWORD dwFlags)
{ int i;

    // pQuery is validated by API - points to accessible, properly sized MIXERLINE structure

    // result - assume failure
    PMXLINEDESC pFound = NULL;
    MMRESULT mmRet = MIXERR_INVALLINE;
    USHORT usLineID;

    switch (dwFlags & MIXER_GETLINEINFOF_QUERYMASK) {
    case MIXER_GETLINEINFOF_DESTINATION:
        DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerLineInfo DESTINATION %x\r\n"), pQuery->dwDestination));
        {
            if (pQuery->dwDestination >= NELEMS(g_dst_lines)) {
                DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineInfo: invalid destination line %d\r\n"), pQuery->dwDestination));
                return MIXERR_INVALLINE;
            }
            usLineID = g_dst_lines[pQuery->dwDestination];
        }
        break;
    case MIXER_GETLINEINFOF_LINEID:
        DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerLineInfo LINEID %x\r\n"), pQuery->dwLineID));
        usLineID = (USHORT) pQuery->dwLineID;
        break;
    case MIXER_GETLINEINFOF_SOURCE:
        DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerLineInfo SOURCE %x %x\r\n"), pQuery->dwDestination, pQuery->dwSource));
        {
            // look up the destination line, then index into it's source table
            // to find the indexed source.
            if (pQuery->dwDestination >= NELEMS(g_dst_lines)) {
                DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineInfo: invalid destination line %d\r\n"), pQuery->dwDestination));
                return MIXERR_INVALLINE;
            }
            PMXLINEDESC pLine = LookupMxLine(g_dst_lines[pQuery->dwDestination]);
            if (pLine == NULL) {
                DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineInfo: inconsistent internal mixer line table\r\n")));
                return MMSYSERR_ERROR;
            }
            if (pQuery->dwSource >= pLine->ucConnections) {
                DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineInfo: invalid source line %d\r\n"), pQuery->dwSource));
                return MIXERR_INVALLINE;
            }
            usLineID = pLine->pSources[pQuery->dwSource];
        }
        break;
    case MIXER_GETLINEINFOF_COMPONENTTYPE:
        DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerLineInfo COMPONENT\r\n")));
        break;

    case MIXER_GETLINEINFOF_TARGETTYPE:
        DEBUGMSG(ZONE_MXDM, (TEXT("GetMixerLineInfo TARGET\r\n")));
        // valid query, but we're not going to form usLineID
        break;
    default:
        DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineInfo: invalid query %08x\r\n"), dwFlags & MIXER_GETLINEINFOF_QUERYMASK));
        return MMSYSERR_INVALPARAM;
    }

    switch (dwFlags & MIXER_GETLINEINFOF_QUERYMASK) {
    case MIXER_GETLINEINFOF_COMPONENTTYPE:
        // scan for line of proper type
        for (i = 0; i < nlines; i++) {
            if (g_mixerline[i].dwComponentType == pQuery->dwComponentType) {
                pFound = &g_mixerline[i];
                break;
            }
        }
#ifdef DEBUG
        if (pFound == NULL) {
            DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineInfo: no line of component type %08x\r\n"), pQuery->dwComponentType));
        }
#endif
        break;
    case MIXER_GETLINEINFOF_TARGETTYPE:
        // scan for target type
        for (i = 0; i < nlines; i++) {
            if (g_mixerline[i].dwTargetType == pQuery->Target.dwType) {
                pFound = &g_mixerline[i];
                break;
            }
        }
#ifdef DEBUG
        if (pFound == NULL) {
            DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineInfo: no line of target type %08x\r\n"), pQuery->Target.dwType));
        }
#endif
        break;

    case MIXER_GETLINEINFOF_DESTINATION:
    case MIXER_GETLINEINFOF_LINEID:
    case MIXER_GETLINEINFOF_SOURCE:
        pFound = LookupMxLine(usLineID);
        if (pFound == NULL) {
            DEBUGMSG(ZONE_ERROR, (TEXT("GetMixerLineInfo: invalid line ID %08x\r\n"), usLineID));
            return MMSYSERR_ERROR;
        }
        break;
    default:
        // should never happen - we filter for this in the first switch()
        break;

    }

    if (pFound != NULL) {
        pQuery->cChannels = pFound->ucChannels;
        pQuery->cConnections = pFound->ucConnections;
        pQuery->cControls = pFound->ucControls;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -