iDevGames Forums
Audio Queues - Printable Version

+- iDevGames Forums (http://www.idevgames.com/forums)
+-- Forum: Development Zone (/forum-3.html)
+--- Forum: Graphics & Audio Programming (/forum-9.html)
+--- Thread: Audio Queues (/thread-2538.html)

Pages: 1 2 3 4 5 6 7 8 9 10


Audio Queues - Xavier - Jul 7, 2008 07:42 AM

Edited by sealfin:

Thread split as requested: New to iPhone: I have some questions.

(Sorry for editing your post Xavier, but I can't delete it without deleting the thread...)


Audio Queues - Talyn - Jul 10, 2008 04:34 PM

AnotherJake Wrote:Can't help you on iPhone audio because of NDA, sorry. Maybe tomorrow. Post a thread on it when we get out of NDA.

In the meantime, on the Mac, I would suggest using OpenAL for short sounds like explosions and laser/gunfire, etc. For background music you can use Audio Queues on Mac OS X 10.5 or greater.

If you are talking about trying to understand using Audio Queues on Mac OS X 10.5 (I am NOT talking about iPhone, because it cannot be discussed as to whether or not it even has Audio Queues) then yes, it is convoluted and difficult to approach -- *especially* the example code.

Alright...I'll bite...

How would you do it on MAC using Audio Queues?


Audio Queues - AnotherJake - Jul 10, 2008 04:57 PM

UPDATE 1/16/09: I recommend using AVAudioPlayer for this as of iPhone OS 2.2

Talyn Wrote:Alright...I'll bite...

How would you do it on MAC using Audio Queues?

Heck, well for Mac, all you had to do was ask! Smile

[Update 12/4/08] Yes, okay, the cat is out of the bag: GBMusicTrack works for iPhone now too Wink

NOTE FOR iPHONE: see this other thread for issues playing with the "silent switch" and conflicts with iPod app:

http://www.idevgames.com/forum/showthread.php?t=16048

*** NOTE *** For iPhone, use this for background music only, and only one track at a time. The iPhone hardware doesn't work with multiple compressed tracks pumping through its dedicated audio decompression hardware.

If you are looping it, it is better to set the track to repeat rather than releasing it and reallocating it again.

You'd use it by alloc-initing a new track every time you want to play a new one, and you release it as soon as it's done playing, and subsequently alloc-init a new one to play (if you are going to play a different track, otherwise set it to repeat). Even if you plan on playing the same track again later, you need to release it first if you want to play a different one in the meantime. It is designed this way to conserve resources. So for now, maybe you can figure out how to get stuff rolling with Audio Queues using this.

You'd use it like this:

Code:
GBMusicTrack *song = [[GBMusicTrack alloc] initWithPath:[[NSBundle mainBundle] pathForResource:@"BackgroundMusic" ofType:@"mp3"]];
[song setRepeat:YES];
[song play];

GBMusicTrack.h
Code:
//
//  GBMusicTrack.h
//  GameBase
//
//  Created by Jake Peterson (AnotherJake) on 7/6/08.
//  Copyright 2008 Jake Peterson. All rights reserved.
//

#import <AppKit/AppKit.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;
    BOOL                            trackEnded;
    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
Code:
//
//  GBMusicTrack.m
//  GameBase
//
//  Created by Jake Peterson (AnotherJake) on 7/6/08.
//  Copyright 2008 Jake Peterson. All rights reserved.
//

// last modified 12/4/08

#import "GBMusicTrack.h"

static UInt32    gBufferSizeBytes = 0x10000; // 64k

// *** NOTE *** GBMusicTrack is only designed to play one track at a time, as background music, so gThereIsAnActiveTrack
// is used to prevent multiple tracks from playing. Use something else like OpenAL to play sounds like lasers and explosions
static BOOL        gThereIsAnActiveTrack = NO;

NSString *GBMusicTrackFinishedPlayingNotification = @"GBMusicTrackFinishedPlayingNotification";

@interface GBMusicTrack (InternalMethods)

static void propertyListenerCallback(void *inUserData, AudioQueueRef queueObject, AudioQueuePropertyID    propertyID);
- (void)playBackIsRunningStateChanged;

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];
    if (packetDescs != nil)
        free(packetDescs);
    [super dealloc];
}

- (void)close
{
    // it is preferrable to call close first, if there is a problem waiting for an autorelease
    if (trackClosed)
        return;
    trackClosed = YES;
    AudioQueueStop(queue, YES); // <-- YES means stop immediately
    AudioQueueDispose(queue, YES);
    AudioFileClose(audioFile);
    gThereIsAnActiveTrack = NO;
}

- (id)initWithPath:(NSString *)path
{
    UInt32        size, maxPacketSize;
    char        *cookie;
    int            i;
    
    if (gThereIsAnActiveTrack)
    {
        NSLog(@"*** WARNING *** GBMusicTrack only plays one track at a time! You must close the previously running track"
                " before you can play another. Requested track was: %@", [path lastPathComponent]);
        return nil;
    }
    
    if (path == nil) return nil;
    if(!(self = [super init])) return nil;
    
    // try to open up the file using the specified path
    if (noErr != AudioFileOpenURL((CFURLRef)[NSURL fileURLWithPath:path], 0x01, 0, &audioFile))
    {
        NSLog(@"*** Error *** GBMusicTrack - 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(@"*** Warning *** GBMusicTrack - initWithPath: had to limit packet size requested for file: %@", [path lastPathComponent]);
        }
        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 descriptions 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);
    }
    
    // we want to know when the playing state changes so we can properly dispose of the audio queue when it's done
    AudioQueueAddPropertyListener(queue, kAudioQueueProperty_IsRunning, propertyListenerCallback, self);
    
    // 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;
    trackEnded = NO;
    gThereIsAnActiveTrack = YES;
    return self;
}

- (void)setGain:(Float32)gain
{
    if (trackClosed)
        return;
    AudioQueueSetParameter(queue, kAudioQueueParam_Volume, gain);
}

- (void)setRepeat:(BOOL)yn
{
    repeat = yn;
}

- (void)play
{
    if (trackClosed)
        return;
    
    OSStatus result = AudioQueuePrime(queue, 1, nil);    
    if (result)
    {
        NSLog(@"*** Error *** GBMusicTrack - play: error priming AudioQueue");
        return;
    }
    AudioQueueStart(queue, nil);
}

- (void)pause
{
    if (trackClosed)
        return;
    AudioQueuePause(queue);
}

#pragma mark -
#pragma mark Callback

static void propertyListenerCallback(void *inUserData, AudioQueueRef queueObject, AudioQueuePropertyID    propertyID)
{
    // redirect back to the class to handle it there instead, so we have direct access to the instance variables
    if (propertyID == kAudioQueueProperty_IsRunning)
        [(GBMusicTrack *)inUserData playBackIsRunningStateChanged];
}

- (void)playBackIsRunningStateChanged
{
    if (trackEnded)
    {
        // go ahead and close the track now
        trackClosed = YES;
        AudioQueueDispose(queue, YES);
        AudioFileClose(audioFile);
        gThereIsAnActiveTrack = NO;
        
        // 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];
    }
}

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
{
    // I guess it's possible for the callback to continue to be called since this is in another thread, so to be safe,
    // don't do anything else if the track is closed, and also don't bother reading anymore packets if the track ended
    if (trackClosed || trackEnded)
        return;
        
    if ([self readPacketsIntoBuffer:buffer] == 0)
    {
        if (repeat)
        {
            // End Of File reached, so rewind and refill the buffer using the beginning of the file instead
            packetIndex = 0;
            [self readPacketsIntoBuffer:buffer];
        }
        else
        {
            // set it to stop, but let it play to the end, where the property listener will pick up that it actually finished
            AudioQueueStop(queue, NO);
            trackEnded = YES;
        }
    }
}

- (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



Audio Queues - Talyn - Jul 10, 2008 05:58 PM

AnotherJake Wrote:This should be split into a different thread by a moderator when they get a chance.



Heck, well for Mac, all you had to do was ask! Smile

Here is what I've been doing so far. This isn't well tested and I can't guarantee any accuracy or that there isn't a memory leak or some other dreadful bug, but I commented the bejeezus out of it -- against my desire not to comment anything. I am tentatively planning on adding it to the GameBase framework project, but I haven't tested it enough to be satisfied with it. Plus, I am in the middle of writing a musicPlayer class to automatically handle these tracks in playlists, like a behind-the-scenes iTunes for game developers. This is just the raw class to play a tune. You'd use it by alloc-initing a new track every time you want to play one, and you release it as soon as it's done playing, and subsequently alloc-init a new one to play. Even if you plan on playing the same track again later, you need to release it first if you want to play a different one in the meantime. It is designed this way to conserve resources. The musicPlayer class I was talking about will manage this automatically. I'd post that too, but it's not *quite* finished (as in, it's feature complete, but it's being tested and bugs are being found and squashed). So for now, maybe you can figure out how to get stuff rolling with Audio Queues using this.

You'd use it like this:

Code:
GBMusicTrack *song = [[GBMusicTrack alloc] initWithPath:[[NSBundle mainBundle] pathForResource:@"BackgroundMusic" ofType:@"mp3"]];
[song setRepeat:YES];
[song play];

GBMusicTrack.h
Code:
//
//  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
Code:
//
//  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

Well, that looks almost identical to the other example code I have been looking through, and I have everything in there. But when I run my code it breaks at AudioQueueEnqueueBuffer. Could this be because it cannot find the audio file I want or perhaps for some other reason?


Audio Queues - AnotherJake - Jul 10, 2008 06:04 PM

Did you actually try GBMusicTrack, or are you assuming it won't work either just by looking at it?


Audio Queues - Talyn - Jul 10, 2008 06:57 PM

AnotherJake Wrote:Did you actually try GBMusicTrack, or are you assuming it won't work either just by looking at it?

Oh no, don't get me wrong, I'm not assuming it won't work. But seeing as I don't wish to plagiarize your material, or the material from which I was deriving my examples, I wrote my own stuff that was VERY similar to your implementation. I keep getting an EXC_BAD_ACCESS error at AudioQueueEnQueueBuffer and I was wondering if you knew what might cause this.


Audio Queues - AnotherJake - Jul 10, 2008 07:38 PM

Can't tell you why you're getting an EXC_BAD_ACCESS without seeing your code and then perhaps spending time tracking it down for you, which is why it's easier to just post known working code for you to use and work off of (which doesn't violate NDA).

Don't worry about "plagiarizing" my material. If it's posted here, it's free to do with as you please or else I wouldn't have posted it. I'm all about sharing knowledge freely (and making money freely too!). Don't worry about calling it your own. I would prefer you use it, find problems, and share your fixes back. It's only under copyright so some malevolent entity can't come back and screw us for sharing free code in GameBase. But if it makes you feel better, since I hold copyright for this file, I hereby give you permission to "plagiarize" it as you see fit. Wink


Audio Queues - reubert - Jul 10, 2008 07:53 PM

<snip> OK NDA not over


Audio Queues - Talyn - Jul 10, 2008 11:28 PM

AnotherJake Wrote:Can't tell you why you're getting an EXC_BAD_ACCESS without seeing your code and then perhaps spending time tracking it down for you, which is why it's easier to just post known working code for you to use and work off of (which doesn't violate NDA).

Don't worry about "plagiarizing" my material. If it's posted here, it's free to do with as you please or else I wouldn't have posted it. I'm all about sharing knowledge freely (and making money freely too!). Don't worry about calling it your own. I would prefer you use it, find problems, and share your fixes back. It's only under copyright so some malevolent entity can't come back and screw us for sharing free code in GameBase. But if it makes you feel better, since I hold copyright for this file, I hereby give you permission to "plagiarize" it as you see fit. Wink

Alrighty then. Thanks! A couple questions: If I do decide to use your implementation, can I specify a file name / file URL for your player to read without having to jump through the hoops that all of the examples I've been referencing have been telling me to? Also, it is suited for a particular file format? I plan on using mostly aiff encoded files. Thanks for the help!

[EDIT]
Man! I didn't even look at the first few lines of code you posted. Very nice! Now why didn't Apple do that to begin with??!!


Audio Queues - Talyn - Jul 10, 2008 11:46 PM

Well, this is going to seem a little strange, and I apologize, but it something that must be said:

HOLY CRAP, ANOTHER JAKE...I LOVE YOU!!!! I tried out your sound engine and it worked like a CHARM!!!! I have spent the last 6 days, tearing my hair out over sound and in one fell swoop you fixed it all!! Thank you, my friend! I will be sure to include you in the credits somewhere, thank you very much!


Audio Queues - Xavier - Jul 11, 2008 01:40 AM

OneSadCookie Wrote:I don't know how it works on the iPhone, but on the Mac you should not assume you have permission to write to your application bundle.

You are right: I tried to save/read data in the Documents directory, and it's working fine.

Thanks a lot.


Audio Queues - AnotherJake - Jul 11, 2008 06:11 AM

Talyn Wrote:Well, this is going to seem a little strange, and I apologize, but it something that must be said:

HOLY CRAP, ANOTHER JAKE...I LOVE YOU!!!! I tried out your sound engine and it worked like a CHARM!!!! I have spent the last 6 days, tearing my hair out over sound and in one fell swoop you fixed it all!! Thank you, my friend! I will be sure to include you in the credits somewhere, thank you very much!

Aww shucks... It was nuthin'... Glad you like it! Grin

It's even easier to use with the GBMusicPlayer class I'm writing for it, to manage it like a jukebox. Hopefully I'll finish that soon, because I'm getting sick of working on it. Sneaky

Quote:Man! I didn't even look at the first few lines of code you posted. Very nice! Now why didn't Apple do that to begin with??!!

I ... don't ... know .... This is the part where I can't help but chuckle about when I read the Audio Queue documentation and saw a note that went something to the effect of: "Note that this is a C interface and doesn't need C++ to use, but we use C++ in the examples to simplify it."

"simplify" it? Riiight...

I think it's more like this is a perfect example of an API designer who is so addicted to C++ that they can't see how convoluted they make things by even barely *touching* C++. I don't know if they were in a rush or what, and just grabbing stuff off the shelf, but C++ was entirely unnecessary.

Now, I'm not a big C++ basher, but I'm going to take this special opportunity to rant a bit: I've said many times in the past that I've seen way too many examples of C++ misused (which is one of the reasons why I avoid using it myself) and this is one of those times. I had to go through a lot of extra hassle trying to comprehend the Audio Queue examples by re-writing them in a more sane language. The documentation leaves me with the impression that the API designer was so encumbered by their own example code that they spent all their time trying to untangle it for the reader, rather than explaining the core concepts in a fluid fashion. Because of this, the documentation left a few core questions that I had along the way, unanswered.

In the end, I like the Audio Queue API and think it is long overdue, but I think Apple should re-work the example code and documentation. It's not the best stuff I've seen from them, but at least it is a far sight better than the HID manager! Audio Queue is appreciated, and I don't want to sound too harsh, but I'll give it a D+ for now, because I think they could do the documentation and example code better.


Audio Queues - TomorrowPlusX - Jul 11, 2008 07:37 AM

AnotherJake Wrote:...C++ ranting...

LOL

Then you'd probably not much care for my audio player code which plays tracks from your iTunes playlists via a mishmash of C++/ObjC++/ObjC.Sneaky


Audio Queues - AnotherJake - Jul 11, 2008 07:43 AM

LOL

Yeah, but you don't count, TomorrowPlusX, you get special C++ abuse privileges. ... Whatever we have to do to keep you happy. Grin


Audio Queues - TomorrowPlusX - Jul 11, 2008 08:17 AM

I appreciate it. I like to think of myself as a sane c++ programmer. No template abuse or metaprogramming, for example. That kind of stuff gives me the shivers.

Also, ObjC where it makes sense, C where it makes sense, etc etc.

And finally, boost smart pointers to keep my memory managed. It's almost like magic.