iDevGames Forums
使い方
GBMusicTrack *song = [[GBMusicTrack alloc] initWithPath:[[NSBundle mainBundle] pathForResource:@"BackgroundMusic" ofType:@"mp3"]];
[song setRepeat:YES];
[song play];
GBMusicTrack.h
#import <Cocoa/Cocoa.h>
#import <AudioToolbox/AudioQueue.h>
#import <AudioToolbox/AudioFile.h>
#define NUM_QUEUE_BUFFERS 3
@interface GBMusicTrack : NSObject
{
AudioFileID audioFile;
AudioStreamBasicDescription dataFormat;
AudioQueueRef queue;
UInt64 packetIndex;
UInt32 numPacketsToRead;
AudioStreamPacketDescription *packetDescs;
BOOL repeat;
BOOL trackClosed;
AudioQueueBufferRef buffers[NUM_QUEUE_BUFFERS];
}
- (id)initWithPath:(NSString *)path;
- (void)setGain:(Float32)gain;
- (void)setRepeat:(BOOL)yn;
- (void)play;
- (void)pause;
- (void)close;
extern NSString *GBMusicTrackFinishedPlayingNotification;
@end
GBMusicTrack.m
#import "GBMusicTrack.h"
static UInt32 gBufferSizeBytes = 0x10000;
NSString *GBMusicTrackFinishedPlayingNotification = @"GBMusicTrackFinishedPlayingNotification";
@interface GBMusicTrack (InternalMethods)
static void BufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef buffer);
- (void)callbackForBuffer:(AudioQueueBufferRef)buffer;
- (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer;
@end
@implementation GBMusicTrack
#pragma mark -
#pragma mark GBMusicTrack
- (void)dealloc
{
[self close];
[super dealloc];
}
- (void)close
{
if (trackClosed)
return;
trackClosed = YES;
AudioQueueStop(queue, YES);
AudioQueueDispose(queue, YES);
AudioFileClose(audioFile);
}
- (id)initWithPath:(NSString *)path
{
UInt32 size, maxPacketSize;
char *cookie;
int i;
if(!(self = [super init])) return nil;
if (path == nil) return nil;
if (noErr != AudioFileOpenURL((CFURLRef)[NSURL fileURLWithPath:path], 0x01, kAudioFileCAFType, &audioFile))
{
NSLog(@"GBMusicTrack Error - initWithPath: could not open audio file. Path given was: %@", path);
return nil;
}
size = sizeof(dataFormat);
AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat, &size, &dataFormat);
AudioQueueNewOutput(&dataFormat, BufferCallback, self, nil, nil, 0, &queue);
if (dataFormat.mBytesPerPacket == 0 || dataFormat.mFramesPerPacket == 0)
{
size = sizeof(maxPacketSize);
AudioFileGetProperty(audioFile, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize);
if (maxPacketSize > gBufferSizeBytes)
{
maxPacketSize = gBufferSizeBytes;
NSLog(@"GBMusicTrack Warning - initWithPath: had to limit packet size requested for file path: %@", path);
}
numPacketsToRead = gBufferSizeBytes / maxPacketSize;
packetDescs = malloc(sizeof(AudioStreamPacketDescription) * numPacketsToRead);
}
else
{
numPacketsToRead = gBufferSizeBytes / dataFormat.mBytesPerPacket;
packetDescs = nil;
}
AudioFileGetPropertyInfo(audioFile, kAudioFilePropertyMagicCookieData, &size, nil);
if (size > 0)
{
cookie = malloc(sizeof(char) * size);
AudioFileGetProperty(audioFile, kAudioFilePropertyMagicCookieData, &size, cookie);
AudioQueueSetProperty(queue, kAudioQueueProperty_MagicCookie, cookie, size);
free(cookie);
}
packetIndex = 0;
for (i = 0; i < NUM_QUEUE_BUFFERS; i++)
{
AudioQueueAllocateBuffer(queue, gBufferSizeBytes, &buffers[i]);
if ([self readPacketsIntoBuffer:buffers[i]] == 0)
{
break;
}
}
repeat = NO;
trackClosed = NO;
return self;
}
- (void)setGain:(Float32)gain
{
AudioQueueSetParameter(queue, kAudioQueueParam_Volume, gain);
}
- (void)setRepeat:(BOOL)yn
{
repeat = yn;
}
- (void)play
{
AudioQueueStart(queue, nil);
}
- (void)pause
{
AudioQueuePause(queue);
}
#pragma mark -
#pragma mark Callback
static void BufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef buffer)
{
[(GBMusicTrack *)inUserData callbackForBuffer:buffer];
}
- (void)callbackForBuffer:(AudioQueueBufferRef)buffer
{
if ([self readPacketsIntoBuffer:buffer] == 0)
{
packetIndex = 0;
[self readPacketsIntoBuffer:buffer];
if (!repeat)
{
AudioQueuePause(queue);
[self performSelectorOnMainThread:@selector(postTrackFinishedPlayingNotification:) withObject:nil waitUntilDone:NO];
}
}
}
- (void)postTrackFinishedPlayingNotification:(id)object
{
[[NSNotificationCenter defaultCenter] postNotificationName:GBMusicTrackFinishedPlayingNotification object:self];
}
- (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer
{
UInt32 numBytes, numPackets;
numPackets = numPacketsToRead;
AudioFileReadPackets(audioFile, NO, &numBytes, packetDescs, packetIndex, &numPackets, buffer->mAudioData);
if (numPackets > 0)
{
buffer->mAudioDataByteSize = numBytes;
AudioQueueEnqueueBuffer(queue, buffer, (packetDescs ? numPackets : 0), packetDescs);
packetIndex += numPackets;
}
return numPackets;
}
@end