Subscribe to me on YouTube

Loading sound from memory into cocos2d’s SimpleAudioEngine

April 19th, 2012 by Cody

This was seriously way more work than I anticipated. In the end, it really wasn’t that complicated, but just took a while to put all the pieces together. Having to wrap the ExtAudioFileRef around an AudioFileID and then having to setup callback functions to get the AudioFileID from memory felt like a bit of overkill… Here is the code I added to CDOpenALSupport.m. I’m sure there is a better solution, but this works so I’m gonna stick with it for now ^_^.

//
// desc: for storing the decrypted audio file data in memory
//
typedef struct {
    unsigned char *data;    // pointer to audio data
    SInt64 dataLength;      // length of audio data
} AudioFileMemory;

//
// desc: callback for reading the audio data,
//       check AudioFileOpenWithCallbacks doc for more details
//
OSStatus AudioFileReadProc(void *inClientData, SInt64 inPosition, UInt32 requestCount, void *buffer, UInt32 *actualCount)
{
    // check parameters
    if (!inClientData || !buffer || !actualCount) {
        return EINVAL;
    }

    AudioFileMemory *audioFileMemory = (AudioFileMemory *)inClientData;

    // make sure position is within bounds
    if (inPosition < 0 || inPosition >= audioFileMemory->dataLength) {
        *actualCount = 0; // don't read anything and tell them everything is just friggin fine,
                          // this is called passive aggressive error handling ^_^
        return noErr;
    }

    // see if we need to cap requested length
    *actualCount = requestCount;
    SInt64 endPosition = inPosition + requestCount;
    if (endPosition >= audioFileMemory->dataLength) {
        *actualCount = requestCount - (endPosition - audioFileMemory->dataLength);
    }

    memcpy(buffer, audioFileMemory->data + inPosition, *actualCount);
    return noErr;
}

//
// desc: callback for getting size of audio data
//       check AudioFileOpenWithCallbacks doc for more details
//
SInt64 AudioFileGetSizeProc(void *inClientData) {
    if (!inClientData) {
        return EINVAL;
    }

    AudioFileMemory *audioFileMemory = (AudioFileMemory *)inClientData;
    return audioFileMemory->dataLength;
}

//
// desc: assumes this is encrypted or packaged file and that
//       the file naming convention is filename.xxx.enc or filename.xxx.tar, etc...
//       determines type based off xxx, only coded for checking for wave and mp3
//       cause that's all I care about right now
//
// params: inFileURL[in] - file url to get audio file type on
//
// returns: audio file type id for file if successful
//          returns 0 if file type is unknown
//
AudioFileTypeID GetAudioFileTypeId(CFURLRef inFileURL)
{
    CFURLRef pathWithoutEncExtension = CFURLCreateCopyDeletingPathExtension(kCFAllocatorDefault, inFileURL);
    CFStringRef extension = CFURLCopyPathExtension(pathWithoutEncExtension);
    AudioFileTypeID audioFileTypeId = 0;
    if (CFStringCompare(extension, (CFStringRef)@"wav", kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
        audioFileTypeId = kAudioFileWAVEType;
    }
    else if (CFStringCompare(extension, (CFStringRef)@"mp3", kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
        audioFileTypeId = kAudioFileMP3Type;
    }

    CFRelease(pathWithoutEncExtension);
    CFRelease(extension);
    return audioFileTypeId;
}

//
// desc: creates an audio file id, checks to see if file type is encrypted.
//       if it's not encrypted, then it loads it like normal and returns audioFileId.
//       if is its encrypted, it will decrypt the file in memory and load it into a AudioFileId.
//       if it decrypts, then it will return pointer to the audio data in audioFileMemory.  when
//       you close the audioFileId, be sure to free() the data pointer inside audioFileMemory.
//       I'm not really sure if we need to keep the data around, but I'm doing it to be safe.
//
// params: inFileURL[in] - url of file to load
//         audioFileId[out] - returns audio file id if file was successfully loaded
//         audioFileMemory[out] - returns pointer to audio memory if the audio file was decrpyted and loaded from mem
//                                BE SURE TO CALL free() ON THE DATA POINTER WHEN YOU ARE DONE WITH THE AUDIO FILE ID
//
// returns: returns  0 if opened file like normal (not encrypted)
//          returns  1 if dectypred file and loaded it from memory
//          returns -1 if failed to open unencrypted file
//          returns -2 if failed to open encrypted file
//          returns -3 if failed to decrypt file
//          returns -4 if failed to load audio file id with decrypted memory
//
int CreateAudioFileId(CFURLRef inFileURL, AudioFileID *audioFileId, AudioFileMemory *audioFileMemory)
{
    CFStringRef extension = CFURLCopyPathExtension(inFileURL);
    OSStatus err = noErr;

    // reset audioFileMemory
    memset(audioFileMemory, 0, sizeof(AudioFileMemory));

    // if not an encrypted file, then get audio id like always
    if (CFStringCompare(extension, (CFStringRef)@"enc", kCFCompareCaseInsensitive) != kCFCompareEqualTo) {
        CFRelease(extension);

        err = AudioFileOpenURL(inFileURL, kAudioFileReadPermission, 0, audioFileId);
        if (err) {
            CDLOG(@"CreateAudioFileId: AudioFileOpenURL FAILED, Error = %ld\n", err);
            return -1;
        }

        return 0;
    }

    CFRelease(extension);

    // else we are dealing with encrypted file, so decrypt it
    @autoreleasepool {
        NSData *encData = [NSData dataWithContentsOfURL:(NSURL *)inFileURL];

        if (!encData) {
            CDLOG(@"CreateAudioFileId: Failed to load %@, could not find file.", CFURLGetString(inFileURL));
            return -2;
        }

        audioFileMemory->dataLength = CCDecryptMemory((unsigned char *)[encData bytes], [encData length], &audioFileMemory->data);
        if (!audioFileMemory->data) {
            CDLOG(@"CreateAudioFileId: Failed to load %@, failed to decrypt.", CFURLGetString(inFileURL));
            return -3;
        }
    }

    err = AudioFileOpenWithCallbacks(audioFileMemory,
                                     AudioFileReadProc, NULL,
                                     AudioFileGetSizeProc, NULL,
                                     GetAudioFileTypeId(inFileURL), audioFileId);

    if (err) {
        char bytes[4];
        bytes[0] = (err >> 24) & 0xFF;
        bytes[1] = (err >> 16) & 0xFF;
        bytes[2] = (err >> 8) & 0xFF;
        bytes[3] = err & 0xFF;
        CDLOG(@"CreateAudioFileId: AudioFileOpenWithCallbacks FAILED, Error = %ld, %c%c%c%c\n", err, bytes[0], bytes[1], bytes[2], bytes[3]);
        return -4;
    }

    return 1;
}



And after adding all that, just had to change CDloadWaveAudioData() and CDloadCafAudioData to use the new CreateAudioFileId() calls.

CDloadWaveAudioData() change:

//Taken from oalTouch MyOpenALSupport 1.1
void* CDloadWaveAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei*	outSampleRate)
{
	OSStatus						err = noErr;
	UInt64							fileDataSize = 0;
	AudioStreamBasicDescription		theFileFormat;
	UInt32							thePropertySize = sizeof(theFileFormat);
	AudioFileID						afid = 0;
	void*							theData = NULL;
    AudioFileMemory                 audioFileMemory;

	// Open a file with ExtAudioFileOpen()
    if (CreateAudioFileId(inFileURL, &afid, &audioFileMemory) < 0) {
        goto Exit;
    }

CDloadCafAudioData change:

//Taken from oalTouch MyOpenALSupport 1.4
void* CDloadCafAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate)
{
	OSStatus						status = noErr;
	BOOL							abort = NO;
	SInt64							theFileLengthInFrames = 0;
	AudioStreamBasicDescription		theFileFormat;
	UInt32							thePropertySize = sizeof(theFileFormat);
	ExtAudioFileRef					extRef = NULL;
	void*							theData = NULL;
	AudioStreamBasicDescription		theOutputFormat;
	UInt32							dataSize = 0;
    AudioFileID                     audioFileId = 0;
    AudioFileMemory                 audioFileMemory;

    // create audio file id
    if (CreateAudioFileId(inFileURL, &audioFileId, &audioFileMemory) < 0) {
        goto Exit;
    }

	// Open a file with ExtAudioFileOpen()
    status = ExtAudioFileWrapAudioFileID(audioFileId, false, &extRef);
	if (status != noErr)
	{
		CDLOG(@"MyGetOpenALAudioData: ExtAudioFileOpenURL FAILED, Error = %ld\n", status);
		abort = YES;
	}
	if (abort)
		goto Exit;

Momentum Lost

December 4th, 2011 by Cody

Sorry for lack of updates, I’ve lost some momentum due to Thanksgiving and Christmas stuff coming up. Starting to get back into the swing of things. Have a plan to tackle tutorial which is next major thing on the list. In the meantime, I got some artwork done. Three of the ten characters are done. Here is a shot (from left to right) of Coco, Bango Blue, and Spin Lock. Click on image to see high rez.

S BAT 2 beta 2.0 now with fancy retina display

November 15th, 2011 by Cody

Sorry for lack of updates. Lost some momentum last few weeks (mainly due to Warhammer 40k: Space Marine and Dragon Age…). I got me a fancy iPhone 4S and got the artwork up-converted for retina display. Cocos2d made it relatively easy. Had one issue with z axis, but it wasn’t too hard to track down. As far as I can remember, the only change for this is retina. So no changelog this time.

SBAT2GXOTheOS_beta_2_0.zip

Retina Background

November 2nd, 2011 by Cody

Started up-converting artwork. I was right, redoing textures is a pain. I spent a good hour and half just trying to find the original brush I had used. Tweaked color on inlay so it blends a little better and doesn’t pop so much (less distracting hopefully). Let me know what you think on twitter. Do you like inlay with slight glow or with shadow? I think I lean towards shadow. I like the glow cause of that bloom effect, but at the same time, it just kind of makes it blurry. The shadowing is much sharper…

Blended:

Emboss:

Slight Shadow:

Slight Glow:
Slight Glow

The original low res:

S BAT 2 beta 1.9

October 30th, 2011 by Cody

And so it continues. Added two new features which I have very mixed feelings about. Please give me feedback on them. I’m mixed cause while I can see value in them, they are also VERY distracting for the core I had built everything around.

Also made first attempt at recording emulator. Came out decent so I’ll try to post in-dev videos every once in a while from now on. Better than screenshots ^__^.



I’m going to let these features sink in a little this week and focus on up-converting artwork for retina display this week. Majority of stuff is vector art, but I’m worried re-texturing is going to be a nightmare… That’s what I get for targeting my crappy 3GS, sigh… And I keep telling myself I’m going to get a 4S. I’m hoping up-converting artwork will force me too get it next weekend ^__^.

  • Mobile towers now act as repeaters for base towers. In other words, if a mobile tower is being touched by a beam, then it will add a new beam of that same color. If you get in the corners you can fire up to five beams at the same time. Langevin had this idea. While it’s kind of cool, it’s very very distracting. Makes the easy patterns cake. Makes the difficult patterns more difficult…
  • Added enemy drops. When you kill an enemy, there is a chance it will drop an item. To pick up an item, just touch it with a mobile tower. Items will expire if they are not picked up. They will start to blink when they are close to expiring. Currently there are only two basic item types, 1) health (blue circle), this will add one health to a tower with lowest amount of health, 2) points, these are basically free points, they range from 500-2500pts and are in increments of 500.
  • Added better score inflation. Enemies now count for more each kill. Left over time in a wave counts for more. Now has a wave multiplier, each wave you complete adds one to the multiplier. In other words, enemies in wave 1 are x1 points, wave 2 are x2 points, wave 3 are x3 points, etc… This applies to item pick ups as well (picking up 1000 point item drop in wave 3 will net you 3000 points).
  • Tweaked some touch logic which I think will be better.
  • Removed sound effects… They were first draft… <_<

SBAT2GXOTheOS_beta_1_9.zip

S BAT 2 beta 1.8

October 24th, 2011 by Cody

Not a lot done this week cause of LDI. Hopefully after this week things will settle down at work so I can focus more on the S BAT 2. Managed to crank a bit to get some cool new stuff out though.

  • Emission Generator now has an attack animation. I think it’s pretty saweet. I’m going to save posting a screenshot for next #screenshotsaturday.
  • Emission generators will now attack three base towers instead of all of them taking one damage. This is per emission generator. So if you don’t destroy three generators before the wave timer is up, then seven of the towers will take one damage and one tower will take two damage (3 generators * 3 damage = 9 damage total, 7 towers * 1 damage + 1 tower * 2 damage = 9 damage total). The attack animation will indicate which base tower it is hitting. It will attack towers with the most health. Each emission generator can only hit a tower once. So if you have two towers left, the generator will only do one damage to each (it won’t do two damage to one tower and one damage to the other).
  • Switch the health bar to hopefully indicate health much more clearly. I want to add an animation for each icon for when you loose a point of health.
  • Now have sound effects! Added prototype menu clicks and polarity switch. The sound effects volume is operational in the options menu.
  • Fix a bug where the background music would stop playing if a track completed while the game was paused.

SBAT2GXOTheOS_beta_1_8.zip

S BAT 2 beta 1.7

October 16th, 2011 by Cody

Man on man, work work work. Between PRG and this I’m dying. Almost got everything I wanted in over the weekend. Spent a lot of time prototyping stuff that I thought would be brilliant and then throwing it out, cause it ended up being awful. There is a lot of stuff, but it’ll all be pretty minor from your stand point. And in other news, uploaded first binary for IGF submission! I had to screenshot to commemorate the occasion.

IGF Uploading

And here are beta v1.7 changes

  • Darkened the white enemy health-bars to make them more visible.
  • Enemies will now shake more the more damage you are doing. In other words, the will shake harder if you are hitting with two beams as opposed to one.
  • Base towers now shake over an interval after being hit, before they’d just shake for one frame and wasn’t very noticeable.
  • Base towers now spit out a little steam when they git hit.
  • Redid artwork for path sprites. They are now thicker, more color agnostic, and have endings. The endings make them look much more polished.
  • Created death animation for barriers, it’s very subtle, but more natural then them just disappearing.
  • Barriers will now display as part of the spawn animation instead of popping in after the generator finishes it’s spawn animation.
  • Emissions are no longer destroyed by the wave timer, only generators are affected by the wave timer.
  • Now randomly selects a background music track to start with on start up. I realized I forgot to mention to IGF that there are three tracks, so now it randomly picks where to start in it’s cycle. The cycle is, “Bango’s Jig”, “Cowboy Coder”, “Welcome to Emission Control”.
  • Upgraded SDK to iOS5. I hate apple by the way, I do not understand the concept of sync for some reason, upgrading is always a nightmare.
  • Fix issue with z ordering on pathing sprites.
  • Fixed hit detection issue with barriers.

SBAT2GXOTheOS_beta_1_7.zip

Website Updates

October 10th, 2011 by Cody

Tweaked the website over the last week. S BAT 2 now has it’s own fancy page. Added an about page as well. You will also notice twitter and youtube icons to link to twitter and youtube accounts at the top right. In other news, I submitted for IGF 2012 yesterday! I’m pretty sure nothing will come of it, but worth a shot. Gave me a concrete deadline to hit. A deadline that cost me money… Still need to upload final binary to IGF by end of this week. I’ll be putting some final graphical polishing into S BAT 2 this week. So no beta release this week, but definitely expect one next week.

S BAT 2 beta 1.6

October 3rd, 2011 by Cody

Sorry it’s a little behind. Nothing major in this release, more of a polish/bug fix release. This week I’ll be moving website over to different host and tweaking it a bit. Also worked on preview video this weekend, so expect that to be up once I get the website moved over. Beta v1.7 will be delayed till I get website maintenance out of the way.

  • Pause menu now works. You can restart a new game from the Pause menu (saves the trouble of having to reset the app, which was really annoying).
  • Menu system code cleanup.
  • Emissions now move a little slower.
  • Enemies and Towers now shake when damage is done to them, I will be tweaking this some more in future releases.
  • Barriers will now be the opposite color of the generators.
  • Barriers can now be destroyed by hitting them with the same color (they will shake if you are doing damage). You do not have to destroy the barriers, and you aren’t awarded extra points for destroying them, so it is better to shoot around them.
  • Emissions no longer need to be destroyed before the wave timer runs out, only generators need to be destroyed before the timer runs out.
  • Fix, emissions spawning on top of each other.
  • Fix, enemies would not always deactivate their collision body when resetting the game.
  • Fix, enemies would not rotate to the next tower when recalculating their path.
  • Fix, enemies will now stop when there are no more towers (you can still kill them while the final towers are exploding for extra points).
  • Fix, emissions getting stuck on each other because the groove constraint was too short and the emission could not back up.
  • Fix, wave timer damage would occur if an enemy was dead but still exploding.

SBAT2GXOTheOS_beta_1_6.zip

S BAT 2 beta 1.5

September 26th, 2011 by Cody

This was rough week. Got menu system in. I’m rather pleased with it. Looks better than I thought. Was not able to get the pause screen in. I got the pause screen layout done in code but I will have to restructure some stuff because of how scene management and pausing the scene works (I didn’t really plan it into the design cause I didn’t know how it worked…). And while this update is a small list, it was a LOT of work. Here is shot of the options screen.

  • Added menu system. Tutorial Mode, Leaderboards, and SFX Volume currently do nothing. Everything else should be functional.
  • Took out phone vibration when disc takes damage.

SBAT2GXOTheOS_beta_1_5.zip