欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS的音频文件的格式转换示例

程序员文章站 2022-03-22 14:53:28
背景 因为我的公司需要设计到app与硬件的通信,所以去年深入的研究了一下音频各种格式的转换,曾写过一篇简书,现在搬过来丰富下自己的blog。 首先介绍一下常用的音频...

背景

因为我的公司需要设计到app与硬件的通信,所以去年深入的研究了一下音频各种格式的转换,曾写过一篇简书,现在搬过来丰富下自己的blog。

首先介绍一下常用的音频文件格式

  • .amr:体积很小,1秒到约为1kb,所以音质缩水也很厉害,一般用于手机铃声或彩信
  • .mp3:比较流行的,有损音频,某些部分失真,,音质随码率的提高,越高越好
  • .wav:为无损音频
  • .pcm:无损的wav文件中音频数据的一种编码方式

由于app是通过avaudiorecorder录制音频,默认格式为pcm,文件比较大,所以不适合用于聊天通信的文件格式,所以最优的选择是转换成amr格式

音频格式转换方式

.pcm-->.wav-->.amr

a)将pcm转成wav

什么是wav和pcm?

wav:wav是一种无损的音频文件格式,wav符合 piff(resource interchange file format)规范。所有的wav都有一个文件头,这个文件头音频流的编码参数。wav对音频流的编码没有硬性规定,除了pcm之外,还有几乎所有支持acm规范的编码都可以为wav的音频流进行编码。

pcm:pcm(pulse code modulation----脉码调制录音)。所谓pcm录音就是将声音等模拟信号变成符号化的脉冲列,再予以记录。pcm信号是由[1]、[0]等符号构成的数字信号,而未经过任何编码和压缩处理。与模拟信号比,它不易受传送系统的杂波及失真的影响。动态范围宽,可得到音质相当好的影响效果。

简单来说:wav是一种无损的音频文件格式,pcm是没有压缩的编码方式。

wav和pcm的关系

wav可以使用多种音频编码来压缩其音频流,不过我们常见的都是音频流被pcm编码处理的wav,但这不表示wav只能使用pcm编码,mp3编码同样也可以运用在wav中,和avi一样,只要安装好了相应的decode,就可以欣赏这些wav了。在windows平台下,基于pcm编码的wav是被支持得最好的音频格式,所有音频软件都能完美支持,由于本身可以达到较高的音质的要求,因此,wav也是音乐编辑创作的首选格式,适合保存音乐素材。因此,基于pcm编码的wav被作为了一种中介的格式,常常使用在其他编码的相互转换之中,例如mp3转换成wma。

简单来说:pcm是无损wav文件中音频数据的一种编码方式,但wav还可以用其它方式编码。

这里详细写了pcm和wav的区别,我简单概括成pcm少了一个wav头描述信息。为此我从讯飞语音的sdk中移植出填写wav头的函数并修改了一下

// 为pcm文件写入wav头
+ (nsdata*) writewavhead:(nsdata *)audiodata {
 long samplerate = [[self getaudiorecordersettingdict][avsampleratekey] longvalue];
 long numofchannelskey = [[self getaudiorecordersettingdict][avnumberofchannelskey] longvalue];
 byte wavehead[44];
 wavehead[0] = 'r';
 wavehead[1] = 'i';
 wavehead[2] = 'f';
 wavehead[3] = 'f';
 
 long totaldatalength = [audiodata length] + 44;
 wavehead[4] = (byte)(totaldatalength & 0xff);
 wavehead[5] = (byte)((totaldatalength >> 8) & 0xff);
 wavehead[6] = (byte)((totaldatalength >> 16) & 0xff);
 wavehead[7] = (byte)((totaldatalength >> 24) & 0xff);
 
 wavehead[8] = 'w';
 wavehead[9] = 'a';
 wavehead[10] = 'v';
 wavehead[11] = 'e';
 
 wavehead[12] = 'f';
 wavehead[13] = 'm';
 wavehead[14] = 't';
 wavehead[15] = ' ';
 
 wavehead[16] = 16; //size of 'fmt '
 wavehead[17] = 0;
 wavehead[18] = 0;
 wavehead[19] = 0;
 
 wavehead[20] = 1; //format
 wavehead[21] = 0;
 
 wavehead[22] = numofchannelskey; //chanel
 wavehead[23] = 0;
 
 wavehead[24] = (byte)(samplerate & 0xff);
 wavehead[25] = (byte)((samplerate >> 8) & 0xff);
 wavehead[26] = (byte)((samplerate >> 16) & 0xff);
 wavehead[27] = (byte)((samplerate >> 24) & 0xff);
 
 long byterate = samplerate * 2 * (16 >> 3);;
 wavehead[28] = (byte)(byterate & 0xff);
 wavehead[29] = (byte)((byterate >> 8) & 0xff);
 wavehead[30] = (byte)((byterate >> 16) & 0xff);
 wavehead[31] = (byte)((byterate >> 24) & 0xff);
 
 wavehead[32] = 2*(16 >> 3);
 wavehead[33] = 0;
 
 wavehead[34] = 16;
 wavehead[35] = 0;
 
 wavehead[36] = 'd';
 wavehead[37] = 'a';
 wavehead[38] = 't';
 wavehead[39] = 'a';
 
 long totalaudiolength = [audiodata length];
 
 wavehead[40] = (byte)(totalaudiolength & 0xff);
 wavehead[41] = (byte)((totalaudiolength >> 8) & 0xff);
 wavehead[42] = (byte)((totalaudiolength >> 16) & 0xff);
 wavehead[43] = (byte)((totalaudiolength >> 24) & 0xff);
 
 nsmutabledata *pcmdata = [[nsmutabledata alloc]initwithbytes:&wavehead length:sizeof(wavehead)];
 [pcmdata appenddata:audiodata];
 
 
 return pcmdata;
 // [pcmdata writetofile:kvoicewav atomically:true];
 
}

同时还需把关键的属性抽取出来(如:采样率,通道数…)

//录音格式的设置
+ (nsdictionary*)getaudiorecordersettingdict{
 nsdictionary *recordsetting = [[nsdictionary alloc] initwithobjectsandkeys:
         [nsnumber numberwithfloat: 8000],avsampleratekey, //采样率
         [nsnumber numberwithint: kaudioformatlinearpcm],avformatidkey,
         [nsnumber numberwithint:16],avlinearpcmbitdepthkey,//采样位数 默认 16
         [nsnumber numberwithint: 2], avnumberofchannelskey,//通道的数目
         nil];
 return recordsetting;
}

b)将wav转成amr

使用voiceconvert(by:tang xiaoping)库能将wav转成amr,后来发现环信的easeui框架中也使用了这个

反过来转换也是差不多的

pcm<--->mp3

这个就很简单了,用lame的框架进行转换,这个框架网上资料一大堆

本人为此花了不少时间整理了一下这些文件格式的转换方法

/**
 * 转换wav到amr
 *
 * @param wavpath wav文件路径
 * @param isdelete 转换成功后是否删除源文件
 *
 * @return no 失败 yes成功
 */
+ (bool) wav2amr:(nsstring *)wavpath isdeletesourchfile:(bool)isdelete;
 
/**
 * 转换amr到wav
 *
 * @param amrpath amr文件路径
 * @param isdelete 转换成功后是否删除源文件
 *
 * @return no 失败 yes成功
 */
+ (bool) amr2wav:(nsstring *)amrpath isdeletesourchfile:(bool)isdelete;
 
/**
 * 转换pcm到mp3
 *
 * @param pcmpath pcm文件路径
 * @param isdelete 转换成功后是否删除源文件
 *
 * @return no 失败 yes成功
 */
+ (bool) pcm2mp3: (nsstring *)pcmpath isdeletesourchfile:(bool)isdelete;
/**
 * 转换pcm到wav
 *
 * @param pcmpath pcm文件路径
 * @param isdelete 转换成功后是否删除源文件
 *
 * @return no 失败 yes成功
 */
+ (bool) pcm2wav: (nsstring *)pcmpath isdeletesourchfile:(bool)isdelete;
 
/**
 * 转换pcm到amr
 *
 * @param pcmpath pcm文件路径
 * @param isdelete 转换成功后是否删除源文件
 *
 * @return no 失败 yes成功
 */
+ (bool) pcm2amr:(nsstring *)pcmpath isdeletesourchfile:(bool)isdelete;
 
/**
 * 为pcm文件写入wav头 
 */
+ (nsdata*) writewavhead:(nsdata *)audiodata;
void conventtomp3(nsstring *pcmfile,nsstring *mp3file);
 
/**
 录音格式设置,转换的时候需要获取.(如:采样率、采样位数、通道的数目)
 建议使用此设置,如有修改,则转换amr时也要对应修改参数,比较麻烦
 
 @returns 录音设置
 */
+ (nsdictionary*)getaudiorecordersettingdict;

demo的下载地址https://github.com/qq631192328/pfaudio.git,如果觉得好麻烦点下星,如果有什么问题欢迎指正

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。