LoginSignup
11
10

More than 5 years have passed since last update.

AVAudioPlayerで曲をストップする際にFadeOutさせる(飛ぶ鳥後を濁さず)

Last updated at Posted at 2014-07-10

ゲームにBGMは欠かせない。

ゲームBGMで「懐かしの名曲集」がYoutubeで人気なのもうなずける。
しかしせっかくの名曲もボタンをタップした瞬間に「ぶっ」と切れてしまっては情緒もへちまもない。

偉大な音楽に敬意を払い、FadeOutでかっこよく曲を停止させる方法をシェアする。

まず曲を鳴らす際にはAVAudioPlayerを使うが、viewDidLoad内でPathを取得したり
ごちゃごちゃするのは美しくない。

[SEEventhandler sharedManaber] bgmSoundPlay: @"opening.mp3"];
って感じで1行でばちっと呼び出したいので、

ゲーム内で使うイベント(音を鳴らしたり、他にもゲーム内でのイベントを発生させる)を
まとめて扱うシングルトンを作成する。

※AVAudioPlayerの使用方法は「yuky_az」さんの下記のストックを参考にさせて頂きました。
この場を借りて、お礼を申し上げます。
http://qiita.com/yuky_az/items/085e30c159cafa8dac1c

ソースコード実例

SEEventHandlerManager.h
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>

@interface SEEventHandlerManager : NSObject
//***** Class Method *****
+(SEEventHandlerManager *)sharedManager;
//***** Instance Method *****
-(void)bgmSoundPlay: (NSString *)fileName;
-(void)bgmStopWithFadeOut;

@end
SEEventHandlerManager.m
#import "SEEventHandlerManager.h"

@interface SEEventHandlerManager ()

@property(nonatomic) NSMutableArray* soundArray;
@property(nonatomic) float soundVolume;

@end

@implementation SEEventHandlerManager

//--------------------------------------------------------------//
#pragma mark -- Initialize --
//--------------------------------------------------------------//
static SEEventHandlerManager *sharedInstance = nil;

+(SEEventHandlerManager *)sharedManager
{
  if (!sharedInstance) {
    sharedInstance = [[SEEventHandlerManager alloc] init];
  }
  return sharedInstance;
}

- (id) init
{
  self = [super init];
  if (self) {
    _soundArray = [[NSMutableArray alloc] init];
    _soundVolume = 1.0;
  }

  return self;
}

-(void)bgmSoundPlay: (NSString *)fileName
{
  NSString *soundPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:fileName];
  NSURL* soundUrl = [NSURL fileURLWithPath:soundPath];
  AVAudioPlayer* audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl error:nil];
  audioPlayer.numberOfLoops = -1;
  audioPlayer.volume = _soundVolume;
  audioPlayer.delegate = (id)self;
  [_soundArray insertObject:audioPlayer atIndex:0];
  [audioPlayer prepareToPlay];
  [audioPlayer play];
}

-(void)bgmStopWithFadeOut
{
  AVAudioPlayer* currentPlayer = [_soundArray objectAtIndex:0];
  if (currentPlayer.volume > 0.1) {
    currentPlayer.volume = currentPlayer.volume - 0.1;
    [self performSelector:@selector(bgmStopWithFadeOut) withObject:nil afterDelay:0.1];
  }else{
    [currentPlayer stop];
    [_soundArray removeAllObjects];
  }

}

@end

bgmStopWithFadeOutがFadeOut処理になっている。
別に難しいことはなく、メソッドをVolumeが0になるまで呼び出しつづけ、0になったらオブジェクトを破棄する。
配列に格納したのは後に音を複数鳴らす際に、必要になるかもしれないと考えてのこと。

シングルトンのおかげでこれがうれしい

また、シングルトンによって下記の利点を得る。
■利点:画面遷移に関係なく、好きなタイミングで音を再生(停止)できる。

シミュレータでは動かないよ・・・

また、上記のソースコードは下記のシミュレータ上では動作しなかった。
OS X 10.9.2
XCode 5.1.1
iOSシミュレータ 7.1(iPhone Retina 4-inch 64bit)

「Cannot find executable for CFBundle CertUIFramework.axbundle」なる
エラーが発生していた。
参考URL:http://stackoverflow.com/questions/18888059/cannot-find-executable-for-cfbundle-certuiframework-axbundle

これはXCodeのバグのようで、実機でシミュレータを動作させた場合には正常に音楽が再生されたので、テストする際にはご注意を。

では!HappyBoyがお送りしました!

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10