1. 程式人生 > >iOS學習筆記23-音效與音樂

iOS學習筆記23-音效與音樂

nslog ini post jpg outer 震動 ucc aml iboutlet

一、音頻

在iOS中,音頻播放從形式上能夠分為音效播放和音樂播放。
* 音效:
* 主要指一些短音頻的播放,這類音頻一般不須要進行進度、循環等控制。
* 在iOS中。音效我們是使用AudioToolbox.framework框架實現。
* 音樂:
* 主要指一些較長的音頻,通常須要對播放進行精確控制。
* 在iOS中,音樂我們是使用AVFoundation.framework框架實現。

技術分享

二、音效

AudioToolbox.framework框架是一套基於C語言的框架
它的實現原理是將短音頻註冊到系統聲音服務(SystemSoundService)

系統聲音服務的一些限制:
  1. 音頻播放時間不能超過30s
  2. 數據必須是PCM或者IMA4格式,如今的基本都符合
  3. 音頻文件必須是CAF、AIF、WAV的一種,實際上有些MP3格式也能夠播放。
使用步驟:
  1. 導入AudioToolbox.framework框架,加入頭文件:
#import <AudioToolbox/AudioToolbox.h>
  1. 獲取音效文件的路徑URL
  2. 加入進系統聲音服務,獲得系統聲音ID。ID是區分不同音效的唯一標示
void AudioServicesCreateSystemSoundID(
          CFURLRef inFileURL,    /* 音效文件URL,須要把NSURL橋接成CGURLRef */
SystemSoundID *outSystemSoundID /* 返回音效唯一標示ID */ );
  1. 假設須要監聽音效播放完畢,須要綁定回調函數
void AudioServicesAddSystemSoundCompletion(  
        SystemSoundID inSystemSoundID, /* 音效ID */
        CFRunLoopRef inRunLoop, /* 所在循環,一般為NULL */
        CFStringRef inRunLoopMode,/* 循環模式,一般為NULL */
        void (*)(SystemSoundID,void
*) inCompletionRoutine,/* 回調C語言函數指針 */ void *inClientData /* 回調函數的參數 */ );
  1. 開始播放,有兩種播放模式:
/* 開始播放音效 */
void AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID);
/* 開始播放音效並帶震動 */
void AudioServicesPlayAlertSound(SystemSoundID inSystemSoundID);
以下是使用實例:
- (void)viewDidLoad{
    [super viewDidLoad];
    [self playSoundEffect:@"bellTone.wav"];
}
#pragma mark -音效
/* 音效播放完畢的回調函數,這個是C語言函數,第一個參數是音效ID,第二個是萬能參數 */
void soundCompleteCallBack(SystemSoundID soundID, void *clientData)
{
    NSLog(@"播放完畢");
}
- (void)playSoundEffect:(NSString *)name {
    //獲取音效文件路徑
    NSString *filePath = [[NSBundle mainBundle] pathForResource:name ofType:nil];
    //創建音效文件URL
    NSURL *fileUrl = [NSURL URLWithString:filePath];
    //音效聲音的唯一標示ID
    SystemSoundID soundID = 0;
    //將音效加入到系統音效服務中。NSURL須要橋接成CFURLRef。會返回一個長整形ID,用來做音效的唯一標示
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)(fileUrl), &soundID);
    //設置音效播放完畢後的回調C語言函數
    AudioServicesAddSystemSoundCompletion(soundID,NULL,NULL,soundCompleteCallBack,NULL);
    //開始播放音效
    AudioServicesPlaySystemSound(soundID);
}

三、音樂

假設播放較大的音頻,須要對其進行精確控制,我們須要使用到另外一個框架。即:
AVFoundation.framework框架,它支持多種音頻格式,能夠進行精確控制。
音樂播放功能我們使用到的是AVFoundation.frameworkAVAudioPlayer音樂播放器來實現。

以下有一些AVAudioPlayer類的經常使用屬性:
@property (readonly, getter=isPlaying) BOOL playing;//是否正在播放
@property NSTimeInterval currentTime;//當前已經播放的時間
@property (readonly) NSTimeInterval duration;//播放的總時間
@property float volume;//音量大小
@property float rate;//播放速率,默覺得1.0
@property (readonly) NSURL *url;//音樂文件的URL
以下是經常使用的對象方法:
/* 初始化方法 */
- (instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError;
- (BOOL)prepareToPlay;/* 把音樂文件載入到緩存區 */
- (BOOL)play;/* 開始播放音樂 */
- (BOOL)playAtTime:(NSTimeInterval)time;/* 在指定時間開始播放音樂 */
- (void)pause;/* 中斷音樂,能夠通過調用play方法繼續播放 */
- (void)stop;/* 終止音樂。無法繼續播放 */
經常使用的代理方法:
/* 播放完畢時調用 */
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
/* 音頻解碼錯誤發生時調用 */
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error;
使用步驟:
  1. 導入AVFoundation.framework框架,加入頭文件:
#import <AVFoundation/AVFoundation.h>
  1. 獲取音樂文件的本地文件路徑URL。不能使用網絡URL
  2. 創建音樂播放器對象AVAudioPlayer,並設置屬性和代理。

  3. 調用perpareToPlay方法載入音樂文件到緩沖區
  4. 調用play方法播放。調用pause中斷播放
  5. 實現AVAudioPlayerDelegate方法,監聽播放完畢。
我們來做個簡易的音樂播放器吧:
  1. 能夠循環播放音樂
  2. 能夠中斷音樂
  3. 能夠切換不同的音樂
  4. 能夠知道播放進度
以下是詳細的簡易音樂播放器項目代碼:
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>

@interface ViewController () <AVAudioPlayerDelegate>

@property (nonatomic, strong) NSArray *musicArray;/*< 音樂列表 */
@property (nonatomic, strong) IBOutlet UIProgressView *progress;/*< 進度條 */
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;/*< 音樂播放器對象 */
@property (nonatomic, strong) NSTimer *timer;/* 定時器 */
@property (nonatomic, strong) IBOutlet UILabel *titleLabel;/* 顯示標題 */
@property (nonatomic, assign) NSInteger selectMusic;/* 當前播放音樂的索引 */

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //音樂文件列表
    self.musicArray = @[@"大夢想家",@"江南",@"酒幹倘賣無",
                        @"泡沫",@"夏洛特煩惱",@"演員"];
    //創建定時器,用於不斷更新進度條
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 
                                                  target:self 
                                                selector:@selector(updataProgress) 
                                                userInfo:nil 
                                                 repeats:YES];
    //創建播放器
    [self initAudioPlayerWithNumber:0];
    //播放器開始播放音樂
    [self.audioPlayer play];
}
/* 初始化播放器 */
- (void)initAudioPlayerWithNumber:(NSInteger)num{
    if (num >= self.musicArray.count) {
        return;
    }
    //獲取音樂文件路徑
    NSString *name = self.musicArray[num];
    NSString *filePath = [[NSBundle mainBundle] pathForResource:name 
                                                         ofType:@"mp3"];
    //創建音樂文件URL。必須是fileURLWithPath,AVAudioPlayer不支持HTTP的URL
    NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
    //創建播放器
    NSError *error = nil;
    AVAudioPlayer *audioPlayer =
            [[AVAudioPlayer alloc] initWithContentsOfURL:fileUrl error:&error];
    if (error) {
        NSLog(@"初始化播放器錯誤,錯誤:%@",error.localizedDescription);
        return;
    }
    audioPlayer.numberOfLoops = 0;//設置循環次數,0表示不循環
    audioPlayer.delegate = self;//設置代理
    [audioPlayer prepareToPlay];//載入音樂文件到緩存,還不會播放

    self.selectMusic = num;//保存當前的音樂索引
    self.audioPlayer = audioPlayer;//保存當前播放器
    self.titleLabel.text = name;//設置標題
}
/* 進度條更新方法,每0.5秒更新一次 */
- (void)updataProgress{
    //currentTime是當前播放時間,duration是播放總時長
    CGFloat progress = self.audioPlayer.currentTime / self.audioPlayer.duration;
    [self.progress setProgress:progress animated:YES];
}
/* 點擊播放button */
- (IBAction)musicPlay:(id)sender {
    //假設播放器沒有在播放,才須要調用播放方法
    if (![self.audioPlayer isPlaying]) {
        [self.audioPlayer play];
        //恢復定時器
        self.timer.fireDate = [NSDate distantPast];
    }
}
/* 點擊暫停button */
- (IBAction)musicPause:(id)sender {
    //假設播放器在播放,才須要調用暫停方法
    if ([self.audioPlayer isPlaying]) {
        [self.audioPlayer pause];
        //停止定時器
        self.timer.fireDate = [NSDate distantFuture];
    }
}
/* 點擊下一首歌button */
- (IBAction)next:(id)sender {
    //音樂索引循環遞增
    self.selectMusic = (self.selectMusic + 1)%self.musicArray.count;
    //又一次設置播放器
    [self initAudioPlayerWithNumber:self.selectMusic];
    //播放器播放
    [self.audioPlayer play];
}
#pragma mark - AVAudioPlayerDelegate代理方法
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
    //自己主動跳轉播放下一首歌
    [self next:nil];
}

技術分享
(⊙﹏⊙)b,也是夠簡陋的,你能夠做精美一點,比方假設每首歌相應一個圖片。到時候切歌的時候,圖片顯示在背景,一定賞心悅目多了,O(∩_∩)O~,我沒有找到好的圖片,就這樣吧。

四、後臺播放音樂

其實上面的播放器有一點問題,那就是一旦進入後臺。我們的音樂器就自己主動暫停了,不能夠/(ㄒoㄒ)/~~!那該怎麽辦呢?

1. 設置後臺執行模式

設置info.plist文件,加入字段Required background modes
並設置App plays audio or streams audio/video using AirPlay
技術分享

2. 使用音頻會話。設置後臺執行類型
//獲取音頻會話單例對象
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
//設置會話為後臺播放
[audioSession setCategory:AVAudioSessionCategoryPlayback error:NULL];
//激活改動。啟動會話
[audioSession setActive:YES error:NULL];

音頻會話除了後臺播放外。還能夠有以下的播放模式:
技術分享

上面的代碼僅僅需改動初始化播放器方法就可以實現後臺播放:
/* 初始化播放器 */
- (void)initAudioPlayerWithNumber:(NSInteger)num{
    if (num >= self.musicArray.count) {
        return;
    }
    //獲取音樂文件路徑
    NSString *name = self.musicArray[num];
    NSString *filePath = [[NSBundle mainBundle] pathForResource:name 
                                                         ofType:@"mp3"];
    //創建音樂文件URL。必須是fileURLWithPath,AVAudioPlayer不支持HTTP的URL
    NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
    //創建播放器
    NSError *error = nil;
    AVAudioPlayer *audioPlayer =
            [[AVAudioPlayer alloc] initWithContentsOfURL:fileUrl error:&error];
    if (error) {
        NSLog(@"初始化播放器錯誤,錯誤:%@",error.localizedDescription);
        return;
    }
    audioPlayer.numberOfLoops = 0;//設置循環次數,0表示不循環
    audioPlayer.delegate = self;//設置代理
    [audioPlayer prepareToPlay];//載入音樂文件到緩存,還不會播放

    //獲取音頻會話單例對象
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    //設置會話為後臺播放
    [audioSession setCategory:AVAudioSessionCategoryPlayback error:NULL];
    //激活改動,啟動會話
    [audioSession setActive:YES error:NULL];

    self.selectMusic = num;//保存當前的音樂索引
    self.audioPlayer = audioPlayer;//保存當前播放器
    self.titleLabel.text = name;//設置標題
}

這樣,我們就能夠後臺播放了。(^o^)/~。

有什麽問題能夠在下方評論區出去。好意見我會採納的,打造一個大家都愜意的學習筆記,O(∩_∩)O哈!

iOS學習筆記23-音效與音樂