一、简单说明
1.关于音乐播放的简单说明
(1)音乐播放用到一个叫做AVAudioPlayer的类
(2)AVAudioPlayer常用方法
加载音乐文件
- (id)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError;
- (id)initWithData:(NSData *)data error:(NSError **)outError;
准备播放(缓冲,提高播放的流畅性) - (BOOL)prepareToPlay;
播放(异步播放)- (BOOL)play;
暂停 - (void)pause;
停止- (void)stop;
是否正在播放 @property(readonly, getter=isPlaying) BOOL playing;
时长 @property(readonly) NSTimeInterval duration;
当前的播放位 @property NSTimeInterval currentTime;
播放次数(-1代表无限循环播放,其他代表播放numberOfLoops+1次 @property NSInteger numberOfLoops;
音量 @property float volume;
是否允许更改速率@property BOOL enableRate;
播放速率(1是正常速率,0.5是一般速率,2是双倍速率) @property float rate;
有多少个声道 @property(readonly) NSUInteger numberOfChannels;
2.播放多个音乐文件
说明:如果要播放多个音乐文件,那么最傻瓜的做法是,创建多个全局的播放器去播放对应的音乐文件,但是这种方法无法适用于需要播放的文件数量巨大的情况。
另外一种做法是:自己封装一个播放音乐文件的工具类。
封装工具类的实现步骤:
新建一个类,继承自NSObject类。提供三个对外的接口:
分别是:
播放音乐(参数:文件名)
暂停音乐(参数:文件名)
停止音乐(参数:文件名)
该工具类中的代码设计如下:
XZAudioTool.h文件
1 #import <Foundation/Foundation.h> 2 3 @interface XZAudioTool : NSObject 4 5 /** 6 * 根据音乐文件名称播放音乐 7 * 8 * @param filename 音乐文件名称 9 */ 10 + (void)playMusicWithFilename:(NSString *)filename; 11 12 /** 13 * 根据音乐文件名称暂停音乐 14 * 15 * @param filename 音乐文件名称 16 */ 17 + (void)pauseMusicWithFilename:(NSString *)filename; 18 19 /** 20 * 根据音乐文件名称停止音乐 21 * 22 * @param filename 音乐文件名称 23 */ 24 + (void)stopMusicWithFilename:(NSString *)filename; 25 @end
XZAudioTool.m文件测试程序:
1 #import "XZAudioTool.h" 2 #import <AVFoundation/AVFoundation.h> 3 4 @implementation XZAudioTool 5 /** 6 * 存放所有的音乐播放器 7 */ 8 static NSMutableDictionary *_players; 9 + (NSMutableDictionary *)players 10 { 11 if (!_players) { 12 _players = [NSMutableDictionary dictionary]; 13 } 14 return _players; 15 } 16 17 /** 18 * 根据音乐文件名称播放音乐 19 * 20 * @param filename 音乐文件名称 21 */ 22 + (void)playMusicWithFilename:(NSString *)filename 23 { 24 // 0.判断文件名是否为nil 25 if (filename == nil) { 26 return; 27 } 28 29 // 1.从字典中取出播放器 30 AVAudioPlayer *player = [self players][filename]; 31 32 // 2.判断播放器是否为nil 33 if (!player) { 34 NSLog(@"创建新的播放器"); 35 36 // 2.1根据文件名称加载音效URL 37 NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:nil]; 38 39 // 2.2判断url是否为nil 40 if (!url) { 41 return; 42 } 43 44 // 2.3创建播放器 45 player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil]; 46 47 // 2.4准备播放 48 if(![player prepareToPlay]) 49 { 50 return; //如果缓冲失败,那么就直接返回 51 } 52 // 允许快进 53 player.enableRate = YES; 54 player.rate = 3; 55 56 // 2.5将播放器添加到字典中 57 [self players][filename] = player; 58 59 } 60 // 3.播放音乐 61 if (!player.playing) 62 { 63 [player play]; 64 } 65 66 } 67 68 /** 69 * 根据音乐文件名称暂停音乐 70 * 71 * @param filename 音乐文件名称 72 */ 73 + (void)pauseMusicWithFilename:(NSString *)filename 74 { 75 // 0.判断文件名是否为nil 76 if (filename == nil) { 77 return; 78 } 79 80 // 1.从字典中取出播放器 81 AVAudioPlayer *player = [self players][filename]; 82 83 // 2.判断播放器是否存在 84 if(player) 85 { 86 // 2.1判断是否正在播放 87 if (player.playing) 88 { 89 // 暂停 90 [player pause]; 91 } 92 } 93 94 } 95 96 /** 97 * 根据音乐文件名称停止音乐 98 * 99 * @param filename 音乐文件名称 100 */ 101 + (void)stopMusicWithFilename:(NSString *)filename 102 { 103 // 0.判断文件名是否为nil 104 if (filename == nil) { 105 return; 106 } 107 108 // 1.从字典中取出播放器 109 AVAudioPlayer *player = [self players][filename]; 110 111 // 2.判断播放器是否为nil 112 if (player) { 113 // 2.1停止播放 114 [player stop]; 115 // 2.2清空播放器 116 // player = nil; 117 // 2.3从字典中移除播放器 118 [[self players] removeObjectForKey:filename]; 119 } 120 } 121 @end
在storyboard中拖拽控件,并进行连线,以做控制。
导入可供播放的音乐素材。
测试程序的代码设计如下:
1 // 2 // ViewController.m 3 // 03-多个音乐文件的播放 4 // 5 // Created by XZ on 14/11/7. 6 // Copyright (c) 2014年 github. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 #import <AVFoundation/AVFoundation.h> 11 #import "XZAudioTool.h" 12 13 @interface ViewController () 14 // 播放器 15 @property (nonatomic, strong) AVAudioPlayer *player; 16 17 // 播放 18 - (IBAction)playMusic; 19 20 // 暂停 21 - (IBAction)pauseMusic; 22 23 // 停止 24 - (IBAction)stopMusic; 25 26 // 下一首 27 - (IBAction)nextMusic; 28 29 // 用一个数组来保存所有的音乐文件 30 @property (nonatomic, strong) NSArray *musics; 31 32 // 用一个int型的属性来记录当前播放音乐的索引 33 @property (nonatomic, assign) int currentIndex; 34 @end 35 36 @implementation ViewController 37 38 #pragma mark - 懒加载 39 - (NSArray *)musics 40 { 41 if (!_musics) { 42 _musics = @[@"最佳损友.mp3", @"心碎了无痕.mp3", @"瓦解.mp3", @"简单爱.mp3"]; 43 } 44 return _musics; 45 } 46 47 - (void)viewDidLoad { 48 [super viewDidLoad]; 49 } 50 51 - (IBAction)playMusic { 52 // 开始播放/继续播放 53 [XZAudioTool playMusicWithFilename:self.musics[self.currentIndex]]; 54 } 55 56 - (IBAction)pauseMusic { 57 // 暂停 58 [XZAudioTool pauseMusicWithFilename:self.musics[self.currentIndex]]; 59 } 60 61 - (IBAction)stopMusic { 62 // 停止 63 [XZAudioTool stopMusicWithFilename:self.musics[self.currentIndex]]; 64 65 } 66 67 - (IBAction)nextMusic { 68 // 下一首 69 70 // 1.递增索引 71 int nextIndex = self.currentIndex + 1; 72 73 // 1.1.判断是否越界 74 if (nextIndex >= self.musics.count) { 75 nextIndex = 0; 76 } 77 NSLog(@"当前 %d 下一首 %d", self.currentIndex, nextIndex); 78 // 2.播放 79 // 2.1停止上一首播放 80 [self stopMusic]; 81 self.currentIndex = nextIndex; 82 // 2.2播放下一首 83 [self playMusic]; 84 } 85 86 @end
二、对工具类进行改造,让其兼能播放音效文件
说明:
音效只有创建、播放和销毁(停止)三个操作,因为音效一般都很短,因此没有暂停的方法。
把对音效文件的播放加入到工具类中,实现的代码如下:
XZAudioTool.h文件
1 #import <Foundation/Foundation.h> 2 3 @interface XZAudioTool : NSObject 4 /** 5 * 根据音效文件名称播放音效 6 * 7 * @param filename 音效文件名称 8 */ 9 + (void)playAudioWithFilename:(NSString *)filename; 10 11 /** 12 * 根据音效文件名称销毁音效 13 * 14 * @param filename 音效文件名称 15 */ 16 + (void)disposeAudioWithFilename:(NSString *)filename; 17 18 /** 19 * 根据音乐文件名称播放音乐 20 * 21 * @param filename 音乐文件名称 22 */ 23 + (void)playMusicWithFilename:(NSString *)filename; 24 25 /** 26 * 根据音乐文件名称暂停音乐 27 * 28 * @param filename 音乐文件名称 29 */ 30 + (void)pauseMusicWithFilename:(NSString *)filename; 31 32 /** 33 * 根据音乐文件名称停止音乐 34 * 35 * @param filename 音乐文件名称 36 */ 37 + (void)stopMusicWithFilename:(NSString *)filename; 38 @end
SLAudioTool.m文件测试程序:
1 #import "XZAudioTool.h" 2 #import <AVFoundation/AVFoundation.h> 3 4 @implementation XZAudioTool 5 /** 6 * 存放所有的音效ID 7 */ 8 static NSMutableDictionary *_soundIDs; 9 + (NSMutableDictionary *)soundIDs 10 { 11 if (!_soundIDs) { 12 _soundIDs = [NSMutableDictionary dictionary]; 13 } 14 return _soundIDs; 15 } 16 17 /** 18 * 存放所有的音乐播放器 19 */ 20 static NSMutableDictionary *_players; 21 + (NSMutableDictionary *)players 22 { 23 if (!_players) { 24 _players = [NSMutableDictionary dictionary]; 25 } 26 return _players; 27 } 28 29 /** 30 * 根据音效文件名称播放音乐 31 * 32 * @param filename 音效文件名称 33 */ 34 + (void)playAudioWithFilename:(NSString *)filename 35 { 36 37 // 0.判断文件名是否为nil 38 if (filename == nil) { 39 return; 40 } 41 42 // 1.从字典中取出音效ID 43 SystemSoundID soundID = [[self soundIDs][filename] unsignedIntValue]; 44 45 // 判断音效ID是否为nil 46 if (!soundID) { 47 NSLog(@"创建新的soundID"); 48 49 // 音效ID为nil 50 // 根据文件名称加载音效URL 51 NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:nil]; 52 53 // 判断url是否为nil 54 if (!url) { 55 return; 56 } 57 58 // 创建音效ID 59 AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url), &soundID); 60 61 // 将音效ID添加到字典中 62 [self soundIDs][filename] = @(soundID); 63 } 64 // 播放音效 65 AudioServicesPlaySystemSound(soundID); 66 } 67 68 /** 69 * 根据音效文件名称销毁音乐 70 * 71 * @param filename 音效文件名称 72 */ 73 + (void)disposeAudioWithFilename:(NSString *)filename 74 { 75 // 0.判断文件名是否为nil 76 if (filename == nil) { 77 return; 78 } 79 80 // 1.从字典中取出音效ID 81 SystemSoundID soundID = [[self soundIDs][filename] unsignedIntValue]; 82 83 if (soundID) { 84 // 2.销毁音效ID 85 AudioServicesDisposeSystemSoundID(soundID); 86 87 // 3.从字典中移除已经销毁的音效ID 88 [[self soundIDs] removeObjectForKey:filename]; 89 } 90 91 } 92 93 94 /** 95 * 根据音乐文件名称播放音乐 96 * 97 * @param filename 音乐文件名称 98 */ 99 + (void)playMusicWithFilename:(NSString *)filename 100 { 101 // 0.判断文件名是否为nil 102 if (filename == nil) { 103 return; 104 } 105 106 // 1.从字典中取出播放器 107 AVAudioPlayer *player = [self players][filename]; 108 109 // 2.判断播放器是否为nil 110 if (!player) { 111 NSLog(@"创建新的播放器"); 112 113 // 2.1根据文件名称加载音效URL 114 NSURL *url = [[NSBundle mainBundle] URLForResource:filename withExtension:nil]; 115 116 // 2.2判断url是否为nil 117 if (!url) { 118 return; 119 } 120 121 // 2.3创建播放器 122 player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil]; 123 124 // 2.4准备播放 125 if(![player prepareToPlay]) 126 { 127 return; //如果缓冲失败,那么就直接返回 128 } 129 // 允许快进 130 player.enableRate = YES; 131 player.rate = 3; 132 133 // 2.5将播放器添加到字典中 134 [self players][filename] = player; 135 136 } 137 // 3.播放音乐 138 if (!player.playing) 139 { 140 [player play]; 141 } 142 143 } 144 145 /** 146 * 根据音乐文件名称暂停音乐 147 * 148 * @param filename 音乐文件名称 149 */ 150 + (void)pauseMusicWithFilename:(NSString *)filename 151 { 152 // 0.判断文件名是否为nil 153 if (filename == nil) { 154 return; 155 } 156 157 // 1.从字典中取出播放器 158 AVAudioPlayer *player = [self players][filename]; 159 160 // 2.判断播放器是否存在 161 if(player) 162 { 163 // 2.1判断是否正在播放 164 if (player.playing) 165 { 166 // 暂停 167 [player pause]; 168 } 169 } 170 171 } 172 173 /** 174 * 根据音乐文件名称停止音乐 175 * 176 * @param filename 音乐文件名称 177 */ 178 + (void)stopMusicWithFilename:(NSString *)filename 179 { 180 // 0.判断文件名是否为nil 181 if (filename == nil) { 182 return; 183 } 184 185 // 1.从字典中取出播放器 186 AVAudioPlayer *player = [self players][filename]; 187 188 // 2.判断播放器是否为nil 189 if (player) { 190 // 2.1停止播放 191 [player stop]; 192 // 2.2清空播放器 193 // player = nil; 194 // 2.3从字典中移除播放器 195 [[self players] removeObjectForKey:filename]; 196 } 197 } 198 @end
代码测试:
- (IBAction)playMusic { // 开始播放/继续播放 // [HMAudioTool playMusicWithFilename:self.musics[self.currentIndex]]; [HMAudioTool playAudioWithFilename:@"buyao.wav"]; }
代码说明:
打印的值为0,播放成功(因为函数是C++中的)