iOS 开发 中级:Audio之利用AVAudioPlayer实现SystemSoundService的功能

在以前的博文中,我们已经讲解了AVAudioPlayer和SystemSoundService的用法。这两种功能在一定程度上都适合作为游戏音效的播放方式。而两者也各有其优缺点。下面我们来总结一下有哪些:

1)AVAudioPlayer的优点

(1)可以播放任意长度音乐;

(2)可以循环播放;

(3)可以控制播放的时间;

(4)可以控制声道的音量实现立体声效果;

(5)可以调整音量。

2)AVAudioPlayer的缺点

(1)播放之前必须先加载,不能立即播放;

(2)一次一个AudioPlayer只能播放所加载的音乐,不能同时播放好几次同样的音乐。

(3)没有振动效果

3)SystemSoundService的优点:

(1)能够立即播放

(2)能够在同一时间播放多次音乐

(3)可以加上振动效果

4)SystemSoundService的缺点:

(1)不能循环播放

(2)不能控制播放时间

(3)不能控制声道

(4)不能控制音量

(5)不能暂停音乐


我们发现,这两种音乐播放方式的优缺点几乎是完全互补的。那么,有什么用呢?

关键:我们这里考虑的是游戏音效的播放!都是短时间的音频播放!

想象一下游戏,有时候我们要重复的播放一个音效,有时候我们想来一个振动,有时候我们需要在短时间内播放同一个音频多次!

因此,我们可以考虑综合两者的功能!

办法:

          利用AVAudioPlayer来实现SystemSoundService的效果!弥补AVAudioPlayer的缺点


我们先明确一下我们需要的功能:

(1)初始化后即可立即播放

(2)能在一个时间段内播放同一音频多次。这个再做个详细说明:我们使用AVAudioPlayer时,play后必须等其停止了才能重新播放。我们这里要改进的是即使前面的播放还没有结束,我们也可以启动新的播放,这个特别适用于播放敲击的声音,这样我们会感觉听到多个敲击的声音,而不是只有一个。记住这里不是讲和其他的AVAudioPlayer混音。

(3)能循环播放

(4)能暂停停止播放

(5)能播放震动和播放音频并震动

(6)能调节声道

(7)能调节音量


下面我们通过新建一个自定义的类来实现。

下面是头文件的代码:

#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

@interface SRAudioPlayer : NSObject
{
    AVAudioPlayer *_audioPlayer1;
    AVAudioPlayer *_audioPlayer2;
}

@property (nonatomic,assign) float pan;    // 调节声道平衡
@property (nonatomic,assign) float volume; // 调节音量

// 初始化
- (id)initWithContentsOfURL:(NSURL *)URL error:(NSError *__autoreleasing *)outError;

// 播放一次
- (void)playOnce;

// 循环播放
- (void)playInfinite;

// 播放并震动
- (void)playOnceWithVibrate;

- (void)pause;

- (void)stop;

// 振动
- (void)vibrate;


@end

我们在这里弄了两个AVAudioPlayer的实例,目的就是模拟 能在一个时间段内播放同一音频多次。


下面是m文件的代码:

#import "SRAudioPlayer.h"

@implementation SRAudioPlayer{
    BOOL _isPlayingAudioPlayer1;
}

- (id)initWithContentsOfURL:(NSURL *)URL error:(NSError *__autoreleasing *)outError
{
    if ((self = [super init])) {
        _audioPlayer1 = [[AVAudioPlayer alloc] initWithContentsOfURL:URL error:outError];
        _audioPlayer2 = [[AVAudioPlayer alloc] initWithContentsOfURL:URL error:outError];
        
        [_audioPlayer1 prepareToPlay];
        [_audioPlayer2 prepareToPlay];
    }
    return self;
}

- (void)setPan:(float)pan
{
    if (_pan != pan) {
        _pan = pan;
        _audioPlayer1.pan = pan;
        _audioPlayer2.pan = pan;
    }

}

- (void)setVolume:(float)volume
{
    if (_volume != volume) {
        _volume = volume;
        _audioPlayer1.volume = volume;
        _audioPlayer2.volume = volume;
    }
}

- (void)playOnce
{
    _audioPlayer1.numberOfLoops = 1;
    if (!_isPlayingAudioPlayer1) {
        if (!_audioPlayer1.isPlaying) [_audioPlayer1 play];
        else _audioPlayer1.currentTime = 0.0f;
        _isPlayingAudioPlayer1 = YES;
    } else {
        if (!_audioPlayer2.isPlaying)[_audioPlayer2 play];
        else _audioPlayer2.currentTime = 0.0f;
        _isPlayingAudioPlayer1 = NO;
    }
}

- (void)playInfinite
{
    [_audioPlayer2 pause];
    _audioPlayer1.currentTime = 0.0f;
    _audioPlayer1.numberOfLoops = -1;  
}

- (void)playOnceWithVibrate  //1
{
    _audioPlayer1.numberOfLoops = 1;
    if (!_isPlayingAudioPlayer1) {
        if (!_audioPlayer1.isPlaying) [_audioPlayer1 play];
        else _audioPlayer1.currentTime = 0.0f;
        _isPlayingAudioPlayer1 = YES;
    } else {
        if (!_audioPlayer2.isPlaying)[_audioPlayer2 play];
        else _audioPlayer2.currentTime = 0.0f;
        _isPlayingAudioPlayer1 = NO;
    }
    [self vibrate];
}

- (void)pause
{
    [_audioPlayer1 pause];
    [_audioPlayer2 pause];
}

- (void)stop
{
    [_audioPlayer1 stop];
    [_audioPlayer2 stop];
}

- (void)vibrate
{
    AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
}


@end

这里主要是说一下功能实现的trick:

我们通过两个播放器。这里时候,如果我们使用了playOnce 方法,那么我们就判断当前是哪个播放器在播放,如果是播放器1,那么我们就用播放器2来播放。另一方面,如果两个播放器同时都在播放,我们就将播放时间拉到头,这样就和重新播放一样。通过这样的方式,我们在播放音效时就会感觉是多个音频。当然,如果要仿得更好的话,就是多弄几个AVAudioPlayer,不过这样会消耗更多的资源。


好了,就说到这吧!如果有不清楚或者发现程序有bug的可以发评论哈!


[本文为原创文章,如需转发,请注明出处:来自songrotek的博客!谢谢合作]

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值