百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

C++易用和高效的音频合成

bigegpt 2024-09-17 12:25 8 浏览

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

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();

}

相关推荐

Go语言泛型-泛型约束与实践(go1.7泛型)

来源:械说在Go语言中,Go泛型-泛型约束与实践部分主要探讨如何定义和使用泛型约束(Constraints),以及如何在实际开发中利用泛型进行更灵活的编程。以下是详细内容:一、什么是泛型约束?**泛型...

golang总结(golang实战教程)

基础部分Go语言有哪些优势?1简单易学:语法简洁,减少了代码的冗余。高效并发:内置强大的goroutine和channel,使并发编程更加高效且易于管理。内存管理:拥有自动垃圾回收机制,减少内...

Go 官宣:新版 Protobuf API(go pro版本)

原文作者:JoeTsai,DamienNeil和HerbieOng原文链接:https://blog.golang.org/a-new-go-api-for-protocol-buffer...

Golang开发的一些注意事项(一)(golang入门项目)

1.channel关闭后读的问题当channel关闭之后再去读取它,虽然不会引发panic,但会直接得到零值,而且ok的值为false。packagemainimport"...

golang 托盘菜单应用及打开系统默认浏览器

之前看到一个应用,用go语言编写,说是某某程序的windows图形化客户端,体验一下发现只是一个托盘,然后托盘菜单的控制面板功能直接打开本地浏览器访问程序启动的webserver网页完成gui相关功...

golang标准库每日一库之 io/ioutil

一、核心函数概览函数作用描述替代方案(Go1.16+)ioutil.ReadFile(filename)一次性读取整个文件内容(返回[]byte)os.ReadFileioutil.WriteFi...

文件类型更改器——GoLang 中的 CLI 工具

我是如何为一项琐碎的工作任务创建一个简单的工具的,你也可以上周我开始玩GoLang,它是一种由Google制作的类C编译语言,非常轻量和快速,事实上它经常在Techempower的基准测...

Go (Golang) 中的 Channels 简介(golang channel长度和容量)

这篇文章重点介绍Channels(通道)在Go中的工作方式,以及如何在代码中使用它们。在Go中,Channels是一种编程结构,它允许我们在代码的不同部分之间移动数据,通常来自不同的goro...

Golang引入泛型:Go将Interface「」替换为“Any”

现在Go将拥有泛型:Go将Interface{}替换为“Any”,这是一个类型别名:typeany=interface{}这会引入了泛型作好准备,实际上,带有泛型的Go1.18Beta...

一文带你看懂Golang最新特性(golang2.0特性)

作者:腾讯PCG代码委员会经过十余年的迭代,Go语言逐渐成为云计算时代主流的编程语言。下到云计算基础设施,上到微服务,越来越多的流行产品使用Go语言编写。可见其影响力已经非常强大。一、Go语言发展历史...

Go 每日一库之 java 转 go 遇到 Apollo?让 agollo 来平滑迁移

以下文章来源于GoOfficialBlog,作者GoOfficialBlogIntroductionagollo是Apollo的Golang客户端Apollo(阿波罗)是携程框架部门研...

Golang使用grpc详解(golang gcc)

gRPC是Google开源的一种高性能、跨语言的远程过程调用(RPC)框架,它使用ProtocolBuffers作为序列化工具,支持多种编程语言,如C++,Java,Python,Go等。gR...

Etcd服务注册与发现封装实现--golang

服务注册register.gopackageregisterimport("fmt""time"etcd3"github.com/cor...

Golang:将日志以Json格式输出到Kafka

在上一篇文章中我实现了一个支持Debug、Info、Error等多个级别的日志库,并将日志写到了磁盘文件中,代码比较简单,适合练手。有兴趣的可以通过这个链接前往:https://github.com/...

如何从 PHP 过渡到 Golang?(php转golang)

我是PHP开发者,转Go两个月了吧,记录一下使用Golang怎么一步步开发新项目。本着有坑填坑,有错改错的宗旨,从零开始,开始学习。因为我司没有专门的Golang大牛,所以我也只能一步步自己去...