AVAudioPlayerでfadein/fadeout(フェードイン・フェードアウト)を実装したライブラリ

AVAudioPlayerを使ったライブラリを作りました。AVAudioPlayerの実例が少なかったからしっかりとまとめた。AudioQueueとかAudioUnitじゃないとできないんじゃないの？ということがAVAudioPlayerでできます。

AudioPlayerDelegateをdelegateして使いたいクラスに取り込んであげてください。

```objc
/* AudioPlayer.h */
#import <Foundation/Foundation.h>
#include <AVFoundation/AVFoundation.h>

@protocol AudioPlayerDelegate
-(void) audioSequence:(double)currentTime;
-(void) audioFadein:(double)volume;
-(void) audioFadeout:(double)volume;
@optional
@end
@interface AudioPlayer : NSObject 
<AVAudioPlayerDelegate>
{
    NSTimer * timer;
    NSTimer * timerFade;
    AVAudioPlayer * audio;
    float power, currentVolume;
    double duration;
    BOOL fading, pausing;
    id<AudioPlayerDelegate> delegate;
}

@property (nonatomic, assign) id<AudioPlayerDelegate> delegate;
@property (nonatomic, retain) AVAudioPlayer * audio;
@property double duration;
@property float power;
@property float currentVolume;

-(id) initWithFilename:(NSString *)filename ofType:(NSString *)ofType delegate:(id)targetDelegate;
-(void)audioStart:(BOOL)fade currentTime:(double)currentTime volume:(float)volume;
-(void)audioStop:(BOOL)fade;
-(void)audioPause;
-(void)audioPlayThreaded:(id)threadAudio;
-(void)setVolume:(double)volume;
@end
```

```objc
/* AudioPlayer.m */
#import "AudioPlayer.h"

@implementation AudioPlayer
@synthesize delegate, duration, power, currentVolume, audio;

#define FEDE_SEED 0.01f
#define VOLUME_SEED 0.005f
#define SEQUENCE_INTERVAL 0.5f
#define AVEPW4CH 0

-(id) initWithFilename:(NSString *)filename ofType:(NSString *)ofType delegate:(id)targetDelegate{
    NSString * path = [[NSBundle mainBundle] pathForResource:filename ofType:ofType];
    NSURL * url = [NSURL fileURLWithPath:path];
    audio = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
    [audio setMeteringEnabled:YES];
    audio.delegate = targetDelegate;
    self.delegate = targetDelegate;
    duration = audio.duration;
    fading = NO;
    currentVolume = 0.5f;
    return self;
}
- (void)audioSequence{
    if(audio == nil) return;
    if(audio.playing){
        [audio updateMeters];
        power = [audio averagePowerForChannel:AVEPW4CH]; // averagePowerForChannel OR peakPowerForChannel
        [self.delegate audioSequence:audio.currentTime];
	}
}
-(void)audioStart:(BOOL)fade currentTime:(double)currentTime volume:(float)volume{
    if(audio.playing) return;
    currentVolume = volume;
    if(fade){
        if(fading == NO){
            [audio setVolume:0.0f];
            timerFade = [NSTimer scheduledTimerWithTimeInterval:FEDE_SEED target:self selector:@selector(audioFadein) userInfo:nil repeats:YES];        
        }
    }
    audio.currentTime = currentTime;
    [NSThread detachNewThreadSelector:@selector(audioPlayThreaded:) toTarget:self withObject:audio];
    timer = [NSTimer scheduledTimerWithTimeInterval:SEQUENCE_INTERVAL target:self selector:@selector(audioSequence) userInfo:nil repeats:YES];
}
-(void)audioStop:(BOOL)fade{
    if(audio == nil) return;
    
    if(fade){
        if(fading == NO) timerFade = [NSTimer scheduledTimerWithTimeInterval:FEDE_SEED target:self selector:@selector(audioFadeout) userInfo:nil repeats:YES];
    } else {
        if(audio.playing){
            [audio prepareToPlay];
            [audio stop];
            [audio setCurrentTime:0.0f];
        }
    }
    
}
-(void)audioPause{
    if(audio == nil) return;
    if(audio.playing){
        [audio pause];
    }    
}
-(void)audioFadein{
    
    if(audio.playing){
        if((audio.volume+VOLUME_SEED) < currentVolume){
            fading = YES;
            [self.delegate audioFadein:audio.volume];
            [audio setVolume:audio.volume+VOLUME_SEED];
        } else {
            fading = NO;
            if([timerFade isValid]) [timerFade invalidate];
        }
    }
    
}
-(void)audioFadeout{
    
    if(audio.volume <= 0.0f){
        fading = NO;
        if([timerFade isValid]) [timerFade invalidate];
        [self audioStop:NO];
    } else {
        fading = YES;
        [self.delegate audioFadeout:audio.volume];
        [audio setVolume:audio.volume-VOLUME_SEED];
    }
    
}
-(void)audioPlayThreaded:(id)threadAudio{
    if(threadAudio == nil) return;
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    [(AVAudioPlayer *)threadAudio prepareToPlay];
    [(AVAudioPlayer *)threadAudio play];
    [pool release];
}
-(void)setVolume:(double)volume{
    [audio setVolume:volume];
}
@end
```

使い方は簡単。

```objc
-(void) main{
    ap = [[AudioPlayer alloc]initWithFilename:@"filename" ofType:@"mp3" delegate:self];
    [ap audioStart:YES currentTime:0.0f volume:0.5f]; // フェードで始まる。
    [ap audioStop:YES]; // フェードで終わる
}
-(void)audioSequence:(double)currentTime{
    // 再生中の処理
    NSLog(@"%f", currentTime); // 現在時間
    NSLog(@"%f", ap.power); // デシベル数 averagePowerForChannelで設定してある
}
// フェードイン中
-(void)audioFadein:(double)volume{
    NSLog(@"fadein = %f", volume);
}
// フェードアウト中
-(void)audioFadeout:(double)volume{
    NSLog(@"fadeout = %f", volume);
}
```