zoukankan      html  css  js  c++  java
  • iOS开发拓展篇—音频处理(音乐播放器3)

    iOS开发拓展篇—音频处理(音乐播放器3)

    说明:这篇文章主要介绍音频工具类和播放工具类的封装。

    一、控制器间数据传递

    1.两个控制器之间数据的传递
      第一种方法:self.parentViewController.music=self.music[indexPath.row];不能满足
      第二种做法:把整个数组传递给它
      第三种做法:设置一个数据源,设置播放控制器的数据源是这个控制器。self.parentViewController.dataSource=self;好处:没有耦合性,任何实现了协议的可以作为数据源。
      第四种做法:把整个项目会使用到的音频资源交给一个工具类去管理,这样就不用传递过去了。直接向工具类索要资源就可以。
     
    二、封装一个音频工具类
    新建一个音频工具类,用来管理音乐数据(音乐模型)
      
    工具类中的代码设计如下:
     YYMusicTool.h文件
     1 //
     2 //  YYMusicTool.h
     3 //
     4 
     5 #import <Foundation/Foundation.h>
     6 @class YYMusicModel;
     7 @interface YYMusicTool : NSObject
     8 /**
     9  *  返回所有的歌曲
    10  */
    11 + (NSArray *)musics;
    12 
    13 /**
    14  *  返回正在播放的歌曲
    15  */
    16 + (YYMusicModel *)playingMusic;
    17 + (void)setPlayingMusic:(YYMusicModel *)playingMusic;
    18 
    19 /**
    20  *  下一首歌曲
    21  */
    22 + (YYMusicModel *)nextMusic;
    23 
    24 /**
    25  *  上一首歌曲
    26  */
    27 + (YYMusicModel *)previousMusic;
    28 @end
    YYMusicTool.m文件
     1 //
     2 //  YYMusicTool.m
     3 //
     4 
     5 #import "YYMusicTool.h"
     6 #import "YYMusicModel.h"
     7 #import "MJExtension.h"
     8 
     9 @implementation YYMusicTool
    10 
    11 static NSArray *_musics;
    12 static  YYMusicModel *_playingMusic;
    13 
    14 /**
    15  *  @return 返回所有的歌曲
    16  */
    17 +(NSArray *)musics
    18 {
    19     if (_musics==nil) {
    20         _musics=[YYMusicModel objectArrayWithFilename:@"Musics.plist"];
    21     }
    22     return _musics;
    23 }
    24 
    25 +(void)setPlayingMusic:(YYMusicModel *)playingMusic
    26 {
    27     /*
    28      *如果没有传入需要播放的歌曲,或者是传入的歌曲名不在音乐库中,那么就直接返回
    29       如果需要播放的歌曲就是当前正在播放的歌曲,那么直接返回
    30      */
    31     if (!playingMusic || ![[self musics]containsObject:playingMusic]) return;
    32     if (_playingMusic == playingMusic) return;
    33     _playingMusic = playingMusic;
    34 }
    35 /**
    36  *  返回正在播放的歌曲
    37  */
    38 +(YYMusicModel *)playingMusic
    39 {
    40     return _playingMusic;
    41 }
    42 
    43 /**
    44  *  下一首歌曲
    45  */
    46 +(YYMusicModel *)nextMusic
    47 {
    48     //设定一个初值
    49     int nextIndex = 0;
    50     if (_playingMusic) {
    51         //获取当前播放音乐的索引
    52         int playingIndex = [[self musics] indexOfObject:_playingMusic];
    53         //设置下一首音乐的索引
    54         nextIndex = playingIndex+1;
    55         //检查数组越界,如果下一首音乐是最后一首,那么重置为0
    56         if (nextIndex>=[self musics].count) {
    57             nextIndex=0;
    58         }
    59     }
    60     return [self musics][nextIndex];
    61 }
    62 
    63 /**
    64  *  上一首歌曲
    65  */
    66 +(YYMusicModel *)previousMusic
    67 {
    68     //设定一个初值
    69     int previousIndex = 0;
    70     if (_playingMusic) {
    71         //获取当前播放音乐的索引
    72         int playingIndex = [[self musics] indexOfObject:_playingMusic];
    73         //设置下一首音乐的索引
    74         previousIndex = playingIndex-1;
    75         //检查数组越界,如果下一首音乐是最后一首,那么重置为0
    76         if (previousIndex<0) {
    77             previousIndex=[self musics].count-1;
    78         }
    79     }
    80     return [self musics][previousIndex];
    81 }
    82 @end

    三、封装一个音乐播放工具类

    该工具类中的代码设计如下:

    YYAudioTool.h文件

     1 //
     2 //  YYAudioTool.h
     3 //
     4 
     5 #import <Foundation/Foundation.h>
     6 #import <AVFoundation/AVFoundation.h>
     7 @interface YYAudioTool : NSObject
     8 /**
     9  *播放音乐文件
    10  */
    11 +(BOOL)playMusic:(NSString *)filename;
    12 /**
    13  *暂停播放
    14  */
    15 +(void)pauseMusic:(NSString *)filename;
    16 /**
    17  *播放音乐文件
    18  */
    19 +(void)stopMusic:(NSString *)filename;
    20 
    21 /**
    22  *播放音效文件
    23  */
    24 +(void)playSound:(NSString *)filename;
    25 /**
    26  *销毁音效
    27  */
    28 +(void)disposeSound:(NSString *)filename;
    29 @end

    YYAudioTool.m文件

      1 //
      2 //  YYAudioTool.m
      3 //
      4 
      5 #import "YYAudioTool.h"
      6 
      7 @implementation YYAudioTool
      8 /**
      9  *存放所有的音乐播放器
     10  */
     11 static NSMutableDictionary *_musicPlayers;
     12 +(NSMutableDictionary *)musicPlayers
     13 {
     14     if (_musicPlayers==nil) {
     15         _musicPlayers=[NSMutableDictionary dictionary];
     16     }
     17     return _musicPlayers;
     18 }
     19 
     20 /**
     21  *存放所有的音效ID
     22  */
     23 static NSMutableDictionary *_soundIDs;
     24 +(NSMutableDictionary *)soundIDs
     25 {
     26     if (_soundIDs==nil) {
     27         _soundIDs=[NSMutableDictionary dictionary];
     28     }
     29     return _soundIDs;
     30 }
     31 
     32 
     33 /**
     34  *播放音乐
     35  */
     36 +(BOOL)playMusic:(NSString *)filename
     37 {
     38     if (!filename) return NO;//如果没有传入文件名,那么直接返回
     39     //1.取出对应的播放器
     40     AVAudioPlayer *player=[self musicPlayers][filename];
     41     
     42     //2.如果播放器没有创建,那么就进行初始化
     43     if (!player) {
     44         //2.1音频文件的URL
     45         NSURL *url=[[NSBundle mainBundle]URLForResource:filename withExtension:nil];
     46         if (!url) return NO;//如果url为空,那么直接返回
     47         
     48         //2.2创建播放器
     49         player=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];
     50         
     51         //2.3缓冲
     52         if (![player prepareToPlay]) return NO;//如果缓冲失败,那么就直接返回
     53         
     54         //2.4存入字典
     55         [self musicPlayers][filename]=player;
     56     }
     57     
     58     //3.播放
     59     if (![player isPlaying]) {
     60         //如果当前没处于播放状态,那么就播放
     61         return [player play];
     62     }
     63 
     64     return YES;//正在播放,那么就返回YES
     65 }
     66 
     67 +(void)pauseMusic:(NSString *)filename
     68 {
     69     if (!filename) return;//如果没有传入文件名,那么就直接返回
     70     
     71     //1.取出对应的播放器
     72     AVAudioPlayer *player=[self musicPlayers][filename];
     73     
     74     //2.暂停
     75     [player pause];//如果palyer为空,那相当于[nil pause],因此这里可以不用做处理
     76 
     77 }
     78 
     79 +(void)stopMusic:(NSString *)filename
     80 {
     81     if (!filename) return;//如果没有传入文件名,那么就直接返回
     82     
     83     //1.取出对应的播放器
     84     AVAudioPlayer *player=[self musicPlayers][filename];
     85     
     86     //2.停止
     87     [player stop];
     88     
     89     //3.将播放器从字典中移除
     90     [[self musicPlayers] removeObjectForKey:filename];
     91 }
     92 
     93 //播放音效
     94 +(void)playSound:(NSString *)filename
     95 {
     96     if (!filename) return;
     97     //1.取出对应的音效
     98     SystemSoundID soundID=[[self soundIDs][filename] unsignedIntegerValue];
     99     
    100     //2.播放音效
    101     //2.1如果音效ID不存在,那么就创建
    102     if (!soundID) {
    103         
    104         //音效文件的URL
    105         NSURL *url=[[NSBundle mainBundle]URLForResource:filename withExtension:nil];
    106         if (!url) return;//如果URL不存在,那么就直接返回
    107         
    108         OSStatus status = AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url), &soundID);
    109         NSLog(@"%ld",status);
    110         //存入到字典中
    111         [self soundIDs][filename]=@(soundID);
    112     }
    113     
    114     //2.2有音效ID后,播放音效
    115     AudioServicesPlaySystemSound(soundID);
    116 }
    117 
    118 //销毁音效
    119 +(void)disposeSound:(NSString *)filename
    120 {
    121     //如果传入的文件名为空,那么就直接返回
    122     if (!filename) return;
    123     
    124     //1.取出对应的音效
    125     SystemSoundID soundID=[[self soundIDs][filename] unsignedIntegerValue];
    126     
    127     //2.销毁
    128     if (soundID) {
    129         AudioServicesDisposeSystemSoundID(soundID);
    130         
    131         //2.1销毁后,从字典中移除
    132         [[self soundIDs]removeObjectForKey:filename];
    133     }
    134 }
    135 @end

    四、在音乐播放控制器中的代码处理

    YYPlayingViewController.m文件

      1 //
      2 //  YYPlayingViewController.m
      3 //
      4 
      5 #import "YYPlayingViewController.h"
      6 #import "YYMusicTool.h"
      7 #import "YYMusicModel.h"
      8 #import "YYAudioTool.h"
      9 
     10 @interface YYPlayingViewController ()
     11 @property (weak, nonatomic) IBOutlet UIImageView *iconView;
     12 @property (weak, nonatomic) IBOutlet UILabel *songLabel;
     13 @property (weak, nonatomic) IBOutlet UILabel *singerLabel;
     14 @property (weak, nonatomic) IBOutlet UILabel *durationLabel;
     15 @property(nonatomic,strong)YYMusicModel *playingMusic;
     16 - (IBAction)exit;
     17 
     18 @end
     19 
     20 @implementation YYPlayingViewController
     21 #pragma mark-公共方法
     22 -(void)show
     23 {
     24     //1.禁用整个app的点击事件
     25     UIWindow *window=[UIApplication sharedApplication].keyWindow;
     26     window.userInteractionEnabled=NO;
     27     
     28     //2.添加播放界面
     29     //设置View的大小为覆盖整个窗口
     30     self.view.frame=window.bounds;
     31     //设置view显示
     32     self.view.hidden=NO;
     33     //把View添加到窗口上
     34     [window addSubview:self.view];
     35     
     36     //3.检测是否换了歌曲
     37     if (self.playingMusic!=[YYMusicTool playingMusic]) {
     38         [self RresetPlayingMusic];
     39     }
     40     
     41     //4.使用动画让View显示
     42     self.view.y=self.view.height;
     43     [UIView animateWithDuration:0.25 animations:^{
     44         self.view.y=0;
     45     } completion:^(BOOL finished) {
     46         
     47         //设置音乐数据
     48         [self starPlayingMusic];
     49         window.userInteractionEnabled=YES;
     50     }];
     51 }
     52 #pragma mark-私有方法
     53 //重置正在播放的音乐
     54 -(void)RresetPlayingMusic
     55 {
     56     //1.重置界面数据
     57     self.iconView.image=[UIImage imageNamed:@"play_cover_pic_bg"];
     58     self.songLabel.text=nil;
     59     self.singerLabel.text=nil;
     60     
     61     //2.停止播放
     62     [YYAudioTool stopMusic:self.playingMusic.filename];
     63 }
     64 //开始播放音乐数据
     65 -(void)starPlayingMusic
     66 {
     67     //1.设置界面数据
     68     
     69     //取出当前正在播放的音乐
     70 //    YYMusicModel *playingMusic=[YYMusicTool playingMusic];
     71     
     72     //如果当前播放的音乐就是传入的音乐,那么就直接返回
     73     if (self.playingMusic==[YYMusicTool playingMusic]) return;
     74     //存取音乐
     75     self.playingMusic=[YYMusicTool playingMusic];
     76     self.iconView.image=[UIImage imageNamed:self.playingMusic.icon];
     77     self.songLabel.text=self.playingMusic.name;
     78     self.singerLabel.text=self.playingMusic.singer;
     79     
     80     //2.开始播放
     81     [YYAudioTool playMusic:self.playingMusic.filename];
     82     
     83 }
     84 
     85 #pragma mark-内部的按钮监听方法
     86 //返回按钮
     87 - (IBAction)exit {
     88     //1.禁用整个app的点击事件
     89     UIWindow *window=[UIApplication sharedApplication].keyWindow;
     90     window.userInteractionEnabled=NO;
     91     
     92     //2.动画隐藏View
     93     [UIView animateWithDuration:0.25 animations:^{
     94         self.view.y=window.height;
     95     } completion:^(BOOL finished) {
     96         window.userInteractionEnabled=YES;
     97         //设置view隐藏能够节省一些性能
     98         self.view.hidden=YES;
     99     }];
    100 }
    101 @end

    注意:先让用户看到界面上的所有东西后,再开始播放歌曲。

    提示:一般的播放器需要做一个重置的操作。
      当从一首歌切换到另外一首时,应该先把上一首的信息删除,因此在show动画显示之前,应该检测是否换了歌曲,如果换了歌曲,则应该做一次重置操作。

     实现效果(能够顺利的切换和播放歌曲,下面是界面显示):

          

    五、补充代码

    YYMusicsViewController.m文件

     1 //
     2 //  YYMusicsViewController.m
     3 //
     4 
     5 #import "YYMusicsViewController.h"
     6 #import "YYMusicModel.h"
     7 #import "MJExtension.h"
     8 #import "YYMusicCell.h"
     9 #import "YYPlayingViewController.h"
    10 #import "YYMusicTool.h"
    11 
    12 @interface YYMusicsViewController ()
    13 
    14 @property(nonatomic,strong)YYPlayingViewController *playingViewController;
    15 @end
    16 
    17 @implementation YYMusicsViewController
    18 #pragma mark-懒加载
    19 
    20 -(YYPlayingViewController *)playingViewController
    21 {
    22     if (_playingViewController==nil) {
    23         _playingViewController=[[YYPlayingViewController alloc]init];
    24     }
    25     return _playingViewController;
    26 }
    27 
    28 - (void)viewDidLoad
    29 {
    30     [super viewDidLoad];
    31 }
    32 
    33 #pragma mark - Table view data source
    34 /**
    35  *一共多少组
    36  */
    37 -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    38 {
    39     return 1;
    40 }
    41 /**
    42  *每组多少行
    43  */
    44 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    45 {
    46     return [YYMusicTool musics].count;
    47 }
    48 /**
    49  *每组每行的cell
    50  */
    51 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    52 {
    53     YYMusicCell *cell=[YYMusicCell cellWithTableView:tableView];
    54     cell.music=[YYMusicTool musics][indexPath.row];
    55     return cell;
    56 }
    57 /**
    58  *  设置每个cell的高度
    59  */
    60 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    61 {
    62     return 70;
    63 }
    64 
    65 /**
    66  *  cell的点击事件
    67  */
    68 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    69 {
    70     //1.取消选中被点击的这行
    71     [tableView deselectRowAtIndexPath:indexPath animated:YES];
    72     
    73     //2.设置正在播放的歌曲
    74     [YYMusicTool setPlayingMusic:[YYMusicTool musics][indexPath.row]];
    75 
    76     //调用公共方法
    77     [self.playingViewController show];
    78     
    79 //    //执行segue跳转
    80 //    [self performSegueWithIdentifier:@"music2playing" sender:nil];
    81 }
    82 @end
  • 相关阅读:
    知识工程及语义网技术 2020-03-19 (第一节)-构建本体
    知识工程及语义网技术 2020-03-12 (第二节)-构建本体
    知识工程及语义网技术 2020-03-12 (第二节)、RDF(S)、OWL
    知识工程及语义网技术(一)-XML、RDF(S)、OWL-2020.3.5第一节
    知识工程及语义网技术(一)-知识工程,万维网、语义网、本体工程 2020-02-20 (第一节)
    本体
    语义网技术及其应用(四)-欧石燕
    一文深度揭秘3GPP:2G/3G/4G/Pre-5G标准化制定流程是这样的
    3GPP更新5G标准时间表
    一张图了解3GPP
  • 原文地址:https://www.cnblogs.com/zengshuilin/p/5770243.html
Copyright © 2011-2022 走看看