2011-05-24 11:09 WINCE6.0 驱动音量调节的实现

来源:互联网 发布:没有windows update 编辑:程序博客网 时间:2024/05/22 12:15

作者:茫天靖剑

嵌入式linux/wince学习交流群:218326927

WINCE6.0 驱动音量调节的实现

WINCE音量调节的实现


       在WINCE平台下,用户可以通过设置控制面板的音量调节按钮,实现系统音量的调节。同时,如果使用一些媒体播放器,如mplayer,则可以对输入的音频流实行单独的调节,而不影响系统其他的音量。我们可以把整个架构理解为WINDOWS平台,用户通过设置右下角的声音按钮,实现整个系统的音量设置,而在播放如千千静听,暴风影音时,可以单独的设置软件的音量,而不影响整个系统的音量。WINCE的音量调节模型正是如此。
在手持机上,会用到专业的音频芯片,比较典型的有UDA1341,WM8976,WM9713等。这些芯片都留有I2C接口,供处理器设置芯片的寄存器,从而达到调节音量等的功能。在底层驱动中,通过留相应接口,实现在调节控制面板里面的音量时,最终调节音频芯片的寄存器,实现音量调节。
这是最常用的一种方法。但是有些OEM厂商为了节约成本,在硬件上大做文章,选择的音频芯片根本没有音量调节的功能,甚至连I2C接口都没有,仅有一个I2S接口用于音频解码。那么这时候,WINCE是否还能像前面的那样,实现音量调节?答案是肯定的。
在Wavemain.cpp中,音量调节程序如下:
    case WODM_GETVOLUME://获取喇叭音量
        {
            PULONG pdwGain = (PULONG)dwParam1;

            if (pStreamContext)
            {
                *pdwGain = pStreamContext->GetGain();
            }
            else
            {
                // Handle device gain in hardware
                //*pdwGain = g_pHWContext->GetOutputGain();//没有硬件音量调节支持
                // Handle device gain in software
                DeviceContext *pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);//软音量获取
                *pdwGain = pDeviceContext->GetGain();
            }
            dwRet = MMSYSERR_NOERROR;
            break;
        }

    case WODM_SETVOLUME://音量设置.
        {
            LONG dwGain = dwParam1;
            if (pStreamContext)//如果存在音频流,则这里调节音频流音量
            {
                    //RETAILMSG(1,(_T("Stream volume set...\n")));// lqm test.
                dwRet = pStreamContext->SetGain(dwGain);// dwGain=dwParam1,由应用层如mplayer传入.
                                //RETAILMSG(1,(_T("Stream volume set dwRet = %d\n"),dwRet));// lqm test.
            }
            else//如果不存在音频流,通过控制面板调节音量最终由这里控制音量。
            {
                    //RETAILMSG(1,(_T("hardware volume set...\n")));// lqm test.
                // Handle device gain in hardware
                //dwRet = g_pHWContext->SetOutputGain(dwGain);//如果音频芯片有音量调节功能,使用硬调节。
                // Handle device gain in software
                DeviceContext *pDeviceContext = g_pHWContext->GetOutputDeviceContext(uDeviceId);
                dwRet = pDeviceContext->SetGain(dwGain);//由于音频芯片没有音量调节功能,使用软算法。
            }
            break;
        }
第一个case: WODM_GETVOLUME用于获得当前音量的大小。注意在else里面,有GetOutputGain()和GetGain()两个函数。前面的函数用于获取硬件音量,即音频芯片的音量,后面的函数用于获取软件音量,即音频流音量。如果音频芯片具备音量调节功能,使用第一个函数,否则使用第二个函数。
第二个case: WODM_SETVOLUME用于设置音量。同样,在else里面,有SetOutputGain和SetGain两个函数。前面的函数用于设置硬件增益,即音频芯片寄存器。如果音频芯片不支持音量调节功能,则需要使用后面的函数。该函数用于音量软设置。
在第二个case中有一个if判断语句,标识位为pStreamContext。也就是说,如果存在音频流,即正在播放音频文件时,如果调用该case语句,则调用if里面程序进行音量设置,否则调用else下面的语句设置。如果采用软设置方法,两者最终都通过GainChange函数来完成,该函数代码如下:
virtual void GainChange()
    {
        m_fxpGain = MapGain(m_dwGain);//m_fxpGain保存音频流的音量大小
    }
这里m_dwGain = dwGain = dwParam1,在HandleWaveMessage函数中,可以看到dwParam1 = pParams->dwParam1;也就是说m_dwGain是应用传下来的值,如通过mplayer,控制面板的音量设置按钮等。
我们再进入MapGain函数:
DWORD StreamContext::MapGain(DWORD Gain)//Gain由应用层如媒体播放器传入,条件是有音频流的情况下。
{
    DWORD TotalGain = Gain & 0xFFFF;
    DWORD SecondaryGain = m_pDeviceContext->GetSecondaryGainLimit(m_SecondaryGainClass) & 0xFFFF;

        //RETAILMSG(1,(_T("MapGain Volume set Gain = 0x%x\n"),Gain));//lqm test.

    if (m_SecondaryGainClass < SECONDARYDEVICEGAINCLASSMAX)
    {
        // Apply device gain
        DWORD DeviceGain = m_pDeviceContext->GetGain() & 0xFFFF;
                RETAILMSG(1,(_T("Gain=0x%x,DeviceGain=0x%x\n"),Gain,DeviceGain));//lqm test.
        TotalGain *= DeviceGain;
        TotalGain += 0xFFFF;  // Round up
        TotalGain >>= 16;     // Shift to lowest 16 bits
    }

    // Apply secondary gain
    TotalGain *= SecondaryGain;
    TotalGain += 0xFFFF;  // Round up
    TotalGain >>= 16;     // Shift to lowest 16 bits

        RETAILMSG(1,(_T("MapGain Volume set TotalGain = 0x%x\n"),TotalGain));//lqm test.

    // Special case 0 as totally muted
    if (TotalGain==0)
    {
        return 0;
    }

    // Convert to index into table
    DWORD Index = 63 - (TotalGain>>10);
        RETAILMSG(1,(_T("MapGain Index = 0x%x\n"),Index));//lqm test.
        //Index = 50;//lqm added for test.10-05-06
    return GainMap[Index];
}
传入参数Gain即上面提到的m_dwGain,该参数为32位寄存器,高16位和低16位分别存放左右声道。由于一般情况下左右声道的音量都是一样的,故程序中只取了低16位。
TotalGain是DeviceGain和m_dwGain的乘积,然后右移16位得到的。其实就是TotalGain=DeviceGain*m_dwGain/最高音量,如果把DeviceGain/最高音量,用百分比来算的话,就很更容易理解了,那么最后的公式就变成TotalGain=DeviceGain*系统音量百分比。那么这里就解释了系统音量是如何限制流音量的疑问。
最终通过一个索引求出对应音量的权值,再通过音量表设置音量。可以看到Index = 63 - (TotalGain>>10);Index在0到63的范围内。返回的GainMap表如下:
const DWORD GainMap[] =
{
0x10000, // 0: 0.000000 dB
0xec77, // 1: -1.587302 dB
0xda6d, // 2: -3.174603 dB
0xc9c2, // 3: -4.761905 dB
0xba5d, // 4: -6.349206 dB
0xac25, // 5: -7.936508 dB
0x9f03, // 6: -9.523810 dB
0x92e1, // 7: -11.111111 dB
0x87ac, // 8: -12.698413 dB
0x7d52, // 9: -14.285714 dB
0x73c2, // 10: -15.873016 dB
0x6aed, // 11: -17.460317 dB
0x62c5, // 12: -19.047619 dB
0x5b3b, // 13: -20.634921 dB
0x5445, // 14: -22.222222 dB
0x4dd7, // 15: -23.809524 dB
0x47e7, // 16: -25.396825 dB
0x426b, // 17: -26.984127 dB
0x3d59, // 18: -28.571429 dB
0x38ab, // 19: -30.158730 dB
0x3458, // 20: -31.746032 dB
0x305a, // 21: -33.333333 dB
0x2ca9, // 22: -34.920635 dB
0x2941, // 23: -36.507937 dB
0x261b, // 24: -38.095238 dB
0x2333, // 25: -39.682540 dB
0x2083, // 26: -41.269841 dB
0x1e08, // 27: -42.857143 dB
0x1bbe, // 28: -44.444444 dB
0x19a0, // 29: -46.031746 dB
0x17ab, // 30: -47.619048 dB
0x15dd, // 31: -49.206349 dB
0x1432, // 32: -50.793651 dB
0x12a7, // 33: -52.380952 dB
0x113b, // 34: -53.968254 dB
0x0fea, // 35: -55.555556 dB
0x0eb3, // 36: -57.142857 dB
0x0d94, // 37: -58.730159 dB
0x0c8b, // 38: -60.317460 dB
0x0b96, // 39: -61.904762 dB
0x0ab4, // 40: -63.492063 dB
0x09e3, // 41: -65.079365 dB
0x0921, // 42: -66.666667 dB
0x086f, // 43: -68.253968 dB
0x07ca, // 44: -69.841270 dB
0x0732, // 45: -71.428571 dB
0x06a6, // 46: -73.015873 dB
0x0624, // 47: -74.603175 dB
0x05ac, // 48: -76.190476 dB
0x053d, // 49: -77.777778 dB
0x04d7, // 50: -79.365079 dB
0x0478, // 51: -80.952381 dB
0x0421, // 52: -82.539683 dB
0x03d0, // 53: -84.126984 dB
0x0386, // 54: -85.714286 dB
0x0341, // 55: -87.301587 dB
0x0301, // 56: -88.888889 dB
0x02c6, // 57: -90.476190 dB
0x0290, // 58: -92.063492 dB
0x025e, // 59: -93.650794 dB
0x0230, // 60: -95.238095 dB
0x0205, // 61: -96.825397 dB
0x01de, // 62: -98.412698 dB
0x01b9, // 63: -100.000000 dB
};
这就是软音量设置最终调用的音量配置表。具体它是如何通过这个表来实现软音量设置的,还需要认真研究,难道通过I2S送到音频芯片的数字信号里面已经带有音量数据?不过到这里,软的音量调节功能已经实现了,详细的原理有空再仔细研究。

原文地址:http://hi.baidu.com/jiandanbinxin/item/4f6db9d6be65f046fb576884
原创粉丝点击