Attention: iDevGames forum has a new home at http://www.idevgames.com/forums.
Please update your bookmarks and linkage.
This forum has been locked and will be available for archival purposes only.
iDevGames - Mac, iPhone, iPad & iPod Game Developers Forum  


Graphics & Audio Programming All aspects of coding 2D/3D graphics.

 
 
Thread Tools Display Modes
Old
  (#1)
Xavier
Member
 
Posts: 8
Join Date: 2008.07
Location: Paris, France
Audio Queues - 2008.07.07, 10: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...)

Last edited by sealfin : 2008.07.11 at 10:32 AM.
   
Old
  (#2)
Talyn
Member
 
Posts: 208
Join Date: 2008.06
Location: Denver, USA
2008.07.10, 07:34 PM

Quote:
Originally Posted by AnotherJake View Post
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?


Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
   
Old
  (#3)
AnotherJake
Moderator
 
Posts: 3,541
Join Date: 2003.06
Location: usa
2008.07.10, 07:57 PM

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

Quote:
Originally Posted by Talyn View Post
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!

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

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

Last edited by AnotherJake : 2009.01.16 at 10:11 PM. Reason: Use AVAudioPlayer instead
   
Old
  (#4)
Talyn
Member
 
Posts: 208
Join Date: 2008.06
Location: Denver, USA
2008.07.10, 08:58 PM

Quote:
Originally Posted by AnotherJake View Post
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!

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?


Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
   
Old
  (#5)
AnotherJake
Moderator
 
Posts: 3,541
Join Date: 2003.06
Location: usa
2008.07.10, 09:04 PM

Did you actually try GBMusicTrack, or are you assuming it won't work either just by looking at it?
   
Old
  (#6)
Talyn
Member
 
Posts: 208
Join Date: 2008.06
Location: Denver, USA
2008.07.10, 09:57 PM

Quote:
Originally Posted by AnotherJake View Post
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.


Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
   
Old
  (#7)
AnotherJake
Moderator
 
Posts: 3,541
Join Date: 2003.06
Location: usa
2008.07.10, 10: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.
   
Old
  (#8)
reubert
Member
 
Posts: 401
Join Date: 2003.06
Location: Wellington, New Zealand
2008.07.10, 10:53 PM

<snip> OK NDA not over


Chopper, iSight Screensavers, DuckDuckDuck: http://majicjungle.com
   
Old
  (#9)
Talyn
Member
 
Posts: 208
Join Date: 2008.06
Location: Denver, USA
2008.07.11, 02:28 AM

Quote:
Originally Posted by AnotherJake View Post
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.
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??!!


Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
   
Old
  (#10)
Talyn
Member
 
Posts: 208
Join Date: 2008.06
Location: Denver, USA
2008.07.11, 02:46 AM

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!


Mac users swear by their computers, PC users swear at their computers. ~Unknown

iSayz
   
Old
  (#11)
Xavier
Member
 
Posts: 8
Join Date: 2008.07
Location: Paris, France
2008.07.11, 04:40 AM

Quote:
Originally Posted by OneSadCookie View Post
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.
   
Old
  (#12)
AnotherJake
Moderator
 
Posts: 3,541
Join Date: 2003.06
Location: usa
2008.07.11, 09:11 AM

Quote:
Originally Posted by Talyn View Post
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!

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.

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.
   
Old
  (#13)
TomorrowPlusX
Member
 
Posts: 1,392
Join Date: 2004.10
Location: Washington DC
2008.07.11, 10:37 AM

Quote:
Originally Posted by AnotherJake View Post
...C++ ranting...


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.
   
Old
  (#14)
AnotherJake
Moderator
 
Posts: 3,541
Join Date: 2003.06
Location: usa
2008.07.11, 10:43 AM



Yeah, but you don't count, TomorrowPlusX, you get special C++ abuse privileges. ... Whatever we have to do to keep you happy.
   
Old
  (#15)
TomorrowPlusX
Member
 
Posts: 1,392
Join Date: 2004.10
Location: Washington DC
2008.07.11, 11: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.
   
 


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump



Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
vBulletin Skin developed by: vBStyles.com
DevServe Network: iDevApps | uDevGames | iDevGames