diff --git a/JGE/include/JSoundSystem.h b/JGE/include/JSoundSystem.h index 0da8ab626..10f25e8e2 100644 --- a/JGE/include/JSoundSystem.h +++ b/JGE/include/JSoundSystem.h @@ -21,6 +21,7 @@ #ifdef ANDROID #include #include "SLES/OpenSLES_Android.h" + #elif defined USE_PHONON #include #include @@ -48,6 +49,8 @@ #endif //------------------------------------------------------------------------------------------------ +using namespace std; + #ifdef USE_PHONON class JMusic : public QObject { @@ -69,6 +72,10 @@ public: void seekAtTheBegining(); #elif defined (PSP) JMP3* mTrack; +#elif defined (IOS) + std::string filename; + std::string key; + std::string ext; #elif defined WITH_FMOD FSOUND_SAMPLE* mTrack; // MP3 needed to be of "sample" type for FMOD, FMUSIC_MODULE is for MODs #elif defined ANDROID @@ -82,7 +89,7 @@ public: }; -//------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------ class JSample { public: @@ -93,6 +100,12 @@ class JSample #if defined (PSP) WAVDATA *mSample; +#elif defined (IOS) + std::string filename; + std::string key; + std::string ext; + + void* mSample; #elif defined (WITH_FMOD) FSOUND_SAMPLE *mSample; #elif defined (USE_PHONON) diff --git a/JGE/src/iOS/JSfx.cpp b/JGE/src/iOS/JSfx.cpp new file mode 100644 index 000000000..260774823 --- /dev/null +++ b/JGE/src/iOS/JSfx.cpp @@ -0,0 +1,175 @@ +// +// JSfx.cpp +// wagic +// +// Created by Michael Nguyen on 2/3/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#include +#include "JFileSystem.h" +#include "JSoundSystem.h" + +#include +#include +#include + +#import "SoundManager.h" +////////////////////////////////////////////////////////////////////////// + +JMusic::JMusic() +{ +} + +void JMusic::Update(){ + +} + +int JMusic::getPlayTime(){ + return 0; +} + +JMusic::~JMusic() +{ +} + +////////////////////////////////////////////////////////////////////////// +JSample::JSample() +{ + +} + +JSample::~JSample() +{ +} + +unsigned long JSample::fileSize() +{ + return 0; +} + +////////////////////////////////////////////////////////////////////////// +JSoundSystem* JSoundSystem::mInstance = NULL; + +JSoundSystem* JSoundSystem::GetInstance() +{ + if (mInstance == NULL) + { + mInstance = new JSoundSystem(); + mInstance->InitSoundSystem(); + } + return mInstance; +} + + +void JSoundSystem::Destroy() +{ + if (mInstance) + { + mInstance->DestroySoundSystem(); + delete mInstance; + mInstance = NULL; + } +} + + +JSoundSystem::JSoundSystem() +{ + mVolume = 0; + mSampleVolume = 0; +} + +JSoundSystem::~JSoundSystem() +{ +} + +void JSoundSystem::InitSoundSystem() +{ + NSLog(@"InitSoundSystem enter"); + [SoundManager sharedSoundManager]; + + + NSLog(@"InitSoundSystem leave"); +} + + +void JSoundSystem::DestroySoundSystem() +{ + +} + + +JMusic *JSoundSystem::LoadMusic(const char *fileName) +{ + JMusic* music = new JMusic(); + string fullpath = JFileSystem::GetInstance()->GetResourceFile(fileName); + music->filename = fullpath; + NSString *filename = [NSString stringWithCString: fileName encoding:NSUTF8StringEncoding]; + NSString *key = [[filename componentsSeparatedByString: @"."] objectAtIndex: 0]; + NSString *fileType = [[key componentsSeparatedByString: @"."] lastObject]; + NSString *path = [NSString stringWithCString: fullpath.c_str() encoding:NSUTF8StringEncoding]; + music->key = [key cStringUsingEncoding:NSUTF8StringEncoding]; + music->ext = [fileType cStringUsingEncoding: NSUTF8StringEncoding]; + + [[SoundManager sharedSoundManager] loadBackgroundMusicWithKey:key musicFile:path]; + + return music; + +} + + +void JSoundSystem::PlayMusic(JMusic *music, bool looping) +{ + NSString *key = [NSString stringWithCString: music->key.c_str() encoding: NSUTF8StringEncoding]; + [[SoundManager sharedSoundManager] playMusicWithKey: key timesToRepeat: looping? -1 : 1]; +} + + +void JSoundSystem::StopMusic(JMusic *music) +{ + [[SoundManager sharedSoundManager] stopMusic]; +} + + +void JSoundSystem::SetVolume(int volume) +{ + SetMusicVolume(volume); + SetSfxVolume(volume); +} + +void JSoundSystem::SetMusicVolume(int volume) +{ + mVolume = volume; + [[SoundManager sharedSoundManager] setMusicVolume: (float ) volume]; +} + +void JSoundSystem::SetSfxVolume(int volume){ + mSampleVolume = volume; + [[SoundManager sharedSoundManager] setFxVolume: (float ) volume]; + SetMusicVolume(mVolume); +} + +JSample *JSoundSystem::LoadSample(const char *fileName) +{ + JSample* sample = new JSample(); + if (sample) + { + NSArray *components = [[NSString stringWithCString:fileName encoding:NSUTF8StringEncoding] componentsSeparatedByString:@"."]; + string fullpath = JFileSystem::GetInstance()->GetResourceFile(fileName); + sample->filename = fullpath; + sample->ext = [[components lastObject] cStringUsingEncoding: NSUTF8StringEncoding]; + NSString *key = [components objectAtIndex:0]; + NSString *musicFile = [NSString stringWithCString: fullpath.c_str() encoding:NSUTF8StringEncoding]; + [[SoundManager sharedSoundManager] loadSoundWithKey: key musicFile: musicFile]; + } + return sample; +} + + +void JSoundSystem::PlaySample(JSample *sample) +{ + SoundManager *soundManager = [SoundManager sharedSoundManager]; + NSString *key = [NSString stringWithCString: sample->key.c_str() encoding:NSUTF8StringEncoding]; + [soundManager playSoundWithKey: key gain: 1.0f pitch: 1.0f location:CGPointZero shouldLoop: NO sourceID: -1]; +} + diff --git a/projects/mtg/iOS/SoundManager/MyOpenALSupport.c b/projects/mtg/iOS/SoundManager/MyOpenALSupport.c new file mode 100755 index 000000000..51265e1af --- /dev/null +++ b/projects/mtg/iOS/SoundManager/MyOpenALSupport.c @@ -0,0 +1,140 @@ +/* + + File: MyOpenALSupport.c +Abstract: OpenAL-related support functions + Version: 1.4 + +Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple +Inc. ("Apple") in consideration of your agreement to the following +terms, and your use, installation, modification or redistribution of +this Apple software constitutes acceptance of these terms. If you do +not agree with these terms, please do not use, install, modify or +redistribute this Apple software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, Apple grants you a personal, non-exclusive +license, under Apple's copyrights in this original Apple software (the +"Apple Software"), to use, reproduce, modify and redistribute the Apple +Software, with or without modifications, in source and/or binary forms; +provided that if you redistribute the Apple Software in its entirety and +without modifications, you must retain this notice and the following +text and disclaimers in all such redistributions of the Apple Software. +Neither the name, trademarks, service marks or logos of Apple Inc. may +be used to endorse or promote products derived from the Apple Software +without specific prior written permission from Apple. Except as +expressly stated in this notice, no other rights or licenses, express or +implied, are granted by Apple herein, including but not limited to any +patent rights that may be infringed by your derivative works or by other +works in which the Apple Software may be incorporated. + +The Apple Software is provided by Apple on an "AS IS" basis. APPLE +MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION +THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND +OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + +IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, +MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED +AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), +STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2009 Apple Inc. All Rights Reserved. + + +*/ + +#include "MyOpenALSupport.h" + +ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq) +{ + static alBufferDataStaticProcPtr proc = NULL; + + if (proc == NULL) { + proc = (alBufferDataStaticProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alBufferDataStatic"); + } + + if (proc) + proc(bid, format, data, size, freq); + + return; +} + +void* MyGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate) +{ + OSStatus err = noErr; + SInt64 theFileLengthInFrames = 0; + AudioStreamBasicDescription theFileFormat; + UInt32 thePropertySize = sizeof(theFileFormat); + ExtAudioFileRef extRef = NULL; + void* theData = NULL; + AudioStreamBasicDescription theOutputFormat; + + // Open a file with ExtAudioFileOpen() + err = ExtAudioFileOpenURL(inFileURL, &extRef); + if(err) { printf("MyGetOpenALAudioData: ExtAudioFileOpenURL FAILED, Error = %ld\n", err); goto Exit; } + + // Get the audio data format + err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &theFileFormat); + if(err) { printf("MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %ld\n", err); goto Exit; } + if (theFileFormat.mChannelsPerFrame > 2) { printf("MyGetOpenALAudioData - Unsupported Format, channel count is greater than stereo\n"); goto Exit;} + + // Set the client format to 16 bit signed integer (native-endian) data + // Maintain the channel count and sample rate of the original source format + theOutputFormat.mSampleRate = theFileFormat.mSampleRate; + theOutputFormat.mChannelsPerFrame = theFileFormat.mChannelsPerFrame; + + theOutputFormat.mFormatID = kAudioFormatLinearPCM; + theOutputFormat.mBytesPerPacket = 2 * theOutputFormat.mChannelsPerFrame; + theOutputFormat.mFramesPerPacket = 1; + theOutputFormat.mBytesPerFrame = 2 * theOutputFormat.mChannelsPerFrame; + theOutputFormat.mBitsPerChannel = 16; + theOutputFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; + + // Set the desired client (output) data format + err = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(theOutputFormat), &theOutputFormat); + if(err) { printf("MyGetOpenALAudioData: ExtAudioFileSetProperty(kExtAudioFileProperty_ClientDataFormat) FAILED, Error = %ld\n", err); goto Exit; } + + // Get the total frame count + thePropertySize = sizeof(theFileLengthInFrames); + err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames); + if(err) { printf("MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileLengthFrames) FAILED, Error = %ld\n", err); goto Exit; } + + // Read all the data into memory + UInt32 dataSize = theFileLengthInFrames * theOutputFormat.mBytesPerFrame;; + theData = malloc(dataSize); + if (theData) + { + AudioBufferList theDataBuffer; + theDataBuffer.mNumberBuffers = 1; + theDataBuffer.mBuffers[0].mDataByteSize = dataSize; + theDataBuffer.mBuffers[0].mNumberChannels = theOutputFormat.mChannelsPerFrame; + theDataBuffer.mBuffers[0].mData = theData; + + // Read the data into an AudioBufferList + err = ExtAudioFileRead(extRef, (UInt32*)&theFileLengthInFrames, &theDataBuffer); + if(err == noErr) + { + // success + *outDataSize = (ALsizei)dataSize; + *outDataFormat = (theOutputFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; + *outSampleRate = (ALsizei)theOutputFormat.mSampleRate; + } + else + { + // failure + free (theData); + theData = NULL; // make sure to return NULL + printf("MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %ld\n", err); goto Exit; + } + } + +Exit: + // Dispose the ExtAudioFileRef, it is no longer needed + if (extRef) ExtAudioFileDispose(extRef); + return theData; +} + diff --git a/projects/mtg/iOS/SoundManager/MyOpenALSupport.h b/projects/mtg/iOS/SoundManager/MyOpenALSupport.h new file mode 100755 index 000000000..2ffe2cffd --- /dev/null +++ b/projects/mtg/iOS/SoundManager/MyOpenALSupport.h @@ -0,0 +1,60 @@ +/* + + File: MyOpenALSupport.h +Abstract: OpenAL-related support functions + Version: 1.4 + +Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple +Inc. ("Apple") in consideration of your agreement to the following +terms, and your use, installation, modification or redistribution of +this Apple software constitutes acceptance of these terms. If you do +not agree with these terms, please do not use, install, modify or +redistribute this Apple software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, Apple grants you a personal, non-exclusive +license, under Apple's copyrights in this original Apple software (the +"Apple Software"), to use, reproduce, modify and redistribute the Apple +Software, with or without modifications, in source and/or binary forms; +provided that if you redistribute the Apple Software in its entirety and +without modifications, you must retain this notice and the following +text and disclaimers in all such redistributions of the Apple Software. +Neither the name, trademarks, service marks or logos of Apple Inc. may +be used to endorse or promote products derived from the Apple Software +without specific prior written permission from Apple. Except as +expressly stated in this notice, no other rights or licenses, express or +implied, are granted by Apple herein, including but not limited to any +patent rights that may be infringed by your derivative works or by other +works in which the Apple Software may be incorporated. + +The Apple Software is provided by Apple on an "AS IS" basis. APPLE +MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION +THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND +OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + +IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, +MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED +AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), +STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +Copyright (C) 2009 Apple Inc. All Rights Reserved. + + + */ + +#import +#import +#import +#import + +typedef ALvoid AL_APIENTRY (*alBufferDataStaticProcPtr) (const ALint bid, ALenum format, ALvoid *data, ALsizei size, ALsizei freq); +ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid *data, ALsizei size, ALsizei freq); + +void* MyGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei *outSampleRate); + + diff --git a/projects/mtg/iOS/SoundManager/SoundManager.h b/projects/mtg/iOS/SoundManager/SoundManager.h new file mode 100644 index 000000000..8885a046b --- /dev/null +++ b/projects/mtg/iOS/SoundManager/SoundManager.h @@ -0,0 +1,167 @@ +// +// SoundManager.h +// SLQTSOR +// +// Created by Michael Daley on 22/05/2009. +// Copyright 2009 Michael Daley. All rights reserved. +// + +#import +#import +#import +#import + +#define kFadeInterval (1.0f/60) // Causes the music volume to be updated 60 times per second when music is fading + +// SoundManager provides a basic wrapper for OpenAL and AVAudioPlayer. It is a singleton +// class that allows sound clips to be loaded and cached with a key and then played back +// using that key. It also allows for music tracks to be played, stopped and paused +// +@interface SoundManager : NSObject { + + //////////////////// Sound Setup + ALCcontext *context; // Context in which all sounds will be played + ALCdevice *device; // Reference to the device to use when playing sounds + ALenum alError; // Any OpenAL errors that are rasied + CGPoint listenerPosition; // Location of the OpenAL Listener + NSString *soundCategory; // The sound category to be used by the sound manager + NSMutableArray *soundSources; // Mutable array of all sound sources + AVAudioSession *audioSession; // Reference to an audio session + NSError *audioSessionError; // Audiosession errors are placed in this ivar + + //////////////////// Sound dicionaries + NSMutableDictionary *soundLibrary; // Dictionary of all sounds loaded and their keys + NSMutableDictionary *musicLibrary; // Dictionary of all music/ambient sounds loaded and their keys + NSMutableDictionary *musicPlaylists; // Dictionary of playlists + NSMutableArray *currentPlaylistTracks; // Array of tracks for the current play list + + //////////////////// Music + AVAudioPlayer *musicPlayer; // AVAudioPlayer instance for the music + + //////////////////// Volume + float currentMusicVolume; // Volume of music/ambient sounds played through AVAudioPlayer + float fxVolume; // Volume of OpenAL sound effects + float musicVolume; // The master music volume. This value is not affected by fading music + + //////////////////// Fading sound + NSTimer *timer; // Timer used fade the music volume up or down + float fadeAmount; // Amount the volume should be faded each timer call + float fadeDuration; // The amount of time the fade has been running + float targetFadeDuration; // The duration the current fade should run for + + //////////////////// Flags + BOOL isExternalAudioPlaying; // YES if music was playing before the sound engine was initialized i.e. + BOOL isFading; // YES if the sound manager is currently fading music + BOOL isMusicPlaying; // YES if music is currently playing + BOOL stopMusicAfterFade; // YES if music is to be stopped once fading has finished + BOOL usePlaylist; // YES if tracks in the playlist should be played one after the other + BOOL loopPlaylist; // YES if the playlist should loop when it reaches the end + BOOL loopLastPlaylistTrack; // YES if you want the last track of the playlist to be looped forever + + //////////////////// Playlist tracking + int playlistIndex; // Current index being played in the playlist + NSString *currentPlaylistName; // Holds the name of the currently playing play list + +} + +@property (nonatomic, assign) float currentMusicVolume; +@property (nonatomic, assign) float fxVolume; +@property (nonatomic, assign) BOOL isExternalAudioPlaying; +@property (nonatomic, assign) BOOL isMusicPlaying; +@property (nonatomic, assign) BOOL usePlaylist; +@property (nonatomic, assign) BOOL loopLastPlaylistTrack; +@property (nonatomic, assign) float musicVolume; + +// Returns as instance of the SoundManager class. If an instance has already been created +// then this instance is returned, otherwise a new instance is created and returned. ++ (SoundManager *)sharedSoundManager; + +// Designated initializer. +- (id)init; + +// Plays the sound which is found with |aSoundKey| using the provided |aGain| and |aPitch|. +// |aLocation| is used to set the location of the sound source in relation to the listener +// and |aLoop| specifies if the sound should be continuously looped or not. +- (NSUInteger)playSoundWithKey:(NSString*)aSoundKey gain:(float)aGain pitch:(float)aPitch + location:(CGPoint)aLocation shouldLoop:(BOOL)aLoop sourceID:(NSUInteger)aSourceID; + +// Stops all sounds playing with the supplied sound key +- (void)stopSoundWithKey:(NSString*)aSoundKey; + +// Loads a sound with the supplied key, filename, file extension and frequency. Frequency +// could be worked out from the file but this implementation takes it as an argument. If no +// sound is found with a matching key then nothing happens. +- (void)loadSoundWithKey:(NSString*)aSoundKey musicFile:(NSString*)aMusicFile; + +// Removes the sound with the supplied key from the sound library. This deletes the buffer that was created +// to hold the sound +- (void)removeSoundWithKey:(NSString*)aSoundKey; + +// Plays the music with the supplied key. If no music is found then nothing happens. +// |aRepeatCount| specifies the number of times the music should loop. +- (void)playMusicWithKey:(NSString*)aMusicKey timesToRepeat:(NSUInteger)aRepeatCount; + +// Plays the next track in the play list if there is one +- (void)playNextTrack; + +// Loads the path of a music files into a dictionary with the a key of |aMusicKey| +- (void)loadBackgroundMusicWithKey:(NSString*)aMusicKey musicFile:(NSString*)aMusicFile; + +// Removes the path to the music file with the matching key from the music library array. +- (void)removeBackgroundMusicWithKey:(NSString*)aMusicKey; + +// Adds a track to the named play list +- (void)addToPlaylistNamed:(NSString*)aPlaylistName track:(NSString*)aTrackName; + +// Plays the contents of the named play list +- (void)startPlaylistNamed:(NSString*)aPlaylistName; + +// Removes the named track from the named playlist +- (void)removeFromPlaylistNamed:(NSString*)aPlaylistName track:(NSString*)aTrackName; + +// Removes the named playlist +- (void)removePlaylistNamed:(NSString*)aPlaylistName; + +// Clears the named playlist +- (void)clearPlaylistNamed:(NSString*)aPlaylistName; + +// Stops any currently playing music. +- (void)stopMusic; + +// Pauses any currently playing music. +- (void)pauseMusic; + +// Resumes music that has been paused +- (void)resumeMusic; + +// Fades the music volume down to the specified value over the specified period of time. This method +// does not change the musicVolume for the sound manager which allows you to always get the music volume +// allowing you to fade music down and then back up to the defined value set inside the settings screen for +// example +- (void)fadeMusicVolumeFrom:(float)aFromVolume toVolume:(float)aToVolume duration:(float)aSeconds stop:(BOOL)aStop; + +// Cross fades between the currently playing track and the track specified over the duration +// specified +- (void)crossFadeTo:(NSString*)aTrack duration:(float)aDuration; + +// Shutsdown the SoundManager class and deallocates resources which have been assigned. +- (void)shutdownSoundManager; + +#pragma mark - +#pragma mark SoundManager settings + +// Set the volume for music which is played. +- (void)setMusicVolume:(float)aVolume; + +// Sets the location of the OpenAL listener. +- (void)setListenerPosition:(CGPoint)aPosition; + +// Sets the orientation of the listener. This is used to make sure that sound +// is played correctly based on the direction the player is moving in +- (void)setOrientation:(CGPoint)aPosition; + +// Sets the volume for all sounds which are played. This acts as a global FX volume for +// all sounds. +- (void)setFxVolume:(float)aVolume; + +@end diff --git a/projects/mtg/iOS/SoundManager/SoundManager.m b/projects/mtg/iOS/SoundManager/SoundManager.m new file mode 100644 index 000000000..0920a0e28 --- /dev/null +++ b/projects/mtg/iOS/SoundManager/SoundManager.m @@ -0,0 +1,861 @@ +// +// SoundManager.m +// SLQTSOR +// +// Created by Michael Daley on 22/05/2009. +// Copyright 2009 Michael Daley. All rights reserved. +// + +#import "SoundManager.h" +#import "SynthesizeSingleton.h" +#import "MyOpenALSupport.h" + +#pragma mark - +#pragma mark Private interface + +@interface SoundManager (Private) + +// This method is used to initialize OpenAL. It gets the default device, creates a new context +// to be used and then preloads the define # sources. This preloading means we wil be able to play up to +// (max 32) different sounds at the same time +- (BOOL)initOpenAL; + +// Used to get the next available OpenAL source. The returned source is then bound to a sound +// buffer so that the sound can be played. This method checks each of the available OpenAL +// soucres which have been generated and returns the first source which is not currently being +// used. If no sources are found to be free then the first looping source is returned. If there +// are no looping sources then the first source created is returned +- (NSUInteger)nextAvailableSource; + +// Used to set the current state of OpenAL. When the game is interrupted the OpenAL state is +// stopped and then restarted when the game becomes active again. +- (void)setActivated:(BOOL)aState; + +// If audio is currently playing this method returns YES +- (BOOL)isAudioPlaying; + +// Checks to see if an OpenAL error has been logged. If so it renders the error to the screen +- (void)checkForErrors; + +@end + + +#pragma mark - +#pragma mark Public implementation + +@implementation SoundManager + +// Make this class a singleton class +SYNTHESIZE_SINGLETON_FOR_CLASS(SoundManager); + +@synthesize currentMusicVolume; +@synthesize fxVolume; +@synthesize isExternalAudioPlaying; +@synthesize isMusicPlaying; +@synthesize usePlaylist; +@synthesize loopLastPlaylistTrack; +@synthesize musicVolume; + +#pragma mark - +#pragma mark Dealloc and Init and Shutdown + +- (void)dealloc { + // Loop through the OpenAL sources and delete them + for(NSNumber *sourceIDVal in soundSources) { + NSUInteger sourceID = [sourceIDVal unsignedIntValue]; + alDeleteSources(1, &sourceID); + [self checkForErrors]; + } + + // Loop through the OpenAL buffers and delete + NSEnumerator *enumerator = [soundLibrary keyEnumerator]; + id key; + while ((key = [enumerator nextObject])) { + NSNumber *bufferIDVal = [soundLibrary objectForKey:key]; + NSUInteger bufferID = [bufferIDVal unsignedIntValue]; + alDeleteBuffers(1, &bufferID); + [self checkForErrors]; + } + + // Release the arrays and dictionaries we have been using + [soundLibrary release]; + [soundSources release]; + [musicLibrary release]; + [musicPlaylists release]; + if (currentPlaylistTracks) { + [currentPlaylistTracks release]; + } + + // If background music has been played then release the AVAudioPlayer + if(musicPlayer) + [musicPlayer release]; + + // Disable and then destroy the context + alcMakeContextCurrent(NULL); + [self checkForErrors]; + alcDestroyContext(context); + [self checkForErrors]; + + // Close the device + alcCloseDevice(device); + [self checkForErrors]; + + [super dealloc]; +} + +- (id)init { + self = [super init]; + if(self != nil) { + + // Initialize the array and dictionaries we are going to use + soundSources = [[NSMutableArray alloc] init]; + soundLibrary = [[NSMutableDictionary alloc] init]; + musicLibrary = [[NSMutableDictionary alloc] init]; + musicPlaylists = [[NSMutableDictionary alloc] init]; + + // Grab a reference to the AVAudioSession singleton + audioSession = [AVAudioSession sharedInstance]; + + // Reset the error ivar + audioSessionError = nil; + + // Check to see if music is already playing. If that is the case then you can leave the sound category as AmbientSound. + // If music is not playing we can set the sound category to SoloAmbientSound so that decoding is done using the hardware. + isExternalAudioPlaying = [self isAudioPlaying]; + + if (!isExternalAudioPlaying) { + NSLog(@"INFO - SoundManager: No external audio playing so using the SoloAmbient audio session category"); + soundCategory = AVAudioSessionCategorySoloAmbient; + } else { + NSLog(@"INFO - SoundManager: External sound detected so using the Ambient audio session category"); + soundCategory = AVAudioSessionCategoryAmbient; + } + + // Having decided on the category we then set it + [audioSession setCategory:soundCategory error:&audioSessionError]; + + if (audioSessionError) { + NSLog(@"WARNING - SoundManager: Unable to set the sound category to ambient"); + } + + // Set up the OpenAL. If an error occurs then nil will be returned. + BOOL success = [self initOpenAL]; + if(!success) { + NSLog(@"ERROR - SoundManager: Error initializing OpenAL"); + return nil; + } + + // Set up the listener position + float listener_pos[] = {0, 0, 0}; + float listener_ori[] = {0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; + float listener_vel[] = {0, 0, 0}; + + alListenerfv(AL_POSITION, listener_pos); + [self checkForErrors]; + alListenerfv(AL_ORIENTATION, listener_ori); + [self checkForErrors]; + alListenerfv(AL_VELOCITY, listener_vel); + [self checkForErrors]; + + // Set the default volume for music and fx along the fading flag + currentMusicVolume = 0.5f; + musicVolume = 0.5f; + fxVolume = 0.5f; + playlistIndex = 0; + + // Set up initial flag values + isFading = NO; + isMusicPlaying = NO; + stopMusicAfterFade = YES; + usePlaylist = NO; + loopLastPlaylistTrack = NO; + } + return self; +} + +- (void)shutdownSoundManager { + @synchronized(self) { + if(sharedSoundManager != nil) { + [self dealloc]; + } + } +} + +#pragma mark - +#pragma mark Sound management + +- (void)loadSoundWithKey:(NSString*)aSoundKey musicFile:(NSString*)aMusicFile { + + // Check to make sure that a sound with the same key does not already exist + NSNumber *numVal = [soundLibrary objectForKey:aSoundKey]; + + // If the key is not found log it and finish + if(numVal != nil) { + NSLog(@"WARNING - SoundManager: Sound key '%@' already exists.", aSoundKey); + return; + } + + NSUInteger bufferID; + + // Generate a buffer within OpenAL for this sound + alGenBuffers(1, &bufferID); + [self checkForErrors]; + + // Set up the variables which are going to be used to hold the format + // size and frequency of the sound file we are loading + ALenum format; + ALsizei size; + ALsizei freq; + ALvoid *data; + alError = AL_NO_ERROR; + + NSBundle *bundle = [NSBundle mainBundle]; + + // Get the audio data from the file which has been passed in + NSString *fileName = [[aMusicFile lastPathComponent] stringByDeletingPathExtension]; + NSString *fileType = [aMusicFile pathExtension]; + NSString *filePath = [bundle pathForResource:fileName ofType:fileType]; + if ( filePath == nil ) + filePath = aMusicFile; + + CFURLRef fileURL = (CFURLRef)[[NSURL fileURLWithPath: filePath] retain]; + + if (fileURL) + { + data = MyGetOpenALAudioData(fileURL, &size, &format, &freq); + CFRelease(fileURL); + + if((alError = alGetError()) != AL_NO_ERROR) { + NSLog(@"ERROR - SoundManager: Error loading sound: %@ with error %x\n", fileName, alError); + + } + + // Use the static buffer data API + alBufferData(bufferID, format, data, size, freq); + [self checkForErrors]; + + if((alError = alGetError()) != AL_NO_ERROR) { + NSLog(@"ERROR - SoundManager: Error attaching audio to buffer: %x\n", alError); + } + + // Free the memory we used when getting the audio data + if (data) + free(data); + } + else + { + NSLog(@"ERROR - SoundManager: Could not find file '%@.%@'", fileName, fileType); + if (data) + free(data); + data = NULL; + } + + // Place the buffer ID into the sound library against |aSoundKey| + [soundLibrary setObject:[NSNumber numberWithUnsignedInt:bufferID] forKey:aSoundKey]; + NSLog(@"INFO - SoundManager: Loaded sound with key '%@' into buffer '%d'", aSoundKey, bufferID); +} + +- (void)removeSoundWithKey:(NSString*)aSoundKey { + + // Reset errors in OpenAL + alError = alGetError(); + alError = AL_NO_ERROR; + + // Find the buffer which has been linked to the sound key provided + NSNumber *numVal = [soundLibrary objectForKey:aSoundKey]; + + // If the key is not found log it and finish + if(numVal == nil) { + NSLog(@"WARNING - SoundManager: No sound with key '%@' was found so cannot be removed", aSoundKey); + return; + } + + // Get the buffer number from + NSUInteger bufferID = [numVal unsignedIntValue]; + NSInteger bufferForSource; + NSInteger sourceState; + for(NSNumber *sourceID in soundSources) { + + NSUInteger currentSourceID = [sourceID unsignedIntValue]; + + // Grab the current state of the source and also the buffer attached to it + alGetSourcei(currentSourceID, AL_SOURCE_STATE, &sourceState); + [self checkForErrors]; + alGetSourcei(currentSourceID, AL_BUFFER, &bufferForSource); + [self checkForErrors]; + + // If this source is not playing then unbind it. If it is playing and the buffer it + // is playing is the one we are removing, then also unbind that source from this buffer + if(sourceState != AL_PLAYING || (sourceState == AL_PLAYING && bufferForSource == bufferID)) { + alSourceStop(currentSourceID); + [self checkForErrors]; + alSourcei(currentSourceID, AL_BUFFER, 0); + [self checkForErrors]; + } + } + + // Delete the buffer + alDeleteBuffers(1, &bufferID); + + // Check for any errors + if((alError = alGetError()) != AL_NO_ERROR) { + NSLog(@"ERROR - SoundManager: Could not delete buffer %d with error %x", bufferID, alError); + exit(1); + } + + // Remove the soundkey from the soundLibrary + [soundLibrary removeObjectForKey:aSoundKey]; + + NSLog(@"INFO - SoundManager: Removed sound with key '%@'", aSoundKey); +} + + +- (void)loadBackgroundMusicWithKey:(NSString*)aMusicKey musicFile:(NSString*)aMusicFile { + + // Get the filename and type from the music file name passed in + NSString *fileName = [[aMusicFile lastPathComponent] stringByDeletingPathExtension]; + NSString *fileType = [aMusicFile pathExtension]; + + // Check to make sure that a sound with the same key does not already exist + NSString *path = [musicLibrary objectForKey:aMusicKey]; + + // If the key is found log it and finish + if(path != nil) { + NSLog(@"WARNING - SoundManager: Music with the key '%@' already exists.", aMusicKey); + return; + } + + path = [[NSBundle mainBundle] pathForResource:fileName ofType:fileType]; + if (!path) { + if ( ![[NSFileManager defaultManager] fileExistsAtPath: aMusicFile] ) + { + NSLog(@"WARNING - SoundManager: Cannot find file '%@.%@'", fileName, fileType); + return; + } + else + path = aMusicFile; + } + + [musicLibrary setObject:path forKey:aMusicKey]; + NSLog(@"INFO - SoundManager: Loaded background music with key '%@'", aMusicKey); +} + +- (void)removeBackgroundMusicWithKey:(NSString*)aMusicKey { + NSString *path = [musicLibrary objectForKey:aMusicKey]; + if(path == NULL) { + NSLog(@"WARNING - SoundManager: No music found with key '%@' was found so cannot be removed", aMusicKey); + return; + } + [musicLibrary removeObjectForKey:aMusicKey]; + NSLog(@"INFO - SoundManager: Removed music with key '%@'", aMusicKey); +} + +- (void)addToPlaylistNamed:(NSString*)aPlaylistName track:(NSString*)aTrackName { + + NSString *path = [musicLibrary objectForKey:aTrackName]; + if (!path) { + NSLog(@"WARNING - SoundManager: Track '%@' does not exist in the music library and cannot be added to the play list."); + return; + } + + // See if the playlist already exists + NSMutableArray *playlistTracks = [musicPlaylists objectForKey:aPlaylistName]; + + if (!playlistTracks) { + playlistTracks = [[NSMutableArray alloc] init]; + } + + [playlistTracks addObject:aTrackName]; + + // Add the track key to the play list + [musicPlaylists setObject:playlistTracks forKey:aPlaylistName]; +} + +- (void)startPlaylistNamed:(NSString*)aPlaylistName { + + NSMutableArray *playlistTracks = [musicPlaylists objectForKey:aPlaylistName]; + + if (!playlistTracks) { + NSLog(@"WARNING - SoundManager: No play list exists with the name '%@'", aPlaylistName); + return; + } + + currentPlaylistName = aPlaylistName; + currentPlaylistTracks = playlistTracks; + usePlaylist = YES; + + [self playMusicWithKey:[playlistTracks objectAtIndex:0] timesToRepeat:0]; +} + +- (void)removeFromPlaylistNamed:(NSString*)aPlaylistName track:(NSString*)aTrackName { + + NSMutableArray *playlistTracks = [musicPlaylists objectForKey:aPlaylistName]; + if (playlistTracks) { + int indexToRemove; + for (int index=0; index < [currentPlaylistTracks count]; index++) { + if ([[currentPlaylistTracks objectAtIndex:index] isEqualToString:aTrackName]) { + indexToRemove = index; + break; + } + } + [currentPlaylistTracks removeObjectAtIndex:indexToRemove]; + } +} + +- (void)removePlaylistNamed:(NSString*)aPlaylistName { + [musicPlaylists removeObjectForKey:aPlaylistName]; +} + +- (void)clearPlaylistNamed:(NSString*)aPlaylistName { + NSMutableArray *playlistTracks = [musicPlaylists objectForKey:aPlaylistName]; + + if (playlistTracks) { + [playlistTracks removeAllObjects]; + } +} + +#pragma mark - +#pragma mark Sound control + +- (NSUInteger)playSoundWithKey:(NSString*)aSoundKey gain:(float)aGain pitch:(float)aPitch location:(CGPoint)aLocation shouldLoop:(BOOL)aLoop sourceID:(NSUInteger)aSourceID { + + // Find the buffer linked to the key which has been passed in + NSNumber *numVal = [soundLibrary objectForKey:aSoundKey]; + if(numVal == nil) return 0; + NSUInteger bufferID = [numVal unsignedIntValue]; + + // Find an available source if -1 has been passed in as the sourceID. If the sourceID is + // not -1 i.e. a source ID has been passed in then check to make sure that source is not playing + // and if not play the identified buffer ID within the provided source + NSUInteger sourceID; + if(aSourceID == -1) { + sourceID = [self nextAvailableSource]; + } else { + NSInteger sourceState; + alGetSourcei(aSourceID, AL_SOURCE_STATE, &sourceState); + if(sourceState == AL_PLAYING) + return 0; + sourceID = aSourceID; + } + + // Make sure that the source is clean by resetting the buffer assigned to the source + // to 0 + alSourcei(sourceID, AL_BUFFER, 0); + + // Attach the buffer we have looked up to the source we have just found + alSourcei(sourceID, AL_BUFFER, bufferID); + + // Set the pitch and gain of the source + alSourcef(sourceID, AL_PITCH, aPitch); + alSourcef(sourceID, AL_GAIN, aGain * fxVolume); + + // Set the looping value + if(aLoop) { + alSourcei(sourceID, AL_LOOPING, AL_TRUE); + } else { + alSourcei(sourceID, AL_LOOPING, AL_FALSE); + } + + // Set the source location + alSource3f(sourceID, AL_POSITION, aLocation.x, aLocation.y, 0.0f); + + // Now play the sound + alSourcePlay(sourceID); + alError = alGetError(); + + // Check to see if there were any errors + [self checkForErrors]; + + // Return the source ID so that loops can be stopped etc + return sourceID; +} + + +- (void)stopSoundWithKey:(NSString*)aSoundKey { + + // Reset errors in OpenAL + alError = alGetError(); + alError = AL_NO_ERROR; + + // Find the buffer which has been linked to the sound key provided + NSNumber *numVal = [soundLibrary objectForKey:aSoundKey]; + + // If the key is not found log it and finish + if(numVal == nil) { + NSLog(@"WARNING - SoundManager: No sound with key '%@' was found so cannot be stopped", aSoundKey); + return; + } + + // Get the buffer number from + NSUInteger bufferID = [numVal unsignedIntValue]; + NSInteger bufferForSource; + NSInteger sourceState; + for(NSNumber *sourceID in soundSources) { + + NSUInteger currentSourceID = [sourceID unsignedIntValue]; + + // Grab the current state of the source and also the buffer attached to it + alGetSourcei(currentSourceID, AL_SOURCE_STATE, &sourceState); + alGetSourcei(currentSourceID, AL_BUFFER, &bufferForSource); + + // If this source is not playing then unbind it. If it is playing and the buffer it + // is playing is the one we are removing, then also unbind that source from this buffer + if(bufferForSource == bufferID) { + alSourceStop(currentSourceID); + alSourcei(currentSourceID, AL_BUFFER, 0); + } + } + + // Check for any errors + [self checkForErrors]; + + // Remove the soundkey from the soundLibrary + [soundLibrary removeObjectForKey:aSoundKey]; + + NSLog(@"INFO - SoundManager: Removed sound with key '%@'", aSoundKey); +} + + +- (void)playMusicWithKey:(NSString*)aMusicKey timesToRepeat:(NSUInteger)aRepeatCount { + + NSError *error; + + NSString *path = [musicLibrary objectForKey:aMusicKey]; + + if(!path) { + NSLog(@"ERROR - SoundManager: The music key '%@' could not be found", aMusicKey); + return; + } + + if(musicPlayer) + [musicPlayer release]; + + // Initialize the AVAudioPlayer using the path that we have retrieved from the music library dictionary + musicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error]; + + // If the backgroundMusicPlayer object is nil then there was an error + if(!musicPlayer) { + NSLog(@"ERROR - SoundManager: Could not play music for key '%d'", error); + return; + } + + // Set the delegate for this music player to be the sound manager + musicPlayer.delegate = self; + + // Set the number of times this music should repeat. -1 means never stop until its asked to stop + [musicPlayer setNumberOfLoops:aRepeatCount]; + + // Set the volume of the music + [musicPlayer setVolume:currentMusicVolume]; + + // Play the music + [musicPlayer play]; + + // Set the isMusicPlaying flag + isMusicPlaying = YES; +} + +- (void)playNextTrack { + if (playlistIndex + 1 == [currentPlaylistTracks count]-1 && loopLastPlaylistTrack) { + playlistIndex += 1; + [self playMusicWithKey:[currentPlaylistTracks objectAtIndex:playlistIndex] timesToRepeat:-1]; + } else if (playlistIndex + 1 < [currentPlaylistTracks count]) { + playlistIndex += 1; + [self playMusicWithKey:[currentPlaylistTracks objectAtIndex:playlistIndex] timesToRepeat:0]; + } else if (loopPlaylist) { + playlistIndex = 0; + [self playMusicWithKey:[currentPlaylistTracks objectAtIndex:playlistIndex] timesToRepeat:0]; + } +} + +- (void)stopMusic { + [musicPlayer stop]; + isMusicPlaying = NO; + usePlaylist = NO; +} + + +- (void)pauseMusic { + if(musicPlayer) + [musicPlayer pause]; + isMusicPlaying = NO; +} + +- (void)resumeMusic { + if (musicPlayer) { + [musicPlayer play]; + isMusicPlaying = YES; + } +} + +#pragma mark - +#pragma mark SoundManager settings + +- (void)setMusicVolume:(float)aVolume { + + // Set the volume iVar + if (aVolume > 1) + aVolume = 1.0f; + + currentMusicVolume = aVolume; + musicVolume = aVolume; + + // Check to make sure that the audio player exists and if so set its volume + if(musicPlayer) { + [musicPlayer setVolume:currentMusicVolume]; + } +} + + +- (void)setFxVolume:(float)aVolume { + fxVolume = aVolume; +} + + +- (void)setListenerPosition:(CGPoint)aPosition { + listenerPosition = aPosition; + alListener3f(AL_POSITION, aPosition.x, aPosition.y, 0.0f); +} + + +- (void)setOrientation:(CGPoint)aPosition { + float orientation[] = {aPosition.x, aPosition.y, 0.0f, 0.0f, 0.0f, 1.0f}; + alListenerfv(AL_ORIENTATION, orientation); +} + +- (void)fadeMusicVolumeFrom:(float)aFromVolume toVolume:(float)aToVolume duration:(float)aSeconds stop:(BOOL)aStop { + + // If there is already a fade timer active, invalidate it so we can start another one + if (timer) { + [timer invalidate]; + timer = NULL; + } + + // Work out how much to fade the music by based on the current volume, the requested volume + // and the duration + fadeAmount = (aToVolume - aFromVolume) / (aSeconds / kFadeInterval); + currentMusicVolume = aFromVolume; + + // Reset the fades duration + fadeDuration = 0; + targetFadeDuration = aSeconds; + isFading = YES; + stopMusicAfterFade = aStop; + + // Set up a timer that fires kFadeInterval times per second calling the fadeVolume method + timer = [NSTimer scheduledTimerWithTimeInterval:kFadeInterval target:self selector:@selector(fadeVolume:) userInfo:nil repeats:TRUE]; +} + +- (void)crossFadeTo:(NSString*)aTrack duration:(float)aDuration { + // TODO: Finish this method +} + + +#pragma mark - +#pragma mark AVAudioPlayerDelegate + +- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { + isMusicPlaying = NO; + + // If we are using a play list then handle the next track to be played + if (usePlaylist) { + [self playNextTrack]; + } +} + +#pragma mark - +#pragma mark AVAudioSessionDelegate + +- (void)beginInterruption { + NSLog(@"BEGIN"); + [self setActivated:NO]; +} + +- (void)endInterruption { + [self setActivated:YES]; +} + +@end + + +#pragma mark - +#pragma mark Private implementation + +@implementation SoundManager (Private) + +// Define the number of sources which will be created. iPhone can have a max of 32 +#define MAX_OPENAL_SOURCES 16 + +- (BOOL)initOpenAL { + NSLog(@"INFO - Sound Manager: Initializing sound manager"); + + // Get the device we are going to use for sound. Using NULL gets the default device + device = alcOpenDevice(NULL); + + // If a device has been found we then need to create a context, make it current and then + // preload the OpenAL Sources + if(device) { + // Use the device we have now got to create a context in which to play our sounds + context = alcCreateContext(device, NULL); + [self checkForErrors]; + + // Make the context we have just created into the active context + alcMakeContextCurrent(context); + [self checkForErrors]; + + // Set the distance model to be used + alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); + [self checkForErrors]; + + // Pre-create sound sources which can be dynamically allocated to buffers (sounds) + NSUInteger sourceID; + for(int index = 0; index < MAX_OPENAL_SOURCES; index++) { + // Generate an OpenAL source + alGenSources(1, &sourceID); + [self checkForErrors]; + + // Configure the generated source so that sounds fade as the player moves + // away from them + alSourcef(sourceID, AL_REFERENCE_DISTANCE, 25.0f); + alSourcef(sourceID, AL_MAX_DISTANCE, 150.0f); + alSourcef(sourceID, AL_ROLLOFF_FACTOR, 6.0f); + [self checkForErrors]; + + // Add the generated sourceID to our array of sound sources + [soundSources addObject:[NSNumber numberWithUnsignedInt:sourceID]]; + } + + NSLog(@"INFO - Sound Manager: Finished initializing the sound manager"); + // Return YES as we have successfully initialized OpenAL + return YES; + } + + // We were unable to obtain a device for playing sound so tell the user and return NO. + NSLog(@"ERROR - SoundManager: Unable to allocate a device for sound."); + return NO; +} + + +- (NSUInteger)nextAvailableSource { + + // Holder for the current state of the current source + NSInteger sourceState; + + // Find a source which is not being used at the moment + for(NSNumber *sourceNumber in soundSources) { + alGetSourcei([sourceNumber unsignedIntValue], AL_SOURCE_STATE, &sourceState); + // If this source is not playing then return it + if(sourceState != AL_PLAYING) return [sourceNumber unsignedIntValue]; + } + + // If all the sources are being used we look for the first non looping source + // and use the source associated with that + NSInteger looping; + for(NSNumber *sourceNumber in soundSources) { + alGetSourcei([sourceNumber unsignedIntValue], AL_LOOPING, &looping); + if(!looping) { + // We have found a none looping source so return this source and stop checking + NSUInteger sourceID = [sourceNumber unsignedIntValue]; + alSourceStop(sourceID); + return sourceID; + } + } + + // If there are no looping sources to be found then just use the first source and use that + NSUInteger sourceID = [[soundSources objectAtIndex:0] unsignedIntegerValue]; + alSourceStop(sourceID); + + // Check for any errors that may have been raised + [self checkForErrors]; + + // Return the sourceID found + return sourceID; +} + + +#pragma mark - +#pragma mark Interruption handling + +- (void)setActivated:(BOOL)aState { + + OSStatus result; + + if(aState) { + NSLog(@"INFO - SoundManager: OpenAL Active"); + + // Set the AudioSession AudioCategory to what has been defined in soundCategory + [audioSession setCategory:soundCategory error:&audioSessionError]; + if(audioSessionError) { + NSLog(@"ERROR - SoundManager: Unable to set the audio session category"); + return; + } + + // Set the audio session state to true and report any errors + [audioSession setActive:YES error:&audioSessionError]; + if (audioSessionError) { + NSLog(@"ERROR - SoundManager: Unable to set the audio session state to YES with error %d.", result); + return; + } + + if (musicPlayer) { + [musicPlayer play]; + } + + // As we are finishing the interruption we need to bind back to our context. + alcMakeContextCurrent(context); + [self checkForErrors]; + } else { + NSLog(@"INFO - SoundManager: OpenAL Inactive"); + + // As we are being interrupted we set the current context to NULL. If this sound manager is to be + // compaitble with firmware prior to 3.0 then the context would need to also be destroyed and + // then re-created when the interruption ended. + alcMakeContextCurrent(NULL); + [self checkForErrors]; + } +} + + +- (BOOL)isAudioPlaying { + + UInt32 audioPlaying = 0; + UInt32 audioPlayingSize = sizeof(audioPlaying); + + AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &audioPlayingSize, &audioPlaying); + + return (BOOL)audioPlaying; +} + + +- (void)fadeVolume:(NSTimer*)aTimer { + fadeDuration += kFadeInterval; + if (fadeDuration > targetFadeDuration) { + if (timer) { + [timer invalidate]; + timer = NULL; + } + + isFading = NO; + if (stopMusicAfterFade) { + [musicPlayer stop]; + isMusicPlaying = NO; + } + } else { + currentMusicVolume += fadeAmount; + } + + // If music is current playing then set its volume + if(isMusicPlaying) { + [musicPlayer setVolume:currentMusicVolume]; + } +} + +- (void)checkForErrors { + alError = alGetError(); + if(alError != AL_NO_ERROR) { + NSLog(@"ERROR - SoundManager: OpenAL reported error '%d'", alError); + } +} + +@end + diff --git a/projects/mtg/iOS/SoundManager/SynthesizeSingleton.h b/projects/mtg/iOS/SoundManager/SynthesizeSingleton.h new file mode 100644 index 000000000..bfd8ed96e --- /dev/null +++ b/projects/mtg/iOS/SoundManager/SynthesizeSingleton.h @@ -0,0 +1,68 @@ +// +// SynthesizeSingleton.h +// CocoaWithLove +// +// Created by Matt Gallagher on 20/10/08. +// Copyright 2009 Matt Gallagher. All rights reserved. +// +// Permission is given to use this source code file without charge in any +// project, commercial or otherwise, entirely at your risk, with the condition +// that any redistribution (in part or whole) of source code must retain +// this copyright and permission notice. Attribution in compiled projects is +// appreciated but not required. +// + +#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \ + \ +static classname *shared##classname = nil; \ + \ ++ (classname *)shared##classname \ +{ \ + @synchronized(self) \ + { \ + if (shared##classname == nil) \ + { \ + shared##classname = [[self alloc] init]; \ + } \ + } \ + \ + return shared##classname; \ +} \ + \ ++ (id)allocWithZone:(NSZone *)zone \ +{ \ + @synchronized(self) \ + { \ + if (shared##classname == nil) \ + { \ + shared##classname = [super allocWithZone:zone]; \ + return shared##classname; \ + } \ + } \ + \ + return nil; \ +} \ + \ +- (id)copyWithZone:(NSZone *)zone \ +{ \ + return self; \ +} \ + \ +- (id)retain \ +{ \ + return self; \ +} \ + \ +- (NSUInteger)retainCount \ +{ \ + return NSUIntegerMax; \ +} \ + \ +- (void)release \ +{ \ +} \ + \ +- (id)autorelease \ +{ \ + return self; \ +} diff --git a/projects/mtg/wagic.xcodeproj/project.pbxproj b/projects/mtg/wagic.xcodeproj/project.pbxproj index 4f200a3f0..7b029797c 100755 --- a/projects/mtg/wagic.xcodeproj/project.pbxproj +++ b/projects/mtg/wagic.xcodeproj/project.pbxproj @@ -56,7 +56,6 @@ 12059D9814980B7300DAC43B /* JSpline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232D3128A01F400C34032 /* JSpline.cpp */; }; 12059D9914980B7300DAC43B /* JSprite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232D4128A01F400C34032 /* JSprite.cpp */; }; 12059D9A14980B7300DAC43B /* JGfx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232D8128A01F400C34032 /* JGfx.cpp */; }; - 12059D9B14980B7300DAC43B /* JSfx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232D9128A01F400C34032 /* JSfx.cpp */; }; 12059D9C14980B7300DAC43B /* tinystr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232DE128A01F400C34032 /* tinystr.cpp */; }; 12059D9D14980B7300DAC43B /* tinyxml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232E0128A01F400C34032 /* tinyxml.cpp */; }; 12059D9E14980B7300DAC43B /* tinyxmlerror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232E2128A01F400C34032 /* tinyxmlerror.cpp */; }; @@ -323,11 +322,8 @@ 128ED4F9148BC94D00C58E83 /* CJSONSerializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 128ED496148BC94C00C58E83 /* CJSONSerializer.m */; }; 128ED4FA148BC94D00C58E83 /* CSerializedJSONData.m in Sources */ = {isa = PBXBuildFile; fileRef = 128ED498148BC94C00C58E83 /* CSerializedJSONData.m */; }; 128ED508148BCB7D00C58E83 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 128ED507148BCB7D00C58E83 /* CoreLocation.framework */; }; - 128ED50C148BCBBC00C58E83 /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 128ED509148BCBBC00C58E83 /* AddressBook.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 128ED50D148BCBBC00C58E83 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 128ED50A148BCBBC00C58E83 /* AVFoundation.framework */; }; - 128ED50E148BCBBC00C58E83 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 128ED50B148BCBBC00C58E83 /* MapKit.framework */; }; 128ED510148BCC1900C58E83 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 128ED50F148BCC1900C58E83 /* libsqlite3.dylib */; settings = {ATTRIBUTES = (Weak, ); }; }; - 128ED519148BF0E000C58E83 /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 128ED518148BF0E000C58E83 /* MediaPlayer.framework */; }; 129654D1148A52740031100B /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 129654D0148A52730031100B /* iAd.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 129654D6148AA23A0031100B /* modrules.xml in Resources */ = {isa = PBXBuildFile; fileRef = 129654D5148AA2390031100B /* modrules.xml */; }; 12B812341404B9E20092E303 /* !Pak0.cpk in Resources */ = {isa = PBXBuildFile; fileRef = 12B8121F1404B9E10092E303 /* !Pak0.cpk */; }; @@ -345,6 +341,14 @@ 12B8124F1404BD0D0092E303 /* ObjectAnalytics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12B8124C1404BD0D0092E303 /* ObjectAnalytics.cpp */; }; 12CCA030144A05D100E343A0 /* AbilityParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12CCA02F144A05D100E343A0 /* AbilityParser.cpp */; }; 12D095E114417D0500F69056 /* libstdc++.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 12D095E014417D0500F69056 /* libstdc++.dylib */; settings = {ATTRIBUTES = (Weak, ); }; }; + 12DCD02114DB917F0023B966 /* MyOpenALSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 12DCD01C14DB917F0023B966 /* MyOpenALSupport.c */; }; + 12DCD02214DB917F0023B966 /* MyOpenALSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 12DCD01C14DB917F0023B966 /* MyOpenALSupport.c */; }; + 12DCD02314DB917F0023B966 /* SoundManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 12DCD01F14DB917F0023B966 /* SoundManager.m */; }; + 12DCD02414DB917F0023B966 /* SoundManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 12DCD01F14DB917F0023B966 /* SoundManager.m */; }; + 12DCD02D14DBE1F90023B966 /* JSfx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12DCD02C14DBE1F90023B966 /* JSfx.cpp */; }; + 12DCD02E14DBE1F90023B966 /* JSfx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 12DCD02C14DBE1F90023B966 /* JSfx.cpp */; }; + 12DCD03414DBECC50023B966 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12DCD03114DBECC50023B966 /* CoreAudio.framework */; }; + 12DCD03514DBECC50023B966 /* OpenAL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 12DCD03214DBECC50023B966 /* OpenAL.framework */; }; 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 28FD15000DC6FC520079059D /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 28FD14FF0DC6FC520079059D /* OpenGLES.framework */; }; @@ -489,7 +493,6 @@ CEE2331A128A01F400C34032 /* JSpline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232D3128A01F400C34032 /* JSpline.cpp */; }; CEE2331B128A01F400C34032 /* JSprite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232D4128A01F400C34032 /* JSprite.cpp */; }; CEE2331E128A01F400C34032 /* JGfx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232D8128A01F400C34032 /* JGfx.cpp */; }; - CEE2331F128A01F400C34032 /* JSfx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232D9128A01F400C34032 /* JSfx.cpp */; }; CEE23323128A01F400C34032 /* tinystr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232DE128A01F400C34032 /* tinystr.cpp */; }; CEE23324128A01F400C34032 /* tinyxml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232E0128A01F400C34032 /* tinyxml.cpp */; }; CEE23325128A01F400C34032 /* tinyxmlerror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CEE232E2128A01F400C34032 /* tinyxmlerror.cpp */; }; @@ -694,6 +697,15 @@ 12CCA02F144A05D100E343A0 /* AbilityParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbilityParser.cpp; sourceTree = ""; }; 12CCA032144A05DF00E343A0 /* AbilityParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbilityParser.h; sourceTree = ""; }; 12D095E014417D0500F69056 /* libstdc++.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libstdc++.dylib"; path = "usr/lib/libstdc++.dylib"; sourceTree = SDKROOT; }; + 12DCD01C14DB917F0023B966 /* MyOpenALSupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = MyOpenALSupport.c; sourceTree = ""; }; + 12DCD01D14DB917F0023B966 /* MyOpenALSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyOpenALSupport.h; sourceTree = ""; }; + 12DCD01E14DB917F0023B966 /* SoundManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SoundManager.h; sourceTree = ""; }; + 12DCD01F14DB917F0023B966 /* SoundManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SoundManager.m; sourceTree = ""; }; + 12DCD02014DB917F0023B966 /* SynthesizeSingleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SynthesizeSingleton.h; sourceTree = ""; }; + 12DCD02C14DBE1F90023B966 /* JSfx.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = JSfx.cpp; path = ../../JGE/src/iOS/JSfx.cpp; sourceTree = SOURCE_ROOT; }; + 12DCD03014DBECC40023B966 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; }; + 12DCD03114DBECC50023B966 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; }; + 12DCD03214DBECC50023B966 /* OpenAL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenAL.framework; path = System/Library/Frameworks/OpenAL.framework; sourceTree = SDKROOT; }; 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 1D6058910D05DD3D006BFB54 /* wagic.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = wagic.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; @@ -952,7 +964,7 @@ CEE2323A128A01DD00C34032 /* JParticleSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JParticleSystem.h; sourceTree = ""; }; CEE2323B128A01DD00C34032 /* JRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JRenderer.h; sourceTree = ""; }; CEE2323C128A01DD00C34032 /* JResourceManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JResourceManager.h; sourceTree = ""; }; - CEE2323E128A01DD00C34032 /* JSoundSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSoundSystem.h; sourceTree = ""; }; + CEE2323E128A01DD00C34032 /* JSoundSystem.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = JSoundSystem.h; sourceTree = ""; }; CEE2323F128A01DD00C34032 /* JSpline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSpline.h; sourceTree = ""; }; CEE23240128A01DD00C34032 /* JSprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSprite.h; sourceTree = ""; }; CEE23242128A01DD00C34032 /* JTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JTypes.h; sourceTree = ""; }; @@ -1034,6 +1046,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 12DCD03414DBECC50023B966 /* CoreAudio.framework in Frameworks */, + 12DCD03514DBECC50023B966 /* OpenAL.framework in Frameworks */, + 128ED380148BAEC900C58E83 /* AudioToolbox.framework in Frameworks */, + 128ED50D148BCBBC00C58E83 /* AVFoundation.framework in Frameworks */, 12D095E114417D0500F69056 /* libstdc++.dylib in Frameworks */, 12211EBB14934A2C00641703 /* CFNetwork.framework in Frameworks */, 12211EB914934A1900641703 /* MobileCoreServices.framework in Frameworks */, @@ -1047,14 +1063,9 @@ 28FD15080DC6FC5B0079059D /* QuartzCore.framework in Frameworks */, CED2152C128DFAFF0050149E /* CoreGraphics.framework in Frameworks */, F2494ADC12A1BD4100D6284A /* libz.dylib in Frameworks */, - 128ED380148BAEC900C58E83 /* AudioToolbox.framework in Frameworks */, 128ED381148BAEC900C58E83 /* MessageUI.framework in Frameworks */, 128ED382148BAEC900C58E83 /* SystemConfiguration.framework in Frameworks */, 128ED508148BCB7D00C58E83 /* CoreLocation.framework in Frameworks */, - 128ED50C148BCBBC00C58E83 /* AddressBook.framework in Frameworks */, - 128ED50D148BCBBC00C58E83 /* AVFoundation.framework in Frameworks */, - 128ED50E148BCBBC00C58E83 /* MapKit.framework in Frameworks */, - 128ED519148BF0E000C58E83 /* MediaPlayer.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1340,6 +1351,7 @@ 129654D2148AA2390031100B /* iOS */ = { isa = PBXGroup; children = ( + 12DCD01A14DB913B0023B966 /* Managers */, CE9A478312B514BA00C9F38A /* wagicAppDelegate.h */, CE9A478412B514BA00C9F38A /* wagicAppDelegate.m */, 128FB96A149537A600ED4EE6 /* Images */, @@ -1408,6 +1420,34 @@ path = Debug; sourceTree = ""; }; + 12DCD01A14DB913B0023B966 /* Managers */ = { + isa = PBXGroup; + children = ( + 12DCD01B14DB917F0023B966 /* SoundManager */, + ); + name = Managers; + sourceTree = ""; + }; + 12DCD01B14DB917F0023B966 /* SoundManager */ = { + isa = PBXGroup; + children = ( + 12DCD01C14DB917F0023B966 /* MyOpenALSupport.c */, + 12DCD01D14DB917F0023B966 /* MyOpenALSupport.h */, + 12DCD01E14DB917F0023B966 /* SoundManager.h */, + 12DCD01F14DB917F0023B966 /* SoundManager.m */, + 12DCD02014DB917F0023B966 /* SynthesizeSingleton.h */, + ); + path = SoundManager; + sourceTree = ""; + }; + 12DCD02B14DBE1AF0023B966 /* ios */ = { + isa = PBXGroup; + children = ( + 12DCD02C14DBE1F90023B966 /* JSfx.cpp */, + ); + name = ios; + sourceTree = ""; + }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( @@ -1452,6 +1492,9 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + 12DCD03014DBECC40023B966 /* AudioUnit.framework */, + 12DCD03114DBECC50023B966 /* CoreAudio.framework */, + 12DCD03214DBECC50023B966 /* OpenAL.framework */, 12211EBA14934A2C00641703 /* CFNetwork.framework */, 12211EB814934A1800641703 /* MobileCoreServices.framework */, 1216D632148F7411000F2295 /* libc++abi.dylib */, @@ -1802,6 +1845,7 @@ CEE232AF128A01F400C34032 /* src */ = { isa = PBXGroup; children = ( + 12DCD02B14DBE1AF0023B966 /* ios */, 12B8121D1404B9E10092E303 /* zipFS */, CEE232B3128A01F400C34032 /* hge */, CEE232D7128A01F400C34032 /* pc */, @@ -2027,7 +2071,6 @@ 12059D9814980B7300DAC43B /* JSpline.cpp in Sources */, 12059D9914980B7300DAC43B /* JSprite.cpp in Sources */, 12059D9A14980B7300DAC43B /* JGfx.cpp in Sources */, - 12059D9B14980B7300DAC43B /* JSfx.cpp in Sources */, 12059D9C14980B7300DAC43B /* tinystr.cpp in Sources */, 12059D9D14980B7300DAC43B /* tinyxml.cpp in Sources */, 12059D9E14980B7300DAC43B /* tinyxmlerror.cpp in Sources */, @@ -2203,6 +2246,9 @@ 12059E4814980B7300DAC43B /* WagicDownloadProgressViewController.m in Sources */, 12272FC514CD57CF00192DC7 /* SimpleButton.cpp in Sources */, 12272FC914CD6A3900192DC7 /* InteractiveButton.cpp in Sources */, + 12DCD02214DB917F0023B966 /* MyOpenALSupport.c in Sources */, + 12DCD02414DB917F0023B966 /* SoundManager.m in Sources */, + 12DCD02E14DBE1F90023B966 /* JSfx.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2237,7 +2283,6 @@ CEE2331A128A01F400C34032 /* JSpline.cpp in Sources */, CEE2331B128A01F400C34032 /* JSprite.cpp in Sources */, CEE2331E128A01F400C34032 /* JGfx.cpp in Sources */, - CEE2331F128A01F400C34032 /* JSfx.cpp in Sources */, CEE23323128A01F400C34032 /* tinystr.cpp in Sources */, CEE23324128A01F400C34032 /* tinyxml.cpp in Sources */, CEE23325128A01F400C34032 /* tinyxmlerror.cpp in Sources */, @@ -2413,6 +2458,9 @@ 12211EC91494360C00641703 /* WagicDownloadProgressViewController.m in Sources */, 12272FC414CD57CF00192DC7 /* SimpleButton.cpp in Sources */, 12272FC814CD6A3900192DC7 /* InteractiveButton.cpp in Sources */, + 12DCD02114DB917F0023B966 /* MyOpenALSupport.c in Sources */, + 12DCD02314DB917F0023B966 /* SoundManager.m in Sources */, + 12DCD02D14DBE1F90023B966 /* JSfx.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };