分享用于学习C++音频处理的代码示例
与《分享用于学习C++图像处理的代码示例》为姊妹篇。
为了便于学习C++音频处理并研究音频算法,
俺写了一个适合初学者学习的小小框架。
麻雀虽小五脏俱全,仅仅考虑单通道处理。
采用Decoder:dr_wav
https://github.com/mackron/dr_libs/blob/master/dr_wav.h
采用Encoder:原本计划采用dr_wav的Encode,但是dr_wav保存的文件头忘记修正音频数据的大小,
采用博主自己实现的代码,仅供学习之用。
dr_wav用于解析wav文件格式.
关于wav格式的解析移步至:
http://soundfile.sapp.org/doc/WaveFormat/

个人习惯,采用int16的处理方式,也可以通过简单的修改,改为float类型。
wav音频样本可以从维基百科上(https://en.wikipedia.org/wiki/WAV)下载。
注:少数wav格式不支持
| Format | Bitrate (kbit/s) | 1 minute (KiB) | Sample |
|---|---|---|---|
| 11,025 Hz 16 bit PCM | 176.4 | 1292 | 11k16bitpcm.wav |
| 8,000 Hz 16 bit PCM | 128 | 938 | 8k16bitpcm.wav |
| 11,025 Hz 8 bit PCM | 88.2 | 646 | 11k8bitpcm.wav |
| 11,025 Hz µ-Law | 88.2 | 646 | 11kulaw.wav |
| 8,000 Hz 8 bit PCM | 64 | 469 | 8k8bitpcm.wav |
| 8,000 Hz µ-Law | 64 | 469 | 8kulaw.wav |
| 11,025 Hz 4 bit ADPCM | 44.1 | 323 | 11kadpcm.wav |
| 8,000 Hz 4 bit ADPCM | 32 | 234 | 8kadpcm.wav |
| 11,025 Hz GSM 06.10 | 18 | 132 | 11kgsm.wav |
| 8,000 Hz MP3 16 kbit/s | 16 | 117 | 8kmp316.wav |
| 8,000 Hz GSM 06.10 | 13 | 103 | 8kgsm.wav |
| 8,000 Hz Lernout & Hauspie SBC 12 kbit/s | 12 | 88 | 8ksbc12.wav |
| 8,000 Hz DSP Group Truespeech | 9 | 66 | 8ktruespeech.wav |
| 8,000 Hz MP3 8 kbit/s | 8 | 60 | 8kmp38.wav |
| 8,000 Hz Lernout & Hauspie CELP | 4.8 | 35 | 8kcelp.wav |
附带处理耗时计算,示例演示了一个简单的将音频前面一半静音处理,并简单注释了一下部分逻辑。
完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <iostream>
//采用https://github.com/mackron/dr_libs/blob/master/dr_wav.h 解码
#define DR_WAV_IMPLEMENTATION
#include "dr_wav.h"
auto const epoch = clock();
static double now()
{
return (clock() - epoch);
};
template <typename FN>
static double bench(const FN &fn)
{
auto took = -now();
;
}
//写wav文件
void wavWrite_int16(char* filename, int16_t* buffer, int sampleRate, uint32_t totalSampleCount) {
FILE* fp = fopen(filename, "wb");
if (fp == NULL) {
printf("文件打开失败.\n");
return;
}
//修正写入的buffer长度
totalSampleCount *= sizeof(int16_t);
;
;
;
] = { 'R', 'I', 'F', 'F' };
uint32_t long_number = + totalSampleCount;
fwrite(text, , , fp);
fwrite(&long_number, , , fp);
text[] = 'W';
text[] = 'A';
text[] = 'V';
text[] = 'E';
fwrite(text, , , fp);
text[] = 'f';
text[] = 'm';
text[] = 't';
text[] = ' ';
fwrite(text, , , fp);
long_number = ;
fwrite(&long_number, , , fp);
int16_t short_number = FORMAT_PCM;//默认音频格式
fwrite(&short_number, , , fp);
short_number = ; // 音频通道数
fwrite(&short_number, , , fp);
long_number = sampleRate; // 采样率
fwrite(&long_number, , , fp);
long_number = sampleRate * nbyte; // 比特率
fwrite(&long_number, , , fp);
short_number = nbyte; // 块对齐
fwrite(&short_number, , , fp);
short_number = nbit; // 采样精度
fwrite(&short_number, , , fp);
] = { 'd', 'a', 't', 'a' };
fwrite(data, , , fp);
long_number = totalSampleCount;
fwrite(&long_number, , , fp);
fwrite(buffer, totalSampleCount, , fp);
fclose(fp);
}
//读取wav文件
int16_t* wavRead_int16(char* filename, uint32_t* sampleRate, uint64_t *totalSampleCount) {
unsigned int channels;
int16_t* buffer = drwav_open_and_read_file_s16(filename, &channels, sampleRate, totalSampleCount);
if (buffer == NULL) {
printf("读取wav文件失败.");
}
//仅仅处理单通道音频
)
{
drwav_free(buffer);
buffer = NULL;
*sampleRate = ;
*totalSampleCount = ;
}
return buffer;
}
//分割路径函数
void splitpath(const char* path, char* drv, char* dir, char* name, char* ext)
{
const char* end;
const char* p;
const char* s;
] && path[] == ':') {
if (drv) {
*drv++ = *path++;
*drv++ = *path++;
*drv = '\0';
}
}
else if (drv)
*drv = '\0';
for (end = path; *end && *end != ':';)
end++;
for (p = end; p > path && *--p != '\\' && *p != '/';)
if (*p == '.') {
end = p;
break;
}
if (ext)
for (s = end; (*ext = *s++);)
ext++;
for (p = end; p > path;)
if (*--p == '\\' || *p == '/') {
p++;
break;
}
if (name) {
for (s = p; s < end;)
*name++ = *s++;
*name = '\0';
}
if (dir) {
for (s = path; s < p;)
*dir++ = *s++;
*dir = '\0';
}
}
int main(int argc, char* argv[])
{
std::cout << "Audio Processing " << std::endl;
std::cout << "博客:http://tntmonks.cnblogs.com/" << std::endl;
std::cout << "支持解析单通道wav格式." << std::endl;
) ;
];
//音频采样率
uint32_t sampleRate = ;
//总音频采样数
uint64_t totalSampleCount = ;
int16_t* wavBuffer = NULL;
double nLoadTime = bench([&]
{
wavBuffer = wavRead_int16(in_file, &sampleRate, &totalSampleCount);
});
std::cout << ) << " 毫秒" << std::endl;
//如果加载成功
if (wavBuffer != NULL)
{
//将前面一般进行静音处理,直接置零即可
; i < totalSampleCount / ; i++)
{
wavBuffer[i] = ;
}
}
//保存结果
double nSaveTime = bench([&]
{
];
];
];
];
];
splitpath(in_file, drive, dir, fname, ext);
sprintf(out_file, "%s%s%s_out%s", drive, dir, fname, ext);
wavWrite_int16(out_file, wavBuffer, sampleRate, totalSampleCount);
});
std::cout << ) << " 毫秒" << std::endl;
getchar();
std::cout << "按任意键退出程序 \n" << std::endl;
;
}
示例具体流程为:
加载wav(拖放wav文件到可执行文件上)->简单静音处理->保存wav
并对 加载,保存 这2个环节都进行了耗时计算并输出。
若有其他相关问题或者需求也可以邮件联系俺探讨。
邮箱地址是:
gaozhihan@vip.qq.com
若此博文能帮到您,欢迎扫码小额赞助。
微信:

支付宝:

分享用于学习C++音频处理的代码示例的更多相关文章
- 分享用于学习C++图像处理的代码示例
为了便于学习图像处理并研究图像算法, 俺写了一个适合初学者学习的小小框架. 麻雀虽小五脏俱全. 采用的加解码库:stb_image 官方:http://nothings.org/ stb_image. ...
- 分享一些学习资料-大量PDF电子书
分享一些学习用的电子书籍,给那些喜欢看书而不一定有机会买书的童鞋. 反对积分下载,提倡自由分享. 分享地址: http://pan.baidu.com/s/1qWK5V0g 提取密码: np33 ...
- 嵌入式 十个最值得阅读学习的C开源项目代码
开源世界有许多优秀的开源项目,我选取其中十个最优秀的.最轻量级的C语言的项目,希望可以为C语言开发人员提供参考. 十个最值得阅读学习的C开源项目代码 1. Webbench 2. Tinyhttpd ...
- Delphi之通过代码示例学习XML解析、StringReplace的用法(异常控制 good)
*Delphi之通过代码示例学习XML解析.StringReplace的用法 这个程序可以用于解析任何合法的XML字符串. 首先是看一下程序的运行效果: 以解析这样一个XML的字符串为例: <? ...
- 分享非常有用的Java程序(关键代码)(八)---Java InputStream读取网络响应Response数据的方法!(重要)
原文:分享非常有用的Java程序(关键代码)(八)---Java InputStream读取网络响应Response数据的方法!(重要) Java InputStream读取数据问题 ======== ...
- ffmpeg音频播放代码示例-avcodec_decode_audio4
一.概述 最近在学习ffmpeg解码的内容,参考了官方的教程http://dranger.com/ffmpeg/tutorial03.html,结果发现这个音频解码的教程有点问题.参考了各种博客,并同 ...
- 音频增益响度分析 ReplayGain 附完整C代码示例
人们所熟知的图像方面的3A算法有: AF自动对焦(Automatic Focus)自动对焦即调节摄像头焦距自动得到清晰的图像的过程 AE自动曝光(Automatic Exposure)自动曝光的是为了 ...
- 音频增益响度分析 ReplayGain 附完整C代码示例【转】
转自:http://www.cnblogs.com/cpuimage/p/8846951.html 人们所熟知的图像方面的3A算法有: AF自动对焦(Automatic Focus)自动对焦即调节摄像 ...
- .net reactor 学习系列(三)---.net reactor代码自动操作相关保护功能
原文:.net reactor 学习系列(三)---.net reactor代码自动操作相关保护功能 接上篇,上篇已经学习了界面的各种功能以及各种配置,这篇准备学习下代码控制许可证. ...
随机推荐
- @Autowired注解在抽象类中实效的原因分析
最近在工作中遇到这个问题,在抽象类中使用Autowired这个注解,注入mybatis的dao时,总是出现空指针异常,通过日志的打印,发现是这个dao注入失败为空.然后通过new出spring上下文对 ...
- 增加tomcat的缓存
起因是我做了一个批量压缩图片的功能,在服务器上跑这个功能的时候,发现服务器有警告.警告的内容大概如下. XX.... to the cache because there was insuffic ...
- mongodb 3.4 集群搭建:分片+副本集
mongodb是最常用的nodql数据库,在数据库排名中已经上升到了前六.这篇文章介绍如何搭建高可用的mongodb(分片+副本)集群. 在搭建集群之前,需要首先了解几个概念:路由,分片.副本集.配置 ...
- 在Office Add-in中实现单点登陆(SSO)
作者:陈希章 发表于 2017年12月27日 这篇文章经过多次修改,终于在今天晚上写完了,演示用的范例代码也终于跑通了.因为这个SSO的功能目前只是Preview的状态,所以本篇文章严格参考了官方的文 ...
- Subscription wildcards(MQTT)
想查看英文原文的请点击原文网址.本文是paho中讲述订阅通配符的.还是那句话,水平有限,如有翻译不当之处,欢迎指正. 订阅通配符 MQTT信息包含一个主题来进行区分.MQTT服务器使用主题来确定哪 ...
- springboot+多数据源配置
作者:纯洁的微笑 出处:http://www.ityouknow.com/ 起多数据源,一般都来解决那些问题呢,主从模式或者业务比较复杂需要连接不同的分库来支持业务.我们项目是后者的模式,网上找了很多 ...
- 浅析JavaScript的字符串查找函数:indexOf和search
语法 ①indexOf:方法可返回某个指定的字符串值在长字符串中首次出现的位置.如果被查找字符串没有找到,返回-1. indexOf 说明:该方法将从头到尾地检索字符串 stringObject,看它 ...
- iOS设计模式之懒加载
一.为什么要懒加载? 答: iPhone设备内存有限,如果在程序在启动后就一次性加载将来会用到的所有资源,那么久可能会耗尽iOS设备的内存.这些资源例如大量的数据,图片,音频,过多的控件等. 二.懒加 ...
- 对Java中堆栈的解析
Java把内存分为两种:一种是栈内存,一种是堆内存 栈内存:在函数中定义的一些基本类型的变量和对象的引用变量,当超过变量的作用域之后,Java自动释放该变量内存 堆内存:存放new创建的对象和数组,由 ...
- #ifdef #else #endif #if #ifndef 的用法
预编译就是在对源文件进行处理之前(如在语法扫描和分析之前),先处理预处理部分,精简代码,然后再进行编译. 预处理命令有:#include 文件包含.#define 宏定义.以及要重点讲的#if.#if ...