iPhone アプリケーション
-
はてな touch/Hatena touch
-
LDR touch
-
テレビ番組表/TV Listings
-
LCD Clock by forYou Inc.
-
MyWebClip by forYou Inc.
-
MyWebClip LITE by forYou Inc.
-
Japan Subway Route Map by Studio Heat
-
こころくろっく by AppBank
-
英辞郎 on the WEB for iPhone by アルク
-
i-Radio by i-Radio
-
くるりんぱ性格診断 by 小学館
-
英辞郎検索ランキング(アルク) by アルク
-
kotobank - コトバンク by genesix
-
miil by frogapps
iPad アプリケーション
共著
2008-10-30
iPhoneで繰り返しループするサウンドを鳴らすコードのメモ (Audio Queueのサンプル)
使い方
GBMusicTrack *song = [[GBMusicTrack alloc] initWithPath:[[NSBundle mainBundle] pathForResource:@"BackgroundMusic" ofType:@"mp3"]]; [song setRepeat:YES]; [song play];
GBMusicTrack.h
// // GBMusicTrack.h // GameBase // // Created by Jake Peterson (AnotherJake) on 7/6/08. // Copyright 2008 Jake Peterson. All rights reserved. // #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; // close is called automatically in GBMusicTrack's dealloc method, but it is recommended // to call close first, so that the associated Audio Queue is released immediately, instead // of having to wait for a possible autorelease, which may cause some conflict - (void)close; extern NSString *GBMusicTrackFinishedPlayingNotification; @end
GBMusicTrack.m
// // GBMusicTrack.m // GameBase // // Created by Jake Peterson (AnotherJake) on 7/6/08. // Copyright 2008 Jake Peterson. All rights reserved. // #import "GBMusicTrack.h" static UInt32 gBufferSizeBytes = 0x10000; // 64k 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 { // it is preferrable to call close first, before dealloc if there is a problem waiting for // an autorelease 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; // try to open up the file using the specified path 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; } // get the data format of the file size = sizeof(dataFormat); AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat, &size, &dataFormat); // create a new playback queue using the specified data format and buffer callback AudioQueueNewOutput(&dataFormat, BufferCallback, self, nil, nil, 0, &queue); // calculate number of packets to read and allocate space for packet descriptions if needed if (dataFormat.mBytesPerPacket == 0 || dataFormat.mFramesPerPacket == 0) { // since we didn't get sizes to work with, then this must be VBR data (Variable BitRate), so // we'll have to ask Core Audio to give us a conservative estimate of the largest packet we are // likely to read with kAudioFilePropertyPacketSizeUpperBound size = sizeof(maxPacketSize); AudioFileGetProperty(audioFile, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize); if (maxPacketSize > gBufferSizeBytes) { // hmm... well, we don't want to go over our buffer size, so we'll have to limit it I guess maxPacketSize = gBufferSizeBytes; NSLog(@"GBMusicTrack Warning - initWithPath: had to limit packet size requested for file path: %@", path); } numPacketsToRead = gBufferSizeBytes / maxPacketSize; // will need a packet description for each packet since this is VBR data, so allocate space accordingly packetDescs = malloc(sizeof(AudioStreamPacketDescription) * numPacketsToRead); } else { // for CBR data (Constant BitRate), we can simply fill each buffer with as many packets as will fit numPacketsToRead = gBufferSizeBytes / dataFormat.mBytesPerPacket; // don't need packet descriptsions for CBR data packetDescs = nil; } // see if file uses a magic cookie (a magic cookie is meta data which some formats use) AudioFileGetPropertyInfo(audioFile, kAudioFilePropertyMagicCookieData, &size, nil); if (size > 0) { // copy the cookie data from the file into the audio queue cookie = malloc(sizeof(char) * size); AudioFileGetProperty(audioFile, kAudioFilePropertyMagicCookieData, &size, cookie); AudioQueueSetProperty(queue, kAudioQueueProperty_MagicCookie, cookie, size); free(cookie); } // allocate and prime buffers with some data packetIndex = 0; for (i = 0; i < NUM_QUEUE_BUFFERS; i++) { AudioQueueAllocateBuffer(queue, gBufferSizeBytes, &buffers[i]); if ([self readPacketsIntoBuffer:buffers[i]] == 0) { // this might happen if the file was so short that it needed less buffers than we planned on using 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) { // redirect back to the class to handle it there instead, so we have direct access to the instance variables [(GBMusicTrack *)inUserData callbackForBuffer:buffer]; } - (void)callbackForBuffer:(AudioQueueBufferRef)buffer { if ([self readPacketsIntoBuffer:buffer] == 0) { // End Of File reached, so rewind and refill the buffer using the beginning of the file instead packetIndex = 0; [self readPacketsIntoBuffer:buffer]; // if not repeating then we'll pause it so it's ready to play again immediately if needed if (!repeat) { AudioQueuePause(queue); // we're not in the main thread during this callback, so enqueue a message on the main thread to post notification // that we're done, or else the notification will have to be handled in this thread, making things more difficult [self performSelectorOnMainThread:@selector(postTrackFinishedPlayingNotification:) withObject:nil waitUntilDone:NO]; } } } - (void)postTrackFinishedPlayingNotification:(id)object { // if we're here then we're in the main thread as specified by the callback, so now we can post notification that // the track is done without the notification observer(s) having to worry about thread safety and autorelease pools [[NSNotificationCenter defaultCenter] postNotificationName:GBMusicTrackFinishedPlayingNotification object:self]; } - (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer { UInt32 numBytes, numPackets; // read packets into buffer from file numPackets = numPacketsToRead; AudioFileReadPackets(audioFile, NO, &numBytes, packetDescs, packetIndex, &numPackets, buffer->mAudioData); if (numPackets > 0) { // - End Of File has not been reached yet since we read some packets, so enqueue the buffer we just read into // the audio queue, to be played next // - (packetDescs ? numPackets : 0) means that if there are packet descriptions (which are used only for Variable // BitRate data (VBR)) we'll have to send one for each packet, otherwise zero buffer->mAudioDataByteSize = numBytes; AudioQueueEnqueueBuffer(queue, buffer, (packetDescs ? numPackets : 0), packetDescs); // move ahead to be ready for next time we need to read from the file packetIndex += numPackets; } return numPackets; } @end
トラックバック - http://d.hatena.ne.jp/KishikawaKatsumi/20081030/1225390899
リンク元
- 32 http://www.apple-style.com/plus/index.html
- 25 http://reader.livedoor.com/reader/
- 9 http://a.hatena.ne.jp/moto_maka/simple
- 9 http://d.hatena.ne.jp/moto_maka/20081025/1224879174
- 7 http://b.hatena.ne.jp/t/iPhone
- 6 http://d.hatena.ne.jp/
- 5 http://moto-maka.net/touch/iphonetenna/iphonetenna.php
- 5 http://www.google.co.jp/reader/view/
- 4 http://b.hatena.ne.jp/add?mode=confirm&title=iPhone%u3092%u632F%u308B%u52D5%u4F5C%u3092%u691C%u51FA%u3059%u308B%u30B3%u30FC%u30C9%u306E%u30E1%u30E2 - 24/7 twenty-four seven&url=http://d.hatena.ne.jp/KishikawaKatsumi/20081030/1225389349
- 4 http://b.hatena.ne.jp/hotentry/diary





















