first commit

This commit is contained in:
2026-09-09 03:08:43 -05:00
commit 0c3c1ffb56
378 changed files with 84045 additions and 0 deletions
@@ -0,0 +1,138 @@
//
// ALBuffer.h
// ObjectAL
//
// Created by Karl Stenerud on 15/12/09.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import <OpenAL/al.h>
@class ALDevice;
#pragma mark ALBuffer
/**
* A buffer for audio data that will be played via a SoundSource.
* @see SoundSource
*/
@interface ALBuffer : NSObject
{
ALDevice* device;
ALuint bufferId;
NSString* name;
ALenum format;
float duration;
/** The uncompressed sound data to play. */
void* bufferData;
bool freeDataOnDestroy;
ALBuffer* parentBuffer;
}
#pragma mark Properties
/** The size of a sample in bits. */
@property(nonatomic,readonly,assign) ALint bits;
/** The ID assigned to this buffer by OpenAL. */
@property(nonatomic,readonly,assign) ALuint bufferId;
/** The number of channels the buffer data plays in. */
@property(nonatomic,readonly,assign) ALint channels;
/** The device this buffer was created for. */
@property(nonatomic,readonly,retain) ALDevice* device;
/** The format of the audio data (see al.h, AL_FORMAT_XXX). */
@property(nonatomic,readonly,assign) ALenum format;
/** The frequency this buffer runs at. */
@property(nonatomic,readonly,assign) ALint frequency;
/** The name given to this buffer upon creation. You may change it at runtime if you wish. */
@property(nonatomic,readwrite,retain) NSString* name;
/** The size, in bytes, of the currently loaded buffer data. */
@property(nonatomic,readonly,assign) ALint size;
/** The duration of the sample in this buffer, in seconds. */
@property(nonatomic,readonly,assign) float duration;
/** If true, calls free() on the audio data when this object gets destroyed.
* Default: YES
*/
@property(nonatomic,readwrite,assign) bool freeDataOnDestroy;
/** The parent buffer (which owns the uncompressed data) */
@property(nonatomic,readwrite,retain) ALBuffer* parentBuffer;
#pragma mark Object Management
/** Make a new buffer.
*
* @param name Optional name that you can use to identify this buffer in your code.
* @param data The sound data. Note: ALBuffer will call free() on this data when it is destroyed!
* @param size The size of the data in bytes.
* @param format The format of the data (see the Core Audio documentation).
* @param frequency The sampling frequency in Hz.
* @return A new buffer.
*/
+ (id) bufferWithName:(NSString*) name
data:(void*) data
size:(ALsizei) size
format:(ALenum) format
frequency:(ALsizei) frequency;
/** Initialize the buffer.
*
* @param name Optional name that you can use to identify this buffer in your code.
* @param data The sound data. Note: ALBuffer will call free() on this data when it is destroyed!
* @param size The size of the data in bytes.
* @param format The format of the data (see the Core Audio documentation).
* @param frequency The sampling frequency in Hz.
* @return The initialized buffer.
*/
- (id) initWithName:(NSString*) name
data:(void*) data
size:(ALsizei) size
format:(ALenum) format
frequency:(ALsizei) frequency;
/** Returns a part of the buffer as a new buffer. You can use this method to split a buffer
* into a sub-buffers. The sub-buffers retain a reference to their parent buffer, and share
* the same memory. Therefore, modifying the parent buffer contents will affect its slices
* and vice-versa.
*
* @param sliceName Optional name that you can use to identify the created buffer in your code.
* @param offset The offset in sound frames where the slice starts.
* @param size The size of the slice in frames.
* @return The requested buffer.
*/
- (ALBuffer*)sliceWithName:(NSString *) sliceName offset:(ALsizei) offset size:(ALsizei) size;
@end
@@ -0,0 +1,135 @@
//
// ALCaptureDevice.h
// ObjectAL
//
// Created by Karl Stenerud on 10-01-11.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import <OpenAL/alc.h>
#pragma mark ALCaptureDevice
/**
* *UNIMPLEMENTED FOR IOS* An OpenAL device for capturing sound data.
* Note: This functionality is NOT implemented in iOS OpenAL! <br>
* This class is a placeholder in case such functionality is added in a future iOS SDK.
*/
@interface ALCaptureDevice : NSObject
{
ALCdevice* device;
}
#pragma mark Properties
/** The number of capture samples available. */
@property(nonatomic,readonly,assign) int captureSamples;
/** The OpenAL device pointer. */
@property(nonatomic,readonly,assign) ALCdevice* device;
/** List of strings describing all extensions available on this device (NSString*). */
@property(nonatomic,readonly,retain) NSArray* extensions;
/** The specification revision for this implementation (major version). */
@property(nonatomic,readonly,assign) int majorVersion;
/** The specification revision for this implementation (minor version). */
@property(nonatomic,readonly,assign) int minorVersion;
#pragma mark Object Management
/** Open the specified device.
*
* @param deviceSpecifier The name of the device to open (nil = default device).
* @param frequency The frequency to capture at.
* @param format The audio format to capture as.
* @param bufferSize The size of buffer that the device must allocate for audio capture.
* @return A new capture device.
*/
+ (id) deviceWithDeviceSpecifier:(NSString*) deviceSpecifier
frequency:(ALCuint) frequency
format:(ALCenum) format
bufferSize:(ALCsizei) bufferSize;
/** Open the specified device.
*
* @param deviceSpecifier The name of the device to open (nil = default device).
* @param frequency The frequency to capture at.
* @param format The audio format to capture as.
* @param bufferSize The size of buffer that the device must allocate for audio capture.
* @return The initialized capture device.
*/
- (id) initWithDeviceSpecifier:(NSString*) deviceSpecifier
frequency:(ALCuint) frequency
format:(ALCenum) format
bufferSize:(ALCsizei) bufferSize;
#pragma mark Audio Capture
/** Start capturing samples.
*
* @return TRUE if the operation was successful.
*/
- (bool) startCapture;
/** Stop capturing samples.
*
* @return TRUE if the operation was successful.
*/
- (bool) stopCapture;
/** Move captured samples to the specified buffer.
* This method will fail if less than the specified number of samples have been captured.
*
* @param numSamples The number of samples to move.
* @param buffer the buffer to move the samples into.
* @return TRUE if the operation was successful.
*/
- (bool) moveSamples:(ALCsizei) numSamples toBuffer:(ALCvoid*) buffer;
#pragma mark Extensions
/** Check if the specified extension is present.
*
* @param name The name of the extension to check.
* @return TRUE if the extension is present.
*/
- (bool) isExtensionPresent:(NSString*) name;
/** Get the address of the specified procedure (C function address).
*
* @param functionName The name of the procedure to get.
* @return the procedure's address, or NULL if it wasn't found.
*/
- (void*) getProcAddress:(NSString*) functionName;
@end
@@ -0,0 +1,239 @@
//
// ChannelSource.h
// ObjectAL
//
// Created by Karl Stenerud on 15/12/09.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import "ALSoundSource.h"
#import "ALSoundSourcePool.h"
#import "ALContext.h"
#pragma mark ALChannelSource
/**
* A Sound source composed of other sources.
* Property values are applied to all sources within the channel. <br>
* Sounds will get played by any free sources within this channel. <br>
* If all sources are busy when playback is requested, it will attempt to interrupt a source
* to free it for playback.
*/
@interface ALChannelSource : NSObject <ALSoundSource>
{
/** Pool holding the actual sources */
ALSoundSourcePool* sourcePool;
ALContext* context;
/** If YES, the defaults of this channel have been initialized */
bool defaultsInitialized;
float pitch;
float gain;
float maxDistance;
float rolloffFactor;
float referenceDistance;
float minGain;
float maxGain;
float coneOuterGain;
float coneInnerAngle;
float coneOuterAngle;
float reverbSendLevel;
float reverbOcclusion;
float reverbObstruction;
ALPoint position;
ALVector velocity;
ALVector direction;
int sourceRelative;
int sourceType;
bool looping;
/** Default pitch */
float defaultPitch;
/** Default gain */
float defaultGain;
/** Default max distance */
float defaultMaxDistance;
/** Default rolloff factor */
float defaultRolloffFactor;
/** Default reference distance */
float defaultReferenceDistance;
/** Default min gain */
float defaultMinGain;
/** Default max gain */
float defaultMaxGain;
/** Default cone outer gain */
float defaultConeOuterGain;
/** Default cone inner angle */
float defaultConeInnerAngle;
/** Default cone outer angle */
float defaultConeOuterAngle;
/** Default position */
ALPoint defaultPosition;
/** Default veloxity */
ALVector defaultVelocity;
/** Default direction */
ALVector defaultDirection;
/** Default source relative */
int defaultSourceRelative;
/** Default source type */
int defaultSourceType;
/** Default looping */
bool defaultLooping;
/** Default reverb send level */
float defaultReverbSendLevel;
/** Default occlusion */
float defaultReverbOcclusion;
/** Default obstruction */
float defaultReverbObstruction;
bool interruptible;
bool muted;
bool paused;
/** Target to inform when the current fade operation completes. */
id fadeCompleteTarget;
/** Selector to call when the current fade operation completes. */
SEL fadeCompleteSelector;
/** The expected number of sources that will callback when fading completes */
int expectedFadeCallbackCount;
/** The actual number of sources that have called back */
int currentFadeCallbackCount;
/** Target to inform when the current pan operation completes. */
id panCompleteTarget;
/** Selector to call when the current pan operation completes. */
SEL panCompleteSelector;
/** The expected number of sources that will callback when panning completes */
int expectedPanCallbackCount;
/** The actual number of sources that have called back */
int currentPanCallbackCount;
/** Target to inform when the current pitch operation completes. */
id pitchCompleteTarget;
/** Selector to call when the current pitch operation completes. */
SEL pitchCompleteSelector;
/** The expected number of sources that will callback when pitch op completes */
int expectedPitchCallbackCount;
/** The actual number of sources that have called back */
int currentPitchCallbackCount;
}
#pragma mark Properties
/** This source's owning context. */
@property(nonatomic,readonly,retain) ALContext* context;
/** All sources being used by this channel. Do not modify! */
@property(nonatomic,readonly,retain) ALSoundSourcePool* sourcePool;
/** The number of sources reserved by this channel. */
@property(nonatomic,readwrite,assign) int reservedSources;
#pragma mark Object Management
/** Create a channel with a number of sources.
*
* @param reservedSources the number of sources to reserve for this channel.
* @return A new channel.
*/
+ (id) channelWithSources:(int) reservedSources;
/** Initialize a channel with a number of sources.
*
* @param reservedSources the number of sources to reserve for this channel.
* @return The initialized channel.
*/
- (id) initWithSources:(int) reservedSources;
/** Set this channel's default values from those in the specified source.
*
* @param source the source to set default values from.
*/
- (void) setDefaultsFromSource:(id<ALSoundSource>) source;
/** Reset all sources in this channel to their default state.
*/
- (void) resetToDefault;
/** Add a source to this channel.
*
* @param source The source to add.
*/
- (void) addSource:(id<ALSoundSource>) source;
/** Remove a source from the channel.
*
* @param source The source to remove. If nil, remove any source.
* @return The source that was removed.
*/
- (id<ALSoundSource>) removeSource:(id<ALSoundSource>) source;
/** Split the specified number of sources from this channel, creating a new
* channel.
*
* @param numSources The number of sources to split off
* @return A new channel with the split-off sources.
*/
- (ALChannelSource*) splitChannelWithSources:(int) numSources;
/** Absorb another channel's sources into this one. All of the channel's sources
* will be moved into this channel.
*
* @param channel The channel to absorb sources from.
*/
- (void) addChannel:(ALChannelSource*) channel;
/** Set all buffers in all non-playing sources to nil.
*
* @return A list of buffers that were cleared.
*/
- (NSArray*) clearUnusedBuffers;
/** Remove all instances of the specified buffer.
*
* @param name The name of the buffer.
*
* @return NO if any of the matching buffers are currently being played.
*/
- (BOOL) removeBuffersNamed:(NSString*) name;
@end
@@ -0,0 +1,245 @@
//
// ALContext.h
// ObjectAL
//
// Created by Karl Stenerud on 10-01-09.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import <OpenAL/alc.h>
#import "ALListener.h"
#import "ALSource.h"
#import "OALSuspendHandler.h"
@class ALDevice;
#pragma mark ALContext
/**
* A context encompasses a single listener and a series of sources.
* A context is created from a device, and many contexts may be created
* (though multiple contexts would be unusual in an iOS app). <br>
*
* Note: Some property values are only valid if this context is the current
* context.
*
* @see ObjectAL.currentContext
*/
@interface ALContext : NSObject <OALSuspendManager>
{
ALCcontext* context;
/** All sound sources associated with this context. */
NSMutableArray* sources;
ALListener* listener;
bool suspended;
/** This context's attributes. */
NSMutableArray* attributes;
/** Handles suspending and interrupting for this object. */
OALSuspendHandler* suspendHandler;
}
#pragma mark Properties
/** OpenAL version string in format
* “[spec major number].[spec minor number] [optional vendor version information]”
* Only valid when this is the current context.
*/
@property(nonatomic,readonly,retain) NSString* alVersion;
/** The current context's attribute list.
* Only valid when this is the current context.
*/
@property(nonatomic,readonly,retain) NSArray* attributes;
/** The OpenAL context pointer. */
@property(nonatomic,readonly,assign) ALCcontext* context;
/** The device this context was opened on. */
@property(nonatomic,readonly,retain) ALDevice* device;
/** The current distance model.
* Legal values are AL_NONE, AL_INVERSE_DISTANCE, AL_INVERSE_DISTANCE_CLAMPED,
* AL_LINEAR_DISTANCE, AL_LINEAR_DISTANCE_CLAMPED, AL_EXPONENT_DISTANCE,
* and AL_EXPONENT_DISTANCE_CLAMPED. See the OpenAL spec for detailed information. <br>
* Only valid when this is the current context.
*/
@property(nonatomic,readwrite,assign) ALenum distanceModel;
/** Exaggeration factor for Doppler effect.
* Only valid when this is the current context.
*/
@property(nonatomic,readwrite,assign) float dopplerFactor;
/** List of available extensions (NSString*).
* Only valid when this is the current context.
*/
@property(nonatomic,readonly,retain) NSArray* extensions;
/** This context's listener. */
@property(nonatomic,readonly,retain) ALListener* listener;
/** Information about the specific renderer.
* Only valid when this is the current context.
*/
@property(nonatomic,readonly,retain) NSString* renderer;
/** All sources associated with this context (ALSource*). */
@property(nonatomic,readonly,retain) NSArray* sources;
/** Speed of sound in same units as velocities.
* Only valid when this is the current context.
*/
@property(nonatomic,readwrite,assign) float speedOfSound;
/** Name of the vendor.
* Only valid when this is the current context.
*/
@property(nonatomic,readonly,retain) NSString* vendor;
#pragma mark Object Management
/** Create a new context on the specified device.
*
* @param device The device to open the context on.
* @param attributes An array of NSNumber in ordered pairs (attribute id followed by integer value).
* Posible attributes: ALC_FREQUENCY, ALC_REFRESH, ALC_SYNC, ALC_MONO_SOURCES, ALC_STEREO_SOURCES
* @return A new context.
*/
+ (id) contextOnDevice:(ALDevice *) device attributes:(NSArray*) attributes;
/** Create a new context on the specified device with attributes.
*
* @param device The device to open the context on.
* @param outputFrequency The frequency to mix all sources to before outputting (ignored by iOS).
* @param refreshIntervals The number of passes per second used to mix the audio sources.
* For games this can be 5-15. For audio intensive apps, it should be higher (ignored by iOS).
* @param synchronousContext If true, this context runs on the main thread and depends on you
* calling alcUpdateContext (ignored by iOS).
* @param monoSources A hint indicating how many sources should support mono (default 28 on iOS).
* @param stereoSources A hint indicating how many sources should support stereo (default 4 on iOS).
* @return A new context.
*/
+ (id) contextOnDevice:(ALDevice*) device
outputFrequency:(int) outputFrequency
refreshIntervals:(int) refreshIntervals
synchronousContext:(bool) synchronousContext
monoSources:(int) monoSources
stereoSources:(int) stereoSources;
/** Initialize this context on the specified device with attributes.
*
* @param device The device to open the context on.
* @param outputFrequency The frequency to mix all sources to before outputting (ignored by iOS).
* @param refreshIntervals The number of passes per second used to mix the audio sources.
* For games this can be 5-15. For audio intensive apps, it should be higher (ignored by iOS).
* @param synchronousContext If true, this context runs on the main thread and depends on you
* calling alcUpdateContext (ignored by iOS).
* @param monoSources A hint indicating how many sources should support mono (default 28 on iOS).
* @param stereoSources A hint indicating how many sources should support stereo (default 4 on iOS).
* @return The initialized context.
*/
- (id) initOnDevice:(ALDevice*) device
outputFrequency:(int) outputFrequency
refreshIntervals:(int) refreshIntervals
synchronousContext:(bool) synchronousContext
monoSources:(int) monoSources
stereoSources:(int) stereoSources;
/** Initialize this context for the specified device and attributes.
*
* @param device The device to open the context on.
* @param attributes An array of NSNumber in ordered pairs (attribute id followed by integer value).
* Posible attributes: ALC_FREQUENCY, ALC_REFRESH, ALC_SYNC, ALC_MONO_SOURCES, ALC_STEREO_SOURCES
* @return The initialized context.
*/
- (id) initOnDevice:(ALDevice *) device attributes:(NSArray*) attributes;
#pragma mark Utility
/** Process this context.
*/
- (void) process;
/** Stop all sound sources in this context.
*/
- (void) stopAllSounds;
/** Clear all buffers being used by sources in this context.
*/
- (void) clearBuffers;
/** Make sure this context is the current context.
* This method is used to work around iOS 4.0 and 4.2 bugs
* that could cause the context to be lost.
*/
- (void) ensureContextIsCurrent;
#pragma mark Extensions
/** Check if the specified extension is present in this context.
* Only valid when this is the current context.
*
* @param name The name of the extension to check.
* @return TRUE if the extension is present in this context.
*/
- (bool) isExtensionPresent:(NSString*) name;
/** Get the address of the specified procedure (C function address).
* Only valid when this is the current context. <br>
* <strong>Note:</strong> The OpenAL implementation is free to return
* a pointer even if it is not valid for this context. Always call isExtensionPresent
* first.
*
* @param functionName the name of the procedure to get.
* @return the procedure's address, or NULL if it wasn't found.
*/
- (void*) getProcAddress:(NSString*) functionName;
#pragma mark Internal Use
/** \cond */
/** (INTERNAL USE) Used by ALSource to announce initialization.
*
* @param source the source that is initializing.
*/
- (void) notifySourceInitializing:(ALSource*) source;
/** (INTERNAL USE) Used by ALSource to announce deallocation.
*
* @param source the source that is deallocating.
*/
- (void) notifySourceDeallocating:(ALSource*) source;
/** \endcond */
@end
@@ -0,0 +1,127 @@
//
// ALDevice.h
// ObjectAL
//
// Created by Karl Stenerud on 10-01-09.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import <OpenAL/alc.h>
#import "ALContext.h"
#import "OALSuspendHandler.h"
#pragma mark ALDevice
/**
* A device is a logical mapping to an audio device through the OpenAL implementation.
*/
@interface ALDevice : NSObject <OALSuspendManager>
{
ALCdevice* device;
/** All contexts opened from this device. */
NSMutableArray* contexts;
/** Handles suspending and interrupting for this object. */
OALSuspendHandler* suspendHandler;
}
#pragma mark Properties
/** All contexts created on this device (ALContext*). */
@property(nonatomic,readonly,retain) NSArray* contexts;
/** The OpenAL device pointer. */
@property(nonatomic,readonly,assign) ALCdevice* device;
/** List of strings describing all extensions available on this device (NSString*). */
@property(nonatomic,readonly,retain) NSArray* extensions;
/** The specification revision for this implementation (major version). */
@property(nonatomic,readonly,assign) int majorVersion;
/** The specification revision for this implementation (minor version). */
@property(nonatomic,readonly,assign) int minorVersion;
#pragma mark Object Management
/** Open the specified device.
*
* @param deviceSpecifier The device to open (nil = default device).
* @return A new device.
*/
+ (id) deviceWithDeviceSpecifier:(NSString*) deviceSpecifier;
/** Initialize with the specified device.
*
* @param deviceSpecifier The device to open (nil = default device).
* @return the initialized device.
*/
- (id) initWithDeviceSpecifier:(NSString*) deviceSpecifier;
#pragma mark Extensions
/** Check if the specified extension is present.
*
* @param name The extension to check.
* @return TRUE if the extension is present.
*/
- (bool) isExtensionPresent:(NSString*) name;
/** Get the address of the specified procedure (C function address).
*
* @param functionName the name of the procedure to get.
* @return the procedure's address, or NULL if it wasn't found.
*/
- (void*) getProcAddress:(NSString*) functionName;
#pragma mark Utility
/** Clear all buffers being used by sources of contexts opened on this device.
*/
- (void) clearBuffers;
#pragma mark Internal Use
/** \cond */
/** (INTERNAL USE) Used by ALContext to announce initialization.
*
* @param context The context that is initializing.
*/
- (void) notifyContextInitializing:(ALContext*) context;
/** (INTERNAL USE) Used by ALContext to announce deallocation.
*
* @param context The context that is deallocating.
*/
- (void) notifyContextDeallocating:(ALContext*) context;
/** \endcond */
@end
@@ -0,0 +1,144 @@
//
// ALListener.h
// ObjectAL
//
// Created by Karl Stenerud on 10-01-07.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import "ALTypes.h"
#import "OALSuspendHandler.h"
@class ALContext;
#pragma mark ALListener
/**
* The listener represents the user who is listening to sounds in 3D space.
* This object controls his position, orientation, and velocity, as well as providing a master
* gain. <br>
* A context contains one and only one listener.
*/
@interface ALListener : NSObject <OALSuspendManager>
{
bool muted;
float gain;
/** Handles suspending and interrupting for this object. */
OALSuspendHandler* suspendHandler;
}
#pragma mark Properties
/** The context this listener belongs to (WEAK reference). */
@property(nonatomic,readonly,assign) ALContext* context;
/** Causes this listener to stop hearing sound.
* It's called "muted" rather than "deaf" to give a consistent name with other mute functions.
*/
@property(nonatomic,readwrite,assign) bool muted;
/** Gain (volume), affecting every sound this listener hears (0.0 = no sound, 1.0 = max volume).
* Only valid if this listener's context is the current context.
*/
@property(nonatomic,readwrite,assign) float gain;
/** Orientation (up: x, y, z, at: x, y, z).
* Only valid if this listener's context is the current context.
*/
@property(nonatomic,readwrite,assign) ALOrientation orientation;
/** Position (x, y, z).
* Only valid if this listener's context is the current context.
*/
@property(nonatomic,readwrite,assign) ALPoint position;
/** Velocity (x, y, z).
* Only valid if this listener's context is the current context.
*/
@property(nonatomic,readwrite,assign) ALVector velocity;
/** Turns on reverb. (iOS 5.0+)
*/
@property(nonatomic,readwrite,assign) bool reverbOn;
/** The global reverb level (from -40.0db to 40.0db). (iOS 5.0+)
*/
@property(nonatomic,readwrite,assign) float globalReverbLevel;
/** The room type to simulate for reverb. (iOS 5.0+)
*
* Allowed room types:
*
* ALC_ASA_REVERB_ROOM_TYPE_SmallRoom
* ALC_ASA_REVERB_ROOM_TYPE_MediumRoom
* ALC_ASA_REVERB_ROOM_TYPE_LargeRoom
* ALC_ASA_REVERB_ROOM_TYPE_MediumHall
* ALC_ASA_REVERB_ROOM_TYPE_LargeHall
* ALC_ASA_REVERB_ROOM_TYPE_Plate
* ALC_ASA_REVERB_ROOM_TYPE_MediumChamber
* ALC_ASA_REVERB_ROOM_TYPE_LargeChamber
* ALC_ASA_REVERB_ROOM_TYPE_Cathedral
* ALC_ASA_REVERB_ROOM_TYPE_LargeRoom2
* ALC_ASA_REVERB_ROOM_TYPE_MediumHall2
* ALC_ASA_REVERB_ROOM_TYPE_MediumHall3
* ALC_ASA_REVERB_ROOM_TYPE_LargeHall2
*/
@property(nonatomic,readwrite,assign) int reverbRoomType;
/** The equalizer gain for reverb. (iOS 5.0+)
*/
@property(nonatomic,readwrite,assign) float reverbEQGain;
/** The equalizer bandwidth for reverb. (iOS 5.0+)
*/
@property(nonatomic,readwrite,assign) float reverbEQBandwidth;
/** The equalizer frequency for reverb. (iOS 5.0+)
*/
@property(nonatomic,readwrite,assign) float reverbEQFrequency;
#pragma mark Object Management
/** \cond */
/** (INTERNAL USE) Create a listener for the specified context.
*
* @param context the context to create this listener on.
* @return A new listener.
*/
+ (id) listenerForContext:(ALContext*) context;
/** (INTERNAL USE) Initialize a listener for the specified context.
*
* @param context the context to create this listener on.
* @return The initialized listener.
*/
- (id) initWithContext:(ALContext*) context;
/** \endcond */
@end
@@ -0,0 +1,243 @@
//
// SoundSource.h
// ObjectAL
//
// Created by Karl Stenerud on 15/12/09.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import "ALBuffer.h"
#import "ALTypes.h"
#pragma mark ALSoundSource
/**
* Manages all properties relating to an OpenAL sound source.
* There are currently two classes that adhere to this protocol: ALSource
* and ChannelSource (which collectively manipulates a set of ALSource objects).
* A full description of the properties themselves is available in the
* OpenAL 1.1 Specification and Reference:
* http://connect.creativelabs.com/openal/Documentation
*/
@protocol ALSoundSource <NSObject>
#pragma mark Properties
/** Cone inner angle (OpenAL property). */
@property(nonatomic,readwrite,assign) float coneInnerAngle;
/** Cone outer angle (OpenAL property). */
@property(nonatomic,readwrite,assign) float coneOuterAngle;
/** Cone outer gain (OpenAL property). */
@property(nonatomic,readwrite,assign) float coneOuterGain;
/** Direction (OpenAL property). */
@property(nonatomic,readwrite,assign) ALVector direction;
/** Gain (volume) (OpenAL property). */
@property(nonatomic,readwrite,assign) float gain;
/** Volume (alias to gain). */
@property(nonatomic,readwrite,assign) float volume;
/** If true, this source may be interrupted when resources are low. */
@property(nonatomic,readwrite,assign) bool interruptible;
/** Looping (OpenAL property). */
@property(nonatomic,readwrite,assign) bool looping;
/** Max distance (OpenAL property). */
@property(nonatomic,readwrite,assign) float maxDistance;
/** Max gain (OpenAL property). */
@property(nonatomic,readwrite,assign) float maxGain;
/** Min gain (OpenAL property). */
@property(nonatomic,readwrite,assign) float minGain;
/** If true, this source is muted. */
@property(nonatomic,readwrite,assign) bool muted;
/** If true, this source is currently paused. */
@property(nonatomic,readwrite,assign) bool paused;
/** Pitch (OpenAL property). */
@property(nonatomic,readwrite,assign) float pitch;
/** If true, this source is currently playing audio. */
@property(nonatomic,readonly,assign) bool playing;
/** Position (OpenAL property). */
@property(nonatomic,readwrite,assign) ALPoint position;
/** Reference distance (OpenAL property). */
@property(nonatomic,readwrite,assign) float referenceDistance;
/** Rolloff factor (OpenAL property). */
@property(nonatomic,readwrite,assign) float rolloffFactor;
/** Source relative (OpenAL property). */
@property(nonatomic,readwrite,assign) int sourceRelative;
/** Source type (OpenAL property). */
@property(nonatomic,readonly,assign) int sourceType;
/** Velocity (OpenAL property). */
@property(nonatomic,readwrite,assign) ALVector velocity;
/** Pan value (-1.0 = far left, 1.0 = far right).
* Note: This effect is simulated by changing the source's X position.
* Do not use this property if you are modifying the position property as well.
*/
@property(nonatomic,readwrite,assign) float pan;
/** Reverb send level (how much reverb affects this source). (iOS 5.0+)
* 0.0 = fully dry, 1.0 = fully wet.
* Default 0.
*/
@property(nonatomic,readwrite,assign) float reverbSendLevel;
/** Reverb occlusion (wall/door between listener and source). (iOS 5.0+)
* -100.0db (most occlusion) to 0.0 (no occlusion).
* Default 0.
*/
@property(nonatomic,readwrite,assign) float reverbOcclusion;
/** Reverb obstruction (object between listener and source). (iOS 5.0+)
* -100.0db (most obstruction) to 0.0 (no obstruction).
* Default 0.
*/
@property(nonatomic,readwrite,assign) float reverbObstruction;
#pragma mark Object Management
#pragma mark Playback
/** Play a sound.
*
* @param buffer the buffer to play.
* @return the source playing the sound, or nil if the sound could not be played.
*/
- (id<ALSoundSource>) play:(ALBuffer*) buffer;
/** Play a sound, optionally looping.
*
* @param buffer the buffer to play.
* @param loop If TRUE, the sound will loop until you call "stop" on the returned sound source.
* @return the source playing the sound, or nil if the sound could not be played.
*/
- (id<ALSoundSource>) play:(ALBuffer*) buffer loop:(bool) loop;
/** Play a sound, setting gain, pitch, pan, and looping.
*
* @param buffer the buffer to play.
* @param gain The gain (volume) to play at (0.0 - 1.0).
* @param pitch The pitch to play at (1.0 = normal pitch).
* @param pan Left-right panning (-1.0 = far left, 1.0 = far right).
* @param loop If TRUE, the sound will loop until you call "stop" on the returned sound source.
* @return the source playing the sound, or nil if the sound could not be played.
*/
- (id<ALSoundSource>) play:(ALBuffer*) buffer
gain:(float) gain
pitch:(float) pitch
pan:(float) pan
loop:(bool) loop;
/** Stop playing the current sound.
*/
- (void) stop;
/** Stop playing the current sound and set its state to AL_INITIAL.
*/
- (void) rewind;
/** Fade to the specified gain value.
*
* @param gain The gain to fade to.
* @param duration The duration of the fade operation in seconds.
* @param target The target to notify when the fade completes (can be nil).
* @param selector The selector to call when the fade completes. The selector must accept
* a single parameter, which will be the object that performed the fade.
*/
- (void) fadeTo:(float) gain
duration:(float) duration
target:(id) target
selector:(SEL) selector;
/** Stop the currently running fade operation, if any.
*/
- (void) stopFade;
/** pan to the specified value.
*
* @param pan The value to pan to.
* @param duration The duration of the pan operation in seconds.
* @param target The target to notify when the pan completes (can be nil).
* @param selector The selector to call when the pan completes. The selector must accept
* a single parameter, which will be the object that performed the pan.
*/
- (void) panTo:(float) pan
duration:(float) duration
target:(id) target
selector:(SEL) selector;
/** Stop the currently running pan operation, if any.
*/
- (void) stopPan;
/** Gradually change pitch to the specified value.
*
* @param pitch The value to change pitch to.
* @param duration The duration of the pitch operation in seconds.
* @param target The target to notify when the pitch change completes (can be nil).
* @param selector The selector to call when the pitch change completes. The selector
* must accept a single parameter, which will be the object that performed the pitch change.
*/
- (void) pitchTo:(float) pitch
duration:(float) duration
target:(id) target
selector:(SEL) selector;
/** Stop the currently running pitch operation, if any.
*/
- (void) stopPitch;
/** Stop any currently running fade, pan, or pitch operations.
*/
- (void) stopActions;
#pragma mark Utility
/** Clear any buffers this source is currently using.
*/
- (void) clear;
@end
@@ -0,0 +1,83 @@
//
// SoundSourcePool.h
// ObjectAL
//
// Created by Karl Stenerud on 17/12/09.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import "ALSoundSource.h"
#pragma mark ALSoundSourcePool
/**
* A pool of sound sources, which can be fetched based on availability.
*/
@interface ALSoundSourcePool : NSObject
{
/** All sources managed by this pool (id<ALSoundSource>). */
NSMutableArray* sources;
}
#pragma mark Properties
/** All sources managed by this pool (id<ALSoundSource>). */
@property(nonatomic,readonly,retain) NSArray* sources;
#pragma mark Object Management
/** Make a new pool.
* @return A new pool.
*/
+ (id) pool;
#pragma mark Source Management
/** Add a source to this pool.
*
* @param source The source to add.
*/
- (void) addSource:(id<ALSoundSource>) source;
/** Remove a source from this pool
*
* @param source The source to remove.
*/
- (void) removeSource:(id<ALSoundSource>) source;
/** Acquire a free or freeable source from this pool.
* It first attempts to find a completely free source.
* Failing this, it will attempt to interrupt a source and return that (if attemptToInterrupt
* is TRUE).
*
* @param attemptToInterrupt If TRUE, attempt to interrupt sources to free them for use.
* @return The freed sound source, or nil if no sources are freeable.
*/
- (id<ALSoundSource>) getFreeSource:(bool) attemptToInterrupt;
@end
@@ -0,0 +1,223 @@
//
// ALSource.h
// ObjectAL
//
// Created by Karl Stenerud on 15/12/09.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import <OpenAL/al.h>
#import "ALSoundSource.h"
#import "ALBuffer.h"
#import "OALAction.h"
#import "OALSuspendHandler.h"
@class ALContext;
@class ALSource;
typedef void (^OALSourceNotificationCallback)(ALSource* source, ALuint notificationID, ALvoid* userData);
#pragma mark ALSource
/**
* A source represents an object that emits sound which can be heard by a listener.
* This source can have position, velocity, and direction.
*/
@interface ALSource : NSObject <ALSoundSource, OALSuspendManager>
{
ALuint sourceId;
bool interruptible;
float gain;
bool muted;
/** Shadow value which keeps the correct state value
* for AL_PLAYING and AL_PAUSED.
* We need this due to a buggy OpenAL implementation.
*/
int shadowState;
/** Used to abort a pending playback resume if the user calls
* stop or pause.
*/
bool abortPlaybackResume;
ALBuffer* buffer;
ALContext* context;
/** Current action operating on the gain control. */
OALAction* gainAction;
/** Current action operating on the pan control. */
OALAction* panAction;
/** Current action operating on the pitch control. */
OALAction* pitchAction;
/** Handles suspending and interrupting for this object. */
OALSuspendHandler* suspendHandler;
}
#pragma mark Properties
/** The sound buffer this source is attached to (set to nil to detach the currently attached
* buffer).
*/
@property(nonatomic,readwrite,retain) ALBuffer* buffer;
/** How many buffers this source has queued. */
@property(nonatomic,readonly,assign) int buffersQueued;
/** How many of these buffers have been processed during playback. */
@property(nonatomic,readonly,assign) int buffersProcessed;
/** The context this source was opened on. */
@property(nonatomic,readonly,retain) ALContext* context;
/** The offset into the current buffer (in bytes). */
@property(nonatomic,readwrite,assign) float offsetInBytes;
/** The offset into the current buffer (in samples). */
@property(nonatomic,readwrite,assign) float offsetInSamples;
/** The offset into the current buffer (in seconds). */
@property(nonatomic,readwrite,assign) float offsetInSeconds;
/** OpenAL's ID for this source. */
@property(nonatomic,readonly,assign) ALuint sourceId;
/** The state of this source. */
@property(nonatomic,readwrite,assign) int state;
#pragma mark Object Management
/** Create a new source.
*
* @return A new source.
*/
+ (id) source;
/** Create a new source on the specified context.
*
* @param context the context to create the source on.
* @return A new source.
*/
+ (id) sourceOnContext:(ALContext*) context;
/** Initialize a new source on the specified context.
*
* @param context the context to create the source on.
* @return A new source.
*/
- (id) initOnContext:(ALContext*) context;
#pragma mark Playback
/** Play the currently attached buffer.
*
* @return the source playing the sound, or nil if the sound could not be played.
*/
- (id<ALSoundSource>) play;
#pragma mark Queued Playback
/** Add a buffer to the buffer queue.
*
* @param buffer the buffer to add to the queue.
* @return TRUE if the operation was successful.
*/
- (bool) queueBuffer:(ALBuffer*) buffer;
/** Add a buffer to the buffer queue, repeating it multiple times.
*
* @param buffer the buffer to add to the queue.
* @param repeats the number of times to repeat the buffer in the queue.
* @return TRUE if the operation was successful.
*/
- (bool) queueBuffer:(ALBuffer*) buffer repeats:(NSUInteger) repeats;
/** Add buffers to the buffer queue.
*
* @param buffers the buffers to add to the queue.
* @return TRUE if the operation was successful.
*/
- (bool) queueBuffers:(NSArray*) buffers;
/** Add buffers to the buffer queue, repeating it multiple times.
* The buffers will be played in order, repeating the specified number of times.
*
* @param buffers the buffers to add to the queue.
* @param repeats the number of times to repeat the buffer in the queue.
* @return TRUE if the operation was successful.
*/
- (bool) queueBuffers:(NSArray*) buffers repeats:(NSUInteger) repeats;
/** Remove a buffer from the buffer queue.
*
* @param buffer the buffer to remove from the queue.
* @return TRUE if the operation was successful.
*/
- (bool) unqueueBuffer:(ALBuffer*) buffer;
/** Remove buffers from the buffer queue
*
* @param buffers the buffers to remove from the queue.
* @return TRUE if the operation was successful.
*/
- (bool) unqueueBuffers:(NSArray*) buffers;
#pragma mark Notifications
/** Register to receive notifications about an event on this source. (iOS 5.0+)
*
* The following notification types are recognized:
* AL_SOURCE_STATE - Sent when a source's state changes.
* AL_BUFFERS_PROCESSED - Sent when all buffers have been processed.
* AL_QUEUE_HAS_LOOPED - Sent when a looping source has looped to it's start point.
*
* @param notificationID The kind of notification to be informed of (see above).
* @param callback The block to call for notification.
* @param userData a pointer that will be passed to the callback.
*/
- (void) registerNotification:(ALuint) notificationID
callback:(OALSourceNotificationCallback) callback
userData:(void*) userData;
/** Unregister notifications for a notification type on this source. (iOS 5.0+)
*
* @param notificationID The kind of notification to remove.
*/
- (void) unregisterNotification:(ALuint) notificationID;
/** Unregister all notifications for this source. (iOS 5.0+)
*/
- (void) unregisterAllNotifications;
@end
@@ -0,0 +1,131 @@
//
// OpenAL.h
// ObjectAL
//
// Created by Karl Stenerud on 15/12/09.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#pragma mark Types
/**
* Represents a 3-dimensional point for certain ObjectAL properties.
*/
typedef struct
{
/** The "X" coordinate */
float x;
/** The "Y" coordinate */
float y;
/** The "Z" coordinate */
float z;
} ALPoint;
/**
* Represents a 3-dimensional vector for certain ObjectAL properties.
* Properties are the same as for ALPoint.
*/
typedef struct
{
/** The "X" coordinate */
float x;
/** The "Y" coordinate */
float y;
/** The "Z" coordinate */
float z;
} ALVector;
/**
* Represents an orientation, consisting of an "at" vector (representing the "forward" direction),
* and the "up" vector (representing "up" for the subject).
*/
typedef struct
{
/** The "at" vector, representing "forward" */
ALVector at;
/** The "up" vector, representing "up" */
ALVector up;
} ALOrientation;
#pragma mark -
#pragma mark Convenience Methods
/** Convenience inline for creating an ALPoint.
*
* @param x The X coordinate.
* @param y The Y coordinate.
* @param z The Z coordinate.
* @return An ALPoint.
*/
static inline ALPoint alpoint(const float x, const float y, const float z)
{
ALPoint point = {x, y, z};
return point;
}
/** Convenience inline for creating an ALVector.
*
* @param x The X component.
* @param y The Y component.
* @param z The Z component.
* @return An ALVector.
*/
static inline ALVector alvector(const float x, const float y, const float z)
{
ALVector vector = {x, y, z};
return vector;
}
/** Convenience inline for creating an ALOrientation.
*
* @param atX The X component of "at".
* @param atY The Y component of "at".
* @param atZ The Z component of "at".
* @param upX The X component of "up".
* @param upY The Y component of "up".
* @param upZ The Z component of "up".
* @return An ALOrientation.
*/
static inline ALOrientation alorientation(const float atX,
const float atY,
const float atZ,
const float upX,
const float upY,
const float upZ)
{
ALOrientation orientation = { {atX, atY, atZ}, {upX,upY,upZ} };
return orientation;
}
static inline ALPoint ALPointMake(float x, float y, float z)
{
ALPoint p;
p.x = x;
p.y = y;
p.z = z;
return p;
}
@@ -0,0 +1,325 @@
//
// OALAction.h
// ObjectAL
//
// Created by Karl Stenerud on 10-09-18.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import "ObjectALConfig.h"
#if OBJECTAL_CFG_USE_COCOS2D_ACTIONS
#pragma mark Cocos2d Subclassing
#import "cocos2d.h"
/** Generates common code required to subclass from a cocos2d action
* while maintaining the functionality of an OALAction.
*/
#define COCOS2D_SUBCLASS_HEADER(CLASS_A,CLASS_B) \
@interface CLASS_A: CLASS_B \
{ \
bool started_; \
} \
\
@property(nonatomic,readonly,assign) bool running; \
- (void) runWithTarget:(id) target; \
- (void) prepareWithTarget:(id) target; \
- (void) stopAction; \
- (void) updateCompletion:(float) proportionComplete; \
\
@end
/** Generates common code required to subclass from a cocos2d action
* while maintaining the functionality of an OALAction.
*/
#define COCOS2D_SUBCLASS(CLASS_A) \
@implementation CLASS_A \
\
- (id) init \
{ \
return [self initWithDuration:0]; \
} \
\
-(void) startWithTarget:(id) targetIn \
{ \
[super startWithTarget:targetIn]; \
[self prepareWithTarget:targetIn]; \
started_ = YES; \
[self runWithTarget:targetIn]; \
} \
\
- (void) update:(float) proportionComplete \
{ \
[super update:proportionComplete]; \
[self updateCompletion:proportionComplete]; \
} \
\
- (bool) running \
{ \
return !self.isDone; \
} \
\
- (void) runWithTarget:(id) targetIn \
{ \
if(!started_) \
{ \
[[CCActionManager sharedManager] addAction:self target:targetIn paused:NO]; \
} \
} \
\
- (void) stopAction \
{ \
[[CCActionManager sharedManager] removeAction:self]; \
} \
#endif /* OBJECTAL_CFG_USE_COCOS2D_ACTIONS */
/* There are two versions of the actions which can be used: ObjectAL and Cocos2d.
* It's usually more convenient when using Cocos2d to have all actions as part of
* the Cocos2d action system. You can set this in ObjectALConfig.h
*/
#if !OBJECTAL_CFG_USE_COCOS2D_ACTIONS
#pragma mark -
#pragma mark OALAction (ObjectAL version)
/**
* Represents an action that can be performed on an object.
*/
@interface OALAction : NSObject
{
/** \cond */
float duration_;
float elapsed_;
bool running_;
/** \endcond */
/** If TRUE, this action is running via OALActionManager. */
bool runningInManager_;
}
#pragma mark Properties
/** The target to perform the action on. WEAK REFERENCE. */
@property(nonatomic,readonly,assign) id target;
/** The duration of the action, in seconds. */
@property(nonatomic,readonly,assign) float duration;
/** The amount of time that has elapsed for this action, in seconds. */
@property(nonatomic,readwrite,assign) float elapsed;
/** If true, the action is currently running. */
@property(nonatomic,readonly,assign) bool running;
#pragma mark Object Management
/** Initialize an action.
*
* @param duration The duration of this action in seconds.
* @return The initialized action.
*/
- (id) initWithDuration:(float) duration;
#pragma mark Functions
/** Run this action on a target.
*
* @param target The target to run the action on.
*/
- (void) runWithTarget:(id) target;
/** Called by runWithTraget to do any final preparations before running.
* Subclasses must ensure that duration is valid when this method returns.
*
* @param target The target to run the action on.
*/
- (void) prepareWithTarget:(id) target;
/** Called by runWithTarget to start the action running.
*/
- (void) startAction;
/** Called by OALActionManager to update this action's progress.
*
* @param proportionComplete The proportion of this action's duration that has elapsed.
*/
- (void) updateCompletion:(float) proportionComplete;
/** Stop this action.
*/
- (void) stopAction;
@end
#else /* !OBJECTAL_CFG_USE_COCOS2D_ACTIONS */
COCOS2D_SUBCLASS_HEADER(OALAction, CCActionInterval);
#endif /* !OBJECTAL_CFG_USE_COCOS2D_ACTIONS */
#pragma mark -
#pragma mark OALPropertyAction
@interface OALPropertyAction: OALAction
/** The value that the property in the target will hold at the start of the action. */
@property(nonatomic,readwrite,assign) float startValue;
/** The value that the property in the target will hold at the end of the action. */
@property(nonatomic,readwrite,assign) float endValue;
#pragma mark Object Management
/** Create a new action using the default function.
* The start value will be the current value of the target this action is applied to.
*
* @param duration The duration of this action in seconds.
* @param propertyKey The property to modify.
* @param endValue The "ending" value that this action will converge upon when setting the target's property.
* @return A new action.
*/
+ (id) actionWithDuration:(float) duration
propertyKey:(NSString*) propertyKey
endValue:(float) endValue;
/** Create a new action.
*
* @param duration The duration of this action in seconds.
* @param propertyKey The property to modify.
* @param startValue The "starting" value that this action will diverge from when setting the target's
* property. If NAN, use the current value from the target.
* @param endValue The "ending" value that this action will converge upon when setting the target's property.
* @return A new action.
*/
+ (id) actionWithDuration:(float) duration
propertyKey:(NSString*) propertyKey
startValue:(float) startValue
endValue:(float) endValue;
/** Initialize an action using the default function.
* The start value will be the current value of the target this action is applied to.
*
* @param duration The duration of this action in seconds.
* @param propertyKey The property to modify.
* @param endValue The "ending" value that this action will converge upon when setting the target's property.
* @return The initialized action.
*/
- (id) initWithDuration:(float) duration
propertyKey:(NSString*) propertyKey
endValue:(float) endValue;
/** Initialize an action.
*
* @param duration The duration of this action in seconds.
* @param propertyKey The property to modify.
* @param startValue The "starting" value that this action will diverge from when setting the target's
* property. If NAN, use the current value from the target.
* @param endValue The "ending" value that this action will converge upon when setting the target's property.
* @return The initialized action.
*/
- (id) initWithDuration:(float) duration
propertyKey:(NSString*) propertyKey
startValue:(float) startValue
endValue:(float) endValue;
@end
#pragma mark -
#pragma mark OALEaseAction
typedef float (*EaseFunctionPtr)(float);
typedef enum
{
kOALEaseIn,
kOALEaseOut,
kOALEaseInOut,
} OALEasePhase;
typedef enum
{
kOALEaseShapeSine,
kOALEaseShapeExponential,
} OALEaseShape;
/**
* Applies an easing function to another action.
* Normally, an action progresses at a linear rate. An ease changes that to a
* curve.
*/
@interface OALEaseAction: OALAction
{
OALAction* action_;
}
/** Create a new ease action.
*
* @param shape The shape of the curve to apply.
* @param phase What phase of the action to apply the curve to.
* @action The action to apple the curve to.
* @return A new action.
*/
+ (OALEaseAction*) actionWithShape:(OALEaseShape) shape
phase:(OALEasePhase) phase
action:(OALAction*) action;
/** Initialize an ease action.
*
* @param shape The shape of the curve to apply.
* @param phase What phase of the action to apply the curve to.
* @action The action to apple the curve to.
* @return The initialized action.
*/
- (id) initWithShape:(OALEaseShape) shape
phase:(OALEasePhase) phase
action:(OALAction*) action;
/** Get a pointer to an ease function of the specified shape and phase.
*
* @param shape The shape of the curve to apply.
* @param phase What phase of the action to apply the curve to.
* @return a pointer to the appropriate function.
*/
+ (EaseFunctionPtr) easeFunctionForShape:(OALEaseShape) shape
phase:(OALEasePhase) phase;
@end
@@ -0,0 +1,102 @@
//
// OALActionManager.h
// ObjectAL
//
// Created by Karl Stenerud on 10-09-18.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import "SynthesizeSingleton.h"
#import "OALAction.h"
#import "ObjectALConfig.h"
/* This object is only available if OBJECTAL_CFG_USE_COCOS2D_ACTIONS is enabled in ObjectALConfig.h.
*/
#if !OBJECTAL_CFG_USE_COCOS2D_ACTIONS
#pragma mark OALActionManager
/**
* Manages all ObjectAL actions.
*/
@interface OALActionManager : NSObject
{
/** All targets that have actions running on them (id). */
NSMutableArray* targets;
/** Parallel array to "targets", maintaining a list of all actions per target (NSMutableArray*) */
NSMutableArray* targetActions;
/** All actions that are to be added on the next pass (OALAction*) */
NSMutableArray* actionsToAdd;
/** All actions that are to be removed on the next pass (OALAction*) */
NSMutableArray* actionsToRemove;
/** The timer which we use to update the actions. */
NSTimer* stepTimer;
/** The last time that was recorded. */
uint64_t lastTimestamp;
}
#pragma mark Object Management
/** Singleton implementation providing "sharedInstance" and "purgeSharedInstance" methods.
*
* <b>- (OALAudioSupport*) sharedInstance</b>: Get the shared singleton instance. <br>
* <b>- (void) purgeSharedInstance</b>: Purge (deallocate) the shared instance.
*/
SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(OALActionManager);
#pragma mark Action Management
/** Stops ALL running actions on ALL targets.
*/
- (void) stopAllActions;
#pragma mark Internal Use
/** \cond */
/** (INTERNAL USE) Used by OALAction to announce that it is starting.
*
* @param action The action that is starting.
*/
- (void) notifyActionStarted:(OALAction*) action;
/** (INTERNAL USE) Used by OALAction to announce that it is stopping.
*
* @param action The action that is stopping.
*/
- (void) notifyActionStopped:(OALAction*) action;
/** \endcond */
@end
#endif /* OBJECTAL_CFG_USE_COCOS2D_ACTIONS */
@@ -0,0 +1,224 @@
//
// OALAudioActions.h
// ObjectAL
//
// Created by Karl Stenerud on 10-10-10.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import "OALAction.h"
#import "ALTypes.h"
#pragma mark -
#pragma mark Audio Property Actions
@interface OALPropertyAction (Audio)
+ (OALPropertyAction*) pitchActionWithDuration:(float) duration
endValue:(float) endValue;
+ (OALPropertyAction*) pitchActionWithDuration:(float) duration
startValue:(float) startValue
endValue:(float) endValue;
+ (OALPropertyAction*) panActionWithDuration:(float) duration
endValue:(float) endValue;
+ (OALPropertyAction*) panActionWithDuration:(float) duration
startValue:(float) startValue
endValue:(float) endValue;
+ (OALPropertyAction*) gainActionWithDuration:(float) duration
endValue:(float) endValue;
+ (OALPropertyAction*) gainActionWithDuration:(float) duration
startValue:(float) startValue
endValue:(float) endValue;
@end
#pragma mark -
#pragma mark OALPlaceAction
/**
* Places the target at the specified position.
*/
@interface OALPlaceAction : OALAction
{
ALPoint position;
}
#pragma mark Properties
/** The position where the target will be placed. */
@property(nonatomic,readwrite,assign) ALPoint position;
#pragma mark Object Management
/** Create an action with the specified position.
*
* @param position The position to place the target at.
* @return A new action.
*/
+ (id) actionWithPosition:(ALPoint) position;
/** Initialize an action with the specified position.
*
* @param position The position to place the target at.
* @return The initialized action.
*/
- (id) initWithPosition:(ALPoint) position;
@end
#pragma mark -
#pragma mark OALMoveToAction
/**
* Moves the target from its current position to the specified
* position over time in 3D space.
*/
@interface OALMoveToAction : OALAction
{
float unitsPerSecond;
/** The point this move is starting at. */
ALPoint startPoint;
ALPoint position;
/** The distance being moved. */
ALPoint delta;
}
#pragma mark Properties
/** The position to move the target to. */
@property(nonatomic,readwrite,assign) ALPoint position;
/** The speed at which to move the target.
* If this is 0, the target will be moved at the speed determined by duration.
*/
@property(nonatomic,readwrite,assign) float unitsPerSecond;
#pragma mark Object Management
/** Create a new action.
*
* @param duration The duration of the move.
* @param position The position to move to.
* @return A new action.
*/
+ (id) actionWithDuration:(float) duration position:(ALPoint) position;
/** Create a new action.
*
* @param unitsPerSecond The rate of movement.
* @param position The position to move to.
* @return A new action.
*/
+ (id) actionWithUnitsPerSecond:(float) unitsPerSecond position:(ALPoint) position;
/** Initialize an action.
*
* @param duration The duration of the move.
* @param position The position to move to.
* @return The initialized action.
*/
- (id) initWithDuration:(float) duration position:(ALPoint) position;
/** Initialize an action.
*
* @param unitsPerSecond The rate of movement.
* @param position The position to move to.
* @return The initialized action.
*/
- (id) initWithUnitsPerSecond:(float) unitsPerSecond position:(ALPoint) position;
@end
#pragma mark -
#pragma mark OALMoveByAction
/**
* Moves the target from its current position by the specified
* delta over time in 3D space.
*/
@interface OALMoveByAction : OALAction
{
float unitsPerSecond;
/** The point this move is starting at. */
ALPoint startPoint;
ALPoint delta;
}
#pragma mark Properties
/** The amount to move the target by. */
@property(nonatomic,readwrite,assign) ALPoint delta;
/** The speed at which to move the target.
* If this is 0, the target will be moved at the speed determined by duration.
*/
@property(nonatomic,readwrite,assign) float unitsPerSecond;
/** Create a new action.
*
* @param duration The duration of the move.
* @param delta The amount to move by.
* @return A new action.
*/
+ (id) actionWithDuration:(float) duration delta:(ALPoint) delta;
/** Create a new action.
*
* @param unitsPerSecond The rate of movement.
* @param delta The amount to move by.
* @return A new action.
*/
+ (id) actionWithUnitsPerSecond:(float) unitsPerSecond delta:(ALPoint) delta;
/** Initialize an action.
*
* @param duration The duration of the move.
* @param delta The amount to move by.
* @return The initialized action.
*/
- (id) initWithDuration:(float) duration delta:(ALPoint) delta;
/** Initialize an action.
*
* @param unitsPerSecond The rate of movement.
* @param delta The amount to move by.
* @return The initialized action.
*/
- (id) initWithUnitsPerSecond:(float) unitsPerSecond delta:(ALPoint) delta;
@end
@@ -0,0 +1,119 @@
//
// OALAudioFile.h
// ObjectAL
//
// Created by Karl Stenerud on 10-12-24.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import "ALBuffer.h"
/**
* Maintains an open audio file and allows loading data from that file into
* new ALBuffer objects.
*/
@interface OALAudioFile : NSObject
{
NSURL* url;
bool reduceToMono;
SInt64 totalFrames;
/** A description of the audio data in this file. */
AudioStreamBasicDescription streamDescription;
/** The OS specific file handle */
ExtAudioFileRef fileHandle;
/** The actual number of channels in the audio data if not reducing to mono */
UInt32 originalChannelsPerFrame;
}
/** The URL of the audio file */
@property(nonatomic,readonly,retain) NSURL* url;
/** A description of the audio data in this file. */
@property(nonatomic,readonly,assign) AudioStreamBasicDescription* streamDescription;
/** The total number of audio frames in this file */
@property(nonatomic,readonly,assign) SInt64 totalFrames;
/** If YES, reduce any stereo data to mono (stereo samples don't support panning or positional audio). */
@property(nonatomic,readwrite,assign) bool reduceToMono;
/** Open the audio file at the specified URL.
*
* @param url The URL to open the audio file from.
* @param reduceToMono If YES, reduce any stereo track to mono
(stereo samples don't support panning or positional audio).
* @return a new audio file object.
*/
+ (OALAudioFile*) fileWithUrl:(NSURL*) url
reduceToMono:(bool) reduceToMono;
/** Initialize this object with the audio file at the specified URL.
*
* @param url The URL to open the audio file from.
* @param reduceToMono If YES, reduce any stereo track to mono
(stereo samples don't support panning or positional audio).
* @return the initialized audio file object.
*/
- (id) initWithUrl:(NSURL*) url
reduceToMono:(bool) reduceToMono;
/** Read audio data from this file into a new buffer.
*
* @param startFrame The starting audio frame to read data from.
* @param numFrames The number of frames to read.
* @param bufferSize On successful return, contains the size of the returned buffer, in bytes.
* @return The audio data or nil on error. You are responsible for calling free() on the data.
*/
- (void*) audioDataWithStartFrame:(SInt64) startFrame
numFrames:(SInt64) numFrames
bufferSize:(UInt32*) bufferSize;
/** Create a new ALBuffer with the contents of this file.
*
* @param name The name to be given to this ALBuffer.
* @param startFrame The starting audio frame to read data from.
* @param numFrames The number of frames to read.
* @return a new ALBuffer containing the audio data.
*/
- (ALBuffer*) bufferNamed:(NSString*) name
startFrame:(SInt64) startFrame
numFrames:(SInt64) numFrames;
/** Convenience method to load the entire contents of a URL into a new ALBuffer.
*
* @param url The URL to open the audio file from.
* @param reduceToMono If YES, reduce any stereo track to mono
(stereo samples don't support panning or positional audio).
* @return an ALBuffer object.
*/
+ (ALBuffer*) bufferFromUrl:(NSURL*) url
reduceToMono:(bool) reduceToMono;
@end
@@ -0,0 +1,200 @@
//
// OALAudioSession.h
// ObjectAL
//
// Created by Karl Stenerud on 10-12-19.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#import "SynthesizeSingleton.h"
#import "OALSuspendHandler.h"
/**
* Handles the audio session and interrupts.
*/
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && !defined(__TV_OS_VERSION_MIN_REQUIRED)
@interface OALAudioSession : NSObject <AVAudioSessionDelegate, OALSuspendManager>
#else
@interface OALAudioSession : NSObject <OALSuspendManager>
#endif
{
/** The current audio session category */
NSString* audioSessionCategory;
/** Flag signifying that we are currently handling an error notification.
* This prevents onAudioError: from becoming reentrant due to
* self.manuallySuspended setting off a chain of calls that result in
* another error notification broadcast.
*/
bool handlingErrorNotification;
bool handleInterruptions;
bool allowIpod;
bool ipodDucking;
bool useHardwareIfAvailable;
bool honorSilentSwitch;
bool audioSessionActive;
/** If true, the audio session was active when the interrupt occurred. */
bool audioSessionWasActive;
/** Handles suspending and interrupting for this object. */
OALSuspendHandler* suspendHandler;
/** Marks the last time the audio session was reset due to error.
* This is used to avoid getting stuck in a rapid-fire reset-error loop.
*/
NSDate* lastResetTime;
}
#pragma mark Properties
/** The current audio session category.
* If this value is explicitly set, the other session properties "allowIpod",
* "useHardwareIfAvailable", "honorSilentSwitch", and "ipodDucking" may be modified
* to remain compatible with the category.
*
* @see AVAudioSessionCategory
*
* Default value: nil
*/
@property(nonatomic,readwrite,retain) NSString* audioSessionCategory;
/** If YES, allow ipod music to continue playing (NOT SUPPORTED ON THE SIMULATOR).
* Note: If this is enabled, and another app is playing music, background audio
* playback will use the SOFTWARE codecs, NOT hardware. <br>
*
* If allowIpod = NO, the application will ALWAYS use hardware decoding. <br>
*
* @see useHardwareIfAvailable
*
* Default value: YES
*/
@property(nonatomic,readwrite,assign) bool allowIpod;
/** If YES, ipod music will duck (lower in volume) when the audio session activates.
*
* Default value: NO
*/
@property(nonatomic,readwrite,assign) bool ipodDucking;
/** Determines what to do if no other application is playing audio and allowIpod = YES
* (NOT SUPPORTED ON THE SIMULATOR). <br>
*
* If NO, the application will ALWAYS use software decoding. The advantage to this is that
* the user can background your application and then start audio playing from another
* application. If useHardwareIfAvailable = YES, the user won't be able to do this. <br>
*
* If this is set to YES, the application will use hardware decoding if no other application
* is currently playing audio. However, no other application will be able to start playing
* audio if it wasn't playing already. <br>
*
* Note: This switch has no effect if allowIpod = NO. <br>
*
* @see allowIpod
*
* Default value: YES
*/
@property(nonatomic,readwrite,assign) bool useHardwareIfAvailable;
/** If true, mute when backgrounded, screen locked, or the ringer switch is
* turned off (NOT SUPPORTED ON THE SIMULATOR). <br>
*
* Default value: YES
*/
@property(nonatomic,readwrite,assign) bool honorSilentSwitch;
/** If true, automatically handle interruptions. <br>
*
* Default value: YES
*/
@property(nonatomic,readwrite,assign) bool handleInterruptions;
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && !defined(__TV_OS_VERSION_MIN_REQUIRED)
/** Delegate that will receive all audio session events (WEAK reference).
*/
@property(nonatomic,readwrite,assign) id<AVAudioSessionDelegate> audioSessionDelegate;
#endif
/** If true, the audio session is active */
@property(nonatomic,readwrite,assign) bool audioSessionActive;
/** The preferred I/O buffer duration, in seconds. Lower values give less
* playback latencey, but use more CPU.
* @deprecated Use AVAudioSession instead.
*/
@property(nonatomic,readwrite,assign) float preferredIOBufferDuration __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA,__MAC_NA,__IPHONE_2_0,__IPHONE_6_1);
/** If true, another application (usually iPod) is playing music.
* @deprecated Use AVAudioSession instead.
*/
@property(nonatomic,readonly,assign) bool ipodPlaying __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA,__MAC_NA,__IPHONE_2_0,__IPHONE_6_1);
/** Get the device's final hardware output volume, as controlled by
* the volume button on the side of the device.
* @deprecated Use AVAudioSession instead.
*/
@property(nonatomic,readonly,assign) float hardwareVolume __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA,__MAC_NA,__IPHONE_2_0,__IPHONE_6_1);
/** Check if the hardware mute switch is on (not supported on the simulator or iOS 5+).
* Note: If headphones are plugged in, hardwareMuted will always return FALSE
* regardless of the switch state.
*
* Note: Please file a bug report with Apple to get this functionality restored in iOS 5!
*/
@property(nonatomic,readonly,assign) bool hardwareMuted __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA,__MAC_NA,__IPHONE_2_0,__IPHONE_5_0);
/** Check what hardware route the audio is taking, such as "Speaker" or "Headphone"
* (not supported on the simulator).
* @deprecated Use AVAudioSession instead.
*/
@property(nonatomic,readonly,retain) NSString* audioRoute __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA,__MAC_NA,__IPHONE_2_0,__IPHONE_6_1);
#pragma mark Object Management
/** Singleton implementation providing "sharedInstance" and "purgeSharedInstance" methods.
*
* <b>- (OALAudioSupport*) sharedInstance</b>: Get the shared singleton instance. <br>
* <b>- (void) purgeSharedInstance</b>: Purge (deallocate) the shared instance.
*/
SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(OALAudioSession);
#pragma mark Utility
/** Force an interrupt end. This can be useful in cases where a buggy OS
* fails to end an interrupt.
*
* Be VERY CAREFUL when using this!
*/
- (void) forceEndInterruption;
@end
@@ -0,0 +1,443 @@
//
// OALAudioTrack.h
// ObjectAL
//
// Created by Karl Stenerud on 10-08-21.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <AVFoundation/AVFoundation.h>
#import "OALAction.h"
#import "OALAudioTrackNotifications.h"
#import "OALSuspendHandler.h"
/**
* Plays an audio track via AVAudioPlayer.
* Unlike AVAudioPlayer, however, it can be re-used to play another file.
* Interruptions can be handled by OALAudioSupport (enabled by default).
*/
@interface OALAudioTrack : NSObject <AVAudioPlayerDelegate, OALSuspendManager>
{
/** If true, this track is recording metering data */
bool meteringEnabled;
bool interrupted;
AVAudioPlayer* player;
NSURL* currentlyLoadedUrl;
bool preloaded;
bool autoPreload;
bool paused;
bool muted;
float gain;
float pan;
NSInteger numberOfLoops;
id<AVAudioPlayerDelegate> delegate; // Weak reference
/** When the simulator is running (and the playback fix is in use),
* player will be copied to here, and then player set to nil.
* This prevents other code from inadvertently raising the volume
* and starting playback.
*/
AVAudioPlayer* simulatorPlayerRef;
/** Operation queue for running asynchronous operations.
* <strong>Note:</strong> Only one asynchronous operation is allowed at a time.
*/
NSOperationQueue* operationQueue;
/** If true, the audio player is currently playing.
* We need to maintain our own value because AVAudioPlayer will
* sometimes say it's not playing when it actually is.
*/
bool playing;
NSTimeInterval currentTime;
/** The current action being applied to gain. */
OALAction* gainAction;
/** The current action being applied to pan. */
OALAction* panAction;
/** Handles suspending and interrupting for this object. */
OALSuspendHandler* suspendHandler;
}
#pragma mark Properties
/** The URL of the currently loaded audio data. */
@property(nonatomic,readonly,retain) NSURL* currentlyLoadedUrl;
/** Optional object that will receive notifications for decoding errors,
* audio interruptions (such as an incoming phone call), and playback completion. <br>
* <strong>Note:</strong> OALAudioTrack keeps a WEAK reference to delegate, so make sure you clear it
* when your object is going to be deallocated.
*/
@property(nonatomic,readwrite,assign) id<AVAudioPlayerDelegate> delegate;
/** The gain (volume) for playback (0.0 - 1.0, where 1.0 = no attenuation). */
@property(nonatomic,readwrite,assign) float gain;
/** The volume (alias to gain) for playback (0.0 - 1.0, where 1.0 = no attenuation). */
@property(nonatomic,readwrite,assign) float volume;
/** Pan value (-1.0 = far left, 1.0 = far right).
* <strong>Note:</strong> This will have no effect on iOS versions prior to 4.0.
*/
@property(nonatomic,readwrite,assign) float pan;
/** If true, audio track is muted */
@property(nonatomic,readwrite,assign) bool muted;
/** If true, automatically preload again when playback stops */
@property(nonatomic,readwrite,assign) bool autoPreload;
/** If true, audio track is in preloaded state */
@property(nonatomic,readonly,assign) bool preloaded;
/** The number of times to loop playback (-1 = forever).
* <strong>Note:</strong> This value will be ignored, and get changed when you call the various playXX methods.
* Only "play" will use the current value of "numberOfLoops".
*/
@property(nonatomic,readwrite,assign) NSInteger numberOfLoops;
/** If true, pause playback. */
@property(nonatomic,readwrite,assign) bool paused;
/** Access to the underlying AVAudioPlayer object.
* WARNING: Be VERY careful when accessing this, as some methods could cause
* it to fall out of sync with OALAudioTrack (particularly play/pause/stop methods).
*/
@property(nonatomic,readonly,retain) AVAudioPlayer* player;
/** If true, background music is currently playing. */
@property(nonatomic,readonly,assign) bool playing;
/** The current playback position in seconds from the start of the sound.
* You can set this to change the playback position, whether it is currently playing or not.
*/
@property(nonatomic,readwrite,assign) NSTimeInterval currentTime;
/** The value of this property increases monotonically while an audio player is playing or paused. <br><br>
*
* If more than one audio player is connected to the audio output device, device time continues
* incrementing as long as at least one of the players is playing or paused. <br><br>
*
* If the audio output device has no connected audio players that are either playing or paused,
* device time reverts to 0. <br><br>
*
* Use this property to indicate “now” when calling the playAtTime: instance method. By configuring
* multiple audio players to play at a specified offset from deviceCurrentTime, you can perform
* precise synchronization—as described in the discussion for that method.
*
* <strong>Note:</strong> This will have no effect on iOS versions prior to 4.0.
*/
@property(nonatomic,readonly,assign) NSTimeInterval deviceCurrentTime;
/** The duration, in seconds, of the currently loaded sound. */
@property(nonatomic,readonly,assign) NSTimeInterval duration;
/** The number of channels in the currently loaded sound. */
@property(nonatomic,readonly,assign) NSUInteger numberOfChannels;
#pragma mark Object Management
/** Create a new audio track.
*
* @return A new audio track.
*/
+ (id) track;
#pragma mark Playback
/** Preload the contents of a URL for playback.
* Once the audio data is preloaded, you can call "play" to play it. <br>
*
* @param url The URL containing the sound data.
* @return TRUE if the operation was successful.
*/
- (bool) preloadUrl:(NSURL*) url;
/** Preload the contents of a URL for playback.
* Once the audio data is preloaded, you can call "play" to play it. <br>
*
* @param url The URL containing the sound data.
* @param seekTime The position in the file to start playing at.
* @return TRUE if the operation was successful.
*/
- (bool) preloadUrl:(NSURL*) url seekTime:(NSTimeInterval)seekTime;
/** Preload the contents of a file for playback.
* Once the audio data is preloaded, you can call "play" to play it. <br>
*
* @param path The file containing the sound data.
* @return TRUE if the operation was successful.
*/
- (bool) preloadFile:(NSString*) path;
/** Preload the contents of a file for playback.
* Once the audio data is preloaded, you can call "play" to play it. <br>
*
* @param path The file containing the sound data.
* @param seekTime The position in the file to start playing at.
* @return TRUE if the operation was successful.
*/
- (bool) preloadFile:(NSString*) path seekTime:(NSTimeInterval)seekTime;
/** Asynchronously preload the contents of a URL for playback.
* Once the audio data is preloaded, you can call "play" to play it. <br>
*
* @param url The URL containing the sound data.
* @param target the target to inform when preparation is complete.
* @param selector the selector to call when preparation is complete.
* @return TRUE if the operation was successfully queued.
*/
- (bool) preloadUrlAsync:(NSURL*) url target:(id) target selector:(SEL) selector;
/** Asynchronously preload the contents of a URL for playback.
* Once the audio data is preloaded, you can call "play" to play it. <br>
*
* @param url The URL containing the sound data.
* @param seekTime The position in the file to start playing at.
* @param target the target to inform when preparation is complete.
* @param selector the selector to call when preparation is complete.
* @return TRUE if the operation was successfully queued.
*/
- (bool) preloadUrlAsync:(NSURL*) url seekTime:(NSTimeInterval)seekTime target:(id) target selector:(SEL) selector;
/** Asynchronously preload the contents of a file for playback.
* Once the audio data is preloaded, you can call "play" to play it. <br>
*
* @param path The file containing the sound data.
* @param target the target to inform when preparation is complete.
* @param selector the selector to call when preparation is complete.
* @return TRUE if the operation was successfully queued.
*/
- (bool) preloadFileAsync:(NSString*) path target:(id) target selector:(SEL) selector;
/** Asynchronously preload the contents of a file for playback.
* Once the audio data is preloaded, you can call "play" to play it. <br>
*
* @param path The file containing the sound data.
* @param seekTime The position in the file to start playing at.
* @param target the target to inform when preparation is complete.
* @param selector the selector to call when preparation is complete.
* @return TRUE if the operation was successfully queued.
*/
- (bool) preloadFileAsync:(NSString*) path seekTime:(NSTimeInterval)seekTime target:(id) target selector:(SEL) selector;
/** Play the contents of a URL once.
*
* @param url The URL containing the sound data.
* @return TRUE if the operation was successful.
*/
- (bool) playUrl:(NSURL*) url;
/** Play the contents of a URL and loop the specified number of times.
*
* @param url The URL containing the sound data.
* @param loops The number of times to loop playback (-1 = forever)
* @return TRUE if the operation was successful.
*/
- (bool) playUrl:(NSURL*) url loops:(NSInteger) loops;
/** Play the contents of a file once.
*
* @param path The file containing the sound data.
* @return TRUE if the operation was successful.
*/
- (bool) playFile:(NSString*) path;
/** Play the contents of a file and loop the specified number of times.
*
* @param path The file containing the sound data.
* @param loops The number of times to loop playback (-1 = forever)
* @return TRUE if the operation was successful.
*/
- (bool) playFile:(NSString*) path loops:(NSInteger) loops;
/** Play the contents of a URL asynchronously once.
*
* @param url The URL containing the sound data.
* @param target the target to inform when playing has started.
* @param selector the selector to call when playing has started.
*/
- (void) playUrlAsync:(NSURL*) url target:(id) target selector:(SEL) selector;
/** Play the contents of a URL asynchronously and loop the specified number of times.
*
* @param url The URL containing the sound data.
* @param loops The number of times to loop playback (-1 = forever)
* @param target the target to inform when playing has started.
* @param selector the selector to call when playing has started.
*/
- (void) playUrlAsync:(NSURL*) url
loops:(NSInteger) loops
target:(id) target
selector:(SEL) selector;
/** Play the contents of a file asynchronously once.
*
* @param path The file containing the sound data.
* @param target the target to inform when playing has started.
* @param selector the selector to call when playing has started.
*/
- (void) playFileAsync:(NSString*) path target:(id) target selector:(SEL) selector;
/** Play the contents of a file asynchronously and loop the specified number of times.
*
* @param path The file containing the sound data.
* @param loops The number of times to loop playback (-1 = forever)
* @param target the target to inform when playing has started.
* @param selector the selector to call when playing has started.
*/
- (void) playFileAsync:(NSString*) path
loops:(NSInteger) loops
target:(id) target
selector:(SEL) selector;
/** Play the currently loaded audio track.
*
* @return TRUE if the operation was successful.
*/
- (bool) play;
/** Plays a sound asynchronously, starting at a specified point in the audio output devices timeline.
*
* <strong>Note:</strong> This will have no effect on iOS versions prior to 4.0.
*
* @param time The time (device time) to start playing at.
* @return YES if the playback was successfully scheduled.
*/
- (bool) playAtTime:(NSTimeInterval) time;
/** Plays the currently preloaded track asynchronously when the specified track completes.
*
* <strong>Note:</strong> This will have no effect on iOS versions prior to 4.0.
*
* @param track The track to play after
* @return YES if the playback was successfully scheduled.
*/
- (bool) playAfterTrack:(OALAudioTrack*) track;
/** Plays the currently preloaded track asynchronously when the specified track completes.
*
* <strong>Note:</strong> This will have no effect on iOS versions prior to 4.0.
*
* @param track The track to play after
* @param timeAdjust fine-tune value added to the time start offset.
* @return YES if the playback was successfully scheduled.
*/
- (bool) playAfterTrack:(OALAudioTrack*) track timeAdjust:(NSTimeInterval) timeAdjust;
/** Stop playing and stop all operations.
*/
- (void) stop;
/** Fade to the specified gain value.
*
* @param gain The gain to fade to.
* @param duration The duration of the fade operation in seconds.
* @param target The target to notify when the fade completes (can be nil).
* @param selector The selector to call when the fade completes. The selector must accept
* a single parameter, which will be the object that performed the fade.
*/
- (void) fadeTo:(float) gain
duration:(float) duration
target:(id) target
selector:(SEL) selector;
/** Stop the currently running fade operation, if any.
*/
- (void) stopFade;
/** Pan to the specified pan value.
*
* <strong>Note:</strong> This will have no effect on iOS versions prior to 4.0.
*
* @param pan The value to pan to.
* @param duration The duration of the pan operation in seconds.
* @param target The target to notify when the pan completes (can be nil).
* @param selector The selector to call when the pan completes. The selector must accept
* a single parameter, which will be the object that performed the pan.
*/
- (void) panTo:(float) pan
duration:(float) duration
target:(id) target
selector:(SEL) selector;
/** Stop the currently running pan operation, if any.
*
* <strong>Note:</strong> This will have no effect on iOS versions prior to 4.0.
*/
- (void) stopPan;
/** Stop any internal fade or pan actions. */
- (void) stopActions;
/** Unload and clear all audio data, stop playing, and stop all operations.
*/
- (void) clear;
#pragma mark Metering
/** If true, metering is enabled. */
@property (nonatomic,readwrite,assign) bool meteringEnabled;
/** Updates the metering system to give current values.
* You must call this method before calling averagePowerForChannel or peakPowerForChannel in
* order to get current values.
*/
- (void) updateMeters;
/** Gives the average power for a given channel, in decibels, for the sound being played.
* 0 dB indicates maximum power (full scale). <br>
* -160 dB indicates minimum power (near silence). <br>
* If the signal provided to the audio player exceeds full scale, then the value may be > 0. <br>
*
* <strong>Note:</strong> The value returned is in reference to when updateMeters was last called.
* You must call updateMeters again before calling this method to get a current value.
*
* @param channelNumber The channel to get the value from. For mono or left, use 0. For right,
* use 1.
* @return the average power for the channel.
*/
- (float) averagePowerForChannel:(NSUInteger)channelNumber;
/** Gives the peak power for a given channel, in decibels, for the sound being played.
* 0 dB indicates maximum power (full scale). <br>
* -160 dB indicates minimum power (near silence). <br>
* If the signal provided to the audio player exceeds full scale, then the value may be > 0. <br>
*
* <strong>Note:</strong> The value returned is in reference to when updateMeters was last called.
* You must call updateMeters again before calling this method to get a current value.
*
* @param channelNumber The channel to get the value from. For mono or left, use 0. For right,
* use 1.
* @return the average power for the channel.
*/
- (float) peakPowerForChannel:(NSUInteger)channelNumber;
@end
@@ -0,0 +1,13 @@
//
// OALAudioTrackNotifications.h
//
// Created by CJ Hanson on 10/16/10.
//
#import <Foundation/Foundation.h>
extern NSString *const OALAudioTrackSourceChangedNotification;
extern NSString *const OALAudioTrackStartedPlayingNotification;
extern NSString *const OALAudioTrackStoppedPlayingNotification;
extern NSString *const OALAudioTrackFinishedPlayingNotification;
extern NSString *const OALAudioTrackLoopedNotification;
@@ -0,0 +1,93 @@
//
// OALAudioTracks.h
// ObjectAL
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import "OALAudioTrack.h"
#import "SynthesizeSingleton.h"
#import "OALSuspendHandler.h"
#pragma mark OALAudioTracks
/**
* Keeps track of all AudioTrack objects.
*/
@interface OALAudioTracks : NSObject <OALSuspendManager>
{
/** All instantiated audio tracks. */
NSMutableArray* tracks;
bool muted;
bool paused;
/** Timer to poll deviceCurrentTime so that it doesn't get reset on a device */
NSTimer* deviceTimePoller;
/** Handles suspending and interrupting for this object. */
OALSuspendHandler* suspendHandler;
}
#pragma mark Properties
/** Pauses/unpauses all audio tracks. */
@property(nonatomic,readwrite,assign) bool paused;
/** Mutes/unmutes all audio tracks. */
@property(nonatomic,readwrite,assign) bool muted;
/** All instantiated audio tracks. */
@property(nonatomic,readonly,retain) NSArray* tracks;
#pragma mark Playback
/** Stop playback on all audio tracks.
*/
- (void) stopAllTracks;
#pragma mark Object Management
/** Singleton implementation providing "sharedInstance" and "purgeSharedInstance" methods.
*
* <b>- (OALAudioTracks*) sharedInstance</b>: Get the shared singleton instance. <br>
* <b>- (void) purgeSharedInstance</b>: Purge (deallocate) the shared instance.
*/
SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(OALAudioTracks);
#pragma mark Internal Use
/** \cond */
/** (INTERNAL USE) Notify that a track is initializing.
*/
- (void) notifyTrackInitializing:(OALAudioTrack*) track;
/** (INTERNAL USE) Notify that a track is deallocating.
*/
- (void) notifyTrackDeallocating:(OALAudioTrack*) track;
/** \endcond */
@end
@@ -0,0 +1,30 @@
//
// OALNotifications.h
// ObjectAL
//
// Created by Karl Stenerud on 11-01-03.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#define OALAudioErrorNotification @"OALAudioErrorNotification"
@@ -0,0 +1,492 @@
//
// OALSimpleAudio.h
// ObjectAL
//
// Created by Karl Stenerud on 10-01-14.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import "SynthesizeSingleton.h"
#import "ALDevice.h"
#import "ALContext.h"
#import "ALSoundSource.h"
#import "ALChannelSource.h"
#import "OALAudioTrack.h"
#pragma mark OALSimpleAudio
/**
* A simpler interface to the ObjectAL sound library. This singleton can be
* used alone for simpler audio needs, or in conjunction with user-created
* audio objects for more advanced needs (as is done in many of the demos).
*
* For sound effects, it initializes OpenAL with the default ALDevice,
* an ALContext, and an ALChannelSource consisting of all 32 interruptible
* ALSource objects (the maximum currently allowed for iOS).
* If you want to create your own sources as well, change the reservedSources
* property.
*
* For background audio, it creates a single OALAudioTrack, which will not reserve
* resources unless used. (you can create more OALAudioTrack objects for your own
* use if you want).
*
* This singleton also provides access to the more common configuration options
* available in OALAudioSupport.
*
* All audio playback commands are delegated either to the ALChannelSource
* (for sound effects), or to the OALAudioTrack (for BG music).
*/
@interface OALSimpleAudio : NSObject
{
/** The device we are using */
ALDevice* device;
/** The context we are using */
ALContext* context;
/** The sound channel used by this object. */
ALChannelSource* channel;
/** Cache for preloaded sound samples. */
NSMutableDictionary* preloadCache;
#if NS_BLOCKS_AVAILABLE && OBJECTAL_CFG_USE_BLOCKS
/** Queue for preloading and async operations that use blocks.
* This ensures all operations are safe because they are guaranteed to run
* in order.
*/
dispatch_queue_t oal_dispatch_queue;
#endif
/** keeping track of how many effects remain to be loaded */
uint pendingLoadCount;
/** Audio track to play background music */
OALAudioTrack* backgroundTrack;
bool muted;
bool bgMuted;
bool effectsMuted;
}
#pragma mark Properties
/** If YES, allow ipod music to continue playing (NOT SUPPORTED ON THE SIMULATOR).
* Note: If this is enabled, and another app is playing music, background audio
* playback will use the SOFTWARE codecs, NOT hardware. <br>
*
* If allowIpod = NO, the application will ALWAYS use hardware decoding. <br>
*
* iOS Only. <br>
*
* @see useHardwareIfAvailable
*
* Default value: YES
*/
@property(nonatomic,readwrite,assign) bool allowIpod;
/** Determines what to do if no other application is playing audio and allowIpod = YES
* (NOT SUPPORTED ON THE SIMULATOR). <br>
*
* If NO, the application will ALWAYS use software decoding. The advantage to this is that
* the user can background your application and then start audio playing from another
* application. If useHardwareIfAvailable = YES, the user won't be able to do this. <br>
*
* If this is set to YES, the application will use hardware decoding if no other application
* is currently playing audio. However, no other application will be able to start playing
* audio if it wasn't playing already. <br>
*
* Note: This switch has no effect if allowIpod = NO. <br>
*
* iOS Only. <br>
*
* @see allowIpod
*
* Default value: YES
*/
@property(nonatomic,readwrite,assign) bool useHardwareIfAvailable;
/** If true, mute when backgrounded, screen locked, or the ringer switch is
* turned off (NOT SUPPORTED ON THE SIMULATOR). <br>
*
* iOS Only. <br>
*
* Default value: YES
*/
@property(nonatomic,readwrite,assign) bool honorSilentSwitch;
/** The number of sources OALSimpleAudio is using (max 32 on current iOS devices). */
@property(nonatomic,readwrite,assign) int reservedSources;
@property(nonatomic,readonly,retain) ALDevice* device;
@property(nonatomic,readonly,retain) ALContext* context;
/** The channel source used by OALSimpleAudio.
* Only mess with this if you know what you are doing!
*/
@property(nonatomic,readonly,retain) ALChannelSource* channel;
/** Background audio URL */
@property(nonatomic,readonly,retain) NSURL* backgroundTrackURL;
/** Background audio track */
@property(nonatomic,readonly,retain) OALAudioTrack* backgroundTrack;
/** Pauses BG music playback */
@property(nonatomic,readwrite,assign) bool bgPaused;
/** Mutes BG music playback */
@property(nonatomic,readwrite,assign) bool bgMuted;
/** If true, BG music is currently playing */
@property(nonatomic,readonly,assign) bool bgPlaying;
/** Background music playback gain/volume (0.0 - 1.0) */
@property(nonatomic,readwrite,assign) float bgVolume;
/** Pauses effects playback */
@property(nonatomic,readwrite,assign) bool effectsPaused;
/** Mutes effects playback */
@property(nonatomic,readwrite,assign) bool effectsMuted;
/** Master effects gain/volume (0.0 - 1.0) */
@property(nonatomic,readwrite,assign) float effectsVolume;
/** Pauses everything */
@property(nonatomic,readwrite,assign) bool paused;
/** Mutes all audio */
@property(nonatomic,readwrite,assign) bool muted;
/** Enables/disables the preload cache.
* If the preload cache is disabled, effects preloading will do nothing
* (BG preloading will still work).
*/
@property(nonatomic,readwrite,assign) bool preloadCacheEnabled;
/** The number of items currently in the preload cache. */
@property(nonatomic,readonly,assign) NSUInteger preloadCacheCount;
/** Set to YES to manually suspend the sound system. */
@property(nonatomic,readwrite,assign) bool manuallySuspended;
/** If YES, the sound system is interrupted. iOS Only. */
@property(nonatomic,readonly,assign) bool interrupted;
/** If YES, the sound system is suspended. */
@property(nonatomic,readonly,assign) bool suspended;
#pragma mark Object Management
/** Singleton implementation providing "sharedInstance" and "purgeSharedInstance" methods.
*
* <b>- (OALSimpleAudio*) sharedInstance</b>: Get the shared singleton instance. <br>
* <b>- (void) purgeSharedInstance</b>: Purge (deallocate) the shared instance. <br>
*/
SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(OALSimpleAudio);
/** Start OALSimpleAudio with the specified number of reserved sources.
* Call this initializer if you want to use OALSimpleAudio, but keep some of the device's
* audio sources (there are 32 in total) for your own use. <br>
* <strong>Note:</strong> This method must be called ONLY ONCE, <em>BEFORE</em>
* any attempt is made to access the shared instance.
* To change the reserved sources after instantiation, modify reservedSources.
*
* @param sources the number of sources OALSimpleAudio will reserve for itself.
* @return The shared instance.
*/
+ (OALSimpleAudio*) sharedInstanceWithSources:(int) sources;
/** Start OALSimpleAudio with the specified parameters.
*
* With this initializer, you can set the total number of mono and stereo sources
* available, as well as how many sources are to be reserved by OALSimpleAudio. <br>
*
* The number of mono and stereo sources represents the GLOBAL number of sources
* available for EVERYONE, not just OALSimpleAudio. Their combined values must
* not exceed 32 (the max allowed sources in iOS). <br>
*
* reservedSources is independent of this; it represents how many of the above
* mentioned sources to reserve for OALSimpleAudio's use. <br>
*
* <strong>Note:</strong> This method must be called ONLY ONCE, <em>BEFORE</em>
* any attempt is made to access the shared instance. <br>
*
* @param reservedSources The number of sources to reserve for OALSimpleAudio's
* use when initializing.
* iOS currently supports up to 32 sources total.
* @param monoSources The GLOBAL number of sources supporting mono (default 28).
* @param stereoSources The GLOBAL number of sources supporting stereo (default 4).
*
* @return The shared instance.
*/
+ (OALSimpleAudio*) sharedInstanceWithReservedSources:(int) reservedSources
monoSources:(int) monoSources
stereoSources:(int) stereoSources;
/** \cond */
/** (INTERNAL USE) Initialize with the specified number of reserved sources.
*
* @param reservedSources the number of sources to reserve when initializing.
* @return The shared instance.
*/
- (id) initWithSources:(int) reservedSources;
/** (INTERNAL USE) Initialize with the specified parameters.
*
* @param reservedSources The number of sources to reserve for OALSimpleAudio's use when initializing.
* @param monoSources The GLOBAL number of sources supporting mono (default 28).
* @param stereoSources The GLOBAL number of sources supporting stereo (default 4).
* @return The shared instance.
*/
- (id) initWithReservedSources:(int) reservedSources
monoSources:(int) monoSources
stereoSources:(int) stereoSources;
/** \endcond */
#pragma mark Background Music
/** Preload background music.
*
* <strong>Note:</strong> only <strong>ONE</strong> background music
* file may be played or preloaded at a time via OALSimpleAudio.
* If you play or preload another file, the one currently playing
* will stop.
*
* @param path The path containing the background music.
* @return TRUE if the operation was successful.
*/
- (bool) preloadBg:(NSString*) path;
/** Preload background music.
*
* <strong>Note:</strong> only <strong>ONE</strong> background music
* file may be played or preloaded at a time via OALSimpleAudio.
* If you play or preload another file, the one currently playing
* will stop.
*
* @param path The path containing the background music.
* @param seekTime the position in the file to start playing at.
* @return TRUE if the operation was successful.
*/
- (bool) preloadBg:(NSString*) path seekTime:(NSTimeInterval)seekTime;
/** Play whatever background music is preloaded.
*
* @return TRUE if the operation was successful.
*/
- (bool) playBg;
/** Play whatever background music is preloaded.
*
* @param loop If true, loop the bg track.
* @return TRUE if the operation was successful.
*/
- (bool) playBgWithLoop:(bool) loop;
/** Play the background music at the specified path.
* If the music has not been preloaded, this method
* will load the music and then play, incurring a slight delay. <br>
*
* <strong>Note:</strong> only <strong>ONE</strong> background music
* file may be played or preloaded at a time via OALSimpleAudio.
* If you play or preload another file, the one currently playing
* will stop.
*
* @param path The path containing the background music.
* @return TRUE if the operation was successful.
*/
- (bool) playBg:(NSString*) path;
/** Play the background music at the specified path.
* If the music has not been preloaded, this method
* will load the music and then play, incurring a slight delay. <br>
*
* <strong>Note:</strong> only <strong>ONE</strong> background music
* file may be played or preloaded at a time via OALSimpleAudio.
* If you play or preload another file, the one currently playing
* will stop.
*
* @param path The path containing the background music.
* @param loop If true, loop the bg track.
* @return TRUE if the operation was successful.
*/
- (bool) playBg:(NSString*) path loop:(bool) loop;
/** Play the background music at the specified path.
* If the music has not been preloaded, this method
* will load the music and then play, incurring a slight delay. <br>
*
* <strong>Note:</strong> only <strong>ONE</strong> background music
* file may be played or preloaded at a time via OALSimpleAudio.
* If you play or preload another file, the one currently playing
* will stop. To play multiple audio tracks, create an OALAudioTrack. <br>
*
* <strong>Note:</strong> pan will have no effect when running on iOS
* versions prior to 4.0.
*
* @param filePath The path containing the sound data.
* @param volume The volume (gain) to play at (0.0 - 1.0).
* @param pan Left-right panning (-1.0 = far left, 1.0 = far right) (Only on iOS 4.0+).
* @param loop If TRUE, the sound will loop until you call "stopBg".
* @return TRUE if the operation was successful.
*/
- (bool) playBg:(NSString*) filePath
volume:(float) volume
pan:(float) pan
loop:(bool) loop;
/** Stop the background music playback and rewind.
*/
- (void) stopBg;
#pragma mark Sound Effects
/** Preload and cache a sound effect for later playback.
*
* @param filePath The path containing the sound data.
*/
- (ALBuffer*) preloadEffect:(NSString*) filePath;
/** Preload and cache a sound effect for later playback.
*
* @param filePath The path containing the sound data.
* @param reduceToMono If true, reduce the sample to mono
* (stereo samples don't support panning or positional audio).
*/
- (ALBuffer*) preloadEffect:(NSString*) filePath reduceToMono:(bool) reduceToMono;
#if NS_BLOCKS_AVAILABLE && OBJECTAL_CFG_USE_BLOCKS
/** Asynchronous preload and cache sound effect for later playback.
*
* @param filePath an NSString with the path containing the sound data.
* @param reduceToMono If true, reduce the sample to mono
* (stereo samples don't support panning or positional audio).
* @param completionBlock Executed when loading is complete.
*/
- (BOOL) preloadEffect:(NSString*) filePath
reduceToMono:(bool) reduceToMono
completionBlock:(void(^)(ALBuffer *)) completionBlock;
/** Asynchronous preload and cache multiple sound effects for later playback.
*
* @param filePaths An NSArray of NSStrings with the paths containing the sound data.
* @param reduceToMono If true, reduce the samples to mono
* (stereo samples don't support panning or positional audio).
* @param progressBlock Executed regularly while file loading is in progress.
*/
- (void) preloadEffects:(NSArray*) filePaths
reduceToMono:(bool) reduceToMono
progressBlock:(void (^)(NSUInteger progress, NSUInteger successCount, NSUInteger total)) progressBlock;
#endif
/** Unload a preloaded effect. Only unloads if no source is currently playing
* that effect (or paused with the effect loaded).
*
* @param filePath The path containing the sound data that was previously loaded.
*
* @return YES if the effect was unloaded. Turn on debug logging to see why an
* effect was not unloaded.
*/
- (bool) unloadEffect:(NSString*) filePath;
/** Unload all preloaded effects that are not currently being played (paused or not).
* Turning on debug logging will show which effects were not unloaded.
* It is useful to put a call to this method in
* "applicationDidReceiveMemoryWarning" in your app delegate.
*/
- (void) unloadAllEffects;
/** Play a sound effect with volume 1.0, pitch 1.0, pan 0.0, loop NO. The sound will be loaded
* and cached if it wasn't already.
*
* @param filePath The path containing the sound data.
* @return The sound source being used for playback, or nil if an error occurred.
*/
- (id<ALSoundSource>) playEffect:(NSString*) filePath;
/** Play a sound effect with volume 1.0, pitch 1.0, pan 0.0. The sound will be loaded and cached
* if it wasn't already.
*
* @param filePath The path containing the sound data.
* @param loop If TRUE, the sound will loop until you call "stop" on the returned sound source.
* @return The sound source being used for playback, or nil if an error occurred.
*/
- (id<ALSoundSource>) playEffect:(NSString*) filePath loop:(bool) loop;
/** Play a sound effect. The sound will be loaded and cached if it wasn't already.
*
* @param filePath The path containing the sound data.
* @param volume The volume (gain) to play at (0.0 - 1.0).
* @param pitch The pitch to play at (1.0 = normal pitch).
* @param pan Left-right panning (-1.0 = far left, 1.0 = far right).
* @param loop If TRUE, the sound will loop until you call "stop" on the returned sound source.
* @return The sound source being used for playback, or nil if an error occurred (You'll need to
* keep this if you want to be able to stop a looped playback).
*/
- (id<ALSoundSource>) playEffect:(NSString*) filePath
volume:(float) volume
pitch:(float) pitch
pan:(float) pan
loop:(bool) loop;
/** Play a sound effect from a user-supplied buffer.
*
* @param buffer The buffer containing the sound data.
* @param volume The volume (gain) to play at (0.0 - 1.0).
* @param pitch The pitch to play at (1.0 = normal pitch).
* @param pan Left-right panning (-1.0 = far left, 1.0 = far right).
* @param loop If TRUE, the sound will loop until you call "stop" on the returned sound source.
* @return The sound source being used for playback, or nil if an error occurred (You'll need to
* keep this if you want to be able to stop a looped playback).
*/
- (id<ALSoundSource>) playBuffer:(ALBuffer*) buffer
volume:(float) volume
pitch:(float) pitch
pan:(float) pan
loop:(bool) loop;
/** Stop ALL sound effect playback.
*/
- (void) stopAllEffects;
#pragma mark Utility
/** Stop all effects and bg music.
*/
- (void) stopEverything;
/** Reset everything in this object to its default state.
*/
- (void) resetToDefault;
@end
@@ -0,0 +1,165 @@
//
// OALSuspendHandler.h
// ObjectAL
//
// Created by Karl Stenerud on 10-12-19.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
/**
* Allows an object to participate in interrupt and suspend operations.
* Objects may hook into OALAudioSession's interrupt and suspend model by
* calling [[OALAudioSession sharedInstance] addSuspendListener:self].
*
* Note: You must NOT set the "interrupted" property manually. It is designed
* to be set automatically by system interrupts.
*
* @see OALAudioSession
*/
@protocol OALSuspendListener
/** Set to YES to manually suspend.
*/
@property(nonatomic,readwrite,assign) bool manuallySuspended;
/** If YES, this object is interrupted.
* Note: This property must NOT be set by the user!
*/
@property(nonatomic,readwrite,assign) bool interrupted;
@end
/**
* A suspend manager is a listener that also allows other objects
* to subscribe to receive events as the manager receives them.
*/
@protocol OALSuspendManager <OALSuspendListener>
/** If YES, this object is suspended.
*/
@property(nonatomic,readonly,assign) bool suspended;
/** Add a listener that will receive manual suspend and interrupt events.
*
* @param listener The listener to register with this handler.
*/
- (void) addSuspendListener:(id<OALSuspendListener>) listener;
/** Remove a registered listener.
*
* @param listener The listener to unregister from this handler.
*/
- (void) removeSuspendListener:(id<OALSuspendListener>) listener;
@end
/**
* Provides two controls (interrupted and manuallySuspended) for suspending
* a slave object, and also propagates such control messages to interested
* listeners.
*
* "interrupted" is meant to be set by the system when an interrupt occurs. <br>
*
* "manuallySuspended" is a user-settable control for suspending an object. <br>
* "manuallySuspended" also has an extra step in its processing: When set,
* the handler makes a note of what its listeners' "manuallySuspended" values are.
* When cleared, it will only clear a listener's "manuallySuspended" value if it
* was not set at suspend time. This allows for ad-hoc setting/clearing of
* "manuallySuspended" in the middle of a handler/listener graph rather than
* only from the top level. <br>
*
* When either control is set, the slave object will be suspended. When both are
* cleared, the slave object will be unsuspended. <br>
*/
@interface OALSuspendHandler: NSObject
{
/** Listeners that will receive manualSuspend and interrupt events. */
NSMutableArray* listeners;
/** Holder for the state of manualSuspend in listeners when this object is
* manually suspended.
*/
NSMutableArray* manualSuspendStates;
/** Selector to be invoked on suspend or unsuspend.
* Takes the signature: setSelected:(bool) value
*/
SEL suspendStatusChangeSelector;
/** Holds the current "manually suspended" state. */
bool manualSuspendLock;
/** Holds the current "interrupted" state. */
bool interruptLock;
}
/** Create a new handler with the specified slave target and selector.
*
* The selector provided must take a single boolean value like so: <br>
* - (void) setSuspended:(bool) value <br>
*
* @param target The slave object that will receive suspend/unsuspend events.
* @param selector The selector for a "set suspended" method, taking a single
* boolean parameter.
*/
+ (OALSuspendHandler*) handlerWithTarget:(id) target selector:(SEL) selector;
/** Initialize a handler with the specified slave target and selector.
*
* The selector provided must take a single boolean value like so: <br>
* - (void) setSuspended:(bool) value <br>
*
* @param target The slave object that will receive suspend/unsuspend events.
* @param selector The selector for a "set suspended" method, taking a single
* boolean parameter.
*/
- (id) initWithTarget:(id) target selector:(SEL) selector;
/** If YES, the manual suspend control is set. */
@property(nonatomic,readwrite,assign) bool manuallySuspended;
/** If YES, the interrupt control is set. */
@property(nonatomic,readwrite,assign) bool interrupted;
/** If YES, the slave object is suspended. */
@property(nonatomic,readonly,assign) bool suspended;
/** Add a listener that will receive manual suspend and interrupt events.
*
* @param listener The listener to register with this handler.
*/
- (void) addSuspendListener:(id<OALSuspendListener>) listener;
/** Remove a registered listener.
*
* @param listener The listener to unregister from this handler.
*/
- (void) removeSuspendListener:(id<OALSuspendListener>) listener;
@end
@@ -0,0 +1,97 @@
//
// OALTools.h
// ObjectAL
//
// Created by Karl Stenerud on 10-12-19.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
/**
* Miscellaneous tools used by ObjectAL.
*/
@interface OALTools : NSObject
{
}
/** Set the default bundle to use when looking up paths.
*
* @param bundle The new default bundle.
*/
+ (void) setDefaultBundle:(NSBundle*) bundle;
/** The default bundle used when looking up paths.
*
* return The default bundle.
*/
+ (NSBundle*) defaultBundle;
/** Returns the URL corresponding to the specified path.
* If the path is not absolute (starts with a "/"), this method will look for
* the file in the default bundle.
*
* @param path The path to convert to a URL.
* @return The corresponding URL or nil if a URL could not be formed.
*/
+ (NSURL*) urlForPath:(NSString*) path;
/** Returns the URL corresponding to the specified path.
* If the path is not absolute (starts with a "/"), this method will look for
* the file in the specified bundle.
*
* @param path The path to convert to a URL.
* @param bundle The bundle to look inside for relative paths.
* @return The corresponding URL or nil if a URL could not be formed.
*/
+ (NSURL*) urlForPath:(NSString*) path bundle:(NSBundle*) bundle;
/** Notify an error if the specified ExtAudio error code indicates an error.
* This will log the error and also potentially post an audio error notification
* (OALAudioErrorNotification) if it is suspected that this error is a result of
* the audio session getting corrupted.
*
* @param errorCode: The error code returned from an OS call.
* @param function: The function name where the error occurred.
* @param description: A printf-style description of what happened.
*/
+ (void) notifyExtAudioError:(OSStatus)errorCode
function:(const char*) function
description:(NSString*) description, ...;
/** Notify an error if the specified AudioSession error code indicates an error.
* This will log the error and also potentially post an audio error notification
* (OALAudioErrorNotification) if it is suspected that this error is a result of
* the audio session getting corrupted.
*
* @param errorCode: The error code returned from an OS call.
* @param function: The function name where the error occurred.
* @param description: A printf-style description of what happened.
*/
+ (void) notifyAudioSessionError:(OSStatus)errorCode
function:(const char*) function
description:(NSString*) description, ...;
@end
@@ -0,0 +1,268 @@
//
// OALUtilityActions.h
// ObjectAL
//
// Created by Karl Stenerud on 10-10-10.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import "OALAction.h"
#pragma mark OALTargetedAction
/**
* Ignores whatever target it was invoked upon and applies the specified action
* on the target specified at creation time.
*/
@interface OALTargetedAction: OALAction
{
/** The action that will be run on the target. */
OALAction* action_;
}
/** The target which this action will actually be invoked upon. */
@property(nonatomic,readwrite,assign) id forcedTarget;
/** Create an action.
*
* @param target The target to run the action upon.
* @param action The action to run.
* @return A new action.
*/
+ (id) actionWithTarget:(id) target action:(OALAction*) action;
/** Initialize an action.
*
* @param target The target to run the action upon.
* @param action The action to run.
* @return The initialized action.
*/
- (id) initWithTarget:(id) target action:(OALAction*) action;
@end
#if !OBJECTAL_CFG_USE_COCOS2D_ACTIONS
#pragma mark -
#pragma mark OALSequentialActions
/**
* A set of actions that get run in sequence.
*/
@interface OALSequentialActions: OALAction
{
/** The index of the action currently being processed. */
NSUInteger actionIndex_;
/** The last completeness proportion value acted upon. */
float pLastComplete_;
/** The proportional duration of the current action. */
float pCurrentActionDuration_;
/** The proportional completeness of the current action. */
float pCurrentActionComplete_;
}
#pragma mark Properties
/** The actions which will be run. */
@property(nonatomic,readwrite,retain) NSMutableArray* actions;
#pragma mark Object Management
/** Create an action.
*
* @param actions The comma separated list of actions.
* @param NS_REQUIRES_NIL_TERMINATION List of actions must be terminated by a nil.
* @return A new set of sequential actions.
*/
+ (id) actions:(OALAction*) actions, ... NS_REQUIRES_NIL_TERMINATION;
/** Create an action.
*
* @param actions The actions to run.
* @return A new set of sequential actions.
*/
+ (id) actionsFromArray:(NSArray*) actions;
/** Initialize an action.
*
* @param actions The actions to run.
* @return The initialized set of sequential actions.
*/
- (id) initWithActions:(NSArray*) actions;
@end
#pragma mark -
#pragma mark OALConcurrentActions
/**
* A set of actions that get run concurrently.
*/
@interface OALConcurrentActions: OALAction
#pragma mark Properties
/** The actions which will be run. */
@property(nonatomic,readwrite,retain) NSMutableArray* actions;
#pragma mark Object Management
/** Create an action.
*
* @param actions The comma separated list of actions.
* @param NS_REQUIRES_NIL_TERMINATION List of actions must be terminated by a nil.
* @return A new set of concurrent actions.
*/
+ (id) actions:(OALAction*) actions, ... NS_REQUIRES_NIL_TERMINATION;
/** Create an action.
*
* @param actions The actions to run.
* @return A new set of concurrent actions.
*/
+ (id) actionsFromArray:(NSArray*) actions;
/** Initialize an action.
*
* @param actions The actions to run.
* @return The initialized set of concurrent actions.
*/
- (id) initWithActions:(NSArray*) actions;
@end
#else /* !OBJECTAL_CFG_USE_COCOS2D_ACTIONS */
COCOS2D_SUBCLASS_HEADER(OALSequentialActions,CCSequence);
COCOS2D_SUBCLASS_HEADER(OALConcurrentActions,CCSpawn);
#endif /* !OBJECTAL_CFG_USE_COCOS2D_ACTIONS */
#pragma mark -
#pragma mark OALCallAction
/**
* Calls a selector on a target.
* This action will ignore whatever target it is run against,
* and will invoke the selector on the target specified at creation
* time.
*/
@interface OALCallAction: OALAction
{
/** The target to call the selector on. */
id callTarget_;
/** The selector to invoke */
SEL selector_;
/** The number of parameters which will be passed to the selector. */
int numObjects_;
/** The first object to pass to the selector, if any. */
id object1_;
/** The second object to pass to the selector, if any. */
id object2_;
}
/** Create an action.
*
* @param callTarget The target to call.
* @param selector The selector to invoke.
* @return A new action.
*/
+ (id) actionWithCallTarget:(id) callTarget
selector:(SEL) selector;
/** Create an action.
*
* @param callTarget The target to call.
* @param selector The selector to invoke.
* @param object The object to pass to the selector.
* @return A new action.
*/
+ (id) actionWithCallTarget:(id) callTarget
selector:(SEL) selector
withObject:(id) object;
/** Create an action.
*
* @param callTarget The target to call.
* @param selector The selector to invoke.
* @param firstObject The first object to pass to the selector.
* @param secondObject The second object to pass to the selector.
* @return A new action.
*/
+ (id) actionWithCallTarget:(id) callTarget
selector:(SEL) selector
withObject:(id) firstObject
withObject:(id) secondObject;
/** Initialize an action.
*
* @param callTarget The target to call.
* @param selector The selector to invoke.
* @return The initialized action.
*/
- (id) initWithCallTarget:(id) callTarget
selector:(SEL) selector;
/** Initialize an action.
*
* @param callTarget The target to call.
* @param selector The selector to invoke.
* @param object The object to pass to the selector.
* @return Initialize an action.
*/
- (id) initWithCallTarget:(id) callTarget
selector:(SEL) selector
withObject:(id) object;
/** Initialize an action.
*
* @param callTarget The target to call.
* @param selector The selector to invoke.
* @param firstObject The first object to pass to the selector.
* @param secondObject The second object to pass to the selector.
* @return The initialized action.
*/
- (id) initWithCallTarget:(id) callTarget
selector:(SEL) selector
withObject:(id) firstObject
withObject:(id) secondObject;
@end
@@ -0,0 +1,724 @@
//
// ObjectAL.h
// ObjectAL
//
// Created by Karl Stenerud on 15/12/09.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
// Actions
#import "OALAction.h"
#import "OALAudioActions.h"
#import "OALUtilityActions.h"
#import "OALActionManager.h"
// AudioTrack
#import "OALAudioTrack.h"
#import "OALAudioTracks.h"
#import "OALAudioTrackNotifications.h"
// OpenAL
#import "ALTypes.h"
#import "ALBuffer.h"
#import "ALCaptureDevice.h"
#import "ALContext.h"
#import "ALDevice.h"
#import "ALListener.h"
#import "ALSource.h"
//#import "ALWrapper.h"
#import "ALChannelSource.h"
#import "ALSoundSourcePool.h"
#import "OpenALManager.h"
#import "OALAudioFile.h"
// Other
//#import "OALNotifications.h"
#import "OALAudioSession.h"
#import "OALSimpleAudio.h"
/** \mainpage ObjectAL for iPhone
<strong>iOS Audio development, minus the headache.</strong> <br><br>
Version 2.2 <br> <br>
Copyright 2009-2013 Karl Stenerud <br><br>
Released under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License v2.0</a>
<br> <br>
\section contents_sec Contents
- \ref intro_sec
- \ref objectal_and_openal_sec
- \ref add_objectal_sec (also, installing the documentation into XCode)
- \ref configuration_sec
- \ref audio_formats_sec
- \ref choosing_sec
- \ref use_iossimpleaudio_sec
- \ref use_objectal_sec
- \ref other_examples_sec
- \ref ios_issues_sec
- \ref simulator_issues_sec
<br> <br>
\section intro_sec Introduction
<strong>ObjectAL for iPhone</strong> is designed to be a simpler, more intuitive interface to
OpenAL and AVAudioPlayer.
There are four main parts to <strong>ObjectAL for iPhone</strong>:<br/><br/>
\image html ObjectAL-Overview1.png
\image latex ObjectAL-Overview1.eps
- <a class="el" href="index.html#objectal_and_openal_sec">ObjectAL</a>
gives you full access to the OpenAL system without the hassle of the C API.
All OpenAL operations can be performed using first class objects and properties, without needing
to muddle around with arrays of data, maintain IDs, or pass around pointers to basic types.
ObjectALManager also provides sound loading routines.
- OALAudioTrack provides a simpler interface to AVAudioPlayer, allowing you to play, stop,
pause, fade, and mute background music tracks.
- OALAudioSession handles audio session management in iOS devices, and provides an easy
way to configure session behavior such as how to handle iPod-style music and the silent
switch.
- OALSimpleAudio layers on top of the other three, providing an even simpler interface for
playing background music and sound effects.
<br> <br>
\section objectal_and_openal_sec ObjectAL and OpenAL
<strong>ObjectAL</strong> follows the same basic principles as the
<a href="http://connect.creativelabs.com/openal">OpenAL API by Creative Labs</a>.
\image html ObjectAL-Overview2.png
\image latex ObjectAL-Overview2.eps
- OpenALManager provides some overall controls that affect everything, manages the current
context, and provides audio loading routines.
- ALDevice represents a physical audio device. <br>
Each device can have one or more contexts (ALContext) created on it, and can have multiple
buffers (ALBuffer) associated with it.
- ALContext controls the overall sound environment, such as distance model, doppler effect, and
speed of sound. <br>
Each context has one listener (ALListener), and can have multiple sources (ALSource) opened on
it (up to a maximum of 32 overall on iPhone).
- ALListener represents the listener of sounds originating on its context (one listener per
context). It has position, orientation, and velocity.
- ALSource is a sound emitting source that plays sound data from an ALBuffer. It has position,
direction, velocity, as well as other properties which determine how the sound is emitted.
- ALChannelSource allows you to reserve a certain number of sources for special purposes.
- ALBuffer is simply a container for sound data. Only linear PCM is supported directly, but
OpenALManager load methods, and OALSimpleAudio effect preload and play methods, will
automatically convert any formats that don't require hardware decoding (though conversion
results in a longer loading time).
<strong>Note:</strong> While OpenAL allows for multiple devices and contexts, in practice
you'll only use one device and one context when using OpenAL under iOS.
Further information regarding the more advanced features of OpenAL (such as distance models)
are available via the
<a href="http://connect.creativelabs.com/openal/Documentation/Forms/AllItems.aspx">
OpenAL Documentation at Creative Labs</a>. <br>
In particular, read up on the various property values for sources and listeners (such as Doppler
Shift) in the
<a href="http://connect.creativelabs.com/openal/Documentation/OpenAL_Programmers_Guide.pdf">OpenAL Programmer's Guide</a>,
and distance models in section 3 of the
<a href="http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.pdf">OpenAL Specification</a>.
<br> <br>
\section add_objectal_sec Adding ObjectAL to your project
To add ObjectAL to your project, do the following:
<ol>
<li>Copy ObjectAL/ObjectAL from this project into your project.
You can simply drag it into the "Groups & Files" section in xcode if you
like (be sure to select "Copy items into destination group's folder"). <br/>
Alternatively, you can build ObjectAL as a static library (as it's configured to do in the
ObjectAL demo project).<br/><br/>
</li>
<li>Add the following frameworks to your project:
<ul>
<li>OpenAL.framework</li>
<li>AudioToolbox.framework</li>
<li>AVFoundation.framework</li>
</ul><br/>
</li>
<li>Start using ObjectAL!<br/><br/></li>
</ol>
<br/>
<strong>Note:</strong> The demos in this project use
<a href="http://www.cocos2d-iphone.org">Cocos2d</a>, a very nice 2d game engine. However,
ObjectAL doesn't require it. You can just as easily use ObjectAL in your Cocoa app or anything
you wish.
<br/> <br/>
<strong>Note #2:</strong> You do NOT have to provide a link to the Apache license from within your
application. Simply including a copy of the license in your project is sufficient.
<br>
\subsection install_dox Installing the ObjectAL Documentation into XCode
By installing the ObjectAL documentation into XCode's Developer Documentation system, you gain
the ability to look up ObjectAL classes and methods just like you'd look up Apple classes and
methods. You can install the ObjectAL documentation into XCode's Developer Documentation
system by doing the following:
-# Install <a href="http://www.doxygen.org">Doxygen</a>. You can either use the OSX installer or
<a href="http://mxcl.github.io/homebrew/">Homebrew</a>.
-# Build the "Documentation" target in this project.
-# Open the developer documentation and type "ObjectAL" into the search box.
<br> <br>
\section configuration_sec Compile-Time Configuration
<strong>ObjectALConfig.h</strong> contains configuration defines that will affect at a high level
how ObjectAL behaves. Look inside <strong>ObjectALConfig.h</strong> to see what can be
configured, and what each configuration value does. <br>
The recommended values are fine for most users, but Cocos2D users may want to set
OBJECTAL_CFG_USE_COCOS2D_ACTIONS so that the audio actions (such as fade) use the Cocos2D action manager.
<br> <br>
\section audio_formats_sec Audio Formats
The audio formats officially supported by Apple are
<a href="http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html">
defined here</a>.
<br><br>
\subsection audio_formats_avaudioplayer OALAudioTrack Supported Formats
OALAudioTrack supports all hardware and software decoded formats.
<br><br>
\subsection audio_formats_openal OpenAL Supported Formats
OpenAL officially supports 8 or 16 bit PCM data only. However, Apple's implementation
only seems to work with 16 bit data. <br>
The effects preloading/playing methods in OALSimpleAudio and the buffer loading methods
in OpenALManager can load any audio file that can be software decoded. However, there
is a cost incurred at load time converting to a native OpenAL format. To avoid this,
convert all of your samples to a CAFF container with 16-bit little endian integer PCM
format and the same sample rate as "mixerOutputFrequency" in OpenALManager
(by default, 44100Hz). Note, however, that uncompressed files can get quite large.<br>
Convert to iOS native uncompressed format using Apple's "afconvert" command line tool:
\code afconvert -f caff -d LEI16@44100 sourcefile.wav destfile.caf \endcode
Alternatively, if sound file load time is not an issue for you, you can lower your app
footprint size (for over-the-air app download) by using a compressed format. <br>
Convert to AAC compressed format with CAFF container using Apple's "afconvert" command
line tool:
\code afconvert -f caff -d aac sourcefile.wav destfile.caf \endcode
<br> <br>
\section choosing_sec Choosing Playback Types
<strong>OpenAL</strong> (ALSource, or effects in OALSimpleAudio) and
<strong>AVAudioPlayer</strong> (OALAudioTrack, or background audio in OALSimpleAudio)
are playback technologies built for different purposes. OpenAL is designed for game-style
short sound effects that have no playback delay. AVAudioPlayer is designed for music
playback. You can of course mix and match as you please.
<table>
<tr>
<td></td>
<td><strong>OpenAL</strong></td>
<td><strong>AVAudioPlayer</strong></td>
</tr>
<tr>
<td><strong>Playback Delay</strong></td>
<td>None</td>
<td>Small delay if not preloaded</td>
</tr>
<tr>
<td><strong>Format on Disk</strong></td>
<td><a href="http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html">
Any software decodable format</a></td>
<td><a href="http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html">
Any software decodable format, or any hardware format if using hardware</a></td>
</tr>
<tr>
<td><strong>Decoding</strong></td>
<td>During load</td>
<td>During playback</td>
</tr>
<tr>
<td><strong>Memory Use</strong></td>
<td>Entire file loaded and decompressed into memory</td>
<td>File streamed realtime (very low memory use)</td>
</tr>
<tr>
<td><strong>Max Simult. Sources</strong></td>
<td>32</td>
<td>As many as the CPU can handle</td>
</tr>
<tr>
<td><strong>Playback Performance</strong></td>
<td>Good</td>
<td>Excellent with 1 track (if using hardware). Good with 2 tracks. Not so good with more
(each non-hardware track taxes the CPU significantly, especially if the files are compressed).</td>
</tr>
<tr>
<td><strong>Looped Playback</strong></td>
<td>Yes (on or off)</td>
<td>Yes (specify number of loops or -1 = forever)</td>
</tr>
<tr>
<td><strong>Panning</strong></td>
<td>Yes (mono files only)</td>
<td>Yes (iOS 4.0+ only)</td>
</tr>
<tr>
<td><strong>Positional Audio</strong></td>
<td>Yes (mono files only)</td>
<td>No</td>
</tr>
<tr>
<td><strong>Modify Pitch</strong></td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td><strong>Audio Power Metering</strong></td>
<td>No</td>
<td>Yes</td>
</tr>
</table>
<br> <br>
\section use_iossimpleaudio_sec Using OALSimpleAudio
By far, the easiest component to use is OALSimpleAudio. You sacrifice some power for
ease-of-use, but for many projects it is more than sufficient. You can also use your own instances
of OALAudioTrack, ALSource, ALBuffer and such alongside of OALSimpleAudio if you want (just be sure
to set OALSimpleAudio's reservedSources to less than 32 if you want to make your own instances of
ALSource).
Here is a code example using purely OALSimpleAudio:
\code
// OALSimpleAudioSample.h
@interface OALSimpleAudioSample : NSObject
{
// No objects to keep track of...
}
@end
// OALSimpleAudioSample.m
#import "OALSimpleAudioSample.h"
#import "ObjectAL.h"
#define SHOOT_SOUND @"shoot.caf"
#define EXPLODE_SOUND @"explode.caf"
#define INGAME_MUSIC_FILE @"bg_music.mp3"
#define GAMEOVER_MUSIC_FILE @"gameover_music.mp3"
@implementation OALSimpleAudioSample
- (id) init
{
if(nil != (self = [super init]))
{
// We don't want ipod music to keep playing since
// we have our own bg music.
[OALSimpleAudio sharedInstance].allowIpod = NO;
// Mute all audio if the silent switch is turned on.
[OALSimpleAudio sharedInstance].honorSilentSwitch = YES;
// This loads the sound effects into memory so that
// there's no delay when we tell it to play them.
[[OALSimpleAudio sharedInstance] preloadEffect:SHOOT_SOUND];
[[OALSimpleAudio sharedInstance] preloadEffect:EXPLODE_SOUND];
}
return self;
}
- (void) onGameStart
{
// Play the BG music and loop it.
[[OALSimpleAudio sharedInstance] playBg:INGAME_MUSIC_FILE loop:YES];
}
- (void) onGamePause
{
[OALSimpleAudio sharedInstance].paused = YES;
}
- (void) onGameResume
{
[OALSimpleAudio sharedInstance].paused = NO;
}
- (void) onGameOver
{
// Could use stopEverything here if you want
[[OALSimpleAudio sharedInstance] stopAllEffects];
// We only play the game over music through once.
[[OALSimpleAudio sharedInstance] playBg:GAMEOVER_MUSIC_FILE];
}
- (void) onShipShotABullet
{
[[OALSimpleAudio sharedInstance] playEffect:SHOOT_SOUND];
}
- (void) onShipGotHit
{
[[OALSimpleAudio sharedInstance] playEffect:EXPLODE_SOUND];
}
- (void) onQuitToMainMenu
{
// Stop all music and sound effects.
[[OALSimpleAudio sharedInstance] stopEverything];
// Unload all sound effects and bg music so that it doesn't fill
// memory unnecessarily.
[[OALSimpleAudio sharedInstance] unloadAllEffects];
}
@end
\endcode
<br> <br>
\section use_objectal_sec Using the OpenAL Objects and OALAudioTrack
The OpenAL objects and OALAudioTrack offer you much more power at the cost
of complexity.
Here's the same thing as above, done using OpenAL components and OALAudioTrack:
\code
// OpenALAudioTrackSample.h
#import <Foundation/Foundation.h>
#import "ObjectAL.h"
@interface OpenALAudioTrackSample : NSObject
{
// Sound Effects
ALDevice* device;
ALContext* context;
ALChannelSource* channel;
ALBuffer* shootBuffer;
ALBuffer* explosionBuffer;
// Background Music
OALAudioTrack* musicTrack;
}
@end
// OpenALAudioTrackSample.m
#import "OpenALAudioTrackSample.h"
#define SHOOT_SOUND @"shoot.caf"
#define EXPLODE_SOUND @"explode.caf"
#define INGAME_MUSIC_FILE @"bg_music.mp3"
#define GAMEOVER_MUSIC_FILE @"gameover_music.mp3"
@implementation OpenALAudioTrackSample
- (id) init
{
if(nil != (self = [super init]))
{
// Create the device and context.
// Note that it's easier to just let OALSimpleAudio handle
// these rather than make and manage them yourself.
device = [[ALDevice deviceWithDeviceSpecifier:nil] retain];
context = [[ALContext contextOnDevice:device attributes:nil] retain];
[OpenALManager sharedInstance].currentContext = context;
// Deal with interruptions for me!
[OALAudioSession sharedInstance].handleInterruptions = YES;
// We don't want ipod music to keep playing since
// we have our own bg music.
[OALAudioSession sharedInstance].allowIpod = NO;
// Mute all audio if the silent switch is turned on.
[OALAudioSession sharedInstance].honorSilentSwitch = YES;
// Take all 32 sources for this channel.
// (we probably won't use that many but what the heck!)
channel = [[ALChannelSource channelWithSources:32] retain];
// Preload the buffers so we don't have to load and play them later.
shootBuffer = [[[OpenALManager sharedInstance]
bufferFromFile:SHOOT_SOUND] retain];
explosionBuffer = [[[OpenALManager sharedInstance]
bufferFromFile:EXPLODE_SOUND] retain];
// Background music track.
musicTrack = [[OALAudioTrack track] retain];
}
return self;
}
- (void) dealloc
{
[musicTrack release];
[channel release];
[shootBuffer release];
[explosionBuffer release];
// Note: You'll likely only have one device and context open throughout
// your program, so in a real program you'd be better off making a
// singleton object that manages the device and context, rather than
// allocating/deallocating it here.
// Most of the demos just let OALSimpleAudio manage the device and context
// for them.
[context release];
[device release];
[super dealloc];
}
- (void) onGameStart
{
// Play the BG music and loop it forever.
[musicTrack playFile:INGAME_MUSIC_FILE loops:-1];
}
- (void) onGamePause
{
musicTrack.paused = YES;
channel.paused = YES;
}
- (void) onGameResume
{
channel.paused = NO;
musicTrack.paused = NO;
}
- (void) onGameOver
{
[channel stop];
[musicTrack stop];
// We only play the game over music through once.
[musicTrack playFile:GAMEOVER_MUSIC_FILE];
}
- (void) onShipShotABullet
{
[channel play:shootBuffer];
}
- (void) onShipGotHit
{
[channel play:explosionBuffer];
}
- (void) onQuitToMainMenu
{
// Stop all music and sound effects.
[channel stop];
[musicTrack stop];
}
@end
\endcode
<br> <br>
\section other_examples_sec Other Examples
The demo scenes in this distribution have been crafted to demonstrate common uses of this library.
Try them out and go through the code to see how it's done. I've done my best to keep the code
readable. Really!
You can try out the demos by building and running the OALDemo target for iOS or OSX.
The current demos are:
- <strong>SingleSourceDemo</strong>: Demonstrates using a location based source and a listener.
- <strong>TwoSourceDemo</strong>: Demonstrates using two location based sources and a listener.
- <strong>VolumePitchPanDemo</strong>: Demonstrates using gain, pitch, and pan controls.
- <strong>CrossFadeDemo</strong>: Demonstrates crossfading between two sources.
- <strong>ChannelsDemo</strong>: Demonstrates using audio channels.
- <strong>FadeDemo</strong>: Demonstrates realtime fading with OALAudioTrack and ALSource.
- <strong>AudioTrackDemo</strong>: Demonstrates using multiple OALAudioTrack objects.
- <strong>PlanetKillerDemo</strong>: Demonstrates using OALSimpleAudio in a game setting.
- <strong>IntroAndMainTrackDemo</strong>: Demonstrates a short intro track followed by a main loop track.
- <strong>SourceNotificationsDemo</strong>: Demonstrates using OpenAL playback notifications.
- <strong>HardwareDemo</strong>: Demonstrates hardware monitoring features.
- <strong>AudioSessionDemo</strong>: Allows you to play with various audio session settings.
<br> <br>
\section ios_issues_sec iOS Issues that can impede playback
Certain versions of iOS have bugs or quirks, requiring workarounds. ObjectAL tries to handle
most of these automatically, but there are cases that require specific handling by the developer.
These are:
<br>
\subsection mpmovieplayercontroller_ios3 MPMoviePlayerController on iOS 3.x
In iOS 3.x, MPMoviePlayerController doesn't play nice, and takes over the audio session when
you play a video. In order to mitigate this, you must manually suspend OpenAL, play the video,
and then manually unsuspend once video playback finishes:
\code
- (void) playVideo
{
if([myMoviePlayer respondsToSelector:@selector(view)])
{
[myMoviePlayer setFullscreen:YES animated:YES];
}
else
{
// No "view" method means we are < 4.0
// Manually suspend so iOS 3.x doesn't clobber our session!
[OpenALManager sharedInstance].manuallySuspended = YES;
}
[myMoviePlayer play];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:myMoviePlayer];
}
-(void)movieFinishedCallback:(NSNotification *)notification
{
if([myMoviePlayer respondsToSelector:@selector(view)])
{
if (myMoviePlayer.fullscreen)
{
[myMoviePlayer setFullscreen:NO animated:YES];
}
}
else
{
// No "view" method means we are < 4.0
// Manually unsuspend
[OpenALManager sharedInstance].manuallySuspended = NO;
}
}
\endcode
<br>
\subsection mpmusicplayercontroller_ios4_0 MPMusicPlayerController on iOS 4.0
On iOS 4.0, MPMusicPlayerController sends an interrupt when it begins playback, but doesn't send
a corresponding "end interrupt" when it ends. To work around this, force an "end interrupt"
after starting playback:
\code
[[OALAudioSession sharedInstance] forceEndInterruption];
\endcode
<br> <br>
\section simulator_issues_sec Simulator Issues
As you've likely heard time and time again, the simulator is no substitute for the real thing.
The simulator is buggy. It can run faster or slower than a real device. It fails system calls
that a real device doesn't. It shows graphics glitches that a real device doesn't. Sounds stop
working, clicks and static, dogs and cats living together, etc, etc.
When things look wrong, try it on a real device before bugging people.
<br>
\subsection simulator_limitations Simulator Limitations
The simulator does not support setting audio modes, so setting allowIpod or honorSilentSwitch
in OALAudioSession will have no effect in the simulator.
<br>
\subsection simulator_errors Error Codes on the Simulator
From time to time, the simulator can get confused, and start spitting out spurious errors.
When this happens, check on a real device to make sure it's not just a simulator issue.
Usually quitting and restarting the simulator will fix it, but sometimes you may have to reboot
your machine as well.
<br>
\subsection simulator_playback Playback Issues
The simulator is notoriously finicky when it comes to audio playback. Any number of programs
you've installed on your mac can cause the simulator to stop playing bg music, or effects, or
both!
Some things to check when sound stops working:
- Try resetting and restarting the simulator.
- Try restarting XCode, cleaning, and recompiling your project.
- Try rebooting your computer.
- Open "Audio MIDI Setup" (type "midi" into spotlight to find it) and make sure "Built-in Output"
is set to 44100.0 Hz.
- Go to System Preferences -> Sound -> Output, and ensure that "Play sound effects through" is set
to "Internal Speakers"
- Go to System Preferences -> Sound -> Input, and ensure that it is using internal sound devices.
- Go to System Preferences -> Sound -> Sound Effects, and ensure "Play user interface sound
effects" is checked.
- Some codecs may cause problems with sound playback. Try removing them.
- Programs that redirect audio can wreak havoc on the simulator. Try removing them.
*/
@@ -0,0 +1,127 @@
//
// ObjectALConfig.h
// ObjectAL
//
// Created by Karl Stenerud on 10-08-02.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
/* Compile-time configuration for ObjectAL.
*
* The defines in this file provide broad guidelines for how ObjectAL will behave
* in your application. They can either be set here, or you can set them as user
* defines in your build configuration.
*/
/** Resets the audio session when an error occurs that may have been caused by
* a messed up session.
*
* In iOS 4.2, there are situations where an underlying sound system such as
* mediaserverd will crash, putting the audio session in an uncertain state.
* If this switch is enabled, OALAudioSession will reset itself when certain
* kinds of audio errors occur.
*
* Recommended setting: 1 for release, possibly 0 during development.
*/
#ifndef OBJECTAL_CFG_RESET_AUDIO_SESSION_ON_ERROR
#define OBJECTAL_CFG_RESET_AUDIO_SESSION_ON_ERROR 1
#endif
/** Enables support for methods that take blocks as arguments.
* Blocks are only supported in iOS 4.0+, so enabling this will make your project
* incompatible with earlier operating systems (a 3.x system will crash the moment it
* encounters a class that supports blocks).
*
* Recommended setting: 0 if you want to support iOS prior to 4.0, 1 if you don't care.
*/
#ifndef OBJECTAL_CFG_USE_BLOCKS
#define OBJECTAL_CFG_USE_BLOCKS 1
#endif
/** Determines how ObjectAL's actions are implemented.
* If this is set to 1, ObjectAL's actions will inherit from cocos2d CCIntervalAction,
* and will use cocos2d's CCActionManager rather than OALActionManager. <br>
*
* Recommended setting: 1 if you use Cocos2d exclusively, 0 if you use UIKit.
*/
#ifndef OBJECTAL_CFG_USE_COCOS2D_ACTIONS
#define OBJECTAL_CFG_USE_COCOS2D_ACTIONS 0
#endif
/** Sets the interval in seconds between steps when performing actions with OALAction
* subclasses. Lower values offer better accuracy, but take up more processing time
* because they fire more often. <br>
*
* Generally, you want at least 4-5 steps in an audio operation, so for durations
* of 0.2 and above, an interval of 1/30 is fine. For anything lower, you'll want a
* smaller interval. <br>
*
* Note: The NSTimer documentation states that a timer will typically have a resolution
* of around 0.05 to 0.1, though in practice smaller values seem to work fine. <br>
*
* Note: This setting only has effect if OBJECTAL_CFG_USE_COCOS2D_ACTIONS is 0. <br>
*
* Recommended setting: 1.0/30.0
*/
#ifndef kActionStepInterval
#define kActionStepInterval (1.0/30.0)
#endif
/** When this option is enabled, all critical ObjectAL operations will be wrapped in
* synchronized blocks. <br>
*
* Turning this off can improve performance a bit if your application makes heavy
* use of audio calls, but you'll be on your own for ensuring two threads don't
* access the same part of the audio library at the same time. <br>
*
* Recommended setting: 1
*/
#ifndef OBJECTAL_CFG_SYNCHRONIZED_OPERATIONS
#define OBJECTAL_CFG_SYNCHRONIZED_OPERATIONS 1
#endif
/** When this option is other than LEVEL_NONE, ObjectAL will output log entries that correspond
* to the LEVEL:
*
* LEVEL_NONE: No output
* LEVEL_ERROR: Errors only
* LEVEL_WARNING: Errors, Warnings
* LEVEL_INFO: Errors, Warnings, Info
* LEVEL_DEBUG: Errors, Warnings, Info, Debug
*
* Setting this to LEVEL_NONE will cause most internal functions to not bother checking error codes.
*
* Recommended setting: LEVEL_WARNING
*/
#ifndef OBJECTAL_CFG_LOG_LEVEL
#define OBJECTAL_CFG_LOG_LEVEL LEVEL_WARNING
#endif
@@ -0,0 +1,251 @@
//
// OpenALManager.h
// ObjectAL
//
// Created by Karl Stenerud on 10-09-25.
//
// Copyright (c) 2009 Karl Stenerud. All rights reserved.
//
// 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 remain in place
// in this source code.
//
// 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.
//
// Attribution is not required, but appreciated :)
//
#import <Foundation/Foundation.h>
#import "SynthesizeSingleton.h"
#import "ALContext.h"
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
#import <OpenAL/oalMacOSX_OALExtensions.h>
#else
#import <OpenAL/MacOSX_OALExtensions.h>
#endif
#pragma mark OpenALManager
/**
* Manager class for OpenAL objects (ObjectAL).
* Keeps track of devices that have been opened, and allows high level OpenAL management. <br>
* Provides methods for loading ALBuffer objects from audio files. <br>
* The OpenAL 1.1 specification is available at
* http://connect.creativelabs.com/openal/Documentation <br>
* Be sure to read through it (especially the part about distance models) as ObjectAL follows the
* OpenAL object model. <br>
*
* Alternatively, you may opt to use OALSimpleAudio for a simpler interface.
*/
@interface OpenALManager : NSObject <OALSuspendManager>
{
/** All opened devices */
NSMutableArray* devices;
/** Handles suspending and interrupting for this object. */
OALSuspendHandler* suspendHandler;
/** Operation queue for asynchronous loading. */
NSOperationQueue* operationQueue;
}
#pragma mark Properties
/** List of available playback devices (NSString*). */
@property(nonatomic,readonly,retain) NSArray* availableDevices;
/** List of available capture devices (NSString*). */
@property(nonatomic,readonly,retain) NSArray* availableCaptureDevices;
/** The current context (some context operations require the context to be the "current" one).
* WEAK reference.
*/
@property(nonatomic,readwrite,assign) ALContext* currentContext;
/** Name of the default capture device. */
@property(nonatomic,readonly,retain) NSString* defaultCaptureDeviceSpecifier;
/** Name of the default playback device. */
@property(nonatomic,readonly,retain) NSString* defaultDeviceSpecifier;
/** List of all open devices (ALDevice*). */
@property(nonatomic,readonly,retain) NSArray* devices;
/** The frequency of the output mixer. */
@property(nonatomic,readwrite,assign) ALdouble mixerOutputFrequency;
/** The rendering quality.
*
* Can be one of:
* - ALC_MAC_OSX_SPATIAL_RENDERING_QUALITY_HIGH
* - ALC_MAC_OSX_SPATIAL_RENDERING_QUALITY_LOW
* - ALC_IPHONE_SPATIAL_RENDERING_QUALITY_HEADPHONES (iOS only)
*/
@property(nonatomic,readwrite,assign) ALint renderingQuality;
#pragma mark Object Management
/** Singleton implementation providing "sharedInstance" and "purgeSharedInstance" methods.
*
* <b>- (OpenALManager*) sharedInstance</b>: Get the shared singleton instance. <br>
* <b>- (void) purgeSharedInstance</b>: Purge (deallocate) the shared instance.
*/
SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(OpenALManager);
#pragma mark Buffers
/** Load an OpenAL buffer with the contents of an audio file.
* The buffer's name will be the fully qualified URL of the path.
*
* See the class description note regarding sound file formats.
*
* @param filePath The path of the file containing the audio data.
* @return An ALBuffer containing the audio data.
*/
- (ALBuffer*) bufferFromFile:(NSString*) filePath;
/** Load an OpenAL buffer with the contents of an audio file.
* The buffer's name will be the fully qualified URL of the path.
*
* See the class description note regarding sound file formats.
*
* @param filePath The path of the file containing the audio data.
* @param reduceToMono If true, reduce the sample to mono
* (stereo samples don't support panning or positional audio).
* @return An ALBuffer containing the audio data.
*/
- (ALBuffer*) bufferFromFile:(NSString*) filePath reduceToMono:(bool) reduceToMono;
/** Load an OpenAL buffer with the contents of an audio file.
* The buffer's name will be the fully qualified URL.
*
* See the class description note regarding sound file formats.
*
* @param url The URL of the file containing the audio data.
* @return An ALBuffer containing the audio data.
*/
- (ALBuffer*) bufferFromUrl:(NSURL*) url;
/** Load an OpenAL buffer with the contents of an audio file.
* The buffer's name will be the fully qualified URL.
*
* See the class description note regarding sound file formats.
*
* @param url The URL of the file containing the audio data.
* @param reduceToMono If true, reduce the sample to mono
* (stereo samples don't support panning or positional audio).
* @return An ALBuffer containing the audio data.
*/
- (ALBuffer*) bufferFromUrl:(NSURL*) url reduceToMono:(bool) reduceToMono;
/** Load an OpenAL buffer with the contents of an audio file asynchronously.
* This method will schedule a request to have the buffer created and filled, and then call the
* specified selector with the newly created buffer. <br>
* The buffer's name will be the fully qualified URL of the path. <br>
* Returns the fully qualified URL of the path, which you can match up to the buffer name in your
* callback method.
*
* See the class description note regarding sound file formats.
*
* @param filePath The path of the file containing the audio data.
* @param target The target to call when the buffer is loaded.
* @param selector The selector to invoke when the buffer is loaded.
* @return The fully qualified URL of the path.
*/
- (NSString*) bufferAsyncFromFile:(NSString*) filePath target:(id) target selector:(SEL) selector;
/** Load an OpenAL buffer with the contents of an audio file asynchronously.
* This method will schedule a request to have the buffer created and filled, and then call the
* specified selector with the newly created buffer. <br>
* The buffer's name will be the fully qualified URL of the path. <br>
* Returns the fully qualified URL of the path, which you can match up to the buffer name in your
* callback method.
*
* See the class description note regarding sound file formats.
*
* @param filePath The path of the file containing the audio data.
* @param reduceToMono If true, reduce the sample to mono
* (stereo samples don't support panning or positional audio).
* @param target The target to call when the buffer is loaded.
* @param selector The selector to invoke when the buffer is loaded.
* @return The fully qualified URL of the path.
*/
- (NSString*) bufferAsyncFromFile:(NSString*) filePath
reduceToMono:(bool) reduceToMono
target:(id) target
selector:(SEL) selector;
/** Load an OpenAL buffer with the contents of a URL asynchronously.
* This method will schedule a request to have the buffer created and filled, and then call the
* specified selector with the newly created buffer. <br>
* The buffer's name will be the fully qualified URL. <br>
* Returns the fully qualified URL, which you can match up to the buffer name in your callback
* method.
*
* See the class description note regarding sound file formats.
*
* @param url The URL of the file containing the audio data.
* @param target The target to call when the buffer is loaded.
* @param selector The selector to invoke when the buffer is loaded.
* @return The fully qualified URL of the path.
*/
- (NSString*) bufferAsyncFromUrl:(NSURL*) url target:(id) target selector:(SEL) selector;
/** Load an OpenAL buffer with the contents of a URL asynchronously.
* This method will schedule a request to have the buffer created and filled, and then call the
* specified selector with the newly created buffer. <br>
* The buffer's name will be the fully qualified URL. <br>
* Returns the fully qualified URL, which you can match up to the buffer name in your callback
* method.
*
* See the class description note regarding sound file formats.
*
* @param url The URL of the file containing the audio data.
* @param reduceToMono If true, reduce the sample to mono
* (stereo samples don't support panning or positional audio).
* @param target The target to call when the buffer is loaded.
* @param selector The selector to invoke when the buffer is loaded.
* @return The fully qualified URL of the path.
*/
- (NSString*) bufferAsyncFromUrl:(NSURL*) url
reduceToMono:(bool) reduceToMono
target:(id) target
selector:(SEL) selector;
#pragma mark Utility
/** Clear all references to sound data from ALL buffers, managed or not.
*/
- (void) clearAllBuffers;
#pragma mark Internal Use
/** \cond */
/** (INTERNAL USE) Notify that a device is initializing.
*/
- (void) notifyDeviceInitializing:(ALDevice*) device;
/** (INTERNAL USE) Notify that a device is deallocating.
*/
- (void) notifyDeviceDeallocating:(ALDevice*) device;
/** \endcond */
@end
@@ -0,0 +1,438 @@
//
// SynthesizeSingleton.h
//
// Modified by Karl Stenerud starting 16/04/2010.
// - Moved the swizzle code to allocWithZone so that non-default init methods may be
// used to initialize the singleton.
// - Added "lesser" singleton which allows other instances besides sharedInstance to be created.
// - Added guard ifndef so that this file can be used in multiple library distributions.
// - Made singleton variable name class-specific so that it can be used on multiple classes
// within the same compilation module.
//
// Modified by CJ Hanson on 26/02/2010.
// This version of Matt's code uses method_setImplementaiton() to dynamically
// replace the +sharedInstance method with one that does not use @synchronized
//
// Based on code by Matt Gallagher from CocoaWithLove
//
// Created by Matt Gallagher on 20/10/08.
// Copyright 2009 Matt Gallagher. All rights reserved.
//
// Permission is given to use this source code file without charge in any
// project, commercial or otherwise, entirely at your risk, with the condition
// that any redistribution (in part or whole) of source code must retain
// this copyright and permission notice. Attribution in compiled projects is
// appreciated but not required.
//
#ifndef SYNTHESIZE_SINGLETON_FOR_CLASS
#import <objc/runtime.h>
#pragma mark -
#pragma mark Singleton
/* Synthesize Singleton For Class
*
* Creates a singleton interface for the specified class with the following methods:
*
* + (MyClass*) sharedInstance;
* + (void) purgeSharedInstance;
*
* Calling sharedInstance will instantiate the class and swizzle some methods to ensure
* that only a single instance ever exists.
* Calling purgeSharedInstance will destroy the shared instance and return the swizzled
* methods to their former selves.
*
*
* Usage:
*
* MyClass.h:
* ========================================
* #import "SynthesizeSingleton.h"
*
* @interface MyClass: SomeSuperclass
* {
* ...
* }
* SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(MyClass);
*
* @end
* ========================================
*
*
* MyClass.m:
* ========================================
* #import "MyClass.h"
*
* // This line is optional. Use it if you've enabled GCC_WARN_UNDECLARED_SELECTOR
* SYNTHESIZE_SINGLETON_FOR_CLASS_PROTOTYPE(MyClass);
*
* @implementation MyClass
*
* SYNTHESIZE_SINGLETON_FOR_CLASS(MyClass);
*
* ...
*
* @end
* ========================================
*
*
* Note: Calling alloc manually will also initialize the singleton, so you
* can call a more complex init routine to initialize the singleton like so:
*
* [[MyClass alloc] initWithParam:firstParam secondParam:secondParam];
*
* Just be sure to make such a call BEFORE you call "sharedInstance" in
* your program.
*/
#define SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(SS_CLASSNAME) \
\
+ (SS_CLASSNAME*) sharedInstance; \
+ (void) purgeSharedInstance;
#if __has_feature(objc_arc) // ARC Version
#define SYNTHESIZE_SINGLETON_FOR_CLASS_PROTOTYPE(SS_CLASSNAME)
#define SYNTHESIZE_SINGLETON_FOR_CLASS(SS_CLASSNAME) \
\
static volatile SS_CLASSNAME* _##SS_CLASSNAME##_sharedInstance = nil; \
\
+ (SS_CLASSNAME*) sharedInstanceNoSynch \
{ \
SS_CLASSNAME* instance = (SS_CLASSNAME*) _##SS_CLASSNAME##_sharedInstance; \
return instance; \
} \
\
+ (SS_CLASSNAME*) sharedInstanceSynch \
{ \
@synchronized(self) \
{ \
if(nil == _##SS_CLASSNAME##_sharedInstance) \
{ \
_##SS_CLASSNAME##_sharedInstance = [[self alloc] init]; \
} \
} \
return (SS_CLASSNAME*) _##SS_CLASSNAME##_sharedInstance; \
} \
\
+ (SS_CLASSNAME*) sharedInstance \
{ \
return [self sharedInstanceSynch]; \
} \
\
+ (id)allocWithZone:(NSZone*) zone \
{ \
@synchronized(self) \
{ \
if (nil == _##SS_CLASSNAME##_sharedInstance) \
{ \
_##SS_CLASSNAME##_sharedInstance = [super allocWithZone:zone]; \
if(nil != _##SS_CLASSNAME##_sharedInstance) \
{ \
Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceNoSynch)); \
method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod)); \
} \
} \
} \
SS_CLASSNAME* instance = (SS_CLASSNAME*) _##SS_CLASSNAME##_sharedInstance; \
return instance; \
} \
\
+ (void)purgeSharedInstance \
{ \
@synchronized(self) \
{ \
if(nil != _##SS_CLASSNAME##_sharedInstance) \
{ \
Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceSynch)); \
method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod)); \
_##SS_CLASSNAME##_sharedInstance = nil; \
} \
} \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
_Pragma ( "unused(zone)" ) \
return self; \
} \
\
#else // Non-ARC Version
#define SYNTHESIZE_SINGLETON_FOR_CLASS_PROTOTYPE(SS_CLASSNAME) \
@interface SS_CLASSNAME (SynthesizeSingletonPrivate) \
- (NSUInteger)retainCountDoNothing; \
- (NSUInteger)retainCountDoSomething; \
- (oneway void)releaseDoNothing; \
- (oneway void)releaseDoSomething; \
- (id)autoreleaseDoNothing; \
- (id)autoreleaseDoSomething; \
@end
#define SYNTHESIZE_SINGLETON_FOR_CLASS(SS_CLASSNAME) \
\
static volatile SS_CLASSNAME* _##SS_CLASSNAME##_sharedInstance = nil; \
\
+ (SS_CLASSNAME*) sharedInstanceNoSynch \
{ \
SS_CLASSNAME* instance = (SS_CLASSNAME*) _##SS_CLASSNAME##_sharedInstance; \
return instance; \
} \
\
+ (SS_CLASSNAME*) sharedInstanceSynch \
{ \
@synchronized(self) \
{ \
if(nil == _##SS_CLASSNAME##_sharedInstance) \
{ \
_##SS_CLASSNAME##_sharedInstance = [[self alloc] init]; \
} \
} \
return (SS_CLASSNAME*) _##SS_CLASSNAME##_sharedInstance; \
} \
\
+ (SS_CLASSNAME*) sharedInstance \
{ \
return [self sharedInstanceSynch]; \
} \
\
+ (id)allocWithZone:(NSZone*) zone \
{ \
@synchronized(self) \
{ \
if (nil == _##SS_CLASSNAME##_sharedInstance) \
{ \
_##SS_CLASSNAME##_sharedInstance = [super allocWithZone:zone]; \
if(nil != _##SS_CLASSNAME##_sharedInstance) \
{ \
Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceNoSynch)); \
method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod)); \
method_setImplementation(class_getInstanceMethod(self, @selector(retainCount)), class_getMethodImplementation(self, @selector(retainCountDoNothing))); \
method_setImplementation(class_getInstanceMethod(self, @selector(release)), class_getMethodImplementation(self, @selector(releaseDoNothing))); \
method_setImplementation(class_getInstanceMethod(self, @selector(autorelease)), class_getMethodImplementation(self, @selector(autoreleaseDoNothing))); \
} \
} \
} \
SS_CLASSNAME* instance = (SS_CLASSNAME*) _##SS_CLASSNAME##_sharedInstance; \
return instance; \
} \
\
+ (void)purgeSharedInstance \
{ \
@synchronized(self) \
{ \
if(nil != _##SS_CLASSNAME##_sharedInstance) \
{ \
Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceSynch)); \
method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod)); \
method_setImplementation(class_getInstanceMethod(self, @selector(retainCount)), class_getMethodImplementation(self, @selector(retainCountDoSomething))); \
method_setImplementation(class_getInstanceMethod(self, @selector(release)), class_getMethodImplementation(self, @selector(releaseDoSomething))); \
method_setImplementation(class_getInstanceMethod(self, @selector(autorelease)), class_getMethodImplementation(self, @selector(autoreleaseDoSomething))); \
[_##SS_CLASSNAME##_sharedInstance release]; \
_##SS_CLASSNAME##_sharedInstance = nil; \
} \
} \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
_Pragma ( "unused(zone)" ) \
return self; \
} \
\
- (id)retain \
{ \
return self; \
} \
\
- (NSUInteger)retainCount \
{ \
NSAssert1(1==0, @"SynthesizeSingleton: %@ ERROR: -(NSUInteger)retainCount method did not get swizzled.", self); \
return NSUIntegerMax; \
} \
\
- (NSUInteger)retainCountDoNothing \
{ \
return NSUIntegerMax; \
} \
- (NSUInteger)retainCountDoSomething \
{ \
return [super retainCount]; \
} \
\
- (oneway void)release \
{ \
NSAssert1(1==0, @"SynthesizeSingleton: %@ ERROR: -(void)release method did not get swizzled.", self); \
} \
\
- (oneway void)releaseDoNothing{} \
\
- (oneway void)releaseDoSomething \
{ \
@synchronized(self) \
{ \
[super release]; \
} \
} \
\
- (id)autorelease \
{ \
NSAssert1(1==0, @"SynthesizeSingleton: %@ ERROR: -(id)autorelease method did not get swizzled.", self); \
return self; \
} \
\
- (id)autoreleaseDoNothing \
{ \
return self; \
} \
\
- (id)autoreleaseDoSomething \
{ \
return [super autorelease]; \
}
#endif
#pragma mark -
#pragma mark Lesser Singleton
/* A lesser singleton has a shared instance, but can also be instantiated on its own.
*
* For a lesser singleton, you still use SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(),
* but use SYNTHESIZE_LESSER_SINGLETON_FOR_CLASS() in the implementation file.
* You must specify which creation methods are to initialize the shared instance
* (besides "sharedInstance") via CALL_LESSER_SINGLETON_INIT_METHOD()
*
* Example:
*
* MyClass.h:
* ========================================
* #import "SynthesizeSingleton.h"
*
* @interface MyClass: SomeSuperclass
* {
* int value;
* ...
* }
* SYNTHESIZE_SINGLETON_FOR_CLASS_HEADER(MyClass);
*
* + (void) initSharedInstanceWithValue:(int) value;
*
* - (id) initWithValue:(int) value;
*
* @end
* ========================================
*
*
* MyClass.m:
* ========================================
* #import "MyClass.h"
*
* // This line is optional. Use it if you've enabled GCC_WARN_UNDECLARED_SELECTOR
* SYNTHESIZE_SINGLETON_FOR_CLASS_PROTOTYPE(MyClass);
*
* @implementation MyClass
*
* SYNTHESIZE_LESSER_SINGLETON_FOR_CLASS(MyClass);
*
* + (void) initSharedInstanceWithValue:(int) value
* {
* CALL_LESSER_SINGLETON_INIT_METHOD(MyClass, initWithValue:value);
* }
*
* ...
*
* @end
* ========================================
*
*
* Note: CALL_LESSER_SINGLETON_INIT_METHOD() will not work if your
* init call contains commas. If you need commas (such as for varargs),
* or other more complex initialization, use the PRE and POST macros:
*
* + (void) initSharedInstanceComplex
* {
* CALL_LESSER_SINGLETON_INIT_METHOD_PRE(MyClass);
*
* int firstNumber = [self getFirstNumberSomehow];
* _sharedInstance = [[self alloc] initWithValues:firstNumber, 2, 3, 4, -1];
*
* CALL_LESSER_SINGLETON_INIT_METHOD_POST(MyClass);
* }
*/
#define SYNTHESIZE_LESSER_SINGLETON_FOR_CLASS(SS_CLASSNAME) \
\
static volatile SS_CLASSNAME* _##SS_CLASSNAME##_sharedInstance = nil; \
\
+ (SS_CLASSNAME*) sharedInstanceNoSynch \
{ \
SS_CLASSNAME* instance = (SS_CLASSNAME*) _##SS_CLASSNAME##_sharedInstance; \
return instance; \
} \
\
+ (SS_CLASSNAME*) sharedInstanceSynch \
{ \
@synchronized(self) \
{ \
if(nil == _##SS_CLASSNAME##_sharedInstance) \
{ \
_##SS_CLASSNAME##_sharedInstance = [[self alloc] init]; \
if(_##SS_CLASSNAME##_sharedInstance) \
{ \
Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceNoSynch)); \
method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod)); \
} \
} \
} \
SS_CLASSNAME* instance = (SS_CLASSNAME*) _##SS_CLASSNAME##_sharedInstance; \
return instance; \
} \
\
+ (SS_CLASSNAME*) sharedInstance \
{ \
return [self sharedInstanceSynch]; \
} \
\
+ (void)purgeSharedInstance \
{ \
@synchronized(self) \
{ \
Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceSynch)); \
method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod)); \
[_##SS_CLASSNAME##_sharedInstance release]; \
_##SS_CLASSNAME##_sharedInstance = nil; \
} \
}
#define CALL_LESSER_SINGLETON_INIT_METHOD_PRE(SS_CLASSNAME) \
@synchronized(self) \
{ \
if(nil == _##SS_CLASSNAME##_sharedInstance) \
{
#define CALL_LESSER_SINGLETON_INIT_METHOD_POST(SS_CLASSNAME) \
if(_##SS_CLASSNAME##_sharedInstance) \
{ \
Method newSharedInstanceMethod = class_getClassMethod(self, @selector(sharedInstanceNoSynch)); \
method_setImplementation(class_getClassMethod(self, @selector(sharedInstance)), method_getImplementation(newSharedInstanceMethod)); \
} \
} \
}
#define CALL_LESSER_SINGLETON_INIT_METHOD(SS_CLASSNAME,__INIT_CALL__) \
CALL_LESSER_SINGLETON_INIT_METHOD_PRE(SS_CLASSNAME); \
_##SS_CLASSNAME##_sharedInstance = [[self alloc] __INIT_CALL__]; \
CALL_LESSER_SINGLETON_INIT_METHOD_POST(SS_CLASSNAME)
#endif /* SYNTHESIZE_SINGLETON_FOR_CLASS */
@@ -0,0 +1,6 @@
framework module ObjectAL {
umbrella header "ObjectAL.h"
export *
module * { export * }
}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleIdentifier</key>
<string>com.apple.xcode.dsym.com.libgdx.ObjectAL</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>dSYM</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>