Hello StackOverflow gurus. This is my first question on here so I am excited to jump right in.
I am trying to understand iOS arrays a little better and I've hit a brick wall. I am making a sound app that is using FMOD. I have everything working perfectly but I have 9 buttons that all perform nearly the exact same thing except each play a different .wav file on press then on release stop that sound. I'd like to put it into an array and simplify and shorten my code, that is where I get lost. I stripped down the code to show what I currently have going on. Any ideas?
.h
@interface {
FMOD::Sound *sound1;
FMOD::Sound *sound2;
FMOD::Sound *sound3;
FMOD::Sound *sound4;
FMOD::Sound *sound5;
FMOD::Sound *sound6;
FMOD::Sound *sound7;
FMOD::Sound *sound8;
FMOD::Sound *sound9;
}
- (IBAction)playSound1:(id)sender;
- (IBAction)stopSound1:(id)sender;
- (IBAction)playSound2:(id)sender;
- (IBAction)stopSound2:(id)sender;
- (IBAction)playSound3:(id)sender;
- (IBAction)stopSound3:(id)sender;
- (IBAction)playSound4:(id)sender;
- (IBAction)stopSound4:(id)sender;
- (IBAction)playSound5:(id)sender;
- (IBAction)stopSound5:(id)sender;
- (IBAction)playSound6:(id)sender;
- (IBAction)stopSound6:(id)sender;
- (IBAction)playSound7:(id)sender;
- (IBAction)stopSound7:(id)sender;
- (IBAction)playSound8:(id)sender;
- (IBAction)stopSound8:(id)sender;
- (IBAction)playSound9:(id)sender;
- (IBAction)stopSound9:(id)sender;
m.
- (void)viewWillAppear:(BOOL)animated {
[[NSString stringWithFormat:@"%@/sound1.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound1);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound2.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound2);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound3.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound3);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound4.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE, NULL, &sound4);
ERRCHECK(result);
result = sound4->setMode(FMOD_LOOP_NORMAL);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound5.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound5);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound6.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound6);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound7.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound7);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound8.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound8);
ERRCHECK(result);
[[NSString stringWithFormat:@"%@/sound9.wav", [[NSBundle mainBundle] resourcePath]] getCString:buffer maxLength:200 encoding:NSASCIIStringEncoding];
result = system->createSound(buffer, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound9);
ERRCHECK(result);
}
- (IBAction)playSound1:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound1, false, &wob01);
ERRCHECK(result);
}
- (IBAction)stopSound1:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob01->stop();
ERRCHECK(result);
}
- (IBAction)playSound2:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound2, false, &wob02);
ERRCHECK(result);
}
- (IBAction)stopSound2:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob02->stop();
ERRCHECK(result);
}
- (IBAction)playSound3:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound3, false, &wob03);
ERRCHECK(result);
}
- (IBAction)stopSound3:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob03->stop();
ERRCHECK(result);
}
- (IBAction)playSound4:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound4, false, &wob04);
ERRCHECK(result);
}
- (IBAction)stopSound4:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob04->stop();
ERRCHECK(result);
}
- (IBAction)playSound5:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound5, false, &wob05);
ERRCHECK(result);
}
- (IBAction)stopSound5:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob05->stop();
ERRCHECK(result);
}
- (IBAction)playSound6:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound6, false, &wob06);
ERRCHECK(result);
}
- (IBAction)stopSound6:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob06->stop();
ERRCHECK(result);
}
- (IBAction)playSound7:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound7, false, &wob07);
ERRCHECK(result);
}
- (IBAction)stopSound7:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob07->stop();
ERRCHECK(result);
}
- (IBAction)playSound8:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound8, false, &wob08);
ERRCHECK(result);
}
- (IBAction)stopSound8:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob08->stop();
ERRCHECK(result);
}
- (IBAction)playSound9:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound9, false, &wob09);
ERRCHECK(result);
}
- (IBAction)stopSound9:(id)sender
{
FMOD_RESULT result = FMOD_OK;
result = wob09->stop();
ERRCHECK(result);
}
As you can see, all the code is just repeated. This is the only way I've been able to get it to work but I know that these can be put into an array, I just can't figure it out. Possibly an NSMutableArray and list out "sound1", "sound2", etc etc.. then assign each button a tag in interface builder? Ideally, I'd like to have one function for stopSound, one for playSound, etc. that uses a tag to play or stop the correct sound file. When using FMOD's system->createSound(), the last argument is a variable to store the newly created sound in. Is there any way to store it in an array or dictionary instead? If so I can't figure it out.
Any advice would be MORE than appreciated. I'd love to stop beating my head against this simple issue.
Thank you!
I would wrap the sound into a subclass of NSObject
and make it a self contained unit. A sound would have operations like play
, stop
, pause
, and accessors like isPlaying
, etc.
Then to make it even more generic I would search for all files matching the pattern "*.wav"
and then for each matched file name, initialize a Sound
object with that file name, and add it to an array.
Here's what I imagine the Sound object would look like:
@interface Sound : NSObject
@property FMOD::Sound *sound;
- (id)initWithSoundFilePath:(NSString *)path;
- (void)play;
- (void)stop;
@end
@implementation Sound
- (void)dealloc {
// free the memory occupied by the sound pointer here
}
- (id)initWithSoundFilePath:(NSString *)path {
self = [super init];
if (self) {
result = system->createSound(path, FMOD_SOFTWARE | FMOD_LOOP_NORMAL, NULL, &sound);
ERRCHECK(result);
}
return self;
}
- (void)play {
FMOD_RESULT result = FMOD_OK;
result = system->playSound(FMOD_CHANNEL_FREE, sound, false, /* What is this wob? */);
ERRCHECK(result);
}
- (void)stop {
FMOD_RESULT result = FMOD_OK;
result = /* What is this wob */->stop();
ERRCHECK(result);
}
@end
So there you have it. A sound is nicely encapsulated now. I found this answer helpful in finding a list of all files in a certain directory matching some criteria. You could use that in your view controller to automatically generate all relevant Sound objects and add it to an array.
- (NSArray *)getPathsOfSoundFiles {
NSString *rootPath = [[NSBundle mainBundle] resourcePath];
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *files = [fm contentsOfDirectoryAtPath:rootPath error:nil];
NSPredicate *soundFileFilter = [NSPredicate predicateWithFormat:@"self ENDSWITH '.wav'"];
NSArray *soundFilePaths = [files filteredArrayUsingPredicate:soundFileFilter];
return soundFilePaths;
}
Ok, now that you can retrieve the paths to all .wav files, the next step is to initialize them in your viewWillAppear
or whatever method makes most sense.
- (void)viewWillAppear:(BOOL)animated {
NSArray *paths = [self getPathsOfSoundFiles];
NSMutableArray *sounds = [NSMutableArray array];
for (NSString *path in paths) {
Sound *sound = [[Sound alloc] initWithSoundFilePath:path];
[sounds addObject:sound];
}
self.sounds = sounds;
}
And with the sounds array setup, playing and stopping a given sound becomes rather easy. Use could create a method that takes an index into the array, or maybe a Sound
object itself and does the job.
- (void)playSoundAtIndex:(NSUInteger)soundIndex {
Sound *sound = [self.sounds objectAtIndex:soundIndex];
[sound play];
}
- (void)stopSoundAtIndex:(NSUInteger)soundIndex {
Sound *sound = [self.sounds objectAtIndex:soundIndex];
[sound stop];
}