一般正常的录音都是对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) 0 ,  0 , 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;
}

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

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

对声卡输出进行录音的设置.相关推荐

  1. C# Naudio 从麦克风输入到声卡输出 录音 放音功能

    本文采用简单的方式,如需使用其他功能,请访问Naudio相关功能 1.using NAudio.Wave;从麦克风输入到声卡输出,并操作数据 //创建输出对象 WaveOut waveOut = ne ...

  2. c++采集声卡输出_耳上明珠 | 魅族双 C 耳机 — EP2C

    魅族双 C 耳机 魅族 16s 取消了 3.5mm 耳机接口,使用 USB 输出数字音频信号,支持 Type-C 数字耳机或数字转接器.除了无线蓝牙耳机和一线难求的魅族 HIFI 解码耳放外,与魅族 ...

  3. c++采集声卡输出_其实声卡不单单只有音效,更多功能看这篇就对了

    其实声卡不仅仅是一块能够发声的卡,而是一块功能众多的多功能卡. 播放数字音乐: 这是声卡最基本的功能,这得益于数字音乐的存储方式的改进.从原始的wav到流行的mp3,在到新兴的wma等音频格式,使得数 ...

  4. matlab 控制声卡,请问高手关于matlab控制声卡输出的问题

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 请问高手,怎么我采样之后经声卡输出在示波器里看到的波形和采样滤波后的信号不一样呢?请高手帮忙 不知道怎么把采样滤波后的信号原样输出来,谢谢. 程序输出部分 ...

  5. matlab输出的图怎么设置网格背景图片,4.11Python数据处理篇之Matplotlib系列(十一)---图例,网格,背景的设置...

    目录 [TOC] 前言 本章节将讲一下三个内容,图例,网格,背景 (一)图例legend 1.默认不带参数的图例 (1)说明: 默认情况下,是自适应的放在图例的位置,需要在绘图的时候,添加Label标 ...

  6. 解决Linux只有Nvidia HDM声卡输出的现象

    解决Linux只有Nvidia HDM声卡输出的现象 起因 ​ 前几天刚刚重装了ArchLinux然后安装桌面后发现声卡不能用,一直在网上找教程找了几天,问题都对不上.倒是在archlinuxcn论坛 ...

  7. python stdout_python中stdout输出不缓存的设置方法

    考虑以下python程序: 复制代码 代码如下: #!/usr/bin/env python import sys sys.stdout.write("stdout1 ") sys ...

  8. 用步进正弦激励法测量计算机声卡输出输入幅值频响函数

    一. 实验目的 (1) 通过对计算机声卡系统的实测加深对频响函数的理解: (2) 对声音振动及测量有直观了解: (3) 对计算机声卡系统的频响特性有直观的认识. 二. 实验内容 (1) 用声卡发出的步 ...

  9. c++采集声卡输出_舒尔 Shure RMCE-LTG Lightning-MMCX接口耳机线[线型声卡]测评报告 [Soomal]...

    舒尔RMCE-LTG Lightning-MMCX接口耳机线,RMCE是Remote+Mic缩写,LTG是Lightning Cable缩写,指支持苹果iOS设备上的Lightning接口.而MMCX ...

最新文章

  1. pycharm Python解释器的配置--可以指定批处理文件为解释器
  2. 废旧光盘手工小制作_佳味家味浓 丨佳人美食手工零食课堂:咸蛋黄牛轧糖夹心小饼干制作活动...
  3. 关于私有变量,静态私有变量
  4. jQuery lazyload插件详解和问题解答
  5. 记录一些容易忘记的属性 -- UITabBarController
  6. 复制文本朗读_原创:昭明文选配乐朗读 卷第五十一 论一 东方曼倩 非有先生论 王子渊 四子讲德论 并序...
  7. 斯坦福大学深度学习公开课cs231n学习笔记(6)神经网路输入数据预处理(归一化,PCA等)及参数初始化
  8. javascript 本地存储(cookies、sessionStorage和localStorage解释及区别)
  9. 【数据预测】基于matlab双向长短时记忆(biLSTM)数据预测【含Matlab源码 1793期】
  10. Python——词频统计
  11. linux主机安装sctp协议栈
  12. shc加密shell脚本
  13. 计算机一级如何添加对角线,如何在表格中添加对角线
  14. WIN7 通过4G模块 拨号上网过程
  15. 【挖坑记】JZOJ 4722 跳楼机
  16. html5 邮箱后缀自动填写,Ant Design Vue AutoComplete 通过自定义选项search实现如自动补充邮箱后缀功能...
  17. python基础----面向对象的程序设计(五个阶段、对小白的忠告、关于OOP常用术语)、类、对象...
  18. 江苏扬州|2021年起,高支模须用盘扣式钢管支架!
  19. 电脑小知识:计算机防火墙到底是什么?能不能阻止黑客的入侵?
  20. VIO测试准备——使用imu_utils和kalibr进行相机与IMU标定

热门文章

  1. 使用自动编码器(Autoencoder)及其变体进行特征学习
  2. 【云原生系列】第四讲:Knative 之 Eventing
  3. GSEA load files errors
  4. Pixhawk PID参数整定
  5. 《炬丰科技-半导体工艺》硅氧化工艺
  6. TR-FS00会计科目创建GL_ACCT_MASTER_SAVE
  7. 英语作业介绍一项发明计算机,关于电脑发明的英语作文
  8. Unity3d AndroidJNI两篇应用示例。羽化的文章。
  9. leetcode703. 数据流中的第K大元素(PriorityQueue 最小堆)
  10. Adobe Bridge CC 2020中文版