与《分享用于学习C++图像处理的代码示例》为姊妹篇。
为了便于学习C++音频处理并研究音频算法,
俺写了一个适合初学者学习的小小框架。
麻雀虽小五脏俱全,仅仅考虑单通道处理。
采用Decoder and Encoder:dr_wav
https://github.com/mackron/dr_libs/blob/master/dr_wav.h
关于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(); return (fn(), took + now()) / 1000; } //写wav文件 void wavWrite_int16(char* filename, int16_t* buffer, int sampleRate, uint32_t totalSampleCount) { drwav_data_format format; format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64. format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes. format.channels = 1; format.sampleRate = sampleRate; format.bitsPerSample = 16; drwav* pWav = drwav_open_file_write(filename, &format); if (pWav) { drwav_uint64 samplesWritten = drwav_write(pWav, totalSampleCount, buffer); drwav_uninit(pWav); } } //读取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文件失败."); } //仅仅处理单通道音频 if (channels != 1) { drwav_free(buffer); buffer = NULL; *sampleRate = 0; *totalSampleCount = 0; } return buffer; } //分割路径函数 void splitpath(const char* path, char* drv, char* dir, char* name, char* ext) { const char* end; const char* p; const char* s; if (path[0] && path[1] == ':') { if (drv) { *drv++ = *path++; *drv++ = *path++; *drv = '