百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

C++易用和高效的音频合成 c++制作音乐播放器

liebian365 2024-11-12 13:07 22 浏览 0 评论

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

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

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

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

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

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

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

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

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

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

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相关的函数,具体的步骤如下。

下面是源码

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

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 Device\n");

return ;

}

//获取指定波形音频设备的功能,第一个参数为设备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_Error\n");

}

//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_Fail\n");

}

}

// 回调函数

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)

{

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

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

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

}

C++音频程序

例子:(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();

}

相关推荐

4万多吨豪华游轮遇险 竟是因为这个原因……

(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...

“菜鸟黑客”必用兵器之“渗透测试篇二”

"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...

科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白

作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...

麦子陪你做作业(二):KEGG通路数据库的正确打开姿势

作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...

知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势

智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...

每日新闻播报(September 14)_每日新闻播报英文

AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...

香港新巴城巴开放实时到站数据 供科技界研发使用

中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...

5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper

本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...

Qt动画效果展示_qt显示图片

今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...

如何从0到1设计实现一门自己的脚本语言

作者:dong...

三年级语文上册 仿写句子 需要的直接下载打印吧

描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...

C++|那些一看就很简洁、优雅、经典的小代码段

目录0等概率随机洗牌:1大小写转换2字符串复制...

二年级上册语文必考句子仿写,家长打印,孩子照着练

二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...

一年级语文上 句子专项练习(可打印)

...

亲自上阵!C++ 大佬深度“剧透”:C++26 将如何在代码生成上对抗 Rust?

...

取消回复欢迎 发表评论: