mp3格式转wav格式 附完整C++算法实现代码
近期偶然间看到一个开源项目minimp3
Minimalistic MP3 decoder single header library
项目地址:
https://github.com/lieff/minimp3
单文件头的最小mp3解码器。
一直很想抽时间好好看上一看。
最好的学习方式就是写个实用性的工程项目。
例如实现mp3转wav格式。
嗯,这篇博文就是这么来的。
阅读了下minimp3的源码,有一两处小bug,
这个解码算法可以进一步提速优化的地方还有不少。
后面有时间,再好好庖丁解牛。
基于这个库,实现mp3转wav的代码行数不到300行。
小巧而简洁,算是简单的抛砖引玉了。
个人习惯,很少写注释,
所以尽可能把代码写得清晰易懂,当然也有犯懒的时候。
完整代码:
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_DEPRECATE 1 #define _CRT_NONSTDC_NO_DEPRECATE 1 #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <time.h> #include <iostream> // ref:https://github.com/lieff/minimp3/blob/master/minimp3.h #define MINIMP3_IMPLEMENTATION #include "minimp3.h" #include <sys/stat.h> auto const epoch = clock(); static double now() { return (clock() - epoch); }; template <typename FN> static double bench(const FN &fn) { auto took = -now(); ; } //写wav文件 ) { FILE* fp = fopen(filename, "wb"); if (fp == NULL) { printf("文件打开失败.\n"); return; } //修正写入的buffer长度 totalSampleCount *= sizeof(int16_t)*channels; ; ; ; ] = { '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 = channels; // 音频通道数 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); } //读取文件buffer char *getFileBuffer(const char *fname, int *size) { FILE * fd = fopen(fname, "rb"); ) ; struct stat st; ; ) goto doexit; file_buf = (); if (file_buf != NULL) { , fd) < ) { fclose(fd); ; } file_buf[st.st_size] = ; } if (size) *size = st.st_size; doexit: fclose(fd); return file_buf; } //mp3解码 int16_t* DecodeMp3ToBuffer(char* filename, uint32_t *sampleRate, uint32_t *totalSampleCount, unsigned int *channels) { ; * , num_samples = ; int16_t *music_buf = (int16_t *) * ); unsigned char *file_buf = (unsigned char *)getFileBuffer(filename, &music_size); if (file_buf != NULL) { unsigned char *buf = file_buf; mp3dec_frame_info_t info; mp3dec_t dec; mp3dec_init(&dec); for (;;) { int16_t frame_buf[ * ]; int samples = mp3dec_decode_frame(&dec, buf, music_size, frame_buf, &info); if (alloc_samples < (num_samples + samples)) { alloc_samples *= ; int16_t* tmp = (int16_t *) * info.channels); if (tmp) music_buf = tmp; } if (music_buf) memcpy(music_buf + num_samples*info.channels, frame_buf, samples*info.channels * ); num_samples += samples; || music_size <= (info.frame_bytes + )) break; buf += info.frame_bytes; music_size -= info.frame_bytes; } if (alloc_samples > num_samples) { int16_t* tmp = (int16_t *) * info.channels); if (tmp) music_buf = tmp; } if (sampleRate) *sampleRate = info.hz; if (channels) *channels = info.channels; if (num_samples) *totalSampleCount = num_samples; free(file_buf); return music_buf; } if (music_buf) free(music_buf); ; } //分割路径函数 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 << "mp3 转 wav." << std::endl; ) ; ]; //总音频采样数 uint32_t totalSampleCount = ; //音频采样率 uint32_t sampleRate = ; //通道数 unsigned ; int16_t* wavBuffer = NULL; double nLoadTime = bench([&] { wavBuffer = DecodeMp3ToBuffer(in_file, &sampleRate, &totalSampleCount, &channels); }); std::cout << ) << " 毫秒" << std::endl; //保存结果 double nSaveTime = bench([&] { ]; ]; ]; ]; ]; splitpath(in_file, drive, dir, fname, ext); sprintf(out_file, "%s%s%s.wav", drive, dir, fname); wavWrite_int16(out_file, wavBuffer, sampleRate, totalSampleCount, channels); }); std::cout << ) << " 毫秒" << std::endl; if (wavBuffer) { free(wavBuffer); } getchar(); std::cout << "按任意键退出程序 \n" << std::endl; ; }
示例具体流程为:
加载mp3(拖放mp3文件到可执行文件上)->解码mp3->保存wav
并对 加载,保存 这2个环节都进行了耗时计算并输出。
若有其他相关问题或者需求也可以邮件联系俺探讨。
邮箱地址是:
gaozhihan@vip.qq.com
若此博文能帮到您,欢迎扫码小额赞助。
微信:
支付宝:
mp3格式转wav格式 附完整C++算法实现代码的更多相关文章
- 声音变调算法PitchShift(模拟汤姆猫) 附完整C++算法实现代码
上周看到一个变调算法,挺有意思的,原本计划尝试用来润色TTS合成效果的. 实测感觉还需要进一步改进,待有空再思考改进方案. 算法细节原文,移步链接: http://blogs.zynaptiq.com ...
- 不用第三方解码码取得图片宽高 附完整C++算法实现代码
在特定的应用场景下,有时候我们只是想获取图片的宽高, 但不想通过解码图片才取得这个信息. 预先知道图片的宽高信息,进而提速图片加载,预处理等相关操作以提升体验. 在stackoverflow有一篇相关 ...
- 不用第三方解码库取得图片宽高 附完整C++算法实现代码
在特定的应用场景下,有时候我们只是想获取图片的宽高, 但不想通过解码图片才取得这个信息. 预先知道图片的宽高信息,进而提速图片加载,预处理等相关操作以提升体验. 在stackoverflow有一篇相关 ...
- 音频算法之小黄人变声 附完整C代码
前面提及到<大话音频变声原理 附简单示例代码>与<声音变调算法PitchShift(模拟汤姆猫) 附完整C++算法实现代码> 都稍微讲过变声的原理和具体实现. 大家都知道,算法 ...
- Android音频: 怎样使用AudioTrack播放一个WAV格式文件?
翻译 By Long Luo 原文链接:Android Audio: Play a WAV file on an AudioTrack 译者注: 1. 因为这是技术文章,所以有些词句使用原文,表达更准 ...
- 微信小程序语音识别开发过程记录 微信小程序silk转mp3 silk转wav 以及ffmpeg使用
说说最近在开发微信小程序语音识别遇到的问题吧 最先使用微信小程序录音控件可以拿到silk格式,后来微信官方又支持mp3格式了 但是我们拿到这些格式以后,都还不能直接使用,做语音识别,因为目前百度的语音 ...
- 使用jave2实现将wav格式的音频转换成mp3格式
最近需要用到语音合成功能,网上查阅了一番,发现可以使用腾讯云的语音合成API来完成这个功能,但是腾讯云的api返回的是wav格式的音频文件,这个格式的文件有些不通用,因此需要转换成mp3格式的文件. ...
- 小程序语音红包中遇到的 语音识别silk转wav格式 如何在线转 或者mp3转wav格式
公司在开发一个小程序语音红包,现在遇到的问题就是通过微信的小程序文档接口拿到的录音文件要么是silk格式的,要么是mp3格式的 但是呢,如果要调用百度的语音接口,又必须是wav格式的.也就是说通过微信 ...
- c# Use NAudio Library to Convert MP3 audio into WAV audio(将Mp3格式转换成Wav格式)
Have you been in need of converting mp3 audios to wav audios? If so, the skill in this article prov ...
随机推荐
- Android内核sysfs中switch类使用实例
Android内核sysfs中switch类使用实例 最终在这个周末,能够干点自己想要干的事了. 由我这个二流的内核驱动开发人员来解析一下sysfs中的switch类.先猜測一下来历,在普通的嵌入式L ...
- HDU1065 I Think I Need a Houseboat 【数学递推】
I Think I Need a Houseboat Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Ja ...
- JavaScript 数组最大值
JavaScript 数组最大值 在js中可以使用Math.max()获取最大值. 如: console.log(Math.max("1","11"," ...
- 浏览器兼容性--IE11以及Edge等下载文件的中文名出现乱码,前后端解决方案
项目中有用到文件下载功能,之前在处理下载时对IE浏览器下文件下载名进行过处理,测试也没有问题,但是功能上线后,业务反馈IE11文件下载文件名依然乱码.打印User-Agent字符串如下: IE11 U ...
- 使用Flink时从Kafka中读取Array[Byte]类型的Schema
使用Flink时,如果从Kafka中读取输入流,默认提供的是String类型的Schema: val myConsumer = new FlinkKafkaConsumer08[String](&qu ...
- 【ANT】一个简单的ANT生成文件build.xml
<?xml version="1.0" ?> <project default="test"> <target name=&quo ...
- JavaScript基础1——基本概念
关于JS的概念 JavaScript 是一种弱类型语言. JavaScript 是一种客户端脚本语言(脚本语言是一种轻量级的编程语言). JavaScript是基于对象的.(因为面向对象需要具有封装. ...
- iOS SDAutoLayout图文混排-共享
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #526eda } span.s1 { color: #4dbf5 ...
- css盒模型研究
css的盒模型一直是一个重点和难点,最近由后端的学习转到前端,觉得有必要深入研究一下css的盒模型. 1.万物皆盒子 我们必须要有一个理念,在html的世界里,万物皆盒子,那就是任何一个html元素都 ...
- 修改Linux内核参数提高Nginx服务器并发性能
当linux下Nginx达到并发数很高,TCP TIME_WAIT套接字数量经常达到两.三万,这样服务器很容易被拖死.事实上,我们可以简单的通过修改Linux内核参数,可以减少Nginx服务器 的TI ...