I thought I’d share some code here for once. I needed to play several MP3 files in sequence. The difficulty here is that you can’t just start a timer as the length of the MP3 files will change in different languages, and you can’t get the MP3 file length in cocos2d. In my case i have a bunch of MP3 files of recorded speech which should naturally be played one after another, as if the sentences were spoken in sequence. The funny part of that application will actually be mixing the sentences up to create some absolutely hilarious speeches.
After first attempting to create a PlayMusicAction that was supposed to be used in conjunction with CCSequence but failing at that i decided i should just make an action that takes an NSArray (or NSMutableArray) of MP3 filenames and plays one after the other without the need for a CCSequence. I used the setBackgroundMusicCompletionListener to wait for the end of each file and then play the next. In the end the action is very simple, and i only subclassed Action because i haven’t really worked with Actions yet and wanted to understand them better. I suppose you can do this without an action just as well but just having that framework already there made it a bit easier in terms of memory management.
You call it like this:
NSMutableArray* files = [NSMutableArray arrayWithCapacity:4];
[files addObject:@"correct_a_en.mp3"];
[files addObject:@"description_a1_en.mp3"];
[files addObject:@"description_a2_en.mp3"];
[files addObject:@"description_a3_en.mp3"];
[self runAction:[PlayMusicAction actionWithFiles:files]];
In my case i simply use the CCLayer and add the PlayMusicAction to that. Since it’ll only play music it won’t harm anything and you can really run it on any CCNode. Just running several of these Actions at once might not be working well but you may try it. Putting the Action on a CCLayer has a positive side effect: it simply stops all background music when the action is deallocated, meaning if the user changes screens i do not have to worry about stopping the speech since some sentences can be several seconds.
Here’s the PlayMusicAction class for cocos2d. Tested with cocos2d v0.9.
PlayMusicAction.h
//
// PlayMusicAction.h
//
// Created by Steffen Itterheim on 30.01.10.
// Copyright 2010 Steffen Itterheim. All rights reserved.
// You're free to use, modify and redistribute this file as long as the Copyright notice is not changed
//
#import "cocos2d.h"
// plays a sequence of music files one after the other
@interface PlayMusicAction : CCAction
{
unsigned int currentFile;
NSArray* musicFiles;
bool isMusicPlaying;
bool noMoreFiles;
}
+(id) actionWithFiles:(NSArray*)file;
-(id) initWithFiles:(NSArray*)file;
@end
PlayMusicAction.m
//
// PlayMusicAction.m
//
// Created by Steffen Itterheim on 30.01.10.
// Copyright 2010 Steffen Itterheim. All rights reserved.
//
#import "CDAudioManager.h"
#import "PlayMusicAction.h"
@interface PlayMusicAction (Private)
-(void) onMusicDone;
@end
@implementation PlayMusicAction
+(id) actionWithFiles:(NSArray*)files
{
return [[[self alloc] initWithFiles:files] autorelease];
}
-(id) initWithFiles:(NSArray*)files
{
if ((self = [super init]))
{
currentFile = 0;
musicFiles = [files copy];
NSAssert([musicFiles count] > 0, @"PlayMusicAction - no files in array!");
[[CDAudioManager sharedManager] setBackgroundMusicCompletionListener:self selector:@selector(onMusicDone)];
}
return self;
}
-(void) dealloc
{
// receive no more notifications as this object is now deallocated
[[CDAudioManager sharedManager] setBackgroundMusicCompletionListener:nil selector:nil];
// stops current speech/music instantly if user switches screens or the action gets deallocated otherwise
// comment this line if you would rather have the current speech/music play to the end (the next one, if any, will not be played)
[[CDAudioManager sharedManager] stopBackgroundMusic];
[super dealloc];
}
-(void) onMusicDone
{
isMusicPlaying = NO;
currentFile++;
}
-(BOOL) isDone
{
// no more files and last file stopped playing? Then we're done ...
return (noMoreFiles && isMusicPlaying == NO);
}
-(void) step:(ccTime)delta
{
// if we still have files and no music is playing, play the next music file
noMoreFiles = (currentFile == [musicFiles count]);
if (!noMoreFiles && isMusicPlaying == NO)
{
isMusicPlaying = YES;
[[CDAudioManager sharedManager] playBackgroundMusic:[musicFiles objectAtIndex:currentFile] loop:NO];
}
}
-(void) update:(ccTime)time
{
}
@end






Gaming Horror - 





