诗剑书生的专栏

我在灌江口上住,花开花落,不知流年度.雁过空遗秋色暮,抚琴细听梧桐雨. 轻舞残虹漫展书,云卷云舒,思愫万千缕.安得婵娟与共处,长作识字耕田夫.                   诗剑书生 于灌江口.听潮居

用户操作
[即时聊天] [发私信] [加为好友]
诗剑书生ID:axman
108734次访问,排名817好友0人,关注者16
一个男人. 一个写程序男人. 一个写程序并从程序中寻找快乐的男人. 一个写程序并从程序中寻找快乐又把快乐传递给大家的男人.
一个书生. 一个寂寞的书生. 一个寂寞的梅香竹影下敲声写韵的书生. 一个寂寞的梅香竹影下敲声写韵晨钟暮鼓中逸气扬剑的书生.
那个男人是位书生。没有人知道他的姓名,居无定所,行无定踪,亦耕亦读,或渔或樵。
axman的文章
原创 87 篇
翻译 0 篇
转载 0 篇
评论 161 篇
axman的公告
最近评论
ZangXT:醍醐灌顶
matay:能不能把这个打包mms的工程源代码共享一下?万分感谢!
mataym@gmail.com
axman:不用说明什么,一切都如我预料的那样.
在整个奥运开幕式期间,我一边看电视,一边访问
http://www.cctvolympics.com/main.php?type=vod这个地址,其间访问一百多次,没有一次成功.大多数时候是前端缓存的squid在报refuse(111).有时以过几分钟的等待,能出来页面,但Flash缓冲的进度条到了99%就一直停止在那儿.
……
myvicc:写得不错,等写下文
chinagavin:我是先读三位正向输出,然后再读三位反向输出来最终达到想要的结果。
文章分类
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 对声卡输出进行录音的设置.收藏

    新一篇: 你适合做架构师吗?简单的一个小测试. | 旧一篇: GSM MODEM发PUSH/MMS 的具体实现.

    一般正常的录音都是对Line in进行录音,但有些需要对line out进行录音,因为有些音源是没有line in的.

    如即时聊天时录取对方的语音.但这些声音都要经过声卡播放,所以它们的音源就是声卡输出.

    对于声卡的输出,在录音控制中有两个,就是Mono mix和stereo mix,当然最好是选取 stereo mix,效果更好.

    编程打开录音设备时,是不能控制打开的设备上的输出还是输入通道的.所在要在打开设备前就设置好.

    用Mixer的API可以对输出源进行牧举,不过不同的设备的定义不同,对于SoundMax能够正确区别stereo mix和Mono mix的区别,但AC 97的声卡它都是相似的输出源.所以只能多次地优选列举.代码逻辑不是完美,但只能如此.否则只能让用户手工选择,致少要按6次mouse才行.

    以下是自己定义的结构,在第一次没有找到正确的输出源时将所有输出源保的index,swLineID和name保存起来.下面

    在结构数组中再优选,而不要再对设备牧举

    typedef struct ControlEnumData{
     INT index;
     CString szName;
     DWORD dwLineID;
    }  CTRL_ENUM_DATA,* LPCTRL_ENUM_DATA;

     

     

    BOOL   XXX::setOutSource()

       UINT deviceCount 
    = ::mixerGetNumDevs();
        
    if(deviceCount < 1){
            MessageBox(
    "没有找到混音设备,请手工选择录音设备的混音输出!");
            
    return TRUE;
        }
        BOOL found 
    = FALSE;

        
    for(UINT devID = 0;devID < deviceCount; devID++){
            HMIXER hMixer;
            
    if (mixerOpen(&hMixer, devID, (DWORD)00, CALLBACK_WINDOW) != MMSYSERR_NOERROR)
            {
            ::mixerClose(hMixer);
                
    continue;
            }

            MIXERLINE line;
            line.cbStruct 
    = sizeof(MIXERLINE);
            
    //注意我们要查找的是录音设备.所以dwComponentType 应该是 MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
            line.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
            
    if(::mixerGetLineInfo((HMIXEROBJ)hMixer,&line,
                MIXER_OBJECTF_HMIXER
    |MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR){
            ::mixerClose(hMixer);
                
    continue;
            }
            DWORD dwConnections 
    = line.cConnections;
            DWORD selectIndex 
    = -1;
            MIXERLINE linesub;
            CTRL_ENUM_DATA enumData[
    8];
            
    int enumIndex = 0;
            
    //然后看录音设备上共一连结了几个线路
            for(DWORD i = 0;i< dwConnections ;i++){    //列举出波形混音输出源的索引并最声音设置最大
                linesub.cbStruct = sizeof(MIXERLINE);   
                linesub.dwSource   
    =   i;   
                linesub.dwDestination 
    = line.dwDestination;
                
    if(mixerGetLineInfo((HMIXEROBJ)hMixer,&linesub,
                    MIXER_OBJECTF_HMIXER
    |MIXER_GETLINEINFOF_SOURCE) == MMSYSERR_NOERROR){
                    
    if(linesub.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT){
                        
    //这是stereo mix的输出源.如果能明确找到,就直接定位到这个index上.
                        
    //并把这个设备选中并把音量调到最大.
                        MIXERCONTROL   mxc;   
                        MIXERLINECONTROLS   mxlc;   
                        mxlc.cbStruct   
    =   sizeof(MIXERLINECONTROLS);   
                        mxlc.dwLineID   
    =   linesub.dwLineID;
                        DWORD  dwControlType 
    = MIXERCONTROL_CONTROLTYPE_VOLUME; 
                        mxlc.dwControlType   
    =   dwControlType;   
                        mxlc.cControls   
    =   1;   
                        mxlc.cbmxctrl   
    =   sizeof(MIXERCONTROL);   
                        mxlc.pamxctrl   
    =   &mxc;   
                        
    if   (::mixerGetLineControls((HMIXEROBJ)hMixer,&mxlc,
                            MIXER_OBJECTF_HMIXER
    |MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)   
                        {   
                            MIXERCONTROLDETAILS_BOOLEAN vumVal[
    1];
                            MIXERCONTROLDETAILS   mxcd;   
                            mxcd.cbStruct   
    =   sizeof(MIXERCONTROLDETAILS);   
                            mxcd.dwControlID   
    =   mxc.dwControlID;//在上面的&mxc得到   
                            mxcd.cChannels   =   1;   
                            mxcd.cMultipleItems  
    = mxc.cMultipleItems;  
                            mxcd.cbDetails   
    =   sizeof(MIXERCONTROLDETAILS_BOOLEAN);   
                            mxcd.paDetails   
    = &vumVal;
                            vumVal[
    0].fValue = 65535;
                            
    //将设备音量调至最大
                            ::mixerSetControlDetails((HMIXEROBJ)hMixer,&mxcd,
                                MIXER_OBJECTF_HMIXER
    |MIXER_GETCONTROLDETAILSF_VALUE);

                        }
                        selectIndex 
    = i;
                        
    break//如果明确找到 MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT,break出去

                    }
                    
    if(linesub.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_ANALOG){ 
                        
    //否则是MIXERLINE_COMPONENTTYPE_SRC_ANALOG的话,保存起来
                        enumData[enumIndex].index = i;
                        enumData[enumIndex].dwLineID 
    = linesub.dwLineID;
                        enumData[enumIndex
    ++].szName = linesub.szName;
                    }
                }

            }
            
    if(selectIndex == -1 && enumIndex < 1) {
            ::mixerClose(hMixer);
            
    continue;
        }
            
    //既没有找到MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT,也没有找到MIXERLINE_COMPONENTTYPE_SRC_ANALOG.

            DWORD vumLineID;    
    //这个ID用于下面对找到的输出源调整音量
            if(selectIndex == -1){    //第一次优选,找STEREO
                for(INT i = 0;i < enumIndex;i++){
                    
    if(enumData[i].szName.MakeUpper().Find("STEREO"!= -1)
                    {    
                        selectIndex 
    = enumData[i].index;
                        vumLineID 
    = enumData[i].dwLineID;
                        
    break;
                    }
                }
            }
            
    if(selectIndex == -1){    //第二次优选,找MONO
                for(INT i = 0;i < enumIndex;i++){
                    
    if(enumData[i].szName.MakeUpper().Find("MONO"!= -1)
                    {    
                        selectIndex 
    = enumData[i].index;
                        vumLineID 
    = enumData[i].dwLineID;
                        
    break;
                    }
                }
            }
            
    if(selectIndex == -1){ //都没有就默认第一个吧.无奈 :(
                selectIndex = enumData[0].index;
                vumLineID 
    = enumData[0].dwLineID;
            }
            
    if(selectIndex != -1){    
                        
    //此时肯selectIndex肯定不为-1,加了条件是想在{}内重新定义mxc,mxlc
                        
    //来设置音量,不和下面的设置选中的mxc,mxlc冲突.
                MIXERCONTROL   mxc;   
                MIXERLINECONTROLS   mxlc;   
                mxlc.cbStruct   
    =   sizeof(MIXERLINECONTROLS);   
                mxlc.dwLineID   
    =   vumLineID;
                DWORD  dwControlType 
    = MIXERCONTROL_CONTROLTYPE_VOLUME; 
                mxlc.dwControlType   
    =   dwControlType;   
                mxlc.cControls   
    =   1;   
                mxlc.cbmxctrl   
    =   sizeof(MIXERCONTROL);   
                mxlc.pamxctrl   
    =   &mxc;   
                
    if   (::mixerGetLineControls((HMIXEROBJ)hMixer,&mxlc,
                    MIXER_OBJECTF_HMIXER
    |MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR)   
                {   
                    MIXERCONTROLDETAILS_BOOLEAN vumVal[
    1];
                    MIXERCONTROLDETAILS   mxcd;   
                    mxcd.cbStruct   
    =   sizeof(MIXERCONTROLDETAILS);   
                    mxcd.dwControlID   
    =   mxc.dwControlID;
                    mxcd.cChannels   
    =   1;   
                    mxcd.cMultipleItems  
    = mxc.cMultipleItems;  
                    mxcd.cbDetails   
    =   sizeof(MIXERCONTROLDETAILS_BOOLEAN);   
                    mxcd.paDetails   
    = &vumVal;
                    vumVal[
    0].fValue = 65535;
                    
    //将设备音量调至最大
                    ::mixerSetControlDetails((HMIXEROBJ)hMixer,&mxcd,
                        MIXER_OBJECTF_HMIXER
    |MIXER_GETCONTROLDETAILSF_VALUE);

                }


            }
            
    //得到了index就能正确定位该输出源并将其选中,这里调试的时候浪费了很多时间,网上的代码
            
    //都是错误的.录音通道列表和控制面板中录音属性中顺序是一致的,但是对其选中的控件的顺序
            
    //是反的.这一点我调试了好久才发现,没有找到相关文档.KAO,网上可以看到的文章都是错误的.

            found 
    =TRUE;
            MIXERCONTROL   mxc;   
            MIXERLINECONTROLS   mxlc;   
            mxlc.cbStruct   
    =   sizeof(MIXERLINECONTROLS);   
            mxlc.dwLineID   
    =   line.dwLineID;
            
    //注意不能在linesub中查找MIXERCONTROL_CONTROLTYPE_MUX,因为"选中"互斥控件是整个录音控制的
            
    //即 MIXERLINE_COMPONENTTYPE_DST_WAVEIN,不是波形混音输出源所独有的.
            DWORD  dwControlType = MIXERCONTROL_CONTROLTYPE_MUX; 
            mxlc.dwControlType   
    =   dwControlType;   
            mxlc.cControls   
    =   1;   
            mxlc.cbmxctrl   
    =   sizeof(MIXERCONTROL);   
            mxlc.pamxctrl   
    =   &mxc;   
            
    if(::mixerGetLineControls((HMIXEROBJ)hMixer,&mxlc,
                MIXER_OBJECTF_HMIXER
    |MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)   
            {   
                MessageBox(
    "无法选中波形混音输出,请从控制面板中手工设置混音输出为录音设备!");
                
    return   FALSE;   
            }

            MIXERCONTROLDETAILS_BOOLEAN vumVal[
    8];
            MIXERCONTROLDETAILS  mxcd;   
            mxcd.cbStruct   
    =   sizeof(MIXERCONTROLDETAILS);   
            mxcd.dwControlID   
    =   mxc.dwControlID;
            mxcd.cChannels   
    =   1;   
            mxcd.cMultipleItems  
    = mxc.cMultipleItems;  
            mxcd.cbDetails   
    =   sizeof(MIXERCONTROLDETAILS_BOOLEAN);   
            mxcd.paDetails   
    =&vumVal;

            
    if(::mixerGetControlDetails((HMIXEROBJ)hMixer,&mxcd,
                MIXER_OBJECTF_HMIXER
    |MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
            {   
                MessageBox(
    "无法选中波形混音输出,请从控制面板中手工设置混音输出为录音设备!");
                
    return   FALSE;   
            }     
            
    for(DWORD i = 0;i<mxc.cMultipleItems;i++){
                vumVal[i].fValue 
    = FALSE;
            }
            vumVal[mxc.cMultipleItems
    -selectIndex-1].fValue = TRUE;
            
    //选中控件顺序和设备顺序相反,TMD
            if(::mixerSetControlDetails((HMIXEROBJ)hMixer,&mxcd,
                MIXER_OBJECTF_HMIXER
    |MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
            {   
                MessageBox(
    "无法选中波形混音输出,请从控制面板中手工设置混音输出为录音设备!");
                
    return   FALSE;   
            }      
            ::mixerClose(hMixer);
            
    break;    //如果到这里已经正确设置了,break出去.
        }
        
    if(!found){
            MessageBox(
    "没有找到录音设备的混音输出,请手工选择!");
        }
        
    return TRUE;
    }

     

     

    另外,因为混音输出是各种声音的在声卡的输出,所以在录音前最好把所有输入源设为禁音,这样可以保证质量.

    并将其它的输出源的音量设为最小(这个是否有影响没有测试)

     

     

    发表于 @ 2007年08月02日 17:40:00|评论(loading...)|编辑

    新一篇: 你适合做架构师吗?简单的一个小测试. | 旧一篇: GSM MODEM发PUSH/MMS 的具体实现.

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © axman