大家都进来了 可以关注一下每天我会分享大家学习资料教程,写的不好的大家也可以评论里发一下我会改,有需要资料,和问题的大家可以私信我知道的必答,资料有需要的必回,免费一起学习交流

C/C++,Linux,golang,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,嵌入式 等。。。关注+私信免费领取一份99的视频学习资料哦

最近做VR开发时需要对麦克风分的录音进行操作,其中涉及到调节录音的大小,检测录音的的大小等功能,我主要使用c++调用windows的音频相关的api来进行对录音的操作,在这里记录一下。

对音频的控制主要用到mixer相关的函数,与它相关的函数主要有以下几个

630e52a171af3f23a1bb138b254928e3.png

现在在来看看如何对麦克风录入音量大小的控制

792aca93ac90773f1b92347d93f41305.png

想要控制麦克风录入音量的大小,主要包括以下几个步骤

①遍历打开系统的混音器,直到找到麦克风的混音器,记录该设备ID

②根据取得的设备ID,取得音频线路相关的通用信息

③根据上面取得的音频线路相关的通用信息取得或者设定该音频线路的控制

具体的取得和控制麦克风设置音量的代码如下

ef2a681dcd96362c5489620678ad1770.png

411f85fc1c6f8a3a85f2ba8da39d361c.png

5db208a6627ce256b559cfcad8477b38.png

mxcd.cbStruct = sizeof(mxcd);

mxcd.dwControlID = mxc.dwControlID;

mxcd.paDetails = &volStruct;

mxcd.cbDetails = sizeof(volStruct);

mxcd.cChannels = 1;

//③获得音量值,取得的信息放在mxcd中

rc = mixerGetControlDetails((HMIXEROBJ)hMixer, &mxcd, MIXER_GETCONTROLDETAILSF_VALUE);

//初始化录音大小的信息

MIXERCONTROLDETAILS_UNSIGNED mxcdVolume_Set = { mxc.Bounds.dwMaximum * dwVolume / 100 };

MIXERCONTROLDETAILS mxcd_Set;

mxcd_Set.cbStruct = sizeof(MIXERCONTROLDETAILS);

mxcd_Set.dwControlID = mxc.dwControlID;

mxcd_Set.cChannels = 1;

mxcd_Set.cMultipleItems = 0;

mxcd_Set.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);

mxcd_Set.paDetails = &mxcdVolume_Set;

//③设置录音大小

mixerSetControlDetails((HMIXEROBJ)(hMixer),&mxcd_Set,MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE)

mixerClose(hMixer);

}

}

知道了如何设置和取得麦克风的默认录音大小后,我们在看看如何实时的检测麦克风录入音量的大小。想要知道麦克风实时录入音量的大小,需要采集录入的音量,然后对音量的波形进行分析,打开麦克风录音具体用到了waveIn相关的函数,具体的步骤如下。

71513b2b673b7209b5f550c74fb46918.png

下面是源码

/ 初始化设备并且开始录音

void WaveRecordStart(void) {

//额外信息的大小,以字节为单位,额外信息添加在WAVEFORMATEX结构的结尾。这个信息可以作为非PCM格式的wFormatTag额外属性,如果wFormatTag不需要额外的信息,此值必需为0,对于PCM格式此值被忽略。

WaveFormat.cbSize = 0;

//声道,2代表立体声,1代表单声道

WaveFormat.nChannels = 2;

//采样频率

WaveFormat.nSamplesPerSec = 44100;

//对齐方式

WaveFormat.nBlockAlign = 4;

//请求的平均数据传输率,单位byte/s

WaveFormat.nAvgBytesPerSec = 88200;

//每次采样样本的大小,以bit为单位

WaveFormat.wBitsPerSample = 16;

WaveFormat.wFormatTag = 1;

MMRESULT result;

result = waveInGetNumDevs();//获取设备数量

if (result == 0)

{

printf("No Sound Devicen");

return ;

}

4d6bb18b73794a959d9f9009e258b504.png

//获取指定波形音频设备的功能,第一个参数为设备id,第二个参数保存设备功能信息,第三个参数为设备结构体大小

result = waveInGetDevCaps(0, &m_WaveInDevCaps, sizeof(WAVEINCAPS));

if (result != MMSYSERR_NOERROR)

{

printf("Cannot determine sound card capabilities !n");

}

//打开录音设备,WaveProc为录音的回调函数

result = waveInOpen(&WaveIn, WAVE_MAPPER, &WaveFormat, (DWORD_PTR)&WaveProc, 0, CALLBACK_FUNCTION);

if (result != MMSYSERR_NOERROR)

{

printf("Opne_Mic_Errorn");

}

//lpData:波形数据的缓冲区地址

//dwBufferLength:波形数据的缓冲区地址的长度

//dwBytesRecorded:当设备用于录音时,标志已经录入的数据长度

//dwUser:用户数据

//dwFlags:波形数据的缓冲区的属性

//dwLoops:播放循环的次数,仅用于播放控制中

//lpNext和reserved均为保留值

//因为是左右两声道,所以要设置两次

WaveHdr[0].lpData = (LPSTR)Data1;

WaveHdr[0].dwBufferLength = MAX_SAMPLES *2;

WaveHdr[1].lpData = (LPSTR)Data2;

WaveHdr[1].dwBufferLength = MAX_SAMPLES * 2;

WaveHdr[0].dwBytesRecorded = WaveHdr[1].dwBytesRecorded = 0;

WaveHdr[0].dwUser = WaveHdr[1].dwUser = 0;

WaveHdr[0].dwFlags = WaveHdr[1].dwFlags = 0;

WaveHdr[0].dwLoops = WaveHdr[1].dwLoops = 0;

WaveHdr[0].lpNext = WaveHdr[1].lpNext = 0;

WaveHdr[0].reserved = WaveHdr[1].reserved = 0;

waveInPrepareHeader(WaveIn, WaveHdr, sizeof(WAVEHDR));

waveInAddBuffer(WaveIn, WaveHdr, sizeof(WAVEHDR));

waveInPrepareHeader(WaveIn, WaveHdr + 1, sizeof(WAVEHDR));

waveInAddBuffer(WaveIn, WaveHdr + 1, sizeof(WAVEHDR));

//开始获取声音

result=waveInStart(WaveIn);

if (result != MMSYSERR_NOERROR)

{

printf("waveInStart_Failn");

}

}

// 回调函数

void CALLBACK WaveProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD) {

if ((uMsg != WIM_DATA)) {

return;

}

//取得录音的数据

MMRESULT result;

WAVEHDR *pWaveHeader = (WAVEHDR *)dwParam1;

//pWaveHeader->lpData为录音数据

OutputWaveData((short *)pWaveHeader->lpData, pWaveHeader->dwBytesRecorded/2);

result = waveInAddBuffer(hwi,pWaveHeader, sizeof(WAVEHDR));

if (result != MMSYSERR_NOERROR)

{

printf("Cannot Add Buffer !");//WAVERR_UNPREPARED

}

}

// 导出数据

void OutputWaveData(short *data, DWORD dataLen)

{

dd35cb31f73795edccc833b9e7d929aa.png

e804ab8a9e3c376cde0ebb2c0bc01fd2.png

tmpResult.fWave_Frame_Avg /= dataLen; //平均值

tmpResult.fWave_Frame_RMS = sqrt(tmpResult.fWave_Frame_RMS /dataLen);//有效值

printf("VoiceInputLevel:%f", tmpResult.fWave_Frame_Max);

}

C++音频程序

dfecc642b79e69780c5028d28fb0b2d9.png

例子:(VC++ program:)

#include

#include

#include

int main(int argc, char* argv[])

{

unsigned FREQUENCY[]={392,392,440,392,523,494,

392,392,440,392,587,523,

392,392,784,659,523,494,440,

698,698,659,523,587,523};

unsigned DELAY[]={375,125,500,500,500,1000,

375,125,500,500,500,1000,

375,125,500,500,500,500,1000,

375,125,500,500,500,1000,};

int CIRCLE;

for(CIRCLE=0;CIRCLE<25;CIRCLE++)

{

Beep(FREQUENCY[CIRCLE],DELAY[CIRCLE]);

}

return 0;

}

附:在TC中输出音乐Speaker,可用函数:sound()、delay()和nosound()。

格式:

sound(频率)

delay(节拍)

nosound() //声音关闭

如上程序可把Beep()替换为:

for(CIRCLE=0;CIRCLE<25;CIRCLE++){

sound(FREQUENCY[CIRCLE]);

delay(DELAY[CIRCLE]);

nosound();

}

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐