Adds Cocos libraries.
authordsc <david.schoonover@gmail.com>
Wed, 8 Jun 2011 23:08:20 +0000 (16:08 -0700)
committerdsc <david.schoonover@gmail.com>
Wed, 8 Jun 2011 23:08:20 +0000 (16:08 -0700)
198 files changed:
libs/CocosDenshion/CDAudioManager.h [new file with mode: 0644]
libs/CocosDenshion/CDAudioManager.m [new file with mode: 0644]
libs/CocosDenshion/CDConfig.h [new file with mode: 0644]
libs/CocosDenshion/CDOpenALSupport.h [new file with mode: 0644]
libs/CocosDenshion/CDOpenALSupport.m [new file with mode: 0644]
libs/CocosDenshion/CocosDenshion.h [new file with mode: 0644]
libs/CocosDenshion/CocosDenshion.m [new file with mode: 0644]
libs/CocosDenshion/SimpleAudioEngine.h [new file with mode: 0644]
libs/CocosDenshion/SimpleAudioEngine.m [new file with mode: 0644]
libs/FontLabel/FontLabel.h [new file with mode: 0644]
libs/FontLabel/FontLabel.m [new file with mode: 0644]
libs/FontLabel/FontLabelStringDrawing.h [new file with mode: 0644]
libs/FontLabel/FontLabelStringDrawing.m [new file with mode: 0644]
libs/FontLabel/FontManager.h [new file with mode: 0644]
libs/FontLabel/FontManager.m [new file with mode: 0644]
libs/FontLabel/ZAttributedString.h [new file with mode: 0644]
libs/FontLabel/ZAttributedString.m [new file with mode: 0644]
libs/FontLabel/ZAttributedStringPrivate.h [new file with mode: 0644]
libs/FontLabel/ZFont.h [new file with mode: 0644]
libs/FontLabel/ZFont.m [new file with mode: 0644]
libs/TouchJSON/CDataScanner.h [new file with mode: 0644]
libs/TouchJSON/CDataScanner.m [new file with mode: 0644]
libs/TouchJSON/Extensions/CDataScanner_Extensions.h [new file with mode: 0644]
libs/TouchJSON/Extensions/CDataScanner_Extensions.m [new file with mode: 0644]
libs/TouchJSON/Extensions/NSDictionary_JSONExtensions.h [new file with mode: 0644]
libs/TouchJSON/Extensions/NSDictionary_JSONExtensions.m [new file with mode: 0644]
libs/TouchJSON/JSON/CJSONDeserializer.h [new file with mode: 0644]
libs/TouchJSON/JSON/CJSONDeserializer.m [new file with mode: 0644]
libs/TouchJSON/JSON/CJSONScanner.h [new file with mode: 0644]
libs/TouchJSON/JSON/CJSONScanner.m [new file with mode: 0644]
libs/TouchJSON/JSON/CJSONSerializer.h [new file with mode: 0644]
libs/TouchJSON/JSON/CJSONSerializer.m [new file with mode: 0644]
libs/TouchJSON/JSON/JSONRepresentation.h [new file with mode: 0644]
libs/cocos2d/CCAction.h [new file with mode: 0644]
libs/cocos2d/CCAction.m [new file with mode: 0644]
libs/cocos2d/CCActionCamera.h [new file with mode: 0644]
libs/cocos2d/CCActionCamera.m [new file with mode: 0644]
libs/cocos2d/CCActionEase.h [new file with mode: 0644]
libs/cocos2d/CCActionEase.m [new file with mode: 0644]
libs/cocos2d/CCActionGrid.h [new file with mode: 0644]
libs/cocos2d/CCActionGrid.m [new file with mode: 0644]
libs/cocos2d/CCActionGrid3D.h [new file with mode: 0644]
libs/cocos2d/CCActionGrid3D.m [new file with mode: 0644]
libs/cocos2d/CCActionInstant.h [new file with mode: 0644]
libs/cocos2d/CCActionInstant.m [new file with mode: 0644]
libs/cocos2d/CCActionInterval.h [new file with mode: 0644]
libs/cocos2d/CCActionInterval.m [new file with mode: 0644]
libs/cocos2d/CCActionManager.h [new file with mode: 0644]
libs/cocos2d/CCActionManager.m [new file with mode: 0644]
libs/cocos2d/CCActionPageTurn3D.h [new file with mode: 0644]
libs/cocos2d/CCActionPageTurn3D.m [new file with mode: 0644]
libs/cocos2d/CCActionProgressTimer.h [new file with mode: 0644]
libs/cocos2d/CCActionProgressTimer.m [new file with mode: 0644]
libs/cocos2d/CCActionTiledGrid.h [new file with mode: 0644]
libs/cocos2d/CCActionTiledGrid.m [new file with mode: 0644]
libs/cocos2d/CCActionTween.h [new file with mode: 0644]
libs/cocos2d/CCActionTween.m [new file with mode: 0644]
libs/cocos2d/CCAnimation.h [new file with mode: 0644]
libs/cocos2d/CCAnimation.m [new file with mode: 0644]
libs/cocos2d/CCAnimationCache.h [new file with mode: 0644]
libs/cocos2d/CCAnimationCache.m [new file with mode: 0644]
libs/cocos2d/CCAtlasNode.h [new file with mode: 0644]
libs/cocos2d/CCAtlasNode.m [new file with mode: 0644]
libs/cocos2d/CCBlockSupport.h [new file with mode: 0644]
libs/cocos2d/CCBlockSupport.m [new file with mode: 0644]
libs/cocos2d/CCCamera.h [new file with mode: 0644]
libs/cocos2d/CCCamera.m [new file with mode: 0644]
libs/cocos2d/CCConfiguration.h [new file with mode: 0644]
libs/cocos2d/CCConfiguration.m [new file with mode: 0644]
libs/cocos2d/CCDirector.h [new file with mode: 0644]
libs/cocos2d/CCDirector.m [new file with mode: 0644]
libs/cocos2d/CCDrawingPrimitives.h [new file with mode: 0644]
libs/cocos2d/CCDrawingPrimitives.m [new file with mode: 0644]
libs/cocos2d/CCGrabber.h [new file with mode: 0644]
libs/cocos2d/CCGrabber.m [new file with mode: 0644]
libs/cocos2d/CCGrid.h [new file with mode: 0644]
libs/cocos2d/CCGrid.m [new file with mode: 0644]
libs/cocos2d/CCLabelAtlas.h [new file with mode: 0644]
libs/cocos2d/CCLabelAtlas.m [new file with mode: 0644]
libs/cocos2d/CCLabelBMFont.h [new file with mode: 0644]
libs/cocos2d/CCLabelBMFont.m [new file with mode: 0644]
libs/cocos2d/CCLabelTTF.h [new file with mode: 0644]
libs/cocos2d/CCLabelTTF.m [new file with mode: 0644]
libs/cocos2d/CCLayer.h [new file with mode: 0644]
libs/cocos2d/CCLayer.m [new file with mode: 0644]
libs/cocos2d/CCMenu.h [new file with mode: 0644]
libs/cocos2d/CCMenu.m [new file with mode: 0644]
libs/cocos2d/CCMenuItem.h [new file with mode: 0644]
libs/cocos2d/CCMenuItem.m [new file with mode: 0644]
libs/cocos2d/CCMotionStreak.h [new file with mode: 0644]
libs/cocos2d/CCMotionStreak.m [new file with mode: 0644]
libs/cocos2d/CCNode.h [new file with mode: 0644]
libs/cocos2d/CCNode.m [new file with mode: 0644]
libs/cocos2d/CCParallaxNode.h [new file with mode: 0644]
libs/cocos2d/CCParallaxNode.m [new file with mode: 0644]
libs/cocos2d/CCParticleExamples.h [new file with mode: 0644]
libs/cocos2d/CCParticleExamples.m [new file with mode: 0644]
libs/cocos2d/CCParticleSystem.h [new file with mode: 0644]
libs/cocos2d/CCParticleSystem.m [new file with mode: 0644]
libs/cocos2d/CCParticleSystemPoint.h [new file with mode: 0644]
libs/cocos2d/CCParticleSystemPoint.m [new file with mode: 0644]
libs/cocos2d/CCParticleSystemQuad.h [new file with mode: 0644]
libs/cocos2d/CCParticleSystemQuad.m [new file with mode: 0644]
libs/cocos2d/CCProgressTimer.h [new file with mode: 0644]
libs/cocos2d/CCProgressTimer.m [new file with mode: 0644]
libs/cocos2d/CCProtocols.h [new file with mode: 0644]
libs/cocos2d/CCRenderTexture.h [new file with mode: 0644]
libs/cocos2d/CCRenderTexture.m [new file with mode: 0644]
libs/cocos2d/CCRibbon.h [new file with mode: 0644]
libs/cocos2d/CCRibbon.m [new file with mode: 0644]
libs/cocos2d/CCScene.h [new file with mode: 0644]
libs/cocos2d/CCScene.m [new file with mode: 0644]
libs/cocos2d/CCScheduler.h [new file with mode: 0644]
libs/cocos2d/CCScheduler.m [new file with mode: 0644]
libs/cocos2d/CCSprite.h [new file with mode: 0644]
libs/cocos2d/CCSprite.m [new file with mode: 0644]
libs/cocos2d/CCSpriteBatchNode.h [new file with mode: 0644]
libs/cocos2d/CCSpriteBatchNode.m [new file with mode: 0644]
libs/cocos2d/CCSpriteFrame.h [new file with mode: 0644]
libs/cocos2d/CCSpriteFrame.m [new file with mode: 0644]
libs/cocos2d/CCSpriteFrameCache.h [new file with mode: 0644]
libs/cocos2d/CCSpriteFrameCache.m [new file with mode: 0644]
libs/cocos2d/CCTMXLayer.h [new file with mode: 0644]
libs/cocos2d/CCTMXLayer.m [new file with mode: 0644]
libs/cocos2d/CCTMXObjectGroup.h [new file with mode: 0644]
libs/cocos2d/CCTMXObjectGroup.m [new file with mode: 0644]
libs/cocos2d/CCTMXTiledMap.h [new file with mode: 0644]
libs/cocos2d/CCTMXTiledMap.m [new file with mode: 0644]
libs/cocos2d/CCTMXXMLParser.h [new file with mode: 0644]
libs/cocos2d/CCTMXXMLParser.m [new file with mode: 0644]
libs/cocos2d/CCTexture2D.h [new file with mode: 0644]
libs/cocos2d/CCTexture2D.m [new file with mode: 0644]
libs/cocos2d/CCTextureAtlas.h [new file with mode: 0644]
libs/cocos2d/CCTextureAtlas.m [new file with mode: 0644]
libs/cocos2d/CCTextureCache.h [new file with mode: 0644]
libs/cocos2d/CCTextureCache.m [new file with mode: 0644]
libs/cocos2d/CCTexturePVR.h [new file with mode: 0644]
libs/cocos2d/CCTexturePVR.m [new file with mode: 0644]
libs/cocos2d/CCTileMapAtlas.h [new file with mode: 0644]
libs/cocos2d/CCTileMapAtlas.m [new file with mode: 0644]
libs/cocos2d/CCTransition.h [new file with mode: 0644]
libs/cocos2d/CCTransition.m [new file with mode: 0644]
libs/cocos2d/CCTransitionPageTurn.h [new file with mode: 0644]
libs/cocos2d/CCTransitionPageTurn.m [new file with mode: 0644]
libs/cocos2d/CCTransitionRadial.h [new file with mode: 0644]
libs/cocos2d/CCTransitionRadial.m [new file with mode: 0644]
libs/cocos2d/Platforms/CCGL.h [new file with mode: 0644]
libs/cocos2d/Platforms/CCNS.h [new file with mode: 0644]
libs/cocos2d/Platforms/Mac/CCDirectorMac.h [new file with mode: 0644]
libs/cocos2d/Platforms/Mac/CCDirectorMac.m [new file with mode: 0644]
libs/cocos2d/Platforms/Mac/CCEventDispatcher.h [new file with mode: 0644]
libs/cocos2d/Platforms/Mac/CCEventDispatcher.m [new file with mode: 0644]
libs/cocos2d/Platforms/Mac/MacGLView.h [new file with mode: 0644]
libs/cocos2d/Platforms/Mac/MacGLView.m [new file with mode: 0644]
libs/cocos2d/Platforms/Mac/MacWindow.h [new file with mode: 0644]
libs/cocos2d/Platforms/Mac/MacWindow.m [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/CCDirectorIOS.h [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/CCDirectorIOS.m [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/CCTouchDelegateProtocol.h [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/CCTouchDispatcher.h [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/CCTouchDispatcher.m [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/CCTouchHandler.h [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/CCTouchHandler.m [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/EAGLView.h [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/EAGLView.m [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/ES1Renderer.h [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/ES1Renderer.m [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/ESRenderer.h [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/glu.c [new file with mode: 0644]
libs/cocos2d/Platforms/iOS/glu.h [new file with mode: 0644]
libs/cocos2d/Support/CCArray.h [new file with mode: 0644]
libs/cocos2d/Support/CCArray.m [new file with mode: 0644]
libs/cocos2d/Support/CCFileUtils.h [new file with mode: 0644]
libs/cocos2d/Support/CCFileUtils.m [new file with mode: 0644]
libs/cocos2d/Support/CCProfiling.h [new file with mode: 0644]
libs/cocos2d/Support/CCProfiling.m [new file with mode: 0644]
libs/cocos2d/Support/CGPointExtension.h [new file with mode: 0644]
libs/cocos2d/Support/CGPointExtension.m [new file with mode: 0644]
libs/cocos2d/Support/OpenGL_Internal.h [new file with mode: 0644]
libs/cocos2d/Support/TGAlib.h [new file with mode: 0644]
libs/cocos2d/Support/TGAlib.m [new file with mode: 0644]
libs/cocos2d/Support/TransformUtils.h [new file with mode: 0644]
libs/cocos2d/Support/TransformUtils.m [new file with mode: 0644]
libs/cocos2d/Support/ZipUtils.h [new file with mode: 0644]
libs/cocos2d/Support/ZipUtils.m [new file with mode: 0644]
libs/cocos2d/Support/base64.c [new file with mode: 0644]
libs/cocos2d/Support/base64.h [new file with mode: 0644]
libs/cocos2d/Support/ccCArray.h [new file with mode: 0644]
libs/cocos2d/Support/ccUtils.c [new file with mode: 0644]
libs/cocos2d/Support/ccUtils.h [new file with mode: 0644]
libs/cocos2d/Support/uthash.h [new file with mode: 0644]
libs/cocos2d/Support/utlist.h [new file with mode: 0644]
libs/cocos2d/ccConfig.h [new file with mode: 0644]
libs/cocos2d/ccMacros.h [new file with mode: 0644]
libs/cocos2d/ccTypes.h [new file with mode: 0644]
libs/cocos2d/cocos2d.h [new file with mode: 0644]
libs/cocos2d/cocos2d.m [new file with mode: 0644]
src/game/QQGame.mm

diff --git a/libs/CocosDenshion/CDAudioManager.h b/libs/CocosDenshion/CDAudioManager.h
new file mode 100644 (file)
index 0000000..2475929
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ Copyright (c) 2010 Steve Oldmeadow
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ $Id$
+ */
+
+#import "CocosDenshion.h"
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 30000
+    #import <AVFoundation/AVFoundation.h>
+#else
+    #import "CDXMacOSXSupport.h"
+#endif
+
+/** Different modes of the engine */
+typedef enum {
+       kAMM_FxOnly,                                    //!Other apps will be able to play audio
+       kAMM_FxPlusMusic,                               //!Only this app will play audio
+       kAMM_FxPlusMusicIfNoOtherAudio, //!If another app is playing audio at start up then allow it to continue and don't play music
+       kAMM_MediaPlayback,                             //!This app takes over audio e.g music player app
+       kAMM_PlayAndRecord                              //!App takes over audio and has input and output
+} tAudioManagerMode;
+
+/** Possible states of the engine */
+typedef enum {
+       kAMStateUninitialised, //!Audio manager has not been initialised - do not use
+       kAMStateInitialising,  //!Audio manager is in the process of initialising - do not use
+       kAMStateInitialised        //!Audio manager is initialised - safe to use
+} tAudioManagerState;
+
+typedef enum {
+       kAMRBDoNothing,                     //Audio manager will not do anything on resign or becoming active
+       kAMRBStopPlay,                          //Background music is stopped on resign and resumed on become active
+       kAMRBStop                                       //Background music is stopped on resign but not resumed - maybe because you want to do this from within your game
+} tAudioManagerResignBehavior;
+
+/** Notifications */
+extern NSString * const kCDN_AudioManagerInitialised;
+
+@interface CDAsynchInitialiser : NSOperation {}        
+@end
+
+/** CDAudioManager supports two long audio source channels called left and right*/
+typedef enum {
+       kASC_Left = 0,
+       kASC_Right = 1
+} tAudioSourceChannel; 
+
+typedef enum {
+       kLAS_Init,
+       kLAS_Loaded,
+       kLAS_Playing,
+       kLAS_Paused,
+       kLAS_Stopped,
+} tLongAudioSourceState;
+
+@class CDLongAudioSource;
+@protocol CDLongAudioSourceDelegate <NSObject>
+@optional
+/** The audio source completed playing */
+- (void) cdAudioSourceDidFinishPlaying:(CDLongAudioSource *) audioSource;
+/** The file used to load the audio source has changed */
+- (void) cdAudioSourceFileDidChange:(CDLongAudioSource *) audioSource;
+@end
+
+/**
+ CDLongAudioSource represents an audio source that has a long duration which makes
+ it costly to load into memory for playback as an effect using CDSoundEngine. Examples
+ include background music and narration tracks. The audio file may or may not be compressed.
+ Bear in mind that current iDevices can only use hardware to decode a single compressed
+ audio file at a time and playing multiple compressed files will result in a performance drop
+ as software decompression will take place.
+ @since v0.99
+ */
+@interface CDLongAudioSource : NSObject <AVAudioPlayerDelegate, CDAudioInterruptProtocol>{
+       AVAudioPlayer   *audioSourcePlayer;
+       NSString                *audioSourceFilePath;
+       NSInteger               numberOfLoops;
+       float                   volume;
+       id<CDLongAudioSourceDelegate> delegate; 
+       BOOL                    mute;
+       BOOL                    enabled_;
+       BOOL                    backgroundMusic;
+@public        
+       BOOL                    systemPaused;//Used for auto resign handling
+       NSTimeInterval  systemPauseLocation;//Used for auto resign handling
+@protected
+       tLongAudioSourceState state;
+}      
+@property (readonly) AVAudioPlayer *audioSourcePlayer;
+@property (readonly) NSString *audioSourceFilePath;
+@property (readwrite, nonatomic) NSInteger numberOfLoops;
+@property (readwrite, nonatomic) float volume;
+@property (assign) id<CDLongAudioSourceDelegate> delegate;
+/* This long audio source functions as background music */
+@property (readwrite, nonatomic) BOOL backgroundMusic;
+
+/** Loads the file into the audio source */
+-(void) load:(NSString*) filePath;
+/** Plays the audio source */
+-(void) play;
+/** Stops playing the audio soruce */
+-(void) stop;
+/** Pauses the audio source */
+-(void) pause;
+/** Rewinds the audio source */
+-(void) rewind;
+/** Resumes playing the audio source if it was paused */
+-(void) resume;
+/** Returns whether or not the audio source is playing */
+-(BOOL) isPlaying;
+
+@end
+
+/** 
+ CDAudioManager manages audio requirements for a game.  It provides access to a CDSoundEngine object
+ for playing sound effects.  It provides access to two CDLongAudioSource object (left and right channel)
+ for playing long duration audio such as background music and narration tracks.  Additionally it manages
+ the audio session to take care of things like audio session interruption and interacting with the audio
+ of other apps that are running on the device.
+ Requirements:
+ - Firmware: OS 2.2 or greater 
+ - Files: CDAudioManager.*, CocosDenshion.*
+ - Frameworks: OpenAL, AudioToolbox, AVFoundation
+ @since v0.8
+ */
+@interface CDAudioManager : NSObject <CDLongAudioSourceDelegate, CDAudioInterruptProtocol, AVAudioSessionDelegate> {
+       CDSoundEngine           *soundEngine;
+       CDLongAudioSource       *backgroundMusic;
+       NSMutableArray          *audioSourceChannels;
+       NSString*                       _audioSessionCategory;
+       BOOL                            _audioWasPlayingAtStartup;
+       tAudioManagerMode       _mode;
+       SEL backgroundMusicCompletionSelector;
+       id backgroundMusicCompletionListener;
+       BOOL willPlayBackgroundMusic;
+       BOOL _mute;
+       BOOL _resigned;
+       BOOL _interrupted;
+       BOOL _audioSessionActive;
+       BOOL enabled_;
+       
+       //For handling resign/become active
+       BOOL _isObservingAppEvents;
+       tAudioManagerResignBehavior _resignBehavior;
+}
+
+@property (readonly) CDSoundEngine *soundEngine;
+@property (readonly) CDLongAudioSource *backgroundMusic;
+@property (readonly) BOOL willPlayBackgroundMusic;
+
+/** Returns the shared singleton */
++ (CDAudioManager *) sharedManager;
++ (tAudioManagerState) sharedManagerState;
+/** Configures the shared singleton with a mode*/
++ (void) configure: (tAudioManagerMode) mode;
+/** Initializes the engine asynchronously with a mode */
++ (void) initAsynchronously: (tAudioManagerMode) mode;
+/** Initializes the engine synchronously with a mode, channel definition and a total number of channels */
+- (id) init: (tAudioManagerMode) mode;
+-(void) audioSessionInterrupted;
+-(void) audioSessionResumed;
+-(void) setResignBehavior:(tAudioManagerResignBehavior) resignBehavior autoHandle:(BOOL) autoHandle;
+/** Returns true is audio is muted at a hardware level e.g user has ringer switch set to off */
+-(BOOL) isDeviceMuted;
+/** Returns true if another app is playing audio such as the iPod music player */
+-(BOOL) isOtherAudioPlaying;
+/** Sets the way the audio manager interacts with the operating system such as whether it shares output with other apps or obeys the mute switch */
+-(void) setMode:(tAudioManagerMode) mode;
+/** Shuts down the shared audio manager instance so that it can be reinitialised */
++(void) end;
+
+/** Call if you want to use built in resign behavior but need to do some additional audio processing on resign active. */
+- (void) applicationWillResignActive;
+/** Call if you want to use built in resign behavior but need to do some additional audio processing on become active. */
+- (void) applicationDidBecomeActive;
+
+//New AVAudioPlayer API
+/** Loads the data from the specified file path to the channel's audio source */
+-(CDLongAudioSource*) audioSourceLoad:(NSString*) filePath channel:(tAudioSourceChannel) channel;
+/** Retrieves the audio source for the specified channel */
+-(CDLongAudioSource*) audioSourceForChannel:(tAudioSourceChannel) channel;
+
+//Legacy AVAudioPlayer API
+/** Plays music in background. The music can be looped or not
+ It is recommended to use .aac files as background music since they are decoded by the device (hardware).
+ */
+-(void) playBackgroundMusic:(NSString*) filePath loop:(BOOL) loop;
+/** Preloads a background music */
+-(void) preloadBackgroundMusic:(NSString*) filePath;
+/** Stops playing the background music */
+-(void) stopBackgroundMusic;
+/** Pauses the background music */
+-(void) pauseBackgroundMusic;
+/** Rewinds the background music */
+-(void) rewindBackgroundMusic;
+/** Resumes playing the background music */
+-(void) resumeBackgroundMusic;
+/** Returns whether or not the background music is playing */
+-(BOOL) isBackgroundMusicPlaying;
+
+-(void) setBackgroundMusicCompletionListener:(id) listener selector:(SEL) selector;
+
+@end
+
+/** Fader for long audio source objects */
+@interface CDLongAudioSourceFader : CDPropertyModifier{}
+@end
+
+static const int kCDNoBuffer = -1;
+
+/** Allows buffers to be associated with file names */
+@interface CDBufferManager:NSObject{
+       NSMutableDictionary* loadedBuffers;
+       NSMutableArray  *freedBuffers;
+       CDSoundEngine *soundEngine;
+       int nextBufferId;
+}
+
+-(id) initWithEngine:(CDSoundEngine *) theSoundEngine;
+-(int) bufferForFile:(NSString*) filePath create:(BOOL) create;
+-(void) releaseBufferForFile:(NSString *) filePath;
+
+@end
+
diff --git a/libs/CocosDenshion/CDAudioManager.m b/libs/CocosDenshion/CDAudioManager.m
new file mode 100644 (file)
index 0000000..0929f3c
--- /dev/null
@@ -0,0 +1,887 @@
+/*
+ Copyright (c) 2010 Steve Oldmeadow
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ $Id$
+ */
+
+
+#import "CDAudioManager.h"
+
+NSString * const kCDN_AudioManagerInitialised = @"kCDN_AudioManagerInitialised";
+
+//NSOperation object used to asynchronously initialise 
+@implementation CDAsynchInitialiser
+
+-(void) main {
+       [super main];
+       [CDAudioManager sharedManager];
+}      
+
+@end
+
+@implementation CDLongAudioSource
+
+@synthesize audioSourcePlayer, audioSourceFilePath, delegate, backgroundMusic;
+
+-(id) init {
+       if ((self = [super init])) {
+               state = kLAS_Init;
+               volume = 1.0f;
+               mute = NO;
+               enabled_ = YES;
+       }
+       return self;
+}
+
+-(void) dealloc {
+       CDLOGINFO(@"Denshion::CDLongAudioSource - deallocating %@", self);
+       [audioSourcePlayer release];
+       [audioSourceFilePath release];
+       [super dealloc];
+}      
+
+-(void) load:(NSString*) filePath {
+       //We have alread loaded a file previously,  check if we are being asked to load the same file
+       if (state == kLAS_Init || ![filePath isEqualToString:audioSourceFilePath]) {
+               CDLOGINFO(@"Denshion::CDLongAudioSource - Loading new audio source %@",filePath);
+               //New file
+               if (state != kLAS_Init) {
+                       [audioSourceFilePath release];//Release old file path
+                       [audioSourcePlayer release];//Release old AVAudioPlayer, they can't be reused
+               }
+               audioSourceFilePath = [filePath copy];
+               NSError *error = nil;
+               NSString *path = [CDUtilities fullPathFromRelativePath:audioSourceFilePath];
+               audioSourcePlayer = [(AVAudioPlayer*)[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
+               if (error == nil) {
+                       [audioSourcePlayer prepareToPlay];
+                       audioSourcePlayer.delegate = self;
+                       if (delegate && [delegate respondsToSelector:@selector(cdAudioSourceFileDidChange:)]) {
+                               //Tell our delegate the file has changed
+                               [delegate cdAudioSourceFileDidChange:self];
+                       }       
+               } else {
+                       CDLOG(@"Denshion::CDLongAudioSource - Error initialising audio player: %@",error);
+               }       
+       } else {
+               //Same file - just return it to a consistent state
+               [self pause];
+               [self rewind];
+       }
+       audioSourcePlayer.volume = volume;
+       audioSourcePlayer.numberOfLoops = numberOfLoops;
+       state = kLAS_Loaded;
+}      
+
+-(void) play {
+       if (enabled_) {
+               self->systemPaused = NO;
+               [audioSourcePlayer play];
+       } else {
+               CDLOGINFO(@"Denshion::CDLongAudioSource long audio source didn't play because it is disabled");
+       }       
+}      
+
+-(void) stop {
+       [audioSourcePlayer stop];
+}      
+
+-(void) pause {
+       [audioSourcePlayer pause];
+}      
+
+-(void) rewind {
+       [audioSourcePlayer setCurrentTime:0];
+}
+
+-(void) resume {
+       [audioSourcePlayer play];
+}      
+
+-(BOOL) isPlaying {
+       if (state != kLAS_Init) {
+               return [audioSourcePlayer isPlaying];
+       } else {
+               return NO;
+       }
+}
+
+-(void) setVolume:(float) newVolume
+{
+       volume = newVolume;
+       if (state != kLAS_Init && !mute) {
+               audioSourcePlayer.volume = newVolume;
+       }       
+}
+
+-(float) volume 
+{
+       return volume;
+}
+
+#pragma mark Audio Interrupt Protocol
+-(BOOL) mute
+{
+       return mute;
+}      
+
+-(void) setMute:(BOOL) muteValue 
+{
+       if (mute != muteValue) {
+               if (mute) {
+                       //Turn sound back on
+                       audioSourcePlayer.volume = volume;
+               } else {
+                       audioSourcePlayer.volume = 0.0f;
+               }
+               mute = muteValue;
+       }       
+}      
+
+-(BOOL) enabled 
+{
+       return enabled_;
+}      
+
+-(void) setEnabled:(BOOL)enabledValue 
+{
+       if (enabledValue != enabled_) {
+               enabled_ = enabledValue;
+               if (!enabled_) {
+                       //"Stop" the sounds
+                       [self pause];
+                       [self rewind];
+               }       
+       }       
+}      
+
+-(NSInteger) numberOfLoops {
+       return numberOfLoops;
+}      
+
+-(void) setNumberOfLoops:(NSInteger) loopCount
+{
+       audioSourcePlayer.numberOfLoops = loopCount;
+       numberOfLoops = loopCount;
+}      
+
+- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
+       CDLOGINFO(@"Denshion::CDLongAudioSource - audio player finished");
+#if TARGET_IPHONE_SIMULATOR    
+       CDLOGINFO(@"Denshion::CDLongAudioSource - workaround for OpenAL clobbered audio issue");
+       //This is a workaround for an issue in all simulators (tested to 3.1.2).  Problem is 
+       //that OpenAL audio playback is clobbered when an AVAudioPlayer stops.  Workaround
+       //is to keep the player playing on an endless loop with 0 volume and then when
+       //it is played again reset the volume and set loop count appropriately.
+       //NB: this workaround is not foolproof but it is good enough for most situations.
+       player.numberOfLoops = -1;
+       player.volume = 0;
+       [player play];
+#endif 
+       if (delegate && [delegate respondsToSelector:@selector(cdAudioSourceDidFinishPlaying:)]) {
+               [delegate cdAudioSourceDidFinishPlaying:self];
+       }       
+}      
+
+-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player {
+       CDLOGINFO(@"Denshion::CDLongAudioSource - audio player interrupted");
+}
+
+-(void)audioPlayerEndInterruption:(AVAudioPlayer *)player {
+       CDLOGINFO(@"Denshion::CDLongAudioSource - audio player resumed");
+       if (self.backgroundMusic) {
+               //Check if background music can play as rules may have changed during 
+               //the interruption. This is to address a specific issue in 4.x when
+               //fast task switching
+               if([CDAudioManager sharedManager].willPlayBackgroundMusic) {
+                       [player play];
+               }       
+       } else {
+               [player play];
+       }       
+}      
+
+@end
+
+
+@interface CDAudioManager (PrivateMethods)
+-(BOOL) audioSessionSetActive:(BOOL) active;
+-(BOOL) audioSessionSetCategory:(NSString*) category;
+-(void) badAlContextHandler;
+@end
+
+
+@implementation CDAudioManager
+#define BACKGROUND_MUSIC_CHANNEL kASC_Left
+
+@synthesize soundEngine, willPlayBackgroundMusic;
+static CDAudioManager *sharedManager;
+static tAudioManagerState _sharedManagerState = kAMStateUninitialised;
+static tAudioManagerMode configuredMode;
+static BOOL configured = FALSE;
+
+-(BOOL) audioSessionSetActive:(BOOL) active {
+       NSError *activationError = nil;
+       if ([[AVAudioSession sharedInstance] setActive:active error:&activationError]) {
+               _audioSessionActive = active;
+               CDLOGINFO(@"Denshion::CDAudioManager - Audio session set active %i succeeded", active); 
+               return YES;
+       } else {
+               //Failed
+               CDLOG(@"Denshion::CDAudioManager - Audio session set active %i failed with error %@", active, activationError); 
+               return NO;
+       }       
+}      
+
+-(BOOL) audioSessionSetCategory:(NSString*) category {
+       NSError *categoryError = nil;
+       if ([[AVAudioSession sharedInstance] setCategory:category error:&categoryError]) {
+               CDLOGINFO(@"Denshion::CDAudioManager - Audio session set category %@ succeeded", category); 
+               return YES;
+       } else {
+               //Failed
+               CDLOG(@"Denshion::CDAudioManager - Audio session set category %@ failed with error %@", category, categoryError); 
+               return NO;
+       }       
+}      
+
+// Init
++ (CDAudioManager *) sharedManager
+{
+       @synchronized(self)     {
+               if (!sharedManager) {
+                       if (!configured) {
+                               //Set defaults here
+                               configuredMode = kAMM_FxPlusMusicIfNoOtherAudio;
+                       }
+                       sharedManager = [[CDAudioManager alloc] init:configuredMode];
+                       _sharedManagerState = kAMStateInitialised;//This is only really relevant when using asynchronous initialisation
+                       [[NSNotificationCenter defaultCenter] postNotificationName:kCDN_AudioManagerInitialised object:nil];
+               }       
+       }
+       return sharedManager;
+}
+
++ (tAudioManagerState) sharedManagerState {
+       return _sharedManagerState;
+}      
+
+/**
+ * Call this to set up audio manager asynchronously.  Initialisation is finished when sharedManagerState == kAMStateInitialised
+ */
++ (void) initAsynchronously: (tAudioManagerMode) mode {
+       @synchronized(self) {
+               if (_sharedManagerState == kAMStateUninitialised) {
+                       _sharedManagerState = kAMStateInitialising;
+                       [CDAudioManager configure:mode];
+                       CDAsynchInitialiser *initOp = [[[CDAsynchInitialiser alloc] init] autorelease];
+                       NSOperationQueue *opQ = [[[NSOperationQueue alloc] init] autorelease];
+                       [opQ addOperation:initOp];
+               }       
+       }
+}      
+
++ (id) alloc
+{
+       @synchronized(self)     {
+               NSAssert(sharedManager == nil, @"Attempted to allocate a second instance of a singleton.");
+               return [super alloc];
+       }
+       return nil;
+}
+
+/*
+ * Call this method before accessing the shared manager in order to configure the shared audio manager
+ */
++ (void) configure: (tAudioManagerMode) mode {
+       configuredMode = mode;
+       configured = TRUE;
+}      
+
+-(BOOL) isOtherAudioPlaying {
+       UInt32 isPlaying = 0;
+       UInt32 varSize = sizeof(isPlaying);
+       AudioSessionGetProperty (kAudioSessionProperty_OtherAudioIsPlaying, &varSize, &isPlaying);
+       return (isPlaying != 0);
+}
+
+-(void) setMode:(tAudioManagerMode) mode {
+
+       _mode = mode;
+       switch (_mode) {
+                       
+               case kAMM_FxOnly:
+                       //Share audio with other app
+                       CDLOGINFO(@"Denshion::CDAudioManager - Audio will be shared");
+                       //_audioSessionCategory = kAudioSessionCategory_AmbientSound;
+                       _audioSessionCategory = AVAudioSessionCategoryAmbient;
+                       willPlayBackgroundMusic = NO;
+                       break;
+                       
+               case kAMM_FxPlusMusic:
+                       //Use audio exclusively - if other audio is playing it will be stopped
+                       CDLOGINFO(@"Denshion::CDAudioManager -  Audio will be exclusive");
+                       //_audioSessionCategory = kAudioSessionCategory_SoloAmbientSound;
+                       _audioSessionCategory = AVAudioSessionCategorySoloAmbient;
+                       willPlayBackgroundMusic = YES;
+                       break;
+                       
+               case kAMM_MediaPlayback:
+                       //Use audio exclusively, ignore mute switch and sleep
+                       CDLOGINFO(@"Denshion::CDAudioManager -  Media playback mode, audio will be exclusive");
+                       //_audioSessionCategory = kAudioSessionCategory_MediaPlayback;
+                       _audioSessionCategory = AVAudioSessionCategoryPlayback;
+                       willPlayBackgroundMusic = YES;
+                       break;
+                       
+               case kAMM_PlayAndRecord:
+                       //Use audio exclusively, ignore mute switch and sleep, has inputs and outputs
+                       CDLOGINFO(@"Denshion::CDAudioManager -  Play and record mode, audio will be exclusive");
+                       //_audioSessionCategory = kAudioSessionCategory_PlayAndRecord;
+                       _audioSessionCategory = AVAudioSessionCategoryPlayAndRecord;
+                       willPlayBackgroundMusic = YES;
+                       break;
+                       
+               default:
+                       //kAudioManagerFxPlusMusicIfNoOtherAudio
+                       if ([self isOtherAudioPlaying]) {
+                               CDLOGINFO(@"Denshion::CDAudioManager - Other audio is playing audio will be shared");
+                               //_audioSessionCategory = kAudioSessionCategory_AmbientSound;
+                               _audioSessionCategory = AVAudioSessionCategoryAmbient;
+                               willPlayBackgroundMusic = NO;
+                       } else {
+                               CDLOGINFO(@"Denshion::CDAudioManager - Other audio is not playing audio will be exclusive");
+                               //_audioSessionCategory = kAudioSessionCategory_SoloAmbientSound;
+                               _audioSessionCategory = AVAudioSessionCategorySoloAmbient;
+                               willPlayBackgroundMusic = YES;
+                       }       
+                       
+                       break;
+       }
+        
+       [self audioSessionSetCategory:_audioSessionCategory];
+       
+}      
+
+/**
+ * This method is used to work around various bugs introduced in 4.x OS versions. In some circumstances the 
+ * audio session is interrupted but never resumed, this results in the loss of OpenAL audio when following 
+ * standard practices. If we detect this situation then we will attempt to resume the audio session ourselves.
+ * Known triggers: lock the device then unlock it (iOS 4.2 gm), playback a song using MPMediaPlayer (iOS 4.0)
+ */
+- (void) badAlContextHandler {
+       if (_interrupted && alcGetCurrentContext() == NULL) {
+               CDLOG(@"Denshion::CDAudioManager - bad OpenAL context detected, attempting to resume audio session");
+               [self audioSessionResumed];
+       }       
+}      
+
+- (id) init: (tAudioManagerMode) mode {
+       if ((self = [super init])) {
+               
+               //Initialise the audio session 
+               AVAudioSession* session = [AVAudioSession sharedInstance];
+               session.delegate = self;
+       
+               _mode = mode;
+               backgroundMusicCompletionSelector = nil;
+               _isObservingAppEvents = FALSE;
+               _mute = NO;
+               _resigned = NO;
+               _interrupted = NO;
+               enabled_ = YES;
+               _audioSessionActive = NO;
+               [self setMode:mode];
+               soundEngine = [[CDSoundEngine alloc] init];
+               
+               //Set up audioSource channels
+               audioSourceChannels = [[NSMutableArray alloc] init];
+               CDLongAudioSource *leftChannel = [[CDLongAudioSource alloc] init];
+               leftChannel.backgroundMusic = YES;
+               CDLongAudioSource *rightChannel = [[CDLongAudioSource alloc] init];
+               rightChannel.backgroundMusic = NO;
+               [audioSourceChannels insertObject:leftChannel atIndex:kASC_Left];       
+               [audioSourceChannels insertObject:rightChannel atIndex:kASC_Right];
+               [leftChannel release];
+               [rightChannel release];
+               //Used to support legacy APIs
+               backgroundMusic = [self audioSourceForChannel:BACKGROUND_MUSIC_CHANNEL];
+               backgroundMusic.delegate = self;
+               
+               //Add handler for bad al context messages, these are posted by the sound engine.
+               [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(badAlContextHandler) name:kCDN_BadAlContext object:nil];
+
+       }       
+       return self;            
+}      
+
+-(void) dealloc {
+       CDLOGINFO(@"Denshion::CDAudioManager - deallocating");
+       [self stopBackgroundMusic];
+       [soundEngine release];
+       [[NSNotificationCenter defaultCenter] removeObserver:self];
+       [self audioSessionSetActive:NO];
+       [audioSourceChannels release];
+       [super dealloc];
+}      
+
+/** Retrieves the audio source for the specified channel */
+-(CDLongAudioSource*) audioSourceForChannel:(tAudioSourceChannel) channel 
+{
+       return (CDLongAudioSource*)[audioSourceChannels objectAtIndex:channel];
+}      
+
+/** Loads the data from the specified file path to the channel's audio source */
+-(CDLongAudioSource*) audioSourceLoad:(NSString*) filePath channel:(tAudioSourceChannel) channel
+{
+       CDLongAudioSource *audioSource = [self audioSourceForChannel:channel];
+       if (audioSource) {
+               [audioSource load:filePath];
+       }
+       return audioSource;
+}      
+
+-(BOOL) isBackgroundMusicPlaying {
+       return [self.backgroundMusic isPlaying];
+}      
+
+//NB: originally I tried using a route change listener and intended to store the current route,
+//however, on a 3gs running 3.1.2 no route change is generated when the user switches the 
+//ringer mute switch to off (i.e. enables sound) therefore polling is the only reliable way to
+//determine ringer switch state
+-(BOOL) isDeviceMuted {
+
+#if TARGET_IPHONE_SIMULATOR
+       //Calling audio route stuff on the simulator causes problems
+       return NO;
+#else  
+       CFStringRef newAudioRoute;
+       UInt32 propertySize = sizeof (CFStringRef);
+       
+       AudioSessionGetProperty (
+                                                        kAudioSessionProperty_AudioRoute,
+                                                        &propertySize,
+                                                        &newAudioRoute
+                                                        );
+       
+       if (newAudioRoute == NULL) {
+               //Don't expect this to happen but playing safe otherwise a null in the CFStringCompare will cause a crash
+               return YES;
+       } else {        
+               CFComparisonResult newDeviceIsMuted =   CFStringCompare (
+                                                                                                                                newAudioRoute,
+                                                                                                                                (CFStringRef) @"",
+                                                                                                                                0
+                                                                                                                                );
+               
+               return (newDeviceIsMuted == kCFCompareEqualTo);
+       }       
+#endif
+}      
+
+#pragma mark Audio Interrupt Protocol
+
+-(BOOL) mute {
+       return _mute;
+}      
+
+-(void) setMute:(BOOL) muteValue {
+       if (muteValue != _mute) {
+               _mute = muteValue;
+               [soundEngine setMute:muteValue];
+               for( CDLongAudioSource *audioSource in audioSourceChannels) {
+                       audioSource.mute = muteValue;
+               }       
+       }       
+}
+
+-(BOOL) enabled {
+       return enabled_;
+}      
+
+-(void) setEnabled:(BOOL) enabledValue {
+       if (enabledValue != enabled_) {
+               enabled_ = enabledValue;
+               [soundEngine setEnabled:enabled_];
+               for( CDLongAudioSource *audioSource in audioSourceChannels) {
+                       audioSource.enabled = enabled_;
+               }       
+       }       
+}
+
+-(CDLongAudioSource*) backgroundMusic
+{
+       return backgroundMusic;
+}      
+
+//Load background music ready for playing
+-(void) preloadBackgroundMusic:(NSString*) filePath
+{
+       [self.backgroundMusic load:filePath];   
+}      
+
+-(void) playBackgroundMusic:(NSString*) filePath loop:(BOOL) loop
+{
+       [self.backgroundMusic load:filePath];
+
+       if (!willPlayBackgroundMusic || _mute) {
+               CDLOGINFO(@"Denshion::CDAudioManager - play bgm aborted because audio is not exclusive or sound is muted");
+               return;
+       }
+               
+       if (loop) {
+               [self.backgroundMusic setNumberOfLoops:-1];
+       } else {
+               [self.backgroundMusic setNumberOfLoops:0];
+       }       
+       [self.backgroundMusic play];
+}
+
+-(void) stopBackgroundMusic
+{
+       [self.backgroundMusic stop];
+}
+
+-(void) pauseBackgroundMusic
+{
+       [self.backgroundMusic pause];
+}      
+
+-(void) resumeBackgroundMusic
+{
+       if (!willPlayBackgroundMusic || _mute) {
+               CDLOGINFO(@"Denshion::CDAudioManager - resume bgm aborted because audio is not exclusive or sound is muted");
+               return;
+       }
+       
+       [self.backgroundMusic resume];
+}      
+
+-(void) rewindBackgroundMusic
+{
+       [self.backgroundMusic rewind];
+}      
+
+-(void) setBackgroundMusicCompletionListener:(id) listener selector:(SEL) selector {
+       backgroundMusicCompletionListener = listener;
+       backgroundMusicCompletionSelector = selector;
+}      
+
+/*
+ * Call this method to have the audio manager automatically handle application resign and
+ * become active.  Pass a tAudioManagerResignBehavior to indicate the desired behavior
+ * for resigning and becoming active again.
+ *
+ * If autohandle is YES then the applicationWillResignActive and applicationDidBecomActive 
+ * methods are automatically called, otherwise you must call them yourself at the appropriate time.
+ *
+ * Based on idea of Dominique Bongard
+ */
+-(void) setResignBehavior:(tAudioManagerResignBehavior) resignBehavior autoHandle:(BOOL) autoHandle { 
+
+       if (!_isObservingAppEvents && autoHandle) {
+               [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(applicationWillResignActive:) name:@"UIApplicationWillResignActiveNotification" object:nil];
+               [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(applicationDidBecomeActive:) name:@"UIApplicationDidBecomeActiveNotification" object:nil];
+               [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(applicationWillTerminate:) name:@"UIApplicationWillTerminateNotification" object:nil];
+               _isObservingAppEvents = TRUE;
+       }
+       _resignBehavior = resignBehavior;
+}      
+
+- (void) applicationWillResignActive {
+       self->_resigned = YES;
+       
+       //Set the audio sesssion to one that allows sharing so that other audio won't be clobbered on resume
+       [self audioSessionSetCategory:AVAudioSessionCategoryAmbient];
+       
+       switch (_resignBehavior) {
+                       
+               case kAMRBStopPlay:
+                       
+                       for( CDLongAudioSource *audioSource in audioSourceChannels) {
+                               if (audioSource.isPlaying) {
+                                       audioSource->systemPaused = YES;
+                                       audioSource->systemPauseLocation = audioSource.audioSourcePlayer.currentTime;
+                                       [audioSource stop];
+                               } else {
+                                       //Music is either paused or stopped, if it is paused it will be restarted
+                                       //by OS so we will stop it.
+                                       audioSource->systemPaused = NO;
+                                       [audioSource stop];
+                               }
+                       }
+                       break;
+                       
+               case kAMRBStop:
+                       //Stop music regardless of whether it is playing or not because if it was paused
+                       //then the OS would resume it
+                       for( CDLongAudioSource *audioSource in audioSourceChannels) {
+                               [audioSource stop];
+                       }       
+                       
+               default:
+                       break;
+                       
+       }                       
+       CDLOGINFO(@"Denshion::CDAudioManager - handled resign active");
+}
+
+//Called when application resigns active only if setResignBehavior has been called
+- (void) applicationWillResignActive:(NSNotification *) notification
+{
+       [self applicationWillResignActive];
+}      
+
+- (void) applicationDidBecomeActive {
+       
+       if (self->_resigned) {
+               _resigned = NO;
+               //Reset the mode incase something changed with audio while we were inactive
+               [self setMode:_mode];
+               switch (_resignBehavior) {
+                               
+                       case kAMRBStopPlay:
+                               
+                               //Music had been stopped but stop maintains current time
+                               //so playing again will continue from where music was before resign active.
+                               //We check if music can be played because while we were inactive the user might have
+                               //done something that should force music to not play such as starting a track in the iPod
+                               if (self.willPlayBackgroundMusic) {
+                                       for( CDLongAudioSource *audioSource in audioSourceChannels) {
+                                               if (audioSource->systemPaused) {
+                                                       [audioSource resume];
+                                                       audioSource->systemPaused = NO;
+                                               }
+                                       }
+                               }
+                               break;
+                               
+                       default:
+                               break;
+                               
+               }
+               CDLOGINFO(@"Denshion::CDAudioManager - audio manager handled become active");
+       }
+}
+
+//Called when application becomes active only if setResignBehavior has been called
+- (void) applicationDidBecomeActive:(NSNotification *) notification
+{
+       [self applicationDidBecomeActive];
+}
+
+//Called when application terminates only if setResignBehavior has been called 
+- (void) applicationWillTerminate:(NSNotification *) notification
+{
+       CDLOGINFO(@"Denshion::CDAudioManager - audio manager handling terminate");
+       [self stopBackgroundMusic];
+}
+
+/** The audio source completed playing */
+- (void) cdAudioSourceDidFinishPlaying:(CDLongAudioSource *) audioSource {
+       CDLOGINFO(@"Denshion::CDAudioManager - audio manager got told background music finished");
+       if (backgroundMusicCompletionSelector != nil) {
+               [backgroundMusicCompletionListener performSelector:backgroundMusicCompletionSelector];
+       }       
+}      
+
+-(void) beginInterruption {
+       CDLOGINFO(@"Denshion::CDAudioManager - begin interruption");
+       [self audioSessionInterrupted];
+}
+
+-(void) endInterruption {
+       CDLOGINFO(@"Denshion::CDAudioManager - end interruption");
+       [self audioSessionResumed];
+}
+
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
+-(void) endInterruptionWithFlags:(NSUInteger)flags {
+       CDLOGINFO(@"Denshion::CDAudioManager - interruption ended with flags %i",flags);
+       if (flags == AVAudioSessionInterruptionFlags_ShouldResume) {
+               [self audioSessionResumed];
+       }       
+}
+#endif
+
+-(void)audioSessionInterrupted 
+{ 
+    if (!_interrupted) {
+               CDLOGINFO(@"Denshion::CDAudioManager - Audio session interrupted"); 
+               _interrupted = YES;
+
+               // Deactivate the current audio session 
+           [self audioSessionSetActive:NO];
+               
+               if (alcGetCurrentContext() != NULL) {
+                       CDLOGINFO(@"Denshion::CDAudioManager - Setting OpenAL context to NULL"); 
+
+                       ALenum  error = AL_NO_ERROR;
+
+                       // set the current context to NULL will 'shutdown' openAL 
+                       alcMakeContextCurrent(NULL); 
+               
+                       if((error = alGetError()) != AL_NO_ERROR) {
+                               CDLOG(@"Denshion::CDAudioManager - Error making context current %x\n", error);
+                       } 
+                       #pragma unused(error)
+               }
+       }       
+} 
+
+-(void)audioSessionResumed 
+{ 
+       if (_interrupted) {
+               CDLOGINFO(@"Denshion::CDAudioManager - Audio session resumed"); 
+               _interrupted = NO;
+               
+               BOOL activationResult = NO;
+               // Reactivate the current audio session
+               activationResult = [self audioSessionSetActive:YES]; 
+               
+               //This code is to handle a problem with iOS 4.0 and 4.01 where reactivating the session can fail if
+               //task switching is performed too rapidly. A test case that reliably reproduces the issue is to call the
+               //iPhone and then hang up after two rings (timing may vary ;))
+               //Basically we keep waiting and trying to let the OS catch up with itself but the number of tries is
+               //limited.
+               if (!activationResult) {
+                       CDLOG(@"Denshion::CDAudioManager - Failure reactivating audio session, will try wait-try cycle"); 
+                       int activateCount = 0;
+                       while (!activationResult && activateCount < 10) {
+                               [NSThread sleepForTimeInterval:0.5];
+                               activationResult = [self audioSessionSetActive:YES]; 
+                               activateCount++;
+                               CDLOGINFO(@"Denshion::CDAudioManager - Reactivation attempt %i status = %i",activateCount,activationResult); 
+                       }       
+               }
+               
+               if (alcGetCurrentContext() == NULL) {
+                       CDLOGINFO(@"Denshion::CDAudioManager - Restoring OpenAL context"); 
+                       ALenum  error = AL_NO_ERROR;
+                       // Restore open al context 
+                       alcMakeContextCurrent([soundEngine openALContext]); 
+                       if((error = alGetError()) != AL_NO_ERROR) {
+                               CDLOG(@"Denshion::CDAudioManager - Error making context current%x\n", error);
+                       } 
+                       #pragma unused(error)
+               }       
+       }       
+}
+
++(void) end {
+       [sharedManager release];
+       sharedManager = nil;
+}      
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////////////
+@implementation CDLongAudioSourceFader
+
+-(void) _setTargetProperty:(float) newVal {
+       ((CDLongAudioSource*)target).volume = newVal;
+}      
+
+-(float) _getTargetProperty {
+       return ((CDLongAudioSource*)target).volume;
+}
+
+-(void) _stopTarget {
+       //Pause instead of stop as stop releases resources and causes problems in the simulator
+       [((CDLongAudioSource*)target) pause];
+}
+
+-(Class) _allowableType {
+       return [CDLongAudioSource class];
+}      
+
+@end
+///////////////////////////////////////////////////////////////////////////////////////
+@implementation CDBufferManager
+
+-(id) initWithEngine:(CDSoundEngine *) theSoundEngine {
+       if ((self = [super init])) {
+               soundEngine = theSoundEngine;
+               loadedBuffers = [[NSMutableDictionary alloc] initWithCapacity:CD_BUFFERS_START];
+               freedBuffers = [[NSMutableArray alloc] init];
+               nextBufferId = 0;
+       }       
+       return self;
+}      
+
+-(void) dealloc {
+       [loadedBuffers release];
+       [freedBuffers release];
+       [super dealloc];
+}      
+
+-(int) bufferForFile:(NSString*) filePath create:(BOOL) create {
+       
+       NSNumber* soundId = (NSNumber*)[loadedBuffers objectForKey:filePath];
+       if(soundId == nil)
+       {
+               if (create) {
+                       NSNumber* bufferId = nil;
+                       //First try to get a buffer from the free buffers
+                       if ([freedBuffers count] > 0) {
+                               bufferId = [[[freedBuffers lastObject] retain] autorelease];
+                               [freedBuffers removeLastObject]; 
+                               CDLOGINFO(@"Denshion::CDBufferManager reusing buffer id %i",[bufferId intValue]);
+                       } else {
+                               bufferId = [[NSNumber alloc] initWithInt:nextBufferId];
+                               [bufferId autorelease];
+                               CDLOGINFO(@"Denshion::CDBufferManager generating new buffer id %i",[bufferId intValue]);
+                               nextBufferId++;
+                       }
+                       
+                       if ([soundEngine loadBuffer:[bufferId intValue] filePath:filePath]) {
+                               //File successfully loaded
+                               CDLOGINFO(@"Denshion::CDBufferManager buffer loaded %@ %@",bufferId,filePath);
+                               [loadedBuffers setObject:bufferId forKey:filePath];
+                               return [bufferId intValue];
+                       } else {
+                               //File didn't load, put buffer id on free list
+                               [freedBuffers addObject:bufferId];
+                               return kCDNoBuffer;
+                       }       
+               } else {
+                       //No matching buffer was found
+                       return kCDNoBuffer;
+               }       
+       } else {
+               return [soundId intValue];
+       }       
+}      
+
+-(void) releaseBufferForFile:(NSString *) filePath {
+       int bufferId = [self bufferForFile:filePath create:NO];
+       if (bufferId != kCDNoBuffer) {
+               [soundEngine unloadBuffer:bufferId];
+               [loadedBuffers removeObjectForKey:filePath];
+               NSNumber *freedBufferId = [[NSNumber alloc] initWithInt:bufferId];
+               [freedBufferId autorelease];
+               [freedBuffers addObject:freedBufferId];
+       }       
+}      
+@end
+
+
+
diff --git a/libs/CocosDenshion/CDConfig.h b/libs/CocosDenshion/CDConfig.h
new file mode 100644 (file)
index 0000000..2bd8f76
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ Copyright (c) 2010 Steve Oldmeadow
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ $Id$
+ */
+#define COCOSDENSHION_VERSION "Aphex.rc"
+
+
+/**
+ If enabled code useful for debugging such as parameter check assertions will be performed.
+ If you experience any problems you should enable this and test your code with a debug build.
+ */
+//#define CD_DEBUG 1
+
+/**
+ The total number of sounds/buffers that can be loaded assuming memory is sufficient
+ */
+//Number of buffers slots that will be initially created
+#define CD_BUFFERS_START 64
+//Number of buffers that will be added 
+#define CD_BUFFERS_INCREMENT 16
+
+/**
+ If enabled, OpenAL code will use static buffers. When static buffers are used the audio
+ data is managed outside of OpenAL, this eliminates a memcpy operation which leads to 
+ higher performance when loading sounds.
+ However, the downside is that when the audio data is freed you must
+ be certain that it is no longer being accessed otherwise your app will crash. Testing on OS 2.2.1
+ and 3.1.2 has shown that this may occur if a buffer is being used by a source with state = AL_PLAYING
+ when the buffer is deleted. If the data is freed too quickly after the source is stopped then
+ a crash will occur. The implemented workaround is that when static buffers are used the unloadBuffer code will wait for
+ any playing sources to finish playing before the associated buffer and data are deleted, however, this delay may negate any 
+ performance gains that are achieved during loading.
+ Performance tests on a 1st gen iPod running OS 2.2.1 loading the CocosDenshionDemo sounds were ~0.14 seconds without
+ static buffers and ~0.12 seconds when using static buffers.
+
+ */
+//#define CD_USE_STATIC_BUFFERS 1
+
+
diff --git a/libs/CocosDenshion/CDOpenALSupport.h b/libs/CocosDenshion/CDOpenALSupport.h
new file mode 100644 (file)
index 0000000..661c69e
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ 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.
+ $Id$
+ */
+
+/*
+ This file contains code from version 1.1 and 1.4 of MyOpenALSupport.h taken from Apple's oalTouch version.
+ The 1.4 version code is used for loading IMA4 files, however, this code causes very noticeable clicking
+ when used to load wave files that are looped so the 1.1 version code is used specifically for loading
+ wav files.
+ */
+
+#ifndef __CD_OPENAL_H
+#define __CD_OPENAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif 
+       
+
+#import <OpenAL/al.h>
+#import <OpenAL/alc.h>
+#import <CoreFoundation/CFURL.h>
+
+
+//Taken from oalTouch MyOpenALSupport 1.1
+void* CDloadWaveAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei*    outSampleRate);
+void* CDloadCafAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate);
+void* CDGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei* outSampleRate);
+       
+#ifdef __cplusplus
+}
+#endif
+
+#endif 
+
+
diff --git a/libs/CocosDenshion/CDOpenALSupport.m b/libs/CocosDenshion/CDOpenALSupport.m
new file mode 100644 (file)
index 0000000..ab0df8e
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ 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.
+ $Id: CDOpenALSupport.h 16 2010-03-11 06:22:10Z steveoldmeadow $
+ */
+
+#import "CDOpenALSupport.h"
+#import "CocosDenshion.h"
+#import <AudioToolbox/AudioToolbox.h>
+#import <AudioToolbox/ExtendedAudioFile.h>
+
+//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;
+       
+       // Open a file with ExtAudioFileOpen()
+       err = AudioFileOpenURL(inFileURL, kAudioFileReadPermission, 0, &afid);
+       if(err) { CDLOG(@"MyGetOpenALAudioData: AudioFileOpenURL FAILED, Error = %ld\n", err); goto Exit; }
+       
+       // Get the audio data format
+       err = AudioFileGetProperty(afid, kAudioFilePropertyDataFormat, &thePropertySize, &theFileFormat);
+       if(err) { CDLOG(@"MyGetOpenALAudioData: AudioFileGetProperty(kAudioFileProperty_DataFormat) FAILED, Error = %ld\n", err); goto Exit; }
+       
+       if (theFileFormat.mChannelsPerFrame > 2)  { 
+               CDLOG(@"MyGetOpenALAudioData - Unsupported Format, channel count is greater than stereo\n"); goto Exit;
+       }
+       
+       if ((theFileFormat.mFormatID != kAudioFormatLinearPCM) || (!TestAudioFormatNativeEndian(theFileFormat))) { 
+               CDLOG(@"MyGetOpenALAudioData - Unsupported Format, must be little-endian PCM\n"); goto Exit;
+       }
+       
+       if ((theFileFormat.mBitsPerChannel != 8) && (theFileFormat.mBitsPerChannel != 16)) { 
+               CDLOG(@"MyGetOpenALAudioData - Unsupported Format, must be 8 or 16 bit PCM\n"); goto Exit;
+       }
+       
+       
+       thePropertySize = sizeof(fileDataSize);
+       err = AudioFileGetProperty(afid, kAudioFilePropertyAudioDataByteCount, &thePropertySize, &fileDataSize);
+       if(err) { CDLOG(@"MyGetOpenALAudioData: AudioFileGetProperty(kAudioFilePropertyAudioDataByteCount) FAILED, Error = %ld\n", err); goto Exit; }
+       
+       // Read all the data into memory
+       UInt32          dataSize = (UInt32)fileDataSize;
+       theData = malloc(dataSize);
+       if (theData)
+       {
+               AudioFileReadBytes(afid, false, 0, &dataSize, theData);
+               if(err == noErr)
+               {
+                       // success
+                       *outDataSize = (ALsizei)dataSize;
+                       //This fix was added by me, however, 8 bit sounds have a clipping sound at the end so aren't really usable (SO)
+                       if (theFileFormat.mBitsPerChannel == 16) { 
+                               *outDataFormat = (theFileFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
+                       } else {
+                               *outDataFormat = (theFileFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8;   
+                       }       
+                       *outSampleRate = (ALsizei)theFileFormat.mSampleRate;
+               }
+               else 
+               { 
+                       // failure
+                       free (theData);
+                       theData = NULL; // make sure to return NULL
+                       CDLOG(@"MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %ld\n", err); goto Exit;
+               }       
+       }
+       
+Exit:
+       // Dispose the ExtAudioFileRef, it is no longer needed
+       if (afid) AudioFileClose(afid);
+       return theData;
+}
+
+//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;
+       
+       // Open a file with ExtAudioFileOpen()
+       status = ExtAudioFileOpenURL(inFileURL, &extRef);
+       if (status != noErr)
+       {
+               CDLOG(@"MyGetOpenALAudioData: ExtAudioFileOpenURL FAILED, Error = %ld\n", status);
+               abort = YES;
+       }
+       if (abort)
+               goto Exit;
+       
+       // Get the audio data format
+       status = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &theFileFormat);
+       if (status != noErr)
+       {
+               CDLOG(@"MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %ld\n", status);
+               abort = YES;
+       }
+       if (abort)
+               goto Exit;
+       
+       if (theFileFormat.mChannelsPerFrame > 2)
+       {
+               CDLOG(@"MyGetOpenALAudioData - Unsupported Format, channel count is greater than stereo\n");
+               abort = YES;
+       }
+       if (abort)
+               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
+       status = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(theOutputFormat), &theOutputFormat);
+       if (status != noErr)
+       {
+               CDLOG(@"MyGetOpenALAudioData: ExtAudioFileSetProperty(kExtAudioFileProperty_ClientDataFormat) FAILED, Error = %ld\n", status);
+               abort = YES;
+       }
+       if (abort)
+               goto Exit;
+       
+       // Get the total frame count
+       thePropertySize = sizeof(theFileLengthInFrames);
+       status = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames);
+       if (status != noErr)
+       {
+               CDLOG(@"MyGetOpenALAudioData: ExtAudioFileGetProperty(kExtAudioFileProperty_FileLengthFrames) FAILED, Error = %ld\n", status);
+               abort = YES;
+       }
+       if (abort)
+               goto Exit;
+       
+       // Read all the data into memory
+       dataSize = (UInt32) 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
+               status = ExtAudioFileRead(extRef, (UInt32*)&theFileLengthInFrames, &theDataBuffer);
+               if(status == 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
+                       CDLOG(@"MyGetOpenALAudioData: ExtAudioFileRead FAILED, Error = %ld\n", status);
+                       abort = YES;
+               }
+       }
+       if (abort)
+               goto Exit;
+       
+Exit:
+       // Dispose the ExtAudioFileRef, it is no longer needed
+       if (extRef) ExtAudioFileDispose(extRef);
+       return theData;
+}
+
+void* CDGetOpenALAudioData(CFURLRef inFileURL, ALsizei *outDataSize, ALenum *outDataFormat, ALsizei*   outSampleRate) {
+       
+       CFStringRef extension = CFURLCopyPathExtension(inFileURL);
+       CFComparisonResult isWavFile = 0;
+       if (extension != NULL) {
+               isWavFile = CFStringCompare (extension,(CFStringRef)@"wav", kCFCompareCaseInsensitive);
+               CFRelease(extension);
+       }       
+       
+       if (isWavFile == kCFCompareEqualTo) {
+               return CDloadWaveAudioData(inFileURL, outDataSize, outDataFormat, outSampleRate);       
+       } else {
+               return CDloadCafAudioData(inFileURL, outDataSize, outDataFormat, outSampleRate);                
+       }
+}
+
diff --git a/libs/CocosDenshion/CocosDenshion.h b/libs/CocosDenshion/CocosDenshion.h
new file mode 100644 (file)
index 0000000..638d852
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ Copyright (c) 2010 Steve Oldmeadow
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ $Id$
+ */
+
+
+
+/** 
+@file
+@b IMPORTANT
+There are 3 different ways of using CocosDenshion. Depending on which you choose you 
+will need to include different files and frameworks.
+
+@par SimpleAudioEngine
+This is recommended for basic audio requirements. If you just want to play some sound fx
+and some background music and have no interest in learning the lower level workings then
+this is the interface to use.
+
+Requirements:
+ - Firmware: OS 2.2 or greater 
+ - Files: SimpleAudioEngine.*, CocosDenshion.*
+ - Frameworks: OpenAL, AudioToolbox, AVFoundation
+@par CDAudioManager
+CDAudioManager is basically a thin wrapper around an AVAudioPlayer object used for playing
+background music and a CDSoundEngine object used for playing sound effects. It manages the
+audio session for you deals with audio session interruption. It is fairly low level and it
+is expected you have some understanding of the underlying technologies. For example, for 
+many use cases regarding background music it is expected you will work directly with the
+backgroundMusic AVAudioPlayer which is exposed as a property.
+Requirements:
+  - Firmware: OS 2.2 or greater 
+  - Files: CDAudioManager.*, CocosDenshion.*
+  - Frameworks: OpenAL, AudioToolbox, AVFoundation
+
+@par CDSoundEngine
+CDSoundEngine is a sound engine built upon OpenAL and derived from Apple's oalTouch 
+example. It can playback up to 32 sounds simultaneously with control over pitch, pan
+and gain.  It can be set up to handle audio session interruption automatically.  You 
+may decide to use CDSoundEngine directly instead of CDAudioManager or SimpleAudioEngine
+because you require OS 2.0 compatibility.
+Requirements:
+  - Firmware: OS 2.0 or greater 
+  - Files: CocosDenshion.*
+  - Frameworks: OpenAL, AudioToolbox
+*/ 
+
+#import <OpenAL/al.h>
+#import <OpenAL/alc.h>
+#import <AudioToolbox/AudioToolbox.h>
+#import <Foundation/Foundation.h>
+#import "CDConfig.h"
+
+
+#if !defined(CD_DEBUG) || CD_DEBUG == 0
+#define CDLOG(...) do {} while (0)
+#define CDLOGINFO(...) do {} while (0)
+
+#elif CD_DEBUG == 1
+#define CDLOG(...) NSLog(__VA_ARGS__)
+#define CDLOGINFO(...) do {} while (0)
+
+#elif CD_DEBUG > 1
+#define CDLOG(...) NSLog(__VA_ARGS__)
+#define CDLOGINFO(...) NSLog(__VA_ARGS__)
+#endif // CD_DEBUG
+
+
+#import "CDOpenALSupport.h"
+
+//Tested source limit on 2.2.1 and 3.1.2 with up to 128 sources and appears to work. Older OS versions e.g 2.2 may support only 32
+#define CD_SOURCE_LIMIT 32 //Total number of sources we will ever want, may actually get less
+#define CD_NO_SOURCE 0xFEEDFAC //Return value indicating playback failed i.e. no source
+#define CD_IGNORE_AUDIO_SESSION 0xBEEFBEE //Used internally to indicate audio session will not be handled
+#define CD_MUTE      0xFEEDBAB //Return value indicating sound engine is muted or non functioning
+#define CD_NO_SOUND = -1;
+
+#define CD_SAMPLE_RATE_HIGH 44100
+#define CD_SAMPLE_RATE_MID  22050
+#define CD_SAMPLE_RATE_LOW  16000
+#define CD_SAMPLE_RATE_BASIC 8000
+#define CD_SAMPLE_RATE_DEFAULT 44100
+
+extern NSString * const kCDN_BadAlContext;
+extern NSString * const kCDN_AsynchLoadComplete;
+
+extern float const kCD_PitchDefault;
+extern float const kCD_PitchLowerOneOctave;
+extern float const kCD_PitchHigherOneOctave;
+extern float const kCD_PanDefault;
+extern float const kCD_PanFullLeft;
+extern float const kCD_PanFullRight;
+extern float const kCD_GainDefault;
+
+enum bufferState {
+       CD_BS_EMPTY = 0,
+       CD_BS_LOADED = 1,
+       CD_BS_FAILED = 2
+};
+
+typedef struct _sourceGroup {
+       int startIndex;
+       int currentIndex;
+       int totalSources;
+       bool enabled;
+       bool nonInterruptible;
+       int *sourceStatuses;//pointer into array of source status information
+} sourceGroup;
+
+typedef struct _bufferInfo {
+       ALuint bufferId;
+       int bufferState;
+       void* bufferData;
+       ALenum format;
+       ALsizei sizeInBytes;
+       ALsizei frequencyInHertz;
+} bufferInfo;  
+
+typedef struct _sourceInfo {
+       bool usable;
+       ALuint sourceId;
+       ALuint attachedBufferId;
+} sourceInfo;  
+
+#pragma mark CDAudioTransportProtocol
+
+@protocol CDAudioTransportProtocol <NSObject>
+/** Play the audio */
+-(BOOL) play;
+/** Pause the audio, retain resources */
+-(BOOL) pause;
+/** Stop the audio, release resources */
+-(BOOL) stop;
+/** Return playback to beginning */
+-(BOOL) rewind;
+@end
+
+#pragma mark CDAudioInterruptProtocol
+
+@protocol CDAudioInterruptProtocol <NSObject>
+/** Is audio mute */
+-(BOOL) mute;
+/** If YES then audio is silenced but not stopped, calls to start new audio will proceed but silently */
+-(void) setMute:(BOOL) muteValue;
+/** Is audio enabled */
+-(BOOL) enabled;
+/** If NO then all audio is stopped and any calls to start new audio will be ignored */
+-(void) setEnabled:(BOOL) enabledValue;
+@end
+
+#pragma mark CDUtilities
+/**
+ Collection of utilities required by CocosDenshion
+ */
+@interface CDUtilities : NSObject
+{
+}      
+
+/** Fundamentally the same as the corresponding method is CCFileUtils but added to break binding to cocos2d */
++(NSString*) fullPathFromRelativePath:(NSString*) relPath;
+
+@end
+
+
+#pragma mark CDSoundEngine
+
+/** CDSoundEngine is built upon OpenAL and works with SDK 2.0.
+ CDSoundEngine is a sound engine built upon OpenAL and derived from Apple's oalTouch 
+ example. It can playback up to 32 sounds simultaneously with control over pitch, pan
+ and gain.  It can be set up to handle audio session interruption automatically.  You 
+ may decide to use CDSoundEngine directly instead of CDAudioManager or SimpleAudioEngine
+ because you require OS 2.0 compatibility.
+ Requirements:
+ - Firmware: OS 2.0 or greater 
+ - Files: CocosDenshion.*
+ - Frameworks: OpenAL, AudioToolbox
+ @since v0.8
+ */
+@class CDSoundSource;
+@interface CDSoundEngine : NSObject <CDAudioInterruptProtocol> {
+       
+       bufferInfo              *_buffers;
+       sourceInfo              *_sources;
+       sourceGroup         *_sourceGroups;
+       ALCcontext              *context;
+       NSUInteger              _sourceGroupTotal;
+       UInt32                  _audioSessionCategory;
+       BOOL                    _handleAudioSession;
+       ALfloat                 _preMuteGain;
+       NSObject        *_mutexBufferLoad;
+       BOOL                    mute_;
+       BOOL                    enabled_;
+
+       ALenum                  lastErrorCode_;
+       BOOL                    functioning_;
+       float                   asynchLoadProgress_;
+       BOOL                    getGainWorks_;
+       
+       //For managing dynamic allocation of sources and buffers
+       int sourceTotal_;
+       int bufferTotal;
+        
+}
+
+@property (readwrite, nonatomic) ALfloat masterGain;
+@property (readonly)  ALenum lastErrorCode;//Last OpenAL error code that was generated
+@property (readonly)  BOOL functioning;//Is the sound engine functioning
+@property (readwrite) float asynchLoadProgress;
+@property (readonly)  BOOL getGainWorks;//Does getting the gain for a source work
+/** Total number of sources available */
+@property (readonly) int sourceTotal;
+/** Total number of source groups that have been defined */
+@property (readonly) NSUInteger sourceGroupTotal;
+
+/** Sets the sample rate for the audio mixer. For best performance this should match the sample rate of your audio content */
++(void) setMixerSampleRate:(Float32) sampleRate;
+
+/** Initializes the engine with a group definition and a total number of groups */
+-(id)init;
+
+/** Plays a sound in a channel group with a pitch, pan and gain. The sound could played looped or not */
+-(ALuint) playSound:(int) soundId sourceGroupId:(int)sourceGroupId pitch:(float) pitch pan:(float) pan gain:(float) gain loop:(BOOL) loop;
+
+/** Creates and returns a sound source object for the specified sound within the specified source group.
+ */
+-(CDSoundSource *) soundSourceForSound:(int) soundId sourceGroupId:(int) sourceGroupId;
+
+/** Stops playing a sound */
+- (void) stopSound:(ALuint) sourceId;
+/** Stops playing a source group */
+- (void) stopSourceGroup:(int) sourceGroupId;
+/** Stops all playing sounds */
+-(void) stopAllSounds;
+-(void) defineSourceGroups:(NSArray*) sourceGroupDefinitions;
+-(void) defineSourceGroups:(int[]) sourceGroupDefinitions total:(NSUInteger) total;
+-(void) setSourceGroupNonInterruptible:(int) sourceGroupId isNonInterruptible:(BOOL) isNonInterruptible;
+-(void) setSourceGroupEnabled:(int) sourceGroupId enabled:(BOOL) enabled;
+-(BOOL) sourceGroupEnabled:(int) sourceGroupId;
+-(BOOL) loadBufferFromData:(int) soundId soundData:(ALvoid*) soundData format:(ALenum) format size:(ALsizei) size freq:(ALsizei) freq;
+-(BOOL) loadBuffer:(int) soundId filePath:(NSString*) filePath;
+-(void) loadBuffersAsynchronously:(NSArray *) loadRequests;
+-(BOOL) unloadBuffer:(int) soundId;
+-(ALCcontext *) openALContext;
+
+/** Returns the duration of the buffer in seconds or a negative value if the buffer id is invalid */
+-(float) bufferDurationInSeconds:(int) soundId;
+/** Returns the size of the buffer in bytes or a negative value if the buffer id is invalid */
+-(ALsizei) bufferSizeInBytes:(int) soundId;
+/** Returns the sampling frequency of the buffer in hertz or a negative value if the buffer id is invalid */
+-(ALsizei) bufferFrequencyInHertz:(int) soundId;
+
+/** Used internally, never call unless you know what you are doing */
+-(void) _soundSourcePreRelease:(CDSoundSource *) soundSource;
+
+@end
+
+#pragma mark CDSoundSource
+/** CDSoundSource is a wrapper around an OpenAL sound source.
+ It allows you to manipulate properties such as pitch, gain, pan and looping while the 
+ sound is playing. CDSoundSource is based on the old CDSourceWrapper class but with much
+ added functionality.
+ @since v1.0
+ */
+@interface CDSoundSource : NSObject <CDAudioTransportProtocol, CDAudioInterruptProtocol> {
+       ALenum lastError;
+@public
+       ALuint _sourceId;
+       ALuint _sourceIndex;
+       CDSoundEngine* _engine;
+       int _soundId;
+       float _preMuteGain;
+       BOOL enabled_;
+       BOOL mute_;
+}
+@property (readwrite, nonatomic) float pitch;
+@property (readwrite, nonatomic) float gain;
+@property (readwrite, nonatomic) float pan;
+@property (readwrite, nonatomic) BOOL looping;
+@property (readonly)  BOOL isPlaying;
+@property (readwrite, nonatomic) int soundId;
+/** Returns the duration of the attached buffer in seconds or a negative value if the buffer is invalid */
+@property (readonly) float durationInSeconds;
+
+/** Stores the last error code that occurred. Check against AL_NO_ERROR */
+@property (readonly) ALenum lastError;
+/** Do not init yourself, get an instance from the sourceForSound factory method on CDSoundEngine */
+-(id)init:(ALuint) theSourceId sourceIndex:(int) index soundEngine:(CDSoundEngine*) engine;
+
+@end
+
+#pragma mark CDAudioInterruptTargetGroup
+
+/** Container for objects that implement audio interrupt protocol i.e. they can be muted and enabled.
+ Setting mute and enabled for the group propagates to all children. 
+ Designed to be used with your CDSoundSource objects to get them to comply with global enabled and mute settings
+ if that is what you want to do.*/
+@interface CDAudioInterruptTargetGroup : NSObject <CDAudioInterruptProtocol> {
+       BOOL mute_;
+       BOOL enabled_;
+       NSMutableArray *children_;
+}
+-(void) addAudioInterruptTarget:(NSObject<CDAudioInterruptProtocol>*) interruptibleTarget;
+@end
+
+#pragma mark CDAsynchBufferLoader
+
+/** CDAsynchBufferLoader
+ TODO
+ */
+@interface CDAsynchBufferLoader : NSOperation {
+       NSArray *_loadRequests;
+       CDSoundEngine *_soundEngine;
+}      
+
+-(id) init:(NSArray *)loadRequests soundEngine:(CDSoundEngine *) theSoundEngine;
+
+@end
+
+#pragma mark CDBufferLoadRequest
+
+/** CDBufferLoadRequest */
+@interface CDBufferLoadRequest: NSObject
+{
+       NSString *filePath;
+       int              soundId;
+       //id       loader;
+}
+
+@property (readonly) NSString *filePath;
+@property (readonly) int soundId;
+
+- (id)init:(int) theSoundId filePath:(const NSString *) theFilePath;
+@end
+
+/** Interpolation type */
+typedef enum {
+       kIT_Linear,                     //!Straight linear interpolation fade
+       kIT_SCurve,                     //!S curved interpolation
+       kIT_Exponential         //!Exponential interpolation
+} tCDInterpolationType;
+
+#pragma mark CDFloatInterpolator
+@interface CDFloatInterpolator: NSObject
+{
+       float start;
+       float end;
+       float lastValue;
+       tCDInterpolationType interpolationType;
+}
+@property (readwrite, nonatomic) float start;
+@property (readwrite, nonatomic) float end;
+@property (readwrite, nonatomic) tCDInterpolationType interpolationType;
+
+/** Return a value between min and max based on t which represents fractional progress where 0 is the start
+ and 1 is the end */
+-(float) interpolate:(float) t;
+-(id) init:(tCDInterpolationType) type startVal:(float) startVal endVal:(float) endVal;
+
+@end
+
+#pragma mark CDPropertyModifier
+
+/** Base class for classes that modify properties such as pitch, pan and gain */
+@interface CDPropertyModifier: NSObject
+{
+       CDFloatInterpolator *interpolator;
+       float startValue;
+       float endValue;
+       id target;
+       BOOL stopTargetWhenComplete;
+       
+}
+@property (readwrite, nonatomic) BOOL stopTargetWhenComplete;
+@property (readwrite, nonatomic) float startValue;
+@property (readwrite, nonatomic) float endValue;
+@property (readwrite, nonatomic) tCDInterpolationType interpolationType;
+
+-(id) init:(id) theTarget interpolationType:(tCDInterpolationType) type startVal:(float) startVal endVal:(float) endVal;
+/** Set to a fractional value between 0 and 1 where 0 equals the start and 1 equals the end*/
+-(void) modify:(float) t;
+
+-(void) _setTargetProperty:(float) newVal;
+-(float) _getTargetProperty;
+-(void) _stopTarget;
+-(Class) _allowableType;
+
+@end
+
+#pragma mark CDSoundSourceFader
+
+/** Fader for CDSoundSource objects */
+@interface CDSoundSourceFader : CDPropertyModifier{}
+@end
+
+#pragma mark CDSoundSourcePanner
+
+/** Panner for CDSoundSource objects */
+@interface CDSoundSourcePanner : CDPropertyModifier{}
+@end
+
+#pragma mark CDSoundSourcePitchBender
+
+/** Pitch bender for CDSoundSource objects */
+@interface CDSoundSourcePitchBender : CDPropertyModifier{}
+@end
+
+#pragma mark CDSoundEngineFader
+
+/** Fader for CDSoundEngine objects */
+@interface CDSoundEngineFader : CDPropertyModifier{}
+@end
+
+
+
+
diff --git a/libs/CocosDenshion/CocosDenshion.m b/libs/CocosDenshion/CocosDenshion.m
new file mode 100644 (file)
index 0000000..8d94116
--- /dev/null
@@ -0,0 +1,1598 @@
+/*
+ Copyright (c) 2010 Steve Oldmeadow
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ $Id$
+ */
+
+#import "CocosDenshion.h"
+
+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)
+{
+       static  alBufferDataStaticProcPtr       proc = NULL;
+    
+    if (proc == NULL) {
+        proc = (alBufferDataStaticProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alBufferDataStatic");
+    }
+    
+    if (proc)
+        proc(bid, format, data, size, freq);
+       
+    return;
+}
+
+typedef ALvoid AL_APIENTRY     (*alcMacOSXMixerOutputRateProcPtr) (const ALdouble value);
+ALvoid  alcMacOSXMixerOutputRateProc(const ALdouble value)
+{
+       static  alcMacOSXMixerOutputRateProcPtr proc = NULL;
+    
+    if (proc == NULL) {
+        proc = (alcMacOSXMixerOutputRateProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcMacOSXMixerOutputRate");
+    }
+    
+    if (proc)
+        proc(value);
+       
+    return;
+}
+
+NSString * const kCDN_BadAlContext = @"kCDN_BadAlContext";
+NSString * const kCDN_AsynchLoadComplete = @"kCDN_AsynchLoadComplete";
+float const kCD_PitchDefault = 1.0f;
+float const kCD_PitchLowerOneOctave = 0.5f;
+float const kCD_PitchHigherOneOctave = 2.0f;
+float const kCD_PanDefault = 0.0f;
+float const kCD_PanFullLeft = -1.0f;
+float const kCD_PanFullRight = 1.0f;
+float const kCD_GainDefault = 1.0f;
+
+@interface CDSoundEngine (PrivateMethods)
+-(BOOL) _initOpenAL;
+-(void) _testGetGain;
+-(void) _dumpSourceGroupsInfo;
+-(void) _getSourceIndexForSourceGroup;
+-(void) _freeSourceGroups;
+-(BOOL) _setUpSourceGroups:(int[]) definitions total:(NSUInteger) total; 
+@end
+
+#pragma mark -
+#pragma mark CDUtilities
+
+@implementation CDUtilities
+
++(NSString*) fullPathFromRelativePath:(NSString*) relPath
+{
+       // do not convert an absolute path (starting with '/')
+       if(([relPath length] > 0) && ([relPath characterAtIndex:0] == '/'))
+       {
+               return relPath;
+       }
+       
+       NSMutableArray *imagePathComponents = [NSMutableArray arrayWithArray:[relPath pathComponents]];
+       NSString *file = [imagePathComponents lastObject];
+       
+       [imagePathComponents removeLastObject];
+       NSString *imageDirectory = [NSString pathWithComponents:imagePathComponents];
+       
+       NSString *fullpath = [[NSBundle mainBundle] pathForResource:file ofType:nil inDirectory:imageDirectory];
+       if (fullpath == nil)
+               fullpath = relPath;
+       
+       return fullpath;        
+}
+
+@end
+
+#pragma mark -
+#pragma mark CDSoundEngine
+
+@implementation CDSoundEngine
+
+static Float32 _mixerSampleRate;
+static BOOL _mixerRateSet = NO;
+
+@synthesize lastErrorCode = lastErrorCode_;
+@synthesize functioning = functioning_;
+@synthesize asynchLoadProgress = asynchLoadProgress_;
+@synthesize getGainWorks = getGainWorks_;
+@synthesize sourceTotal = sourceTotal_;
+
++ (void) setMixerSampleRate:(Float32) sampleRate {
+       _mixerRateSet = YES;
+       _mixerSampleRate = sampleRate;
+}      
+
+- (void) _testGetGain {
+       float testValue = 0.7f;
+       ALuint testSourceId = _sources[0].sourceId;
+       alSourcef(testSourceId, AL_GAIN, 0.0f);//Start from know value
+       alSourcef(testSourceId, AL_GAIN, testValue);
+       ALfloat gainVal;
+       alGetSourcef(testSourceId, AL_GAIN, &gainVal);
+       getGainWorks_ = (gainVal == testValue);
+}
+
+//Generate sources one at a time until we fail
+-(void) _generateSources {
+       
+       _sources = (sourceInfo*)malloc( sizeof(_sources[0]) * CD_SOURCE_LIMIT);
+       BOOL hasFailed = NO;
+       sourceTotal_ = 0;
+       alGetError();//Clear error
+       while (!hasFailed && sourceTotal_ < CD_SOURCE_LIMIT) {
+               alGenSources(1, &(_sources[sourceTotal_].sourceId));
+               if (alGetError() == AL_NO_ERROR) {
+                       //Now try attaching source to null buffer
+                       alSourcei(_sources[sourceTotal_].sourceId, AL_BUFFER, 0);
+                       if (alGetError() == AL_NO_ERROR) {
+                               _sources[sourceTotal_].usable = true;   
+                               sourceTotal_++;
+                       } else {
+                               hasFailed = YES;
+                       }       
+               } else {
+                       _sources[sourceTotal_].usable = false;
+                       hasFailed = YES;
+               }       
+       }
+       //Mark the rest of the sources as not usable
+       for (int i=sourceTotal_; i < CD_SOURCE_LIMIT; i++) {
+               _sources[i].usable = false;
+       }       
+}      
+
+-(void) _generateBuffers:(int) startIndex endIndex:(int) endIndex {
+       if (_buffers) {
+               alGetError();
+               for (int i=startIndex; i <= endIndex; i++) {
+                       alGenBuffers(1, &_buffers[i].bufferId);
+                       _buffers[i].bufferData = NULL;
+                       if (alGetError() == AL_NO_ERROR) {
+                               _buffers[i].bufferState = CD_BS_EMPTY;
+                       } else {
+                               _buffers[i].bufferState = CD_BS_FAILED;
+                               CDLOG(@"Denshion::CDSoundEngine - buffer creation failed %i",i);
+                       }       
+               }
+       }       
+}
+
+/**
+ * Internal method called during init
+ */
+- (BOOL) _initOpenAL
+{
+       //ALenum                        error;
+       context = NULL;
+       ALCdevice               *newDevice = NULL;
+
+       //Set the mixer rate for the audio mixer
+       if (!_mixerRateSet) {
+               _mixerSampleRate = CD_SAMPLE_RATE_DEFAULT;
+       }
+       alcMacOSXMixerOutputRateProc(_mixerSampleRate);
+       CDLOGINFO(@"Denshion::CDSoundEngine - mixer output rate set to %0.2f",_mixerSampleRate);
+       
+       // Create a new OpenAL Device
+       // Pass NULL to specify the system's default output device
+       newDevice = alcOpenDevice(NULL);
+       if (newDevice != NULL)
+       {
+               // Create a new OpenAL Context
+               // The new context will render to the OpenAL Device just created 
+               context = alcCreateContext(newDevice, 0);
+               if (context != NULL)
+               {
+                       // Make the new context the Current OpenAL Context
+                       alcMakeContextCurrent(context);
+                       
+                       // Create some OpenAL Buffer Objects
+                       [self _generateBuffers:0 endIndex:bufferTotal-1];
+                       
+                       // Create some OpenAL Source Objects
+                       [self _generateSources];
+                       
+               }
+       } else {
+               return FALSE;//No device
+       }       
+       alGetError();//Clear error
+       return TRUE;
+}
+
+- (void) dealloc {
+       
+       ALCcontext      *currentContext = NULL;
+    ALCdevice  *device = NULL;
+       
+       [self stopAllSounds];
+
+       CDLOGINFO(@"Denshion::CDSoundEngine - Deallocing sound engine.");
+       [self _freeSourceGroups];
+       
+       // Delete the Sources
+       CDLOGINFO(@"Denshion::CDSoundEngine - deleting sources.");
+       for (int i=0; i < sourceTotal_; i++) {
+               alSourcei(_sources[i].sourceId, AL_BUFFER, 0);//Detach from current buffer
+           alDeleteSources(1, &(_sources[i].sourceId));
+               if((lastErrorCode_ = alGetError()) != AL_NO_ERROR) {
+                       CDLOG(@"Denshion::CDSoundEngine - Error deleting source! %x\n", lastErrorCode_);
+               } 
+       }       
+
+       // Delete the Buffers
+       CDLOGINFO(@"Denshion::CDSoundEngine - deleting buffers.");
+       for (int i=0; i < bufferTotal; i++) {
+               alDeleteBuffers(1, &_buffers[i].bufferId);
+#ifdef CD_USE_STATIC_BUFFERS
+               if (_buffers[i].bufferData) {
+                       free(_buffers[i].bufferData);
+               }       
+#endif         
+       }       
+       CDLOGINFO(@"Denshion::CDSoundEngine - free buffers.");
+       free(_buffers);
+    currentContext = alcGetCurrentContext();
+    //Get device for active context
+    device = alcGetContextsDevice(currentContext);
+    //Release context
+       CDLOGINFO(@"Denshion::CDSoundEngine - destroy context.");
+    alcDestroyContext(currentContext);
+    //Close device
+       CDLOGINFO(@"Denshion::CDSoundEngine - close device.");
+    alcCloseDevice(device);
+       CDLOGINFO(@"Denshion::CDSoundEngine - free sources.");
+       free(_sources);
+       
+       //Release mutexes
+       [_mutexBufferLoad release];
+       
+       [super dealloc];
+}      
+
+-(NSUInteger) sourceGroupTotal {
+       return _sourceGroupTotal;
+}      
+
+-(void) _freeSourceGroups 
+{
+       CDLOGINFO(@"Denshion::CDSoundEngine freeing source groups");
+       if(_sourceGroups) {
+               for (int i=0; i < _sourceGroupTotal; i++) {
+                       if (_sourceGroups[i].sourceStatuses) {
+                               free(_sourceGroups[i].sourceStatuses);
+                               CDLOGINFO(@"Denshion::CDSoundEngine freed source statuses %i",i);
+                       }       
+               }
+               free(_sourceGroups);
+       }       
+}      
+
+-(BOOL) _redefineSourceGroups:(int[]) definitions total:(NSUInteger) total
+{
+       if (_sourceGroups) {
+               //Stop all sounds
+               [self stopAllSounds];
+               //Need to free source groups
+               [self _freeSourceGroups];
+       }
+       return [self _setUpSourceGroups:definitions total:total];
+}      
+
+-(BOOL) _setUpSourceGroups:(int[]) definitions total:(NSUInteger) total 
+{
+       _sourceGroups = (sourceGroup *)malloc( sizeof(_sourceGroups[0]) * total);
+       if(!_sourceGroups) {
+               CDLOG(@"Denshion::CDSoundEngine - source groups memory allocation failed");
+               return NO;
+       }
+       
+       _sourceGroupTotal = total;
+       int sourceCount = 0;
+       for (int i=0; i < _sourceGroupTotal; i++) {
+               
+               _sourceGroups[i].startIndex = 0;
+               _sourceGroups[i].currentIndex = _sourceGroups[i].startIndex;
+               _sourceGroups[i].enabled = false;
+               _sourceGroups[i].nonInterruptible = false;
+               _sourceGroups[i].totalSources = definitions[i];
+               _sourceGroups[i].sourceStatuses = malloc(sizeof(_sourceGroups[i].sourceStatuses[0]) * _sourceGroups[i].totalSources);
+               if (_sourceGroups[i].sourceStatuses) {
+                       for (int j=0; j < _sourceGroups[i].totalSources; j++) {
+                               //First bit is used to indicate whether source is locked, index is shifted back 1 bit
+                               _sourceGroups[i].sourceStatuses[j] = (sourceCount + j) << 1;    
+                       }       
+               }       
+               sourceCount += definitions[i];
+       }
+       return YES;
+}
+
+-(void) defineSourceGroups:(int[]) sourceGroupDefinitions total:(NSUInteger) total {
+       [self _redefineSourceGroups:sourceGroupDefinitions total:total];
+}
+
+-(void) defineSourceGroups:(NSArray*) sourceGroupDefinitions {
+       CDLOGINFO(@"Denshion::CDSoundEngine - source groups defined by NSArray.");
+       NSUInteger totalDefs = [sourceGroupDefinitions count];
+       int* defs = (int *)malloc( sizeof(int) * totalDefs);
+       int currentIndex = 0;
+       for (id currentDef in sourceGroupDefinitions) {
+               if ([currentDef isKindOfClass:[NSNumber class]]) {
+                       defs[currentIndex] = (int)[(NSNumber*)currentDef integerValue];
+                       CDLOGINFO(@"Denshion::CDSoundEngine - found definition %i.",defs[currentIndex]);
+               } else {
+                       CDLOG(@"Denshion::CDSoundEngine - warning, did not understand source definition.");
+                       defs[currentIndex] = 0;
+               }       
+               currentIndex++;
+       }
+       [self _redefineSourceGroups:defs total:totalDefs];
+       free(defs);
+}      
+
+- (id)init
+{      
+       if ((self = [super init])) {
+               
+               //Create mutexes
+               _mutexBufferLoad = [[NSObject alloc] init];
+               
+               asynchLoadProgress_ = 0.0f;
+               
+               bufferTotal = CD_BUFFERS_START;
+               _buffers = (bufferInfo *)malloc( sizeof(_buffers[0]) * bufferTotal);
+       
+               // Initialize our OpenAL environment
+               if ([self _initOpenAL]) {
+                       //Set up the default source group - a single group that contains all the sources
+                       int sourceDefs[1];
+                       sourceDefs[0] = self.sourceTotal;
+                       [self _setUpSourceGroups:sourceDefs total:1];
+
+                       functioning_ = YES;
+                       //Synchronize premute gain
+                       _preMuteGain = self.masterGain;
+                       mute_ = NO;
+                       enabled_ = YES;
+                       //Test whether get gain works for sources
+                       [self _testGetGain];
+               } else {
+                       //Something went wrong with OpenAL
+                       functioning_ = NO;
+               }
+       }
+       
+       return self;
+}
+
+/**
+ * Delete the buffer identified by soundId
+ * @return true if buffer deleted successfully, otherwise false
+ */
+- (BOOL) unloadBuffer:(int) soundId 
+{
+       //Ensure soundId is within array bounds otherwise memory corruption will occur
+    &