2011-06-29 AVAudioPlayerを使った音楽ファイルの再生
AVAudioPlayerを使った音楽ファイルの再生
AVAudioPlayerを使って音楽を再生する方法です。再生時間をNSTimerを使って表示しています。NSRunLoopでも表示は可能かと思いますがNSTimerのほうがはるかに楽です。
.hファイル
#include <AVFoundation/AVFoundation.h>
@interface audioplayer : NSObject
<AVAudioPlayerDelegate>
{
NSTimer * timer;
AVAudioPlayer * audio;
}
@end
.mファイル
// 音楽再生を開始
@implementation audioplayer
- (void)main
{
[super viewDidLoad];
NSString * path = [[NSBundle mainBundle] pathForResource:@"soundfile" ofType:@"mp3"];
NSURL * url = [NSURL fileURLWithPath:path];
// errorを取得したいときはscheduledTimerWithTimeIntervalのerrorにNSError errorポインタ(&error)を投げます
audio = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
audio.delegate = self;
[audio play];
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(playSequence) userInfo:nil repeats:YES];
}
// 再生時間を表示
- (void) playSequence{
if(audio.playing){
NSLog(@"%@", [NSString stringWithFormat:@"%f", audio.currentTime]);
} else {
[timer invalidate];
}
}
@end
ちなみにNSRunLoopを使うと下記のような記述になります。NSTimerのほうがいいですね。
NSDate *now = [[NSDate alloc]init];
NSTimer *timer = [[NSTimer alloc]initWithFireDate:now interval:0.1 target:self selector:@selector(playing) userInfo:nil repeats:YES];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSDefaultRunLoopMode];
[runLoop run];
AVAudioPlayerでfadein/fadeout(フェードイン・フェードアウト)を実装したライブラリ
AVAudioPlayerを使ったライブラリを作りました。AVAudioPlayerの実例が少なかったからしっかりとまとめた。AudioQueueとかAudioUnitじゃないとできないんじゃないの?ということがAVAudioPlayerでできます。
AudioPlayerDelegateをdelegateして使いたいクラスに取り込んであげてください。
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
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
使い方は簡単。
-(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);
}
