iPhone音频基础

原文:http://www.raywenderlich.com/zh-hans/20608


前提:每个音频文件有两部分:1是文件格式(也叫音频容器),2是数据格式(也叫音频编码)。
数据格式(或者是音频编码):
AAC: Aaac其实是“高级音频编码(advanced audio coding)”的缩写,它是被设计用来取代MP3格式的。你可能会想,它压缩了原始的声音,导致容量占用少但是质量肯定会有所下降。不过这些质量的损失取决于声音比特率的大小,当比特率合适的时候,这些损失人耳是很难听出来的。事实上,aac比mp3有更好的压缩率,特别是在比特率低于128bit/s的时候。
HE-AAC: HE-AAC是AAC的一个超集,这个“HE”代表的是“High efficiency”。 HE-AAC是专门为低比特率所优化的一种音频编码格式,比如streaming audio就特别适合使用这种编码格式。
AMR: AMR全称是“Adaptive Multi-Rate”,它也是另一个专门为“说话(speech)”所优化的编码格式,也是适合低比特率环境下采用。
ALAC: 它全称是“Apple Lossless”,这是一种没有任何质量损失的音频编码方式,也就是我们说的无损压缩。在实际使用过程中,它能够压缩40%-60%的原始数据。这种编码格式的解码速度非常快,这对iphone或者ipod这种小型设备来说非常适合。
iLBC: 这是另一种专门为说话所设计的音频编码格式,它非常适合于IP电话等其它需要流式音频的场合。
IMA4: 这是一个在16-bit音频文件下按照4:1的压缩比来进行压缩的格式。这是iphone上面一种非常重要的编码格式,我们将在以后讨论原因。
它的中文意思是基于线性脉冲编码调制,用于将模拟声音数据转换成数字声音数据。简而言之,就是意味着无压缩数据。由于数据是非压缩的,它可以非常快的播放,并且当空间不是问题时,这是在iphone上面首选的音频编码方式。
μ-law and a-law: 就我所知道的,这种编码是交替的编码模拟数据为数字格式数据,但是在speech优化方面比linear PCM更好。
MP3: 这种格式是我们都知道也喜欢的,虽然很多年过去了,但MP3到目前为止仍然是一种非常流行的编码格式,它也能被iphone很好地支持。


编码格式:
你可以播放linear PCM, IMA4和一些其它没有压缩的或者简单压缩的音频格式,这些格式可以很好地被iphone的硬件解码。(还有一个很重要的关于linear PCM的问题需要强调,那就是这种无压缩的数据格式是iphone上面编程首选的。针对不同的数据存储,这里有一些linear PCM变种。这些数据可以使用高尾数或者低尾数格式来储存,它们之间的差别,就像浮点型和整型它们占用的位宽不同。
这里最重要的一件事就是,在iphone上面首选的linear PCM是低尾数(little-endian)格式的16位整型,或者是”LEI16″(好像是一种编码格式,apple caf audio format code: LEI16, ios设备的音频格式是16位低尾数编码)。这个是和Mac os x不一样的,它使用的是本地32位浮点型尾数编码。因为音频文件经常要在Mac上面创建,所以检查文件并把他们转换为iphone首选的音频编码格式是个很好的主意。)
对于更多高级的压缩格式,例如AAC,MP3,和ALAC,iphone并没有提供硬件编解码器的支持来很快解压缩这些数据,并且在一个时候只能处理一个文件。因此,假如你播放超过一个使用这些编码的音频文件,系统将选择使用软件来解码,那样会比较慢,还会占用CPU。
因此选择什么样的数据格式,这里有两条建议:
假如空间不是问题,那么使用linear PCM来编码每个音频。这样不仅使你的音频最快地播放,而且你能够在不占用CPU资源的情况下同时播放多个声音。
假如空间是问题, 你大多数时候要使用AAC来编码你的背景音乐和IMA4来编码你的音效。


文件格式(或者说是音频容器)
iphone支持很多文件格式,包括MPEG-1 (.mp3), MPEG-2 ADTS (.aac), AIFF, CAF, and WAVE。但是最重要的事是你可以只使用CAF,因为它能包含任何iphone支持的编码格式的数据,在iPhone上面它是推荐的文件格式。
(泰然注:在这里我在啰嗦点,其实文件格式就像是桶一样,里面可以装很多水,那些水就是那些音频数据。桶有很多种,也就是有很多种文件格式,而且不一样的桶,也需要装不同的水。CAF这种桶就可以装各种各样的水,不过有些就只能装几种类型的水。希望我这样的比喻你可以很好的理解。)
比特率
这有一个有关音频编码很重要的术语,我们接下来会提及:比特率。
比特率是音频文件每秒占据的字节数(比特数)。一些像AAC或者MP3编码会指定音频文件压缩的比特数。当你在使用比较低的比特率时,你将会丢失声音质量。
你应该根据特定的声音文件的不同来选择不同的比特率,试着使用不同的比特率,来比较哪个是最合适的,在声音文件大小和声音质量之间做一些权衡。假如你的文件大多数是语音说话数据,你可以使用比较低的比特率。
这里有一个表,给你一个最常见的比特率的概述:
32kbit/s: 调幅(AM)广播的质量
48kbit/s: 一般比较长时间的语音播客的比特率
64kbit/s: 一般正常长度的语音播客的比特率
96kbit/s: 调频(FM)广播的质量
128kbit/s: 大多数MP3音乐的比特率
160kbit/s: 那些很喜欢音乐的,想要听觉感受的人更喜欢的在128kbit/s之上的一个比特率
192kbit/s: 数字电台的质量
320kbit/s: 在这个比特率下人们几乎和CD的播放效果一样,不能区别
500kbit/s-1,411kbit/s: 无损的音频编码,就像linear PCM
采样率
在我们继续介绍音频之前,这里还有一个术语我们需要了解一下,就是:采样率。
当转换一个模拟信号到数字格式,采样率表示多久抽取一次声音波形试样来转换成一个数字信号。
大多情况下,44100Hz是被经常使用的,因为这和CD音频一样的采样率。




1,在mac上转换音频,使用三条内置的命令行工具即可:afplay,afconvert,afinfo。
afplay:最简单,在终端输入音频名字,即可播放。(在听不同比特率的压缩文件差别时,尤为方便)
afinfo:输入音频名字,即可查看格式,编码,比特率以及其他相关信息。
afconvert:将一份文件转化为另一种格式的文件。line:afconvert -d [out data format] -f [out file format] -b [bit/s][in file] [out file](bit/s 可选),例如:afconvert -d LEI16 -f 'caff' input_file.xxx output_file.caf


2,在iPhone上播放音频方法:


A:system sound services:简单的播放音频文件,c语言风格的音频服务,适合播放自定义的警告音或者消息提示-比较节省资源。缺点:a-只支持音频数据格式linear PCM或者IMA4以及只支持音频文件格式CAF,AIF,WAV;b-声音长度<=30s;c-简单音频只可从磁盘播放,不可从内存;d-无法中途控制(但播放结束可回调函数)。
代码:需加如AudioToolbox.framework库
- (IBAction)play:(id)sender
{
    NSString *audioString=[[NSBundle mainBundle] pathForResource:@"roof" ofType:@"caf"];
    
    NSURL *audioURL=[NSURL fileURLWithPath:audioString];
    
    SystemSoundID audioSoundId;
    OSStatus error=AudioServicesCreateSystemSoundID((__bridge CFURLRef)audioURL, &audioSoundId);
    if(error)
    {
        return;
    }
    /*添加音频结束时的回调*/
    AudioServicesAddSystemSoundCompletion(audioSoundId, NULL, NULL, SoundFinished,(__bridge void *)(audioURL));
    AudioServicesPlaySystemSound(audioSoundId);
    CFRunLoopRun();
}
//音频播放结束调用此方法
static void SoundFinished(SystemSoundID soundID,void* sample)
{
    /*播放全部结束,因此释放所有资源 */
    AudioServicesDisposeSystemSoundID((SystemSoundID)sample);
    CFRelease(sample);
    CFRunLoopStop(CFRunLoopGetCurrent());
}
B: AVAudioPlayer:使用AAC或者mp3来作为背景音乐,可以使用之。
缺点:运行较慢,有点延迟;建议和意见:播放前应检查设备是否有另一个音频在播放;当播放自动中断,如用户接听电话,可以注册AVAudioPlayerDelegate,使用audioPlayEndInterruption恢复播放;
使用前需要导入AVFoundation.framework库。
AVAudioPlayer类封装了播放单个声音的能力。播放器可以用NSURL或者NSData来初始化,要注意的是NSURL并不可以是网络url而必须是本地文件URL,因为AVAudioPlayer不具备播放网络音频的能力(但可以变相实现之,即AVAudioPlayer不可以播放网络URL,但是可以播放NSData,我们似乎受到了点启发,我们可以通过网络URL去创建NSData,然后在通过AVAudioPlayer来播放NSData,这样是不是就可以播放网络音乐了呢?但是此法并不可取,因为AVAudioPlayer只能播放一个完整的文件,并不支持流式播放,所以必须是缓冲完才能播放,所以如果网络文件过大抑或是网速不够岂不是要等很久?所以播放网络音频我们一般用音频队列。)。
一个AVAudioPlayer只能播放一个音频,如果你想混音你可以创建多个AVAudioPlayer实例,每个相当于混音板上的一个轨道。
代码:
- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    NSError *error;
    
    NSURL *url=[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:@"roof" ofType:@"mp3"]];
    player=[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];//使用本地URL创建
    //AVAudioPlayer* player = [[AVAudioPlayer alloc]
    //initWithContentsOfURL:url error:&error ];
    player.delegate = self;
    
    player.volume=1.0;//0.0~1.0之间
    player.numberOfLoops = 3;//默认只播放一次
    player.currentTime = 15.0;//可以指定从任意位置开始播放
    
    NSUInteger channels = player.numberOfChannels;//只读属性
    NSTimeInterval duration = player.duration;//获取采样的持续时间
    player.meteringEnabled = YES;//开启仪表计数功能
    [ player updateMeters];//更新仪表读数
    //读取每个声道的平均电平和峰值电平,代表每个声道的分贝数,范围在-100~0之间。
    for(int i = 0; i     {
        float power = [player averagePowerForChannel:i];
        float peak = [player peakPowerForChannel:i];
    }


}
- (IBAction)play:(id)sender
{
    
    [player prepareToPlay];//分配播放所需的资源,并将其加入内部播放队列
    [player play];//播放
    //[player stop];//停止

}

附录:google的TTS接口实现例子:

NSString *urlString = [@"http://translate.google.com/translate_tts?ie=UTF-8&oe=UTF-8&tl=zh&q="stringByAppendingString:@"++中国人"];

    urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    NSURL *url = [[NSURLalloc] initWithString:[urlString stringByReplacingOccurrencesOfString:@" "withString:@"+"]];

    //获得返回的mp3文件,格式为NSdata

    NSData *voiceData = [[NSDataalloc] initWithContentsOfURL:url];

    [NSThreadsleepForTimeInterval:3.0];//等待3秒获取google词库的发音数据

    if(voiceData)

    {

        NSLog(@"已经1次性获取到voice");

    }

    else

    {

        int k=0;

        while(k<5&&!voiceData)//voiceData为空,则继续获取voiceData5次,防止单词没有读音

        {

             NSString *urlString = [@"http://translate.google.com/translate_tts?tl=zh-CN&q="stringByAppendingString:@"++中国人"];

            NSURL *url = [[NSURLalloc] initWithString:[urlString stringByReplacingOccurrencesOfString:@" "withString:@"+"]];

            //获得返回的mp3文件,格式为NSdata

            voiceData = [[NSData alloc] initWithContentsOfURL:url];

            [NSThreadsleepForTimeInterval:5.0];

            k++;

        }

        if(voiceData){NSLog(@"%d次获取到voice",k+1);}

    }

    NSArray *paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);

    NSString *documentsDirectory = [paths objectAtIndex:0];

    NSLog(@"%@",documentsDirectory);

    [voiceData writeToFile:[documentsDirectorystringByAppendingPathComponent:@"test2"]atomically:YES];


C: Audio Queue Services

如果以上两种音频播放的解决方案都无法满足你的需求,那么我想你肯定需要使用 Audio Queue Services。使用 Audio Queue Services 对音频进行播放,你可以完全实现对声音的控制。例如,你可以在声音数据从文件读到内存缓冲区后对声音进行一定处理再进行播放,从而实现对音频的快速/慢速播放的功能。

因为 Audio Queue Services 相对复杂很多,Apple 官方已经把它整理为一本书了,具体可以参考 Audio Queue Services Programming Guide 和 SpeakHere 的程序示例。


D:OpenAL:写一个游戏或者应用,并且需要使用底层的技术来操纵视频,使用该技术,可以支持跨平台的音频库。

OpenAL 是一套跨平台的开源的音频处理接口,与图形处理的 OpenGL 类似,它为音频播放提供了一套更加优化的方案。它最适合开发游戏的音效,用法也与其他平台下相同。

iPhone 支持 OpenAL 1.1,我没有在实际开发中使用过,具体的文档可以参考 OpenAL 的网站http://openal.org 和 oalTouch 的程序示例。



你可能感兴趣的:(iPhone开发笔记)