与《分享用于学习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

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

完整代码:

  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

 

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

微信:  

 

 

支付宝: 

版权声明:本文为tntmonks原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/tntmonks/p/8278451.html