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 ...
随机推荐
- 学习vi和vim编辑器(5):越过基础的藩篱
本章将对之前学习的编辑命令如" c "." d "." y "等命令进行总结,并学习一些新的知识:其它进入vi的方法,利用缓冲区来存储拖曳或 ...
- x86内存映射
Contents 1 "Low" memory (< 1 MiB) 1.1 Overview 1.2 BIOS Data Area (BDA) 1.3 Extended BI ...
- Oracle集合操作
在Oracle中提供了三种类型的集合操作: 并(UNION).交(INTERSECT).差(MINUS) UNION:将多个查询的结果组合到一个查询结果之中,并去掉反复值 UNION ALL:将多个查 ...
- Office Web Add-in的技术原理和开发常见问题剖析
作者:陈希章 发表于 2017年12月20日 我过去发表过一些Office Add-in开发的文章,并且也在不同的场合分享过新的开发模式及其带来的机遇.有不少朋友给我反馈,也讨论到一些常见问题,我这里 ...
- 用maven建立java web项目
1.在eclipse的菜单栏选择File->New->Other->Maven->Maven ,并在第一个框打勾,然后点击下一步 2.转换为java的Dynamic Web P ...
- 关于redis的使用
距离上次写博客有两三个月了,这段时间去了新公司上班,忙了很多.接手了一个项目,刚好用到redis,先总结下遇到的问题(跟redis相关的问题): 1.列表问题 举例:展示商品列表,但是要先展示运营置顶 ...
- IntelliJ IDEA创建java项目
IntelliJ IDEA创建java项目 进入到IntelliJ IDEA启动界面,点击Create New Project 2.这样就进入到了创建项目页面,这里可以创建好多项目,这里我们以java ...
- 《决战大数据:驾驭未来商业的利器》【PDF】下载
内容简介 大数据时代的来临,给当今的商业带来了极大的冲击,多数电商人无不"谈大数据色变",并呈现出一种观望.迷茫.手足无措的状态.车品觉,作为一名经验丰富的电商人,在敬畏大数据的同 ...
- mybatis防止sql注入
SQL注入是一种代码注入技术,用于攻击数据驱动的应用,恶意的SQL语句被插入到执行的实体字段中(例如,为了转储数据库内容给攻击者).[摘自] SQL injection - Wikipedi ...
- 【MySQL】查看字符集对应的校对规则show collation like 'gbk%';