iOS音頻音效設(shè)置框架AVFoundation框架

在制作APP的時(shí)候很多時(shí)候都會(huì)用到聲音輸出,畢竟一款有聲音的APP才讓人感到有生命,有活力,沒有聲音的話,整個(gè)APP死氣沉沉的,所以在這里簡(jiǎn)單說一下iOS中的音頻播放。
在iOS設(shè)備中,聲音分為兩種,一種是音效輸出,一種是音頻輸出,音效,就是利用系統(tǒng)的聲音,用來播放比較短的音頻,主要用途是用來做系統(tǒng)的提示音,使用的框架是AudioToolBox,但是今天不重要介紹它,因?yàn)檫@種音效的播放方式和音頻的播放相同,同時(shí)功能也沒有音頻播放強(qiáng)大。
說一下簡(jiǎn)單的音效播放需要的幾個(gè)條件吧。

音效播放

1.聲明一個(gè)聲音ID(SoundID),靠這個(gè)聲音ID來區(qū)分哪個(gè)音頻(音效),類型是無符號(hào)長(zhǎng)整形的.
2.創(chuàng)建播放聲音的服務(wù)(告訴系統(tǒng) 有一個(gè)可以使用的SoundID) 聲音文件的路徑 SoundID。
3.播放聲音

音頻播放

播放音頻和音效都需要這三個(gè)步驟,音頻播放需要的框架也和音效的框架不同,音頻使用的框架式AVFoundation框架,這個(gè)框架中不僅有音頻播放的類,也有視頻播放的類,當(dāng)然今天主要還是說音頻類AVAudioPlayer(音頻播放器)。

在寫一個(gè)音頻播放器之前,有兩點(diǎn)需要我們注意。
1.音頻播放器必須寫為全局變量、屬性,音樂的播放對(duì)象才能播放。
2.在退出播放頁(yè)面的時(shí)候,一定要把播放對(duì)象置空,同時(shí)吧delegate置空。
3.導(dǎo)入#import <AVFoundation/AVFoundation.h>框架
音頻的播放和音效的也有一定區(qū)別
1.資源文件路徑
2.初始化播放器
3.設(shè)置播放器
4.預(yù)播放
5.播放

首先我們要生命一個(gè)全部變量的AVAudioPlayer對(duì)象。

@interface ViewController () <AVAudioPlayerDelegate>
{
    AVAudioPlayer *audioPlayer;
}
@end

第一步,需要一個(gè)資源文件的路徑需要一個(gè)控制器來調(diào)用這個(gè)方法。

我們?yōu)榱俗尣シ盼募雍?jiǎn)便,寫了一個(gè)用來讀取文件路徑的方法

- (void)playMusicWithName:(NSString *)name
{
    NSError *error;
//初始化并讀取文件路徑,讀取的音頻文件名我們用一個(gè)參數(shù)name來代替
    audioPlayer = [[AVAudioPlayer   alloc]initWithContentsOfURL:[[NSBundle   mainBundle]URLForResource:name withExtension:nil]  error:&error];
    if (error) {
        NSLog(@"%@",error);
    }
//    預(yù)播放   在初始化播放器和路徑的同時(shí)給他設(shè)置預(yù)播放,不然后面播放其他音頻文件還需要再次預(yù)播放
    [audioPlayer prepareToPlay];
//    播放
//    [audioPlayer play];
}

然后接下來是我們?cè)赩iewDidLoad里面寫的方法,我寫了一個(gè)按鈕來使這個(gè)播放器播放音頻。

[self playMusicWithName:@"音頻文件的文件名(即傳過去的參數(shù)name)"];
    UIButton *button = [UIButton     buttonWithType:UIButtonTypeCustom];
    button.frame = CGRectMake(100, 100, 100, 100);
    button.backgroundColor = [UIColor brownColor];
    [button setTitle:@"Play" forState:UIControlStateNormal];
    [button setTitle:@"Pause" forState:UIControlStateSelected];
    [button addTarget:self action:@selector(play:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];

然后在觸發(fā)方法里面我們進(jìn)行播放

- (void)play:(UIButton *)sender{
//    [audioPlayer playAtTime:30];

    sender.selected = !sender.selected;
    sender.selected!=YES?[audioPlayer pause]: [audioPlayer play];
    //    [audioPlayer play];開始播放
    //    [audioPlayer pause];暫停播放
    //    [audioPlayer stop];停止播放,停止之后不能再次打開播放器,需要再次初始化才可以
//然后是一些屬性
//    duration 獲得播放音頻的時(shí)間
//    volum 設(shè)置音量
//    設(shè)置速率必須先設(shè)置enableRate為YES
    audioPlayer.enableRate = YES;
    audioPlayer.rate = 1.5;

//    獲得峰值 必須設(shè)置Metersenable為YES
    audioPlayer.meteringEnabled = YES;
//    更新峰值
    [audioPlayer updateMeters];
//    獲得當(dāng)前峰值
    NSLog(@"當(dāng)前峰值%f",[audioPlayer peakPowerForChannel:2]);
    NSLog(@"平均峰值%f",[audioPlayer averagePowerForChannel:2]);
//    設(shè)置播放次數(shù)
//    負(fù)數(shù)是無限循環(huán)    0是一次  1是2次
    audioPlayer.numberOfLoops = -1;
    audioPlayer.delegate = self;

}

這樣我們就可以想要播放那個(gè)音頻文件的時(shí)候直接調(diào)用playMusicWithName:這個(gè)方法來得到路徑和預(yù)播放,然后開始播放和進(jìn)行的一些操作。

代理

接下來是一些常見的代理方法
代理的名字<AVAudioPlayerDelegate>

//播放完成的時(shí)候調(diào)用
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    //在制作音樂播放器時(shí)可以進(jìn)行一些單曲循環(huán)的使用等,也可以進(jìn)行下一曲操作,判斷循環(huán)按鈕的狀態(tài)來決定下一曲或者循環(huán)播放
}
//解碼出現(xiàn)錯(cuò)誤的時(shí)候調(diào)用
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error
{
    //如果播放文件出現(xiàn)問題的話可以在這里進(jìn)行提示用戶播放的文件有誤
}
//被打擾開始中斷的時(shí)候調(diào)用
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player
{
    //因?yàn)橐恍╇娫捇蛘咂渌僮髟斐刹シ胖袛鄷?huì)調(diào)用這個(gè)方法,可以在這里進(jìn)行保存播放器等操作
}
//中斷結(jié)束調(diào)用
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags
{
     //對(duì)應(yīng)可以在這里進(jìn)行恢復(fù)設(shè)置
}

然后還有一點(diǎn)需要大家注意的就是上面說的在退出頁(yè)面的時(shí)候一定 一定 一定 要釋放掉播放器和代理方法
重要的話說三遍

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    audioPlayer = nil;
    audioPlayer.delegate = nil;
}

然后關(guān)于AVFoundation框架還有其錄音的功能
使用的類名也不同,當(dāng)然也需要是全局變量的對(duì)象。

{
    AVAudioRecorder *audioRecorder;
}
接下來要說一下錄音的時(shí)候需要設(shè)置一些屬性
/*
 AVAudioRecorder
 <1>AVNumberOfChannelsKey  通道數(shù)
 <2>AVSampleRateKey  采樣率44100
 <3>AVLinearPCMBitDepthKey    bit 16  32
 <4>AVEncoderAudioQualityKey    質(zhì)量
 <5>AVEncoderBitRateKey   bit采樣率128000
 */

這點(diǎn)需要我們記下來
它需要我們給他一個(gè)URL,本地的一個(gè)URL,來確保錄制的音頻文件存儲(chǔ)的位置

NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"文件的名字"];

我們知道我們?cè)谟肁PP錄音的時(shí)候,他們存儲(chǔ)之后的名字都是一些數(shù)字,這樣來保證他們不重名,那又怎么保證不創(chuàng)建重復(fù)名字的呢,我們知道,時(shí)間戳是一排數(shù)字,而且絕對(duì)不會(huì)有重復(fù)的數(shù)字,所以在這里我們用時(shí)間戳來設(shè)置他的名字。

 NSString *name = [NSString stringWithFormat:@"%d.aiff",(int)[NSDate date].timeIntervalSince1970];
 NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:name];

這里我把它保存到了本地的文件夾中,也可以保存在Library等文件夾中,至于這些文件夾在本地中的區(qū)別,后面我會(huì)涉及到在這里更新出來。

接下來就要給錄音器對(duì)象來初始化并設(shè)置其屬性

NSError *error;
    audioRecorder = [[AVAudioRecorder alloc]initWithURL:[NSURL URLWithString:path] settings:@{AVNumberOfChannelsKey:@2,AVSampleRateKey:@44100,AVLinearPCMBitDepthKey:@32,AVEncoderAudioQualityKey:@(AVAudioQualityMax),AVEncoderBitRateKey:@128000} error:&error];
    audioRecorder.delegate = self;
//準(zhǔn)備錄制
    [audioRecorder prepareToRecord];
//錄制
    [audioRecorder record];
//我們可以打印一下路徑來查看我們錄制結(jié)束之后的文件
    NSLog(@"%@",path);

在這里我同樣是使用了一個(gè)按鈕來開始,和停止錄制

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = CGRectMake(100, 100, 100, 100);
    [button setTitle:@"錄制" forState:UIControlStateNormal];
    button.backgroundColor = [UIColor brownColor];
    [button addTarget:self action:@selector(startAudioRecoder:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];

- (void)startAudioRecoder:(UIButton *)sender
{
    sender.selected =!sender.selected;
    if (sender.selected!=YES) {
//[audioRecorder pause];暫停錄制
        [audioRecorder stop];//停止錄制
        return;
    }

}

另外說一個(gè)代理方法,其實(shí)和音頻播放的都大致相同,這里就說一個(gè)錄制結(jié)束的方法

- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag
{
    NSLog(@"錄音結(jié)束");
NSString *path = [  NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject];
//    文件操作類
    NSFileManager *manager = [NSFileManager defaultManager];
//    獲得當(dāng)前文件的所有子文件subPathAtPath
    NSArray *pathList = [manager subpathsAtPath:path];
    NSLog(@"%@",pathList);
//    需要只獲得錄音文件
    NSMutableArray *audioPathList = [NSMutableArray   array];
//    便利所有這個(gè)文件夾下面的子文件
    for (NSString *audioPath in pathList) {
//        通過對(duì)比文件的延展名,擴(kuò)展名來區(qū)分是不是錄音文件
        if ([audioPath.pathExtension isEqualToString:@"aiff"]) {
            NSLog(@"%@",audioPath);
//              把篩選出來的文件   放到數(shù)組中  得到所有的音頻文件
            [audioPathList addObject:audioPath];
        }
    }
    NSLog(@"%@",audioPathList);
}

這里我做了一個(gè)操作就是把錄制完成之后的文件挪到了我想要的地方,這樣我就可以在錄制結(jié)束的時(shí)候在桌面上找到我錄制成功的文件,當(dāng)然如果是在APP上面可以選擇存在其他的一些文件夾里,通過文件的閆占明來判斷是否是錄音文件等等。

在輸出獲得當(dāng)前文件的所有子文件的時(shí)候可以看到里面不只有我們錄音的文件也有其他文件,然后對(duì)比來篩選出來,也可以在桌面上直接command+G找到輸出的地址來找到文件

簡(jiǎn)單的音頻播放大致就這些,關(guān)于AVFoundation框架還有視頻播放的功能,http://www.lxweimin.com/p/f20342033622
在這里寫的是一些視頻播放的一些相關(guān)介紹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容