分享用于学习C++音频处理的代码示例

2018-01-13 11:42:25来源:cnblogs.com作者:落羽の殇人点击

分享

与《分享用于学习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格式不支持

FormatBitrate (kbit/s)1 minute (KiB)Sample
11,025 Hz 16 bit PCM176.4129211k16bitpcm.wav
8,000 Hz 16 bit PCM1289388k16bitpcm.wav
11,025 Hz 8 bit PCM88.264611k8bitpcm.wav
11,025 Hz µ-Law88.264611kulaw.wav
8,000 Hz 8 bit PCM644698k8bitpcm.wav
8,000 Hz µ-Law644698kulaw.wav
11,025 Hz 4 bit ADPCM44.132311kadpcm.wav
8,000 Hz 4 bit ADPCM322348kadpcm.wav
11,025 Hz GSM 06.101813211kgsm.wav
8,000 Hz MP3 16 kbit/s161178kmp316.wav
8,000 Hz GSM 06.10131038kgsm.wav
8,000 Hz Lernout & Hauspie SBC 12 kbit/s12888ksbc12.wav
8,000 Hz DSP Group Truespeech9668ktruespeech.wav
8,000 Hz MP3 8 kbit/s8608kmp38.wav
8,000 Hz Lernout & Hauspie CELP4.8358kcelp.wav

附带处理耗时计算,示例演示了一个简单的将音频前面一半静音处理,并简单注释了一下部分逻辑。

完整代码:

  1   2 #include <stdio.h>  3 #include <stdlib.h>      4 #include <stdint.h>      5 #include <time.h>   6 #include <iostream>   7 //采用https://github.com/mackron/dr_libs/blob/master/dr_wav.h 解码  8 #define DR_WAV_IMPLEMENTATION  9 #include "dr_wav.h" 10  11 auto const epoch = clock(); 12 static double now() 13 { 14     return  (clock() - epoch); 15 }; 16  17 template <typename FN> 18 static double bench(const FN &fn) 19 { 20     auto took = -now(); 21     return (fn(), took + now()) / 1000; 22 } 23  24 //写wav文件 25 void wavWrite_int16(char* filename, int16_t* buffer, int sampleRate, uint32_t totalSampleCount) { 26  27     FILE* fp = fopen(filename, "wb"); 28     if (fp == NULL) { 29         printf("文件打开失败./n"); 30         return; 31     } 32     //修正写入的buffer长度 33     totalSampleCount *= sizeof(int16_t); 34     int nbit = 16; 35     int FORMAT_PCM = 1; 36     int nbyte = nbit / 8; 37     char text[4] = { 'R', 'I', 'F', 'F' }; 38     uint32_t long_number = 36 + totalSampleCount; 39     fwrite(text, 1, 4, fp); 40     fwrite(&long_number, 4, 1, fp); 41     text[0] = 'W'; 42     text[1] = 'A'; 43     text[2] = 'V'; 44     text[3] = 'E'; 45     fwrite(text, 1, 4, fp); 46     text[0] = 'f'; 47     text[1] = 'm'; 48     text[2] = 't'; 49     text[3] = ' '; 50     fwrite(text, 1, 4, fp); 51  52     long_number = 16; 53     fwrite(&long_number, 4, 1, fp); 54     int16_t short_number = FORMAT_PCM;//默认音频格式 55     fwrite(&short_number, 2, 1, fp); 56     short_number = 1; // 音频通道数 57     fwrite(&short_number, 2, 1, fp); 58     long_number = sampleRate; // 采样率 59     fwrite(&long_number, 4, 1, fp); 60     long_number = sampleRate * nbyte; // 比特率 61     fwrite(&long_number, 4, 1, fp); 62     short_number = nbyte; // 块对齐 63     fwrite(&short_number, 2, 1, fp); 64     short_number = nbit; // 采样精度 65     fwrite(&short_number, 2, 1, fp); 66     char data[4] = { 'd', 'a', 't', 'a' }; 67     fwrite(data, 1, 4, fp); 68     long_number = totalSampleCount; 69     fwrite(&long_number, 4, 1, fp); 70     fwrite(buffer, totalSampleCount, 1, fp); 71     fclose(fp); 72 } 73 //读取wav文件 74 int16_t* wavRead_int16(char* filename, uint32_t* sampleRate, uint64_t    *totalSampleCount) { 75  76     unsigned int channels; 77     int16_t* buffer = drwav_open_and_read_file_s16(filename, &channels, sampleRate, totalSampleCount); 78     if (buffer == NULL) { 79         printf("读取wav文件失败."); 80     } 81     //仅仅处理单通道音频 82     if (channels != 1) 83     { 84         drwav_free(buffer); 85         buffer = NULL; 86         *sampleRate = 0; 87         *totalSampleCount = 0; 88     } 89     return buffer; 90 } 91  92 //分割路径函数 93 void splitpath(const char* path, char* drv, char* dir, char* name, char* ext) 94 { 95     const char* end; 96     const char* p; 97     const char* s; 98     if (path[0] && path[1] == ':') { 99         if (drv) {100             *drv++ = *path++;101             *drv++ = *path++;102             *drv = '/0';103         }104     }105     else if (drv)106         *drv = '/0';107     for (end = path; *end && *end != ':';)108         end++;109     for (p = end; p > path && *--p != '//' && *p != '/';)110         if (*p == '.') {111             end = p;112             break;113         }114     if (ext)115         for (s = end; (*ext = *s++);)116             ext++;117     for (p = end; p > path;)118         if (*--p == '//' || *p == '/') {119             p++;120             break;121         }122     if (name) {123         for (s = p; s < end;)124             *name++ = *s++;125         *name = '/0';126     }127     if (dir) {128         for (s = path; s < p;)129             *dir++ = *s++;130         *dir = '/0';131     }132 }133 134 int main(int argc, char* argv[])135 {136     std::cout << "Audio Processing " << std::endl;137     std::cout << "博客:http://tntmonks.cnblogs.com/" << std::endl;138     std::cout << "支持解析单通道wav格式." << std::endl;139 140     if (argc < 2) return -1;141     char* in_file = argv[1];142 143     //音频采样率144     uint32_t sampleRate = 0;145     //总音频采样数146     uint64_t totalSampleCount = 0;147     int16_t* wavBuffer = NULL;148     double nLoadTime = bench([&]149     {150         wavBuffer = wavRead_int16(in_file, &sampleRate, &totalSampleCount);151     });152     std::cout << " 加载耗时: " << int(nLoadTime * 1000) << " 毫秒" << std::endl;153 154     //如果加载成功155     if (wavBuffer != NULL)156     {157         //将前面一般进行静音处理,直接置零即可158         for (uint64_t i = 0; i < totalSampleCount / 2; i++)159         {160             wavBuffer[i] = 0;161         }162     }163     //保存结果164     double nSaveTime = bench([&]165     {166         char drive[3];167         char dir[256];168         char fname[256];169         char ext[256];170         char out_file[1024];171         splitpath(in_file, drive, dir, fname, ext);172         sprintf(out_file, "%s%s%s_out%s", drive, dir, fname, ext);173         wavWrite_int16(out_file, wavBuffer, sampleRate, totalSampleCount);174     });175     std::cout << " 保存耗时: " << int(nSaveTime * 1000) << " 毫秒" << std::endl;176 177     getchar();178     std::cout << "按任意键退出程序 /n" << std::endl;179     return 0;180 }

示例具体流程为:

加载wav(拖放wav文件到可执行文件上)->简单静音处理->保存wav

并对 加载,保存 这2个环节都进行了耗时计算并输出。

  

若有其他相关问题或者需求也可以邮件联系俺探讨。

邮箱地址是: 
gaozhihan@vip.qq.com

若此博文能帮到您,欢迎扫码小额赞助。

微信:  

 

支付宝: 

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台