Skip to content
Browse files

classes

  • Loading branch information...
1 parent 672d36f commit 1e1fd339669ebdd0c7f1e009b76a7e7f2ef13eaa Steve Dekorte committed Aug 20, 2009
Showing with 972 additions and 0 deletions.
  1. +27 −0 ALBuffer.h
  2. +226 −0 ALBuffer.m
  3. +25 −0 ALContext.h
  4. +79 −0 ALContext.m
  5. +19 −0 ALDevice.h
  6. +61 −0 ALDevice.m
  7. +22 −0 ALListener.h
  8. +57 −0 ALListener.m
  9. +29 −0 ALObject.h
  10. +52 −0 ALObject.m
  11. +48 −0 ALSource.h
  12. +222 −0 ALSource.m
  13. +24 −0 ALState.h
  14. +72 −0 ALState.m
  15. +9 −0 README
View
27 ALBuffer.h
@@ -0,0 +1,27 @@
+#import "ALObject.h"
+
+@interface ALBuffer : ALObject
+{
+ NSData *data;
+ ALenum alFormat;
+ int sampleRate;
+ ALuint alcBuffer;
+}
+
++ bufferFromCacheForPath:(NSString *)path;
+
+@property (nonatomic, assign) NSData *data;
+@property (nonatomic, assign) ALuint alcBuffer;
+
+- (ALuint)alcBuffer;
+- (ALenum)alFormat;
+- (int)sampleRate;
+- (int)bitsPerSample;
+- (int)channels;
+- (int)size;
+
+// ugly - move to a sound file object
+- (BOOL)loadURL:(NSURL *)url;
+- (BOOL)loadPath:(NSString *)path;
+
+@end
View
226 ALBuffer.m
@@ -0,0 +1,226 @@
+#import "ALBuffer.h"
+#import <AVFoundation/AVFoundation.h>
+#import <AudioToolbox/AudioToolbox.h>
+#import <AudioToolbox/ExtendedAudioFile.h>
+
+@interface ALBuffer (Private)
+- (BOOL)open;
+- (void)close;
+@end
+
+@implementation ALBuffer
+
+@synthesize data;
+@synthesize alcBuffer;
+
+static NSMutableDictionary *bufferCache = 0x0;
+
++ (NSMutableDictionary *)bufferCache
+{
+ if (!bufferCache) bufferCache = [[NSMutableDictionary dictionary] retain];
+ return bufferCache;
+}
+
++ bufferFromCacheForPath:(NSString *)path
+{
+ NSMutableDictionary *cache = [self bufferCache];
+ id b = [cache objectForKey:path];
+ if (b) return b;
+ b = [[[ALBuffer alloc] init] autorelease];
+ [b loadPath:path];
+ [cache setObject:b forKey:path];
+ return b;
+}
+
+- (id)init
+{
+ if (self = [super init])
+ {
+ [self open];
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [self close];
+ [self setData:nil];
+ [super dealloc];
+}
+
+- (ALuint)alcBuffer
+{
+ return alcBuffer;
+}
+
+- (BOOL)open
+{
+ if (!alcBuffer) alGenBuffers(1, &alcBuffer);
+ if ([self checkError]) return NO;
+ return YES;
+}
+
+- (void)close
+{
+ if (alcBuffer) alDeleteBuffers(1, &alcBuffer);
+ alcBuffer = 0x0;
+}
+
+- (BOOL)bindToData
+{
+ alBufferData(alcBuffer, alFormat, [data bytes], [data length], sampleRate);
+ if ([self checkError]) return NO;
+ return YES;
+}
+
+- (ALenum)alFormat
+{
+ return alFormat;
+}
+
+- (BOOL)loadPath:(NSString *)path
+{
+ //NSLog(@"loadPath: %@\n", path);
+ return [self loadURL:[NSURL fileURLWithPath:path]];
+}
+
+- (BOOL)loadURL:(NSURL *)url
+{
+ AudioStreamBasicDescription outFormat;
+ AudioStreamBasicDescription inFormat;
+
+ OSStatus err = noErr;
+ SInt64 theFileLengthInFrames = 0;
+ UInt32 thePropertySize = sizeof(inFormat);
+ ExtAudioFileRef extRef = NULL;
+ void *theData = NULL;
+
+ err = ExtAudioFileOpenURL((CFURLRef)url, &extRef);
+
+ if (err)
+ {
+ [self setError:[NSString stringWithFormat:@"ExtAudioFileOpenURL FAILED, Error = %ld\n", err]];
+ goto Exit;
+ }
+
+ // Get the audio data format
+ err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &inFormat);
+ if (err)
+ {
+ printf("ExtAudioFileGetProperty(kExtAudioFileProperty_FileDataFormat) FAILED, Error = %ld\n", err);
+ goto Exit;
+ }
+
+ if (inFormat.mChannelsPerFrame > 2)
+ {
+ [self setError:@"Unsupported Format, channel count is greater than stereo\n"];
+ goto Exit;
+ }
+
+ // Set the client format to 16 bit signed integer (native-endian) data
+ // Maintain the channel count and sample rate of the original source format
+ outFormat.mSampleRate = inFormat.mSampleRate;
+ outFormat.mChannelsPerFrame = inFormat.mChannelsPerFrame;
+ outFormat.mFormatID = kAudioFormatLinearPCM;
+ outFormat.mBytesPerPacket = 2 * outFormat.mChannelsPerFrame;
+ outFormat.mFramesPerPacket = 1;
+ outFormat.mBytesPerFrame = 2 * outFormat.mChannelsPerFrame;
+ outFormat.mBitsPerChannel = 16;
+ outFormat.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;
+
+ // Set the desired client (output) data format
+ err = ExtAudioFileSetProperty(extRef, kExtAudioFileProperty_ClientDataFormat, sizeof(outFormat), &outFormat);
+ if (err)
+ {
+ [self setError:[NSString stringWithFormat:@"ExtAudioFileSetProperty %ld\n", err]];
+ goto Exit;
+ }
+
+ // Get the total frame count
+ thePropertySize = sizeof(theFileLengthInFrames);
+ err = ExtAudioFileGetProperty(extRef, kExtAudioFileProperty_FileLengthFrames, &thePropertySize, &theFileLengthInFrames);
+ if (err)
+ {
+ [self setError:[NSString stringWithFormat:@"ExtAudioFileGetProperty %ld\n", err]];
+ goto Exit;
+ }
+
+ // Read all the data into memory
+ UInt32 dataSize = theFileLengthInFrames * outFormat.mBytesPerFrame;
+ theData = malloc(dataSize);
+
+ if (theData)
+ {
+ AudioBufferList theDataBuffer;
+ theDataBuffer.mNumberBuffers = 1;
+ theDataBuffer.mBuffers[0].mDataByteSize = dataSize;
+ theDataBuffer.mBuffers[0].mNumberChannels = outFormat.mChannelsPerFrame;
+ theDataBuffer.mBuffers[0].mData = theData;
+
+ // Read the data into an AudioBufferList
+ err = ExtAudioFileRead(extRef, (UInt32*)&theFileLengthInFrames, &theDataBuffer);
+ if (err == noErr)
+ {
+ // success
+ alFormat = (outFormat.mChannelsPerFrame > 1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
+ }
+ else
+ {
+ // failure
+ free(theData);
+ theData = NULL; // make sure to return NULL
+ printf("ExtAudioFileRead FAILED, Error = %ld\n", err);
+ goto Exit;
+ }
+ }
+
+ [self setData:[NSMutableData dataWithBytes:theData length:dataSize]];
+ sampleRate = inFormat.mSampleRate;
+
+ [self bindToData];
+ return YES;
+
+Exit:
+ // Dispose the ExtAudioFileRef, it is no longer needed
+ if (extRef) ExtAudioFileDispose(extRef);
+ return NO;
+}
+
+//alBufferi(alcBuffer, AL_FREQUENCY, iFreq);
+
+
+- (int)sampleRate
+{
+ ALint i;
+ alGetBufferi(alcBuffer, AL_FREQUENCY, &i);
+ [self checkError];
+ return i;
+}
+
+- (int)bitsPerSample
+{
+ ALint i;
+ alGetBufferi(alcBuffer, AL_FREQUENCY, &i);
+ [self checkError];
+ return i;
+}
+
+- (int)channels
+{
+ ALint i;
+ alGetBufferi(alcBuffer, AL_CHANNELS, &i);
+ [self checkError];
+ return i;
+}
+
+- (int)size
+{
+ ALint i;
+ alGetBufferi(alcBuffer, AL_SIZE, &i);
+ [self checkError];
+ return i;
+}
+
+
+@end
View
25 ALContext.h
@@ -0,0 +1,25 @@
+//metadoc ALContext copyright Steve Dekorte 2009
+//metadoc ALContext license BSD revised
+
+#import "ALObject.h"
+#import "ALDevice.h"
+#import "ALListener.h"
+#import "ALSource.h"
+
+@interface ALContext : ALObject
+{
+ ALDevice *device;
+ ALListener *listener;
+ ALCcontext *alcContext;
+}
+
++ defaultContext;
+
+@property (nonatomic, assign) ALDevice *device;
+@property (nonatomic, assign) ALListener *listener;
+
+- (void)open;
+- (void)makeCurrent;
+- (void)close;
+
+@end
View
79 ALContext.m
@@ -0,0 +1,79 @@
+#import "ALContext.h"
+
+@implementation ALContext
+
+@synthesize device;
+@synthesize listener;
+//@synthesize sources;
+
++ defaultContext
+{
+ ALContext *c = [[[ALContext alloc] init] autorelease];
+ [c open];
+ return c;
+}
+
+- (id)init
+{
+ if (self = [super init])
+ {
+ self.listener = [[[ALListener alloc] init] autorelease];
+ [listener setContext:self];
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [self close];
+ [self setDevice:nil];
+ [self setListener:nil];
+ [super dealloc];
+}
+
+- (void)process
+{
+ alcProcessContext(alcContext);
+ [self checkError];
+}
+
+- (void)suspend
+{
+ alcSuspendContext(alcContext);
+ [self checkError];
+}
+
+- (void)open
+{
+ if (!device)
+ {
+ id d = [ALDevice defaultDevice];
+ [d retain];
+ [self setDevice:d];
+ }
+
+ alcContext = alcCreateContext([device alcDevice], 0);
+ [self checkError];
+ if (alcContext) [self makeCurrent];
+ [self process];
+}
+
+- (void)makeCurrent
+{
+ if (alcContext) alcMakeContextCurrent(alcContext);
+}
+
+- (void)close
+{
+ if (alcContext) alcDestroyContext(alcContext);
+ alcContext = NULL;
+ [device close];
+}
+
+- (ALCdevice *)alcDevice
+{
+ return alcGetContextsDevice(alcContext);
+}
+
+@end
View
19 ALDevice.h
@@ -0,0 +1,19 @@
+//metadoc ALDevice copyright Steve Dekorte 2009
+//metadoc ALDevice license BSD revised
+
+#import "ALObject.h"
+
+@interface ALDevice : ALObject
+{
+ ALCdevice *alcDevice;
+}
+
++ defaultDevice;
+
+- (void)openDefault;
+- (void)close;
+
+- (ALCdevice *)alcDevice;
+- newContext;
+
+@end
View
61 ALDevice.m
@@ -0,0 +1,61 @@
+#import "ALDevice.h"
+#import "ALContext.h"
+@implementation ALDevice
+
++ defaultDevice
+{
+ ALDevice *device = [[[ALDevice alloc] init] autorelease];
+ [device openDefault];
+ return device;
+}
+
+- (id)init
+{
+ if (self = [super init])
+ {
+ //AudioSesssion...
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [self close];
+ [super dealloc];
+}
+
+- (void)openDefault
+{
+ if (alcDevice) [self close];
+ alcDevice = alcOpenDevice(NULL);
+ [self checkError];
+}
+
+- (void)close
+{
+ if (alcDevice)
+ {
+ // need to close contexts?
+ alcCloseDevice(alcDevice);
+ [self checkError];
+ }
+
+ alcDevice = NULL;
+}
+
+- (ALCdevice *)alcDevice
+{
+ return alcDevice;
+}
+
+- newContext
+{
+ ALContext *context = [[[ALContext alloc] init] autorelease];
+ [context setDevice:self];
+ return context;
+}
+
+
+
+@end
View
22 ALListener.h
@@ -0,0 +1,22 @@
+//metadoc ALListener copyright Steve Dekorte 2009
+//metadoc ALListener license BSD revised
+
+#import "ALObject.h"
+
+@interface ALListener : ALObject
+{
+ id context;
+}
+
+@property (nonatomic, assign) id context;
+
+- (void)setPosition:(ALpoint)p;
+- (ALpoint)position;
+
+- (void)setVelocity:(ALpoint)p;
+- (ALpoint)velocity;
+
+- (void)setRotation:(ALfloat)radians;
+- (ALfloat)rotation;
+
+@end
View
57 ALListener.m
@@ -0,0 +1,57 @@
+#import "ALListener.h"
+#import "ALContext.h"
+
+@implementation ALListener
+
+@synthesize context;
+
+- (void)setPoint:(ALpoint)p forParam:(ALenum)param
+{
+ [context makeCurrent];
+ alListener3f(param, p.x, p.y, p.z);
+ [self checkError];
+}
+
+- (ALpoint)getPointForParam:(ALenum)param
+{
+ ALpoint p;
+ [context makeCurrent];
+ alGetListener3f(param, &p.x, &p.y, &p.z);
+ [self checkError];
+ return p;
+}
+
+- (void)setPosition:(ALpoint)p
+{
+ [self setPoint:p forParam:AL_POSITION];
+}
+
+- (ALpoint)position
+{
+ return [self getPointForParam:AL_POSITION];
+}
+
+- (void)setVelocity:(ALpoint)p
+{
+ [self setPoint:p forParam:AL_VELOCITY];
+}
+
+- (ALpoint)velocity
+{
+ return [self getPointForParam:AL_VELOCITY];
+}
+
+- (void)setRotation:(ALfloat)radians
+{
+ float ori[] = {cos(radians + M_PI_2), sin(radians + M_PI_2), 0., 0., 0., 1.};
+ [context makeCurrent];
+ alListenerfv(AL_ORIENTATION, ori);
+ [self checkError];
+}
+
+- (ALfloat)rotation
+{
+ return 0;
+}
+
+@end
View
29 ALObject.h
@@ -0,0 +1,29 @@
+//metadoc ALObject copyright Steve Dekorte 2009
+//metadoc ALObject license BSD revised
+
+//#import <UIKit/UIKit.h>
+#import <OpenAL/al.h>
+#import <OpenAL/alc.h>
+
+typedef struct
+{
+ float x;
+ float y;
+ float z;
+} ALpoint;
+
+@interface ALObject : NSObject
+{
+ NSString *error;
+}
+
++ (void)setLogsErrors:(BOOL)aBool;
++ (BOOL)logsErrors;
+
+- (void)setError:(NSString *)error;
+- (NSString *)error;
+
+- (BOOL)checkError;
+
+
+@end
View
52 ALObject.m
@@ -0,0 +1,52 @@
+//metadoc ALObject copyright Steve Dekorte 2009
+//metadoc ALObject license BSD revised
+
+#import "ALObject.h"
+
+@implementation ALObject
+
+static BOOL logsErrors;
+
++ (void)setLogsErrors:(BOOL)aBool
+{
+ logsErrors = aBool;
+}
+
++ (BOOL)logsErrors
+{
+ return logsErrors;
+}
+
+- (NSString *)stringForAlErrorCode:(ALenum)err
+{
+ return [NSString stringWithCString:alGetString(err)];
+}
+
+- (void)setError:(NSString *)e
+{
+ [error autorelease];
+ error = [e retain];
+ logsErrors = YES;
+ if (e && logsErrors) NSLog(@"%@ error: %@\n",
+ NSStringFromClass([self class]), e);
+}
+
+- (NSString *)error
+{
+ return error;
+}
+
+- (BOOL)checkError
+{
+ ALenum errorCode = alGetError();
+
+ if (errorCode != AL_NO_ERROR)
+ {
+ [self setError:[self stringForAlErrorCode:errorCode]];
+ return NO;
+ }
+
+ return YES;
+}
+
+@end
View
48 ALSource.h
@@ -0,0 +1,48 @@
+//metadoc ALSource copyright Steve Dekorte 2009
+//metadoc ALSource license BSD revised
+
+#import "ALObject.h"
+#import "ALBuffer.h"
+
+@interface ALSource : ALObject
+{
+ ALuint alcSource;
+ ALBuffer *buffer;
+}
+
++ newWithPath:(NSString *)path;
+
+- (void)setBuffer:(ALBuffer *)buffer;
+- (ALBuffer *)buffer;
+
+- (void)setVolume:(float)v;
+- (float)volume;
+
+- (void)setLooping:(BOOL)aBool;
+- (BOOL)isLooping;
+
+- (void)setReferenceDistance:(float)d;
+- (float)referenceDistance;
+
+- (void)setPosition:(ALpoint)p;
+- (ALpoint)position;
+
+- (void)setVelocity:(ALpoint)p;
+- (ALpoint)velocity;
+
+- (void)setDirection:(ALpoint)p;
+- (ALpoint)direction;
+
+- (BOOL)play;
+- (void)pause;
+- (void)rewind;
+- (void)stop;
+
+- (BOOL)isActive;
+- (BOOL)isInitializing;
+- (BOOL)isPlaying;
+- (BOOL)isPaused;
+- (BOOL)isStopped;
+
+
+@end
View
222 ALSource.m
@@ -0,0 +1,222 @@
+#import "ALSource.h"
+#import "ALContext.h"
+
+@interface ALSource (Private)
+- (BOOL)open;
+- (void)close;
+@end
+
+@implementation ALSource
+
++ newWithPath:(NSString *)path
+{
+ ALSource *source = [[[ALSource alloc] init] autorelease];
+ [source setBuffer:[ALBuffer bufferFromCacheForPath:path]];
+ return source;
+}
+
+- (id)init
+{
+ if (self = [super init])
+ {
+ [self open];
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [self close];
+ [self setBuffer:nil];
+ [super dealloc];
+}
+
+- (void)setBuffer:(ALBuffer *)aBuffer
+{
+ [buffer autorelease];
+ buffer = [aBuffer retain];
+
+ if (buffer)
+ {
+ alSourcei(alcSource, AL_BUFFER, [buffer alcBuffer]);
+ [self checkError];
+ }
+}
+
+- (ALBuffer *)buffer
+{
+ return buffer;
+}
+
+- (void)setVolume:(float)v
+{
+ alSourcef(alcSource, AL_GAIN, v);
+ [self checkError];
+}
+
+- (float)volume
+{
+ float v;
+ alGetSourcef(alcSource, AL_GAIN, &v);
+ [self checkError];
+ return v;
+}
+
+- (void)setLooping:(BOOL)aBool
+{
+ alSourcei(alcSource, AL_LOOPING, aBool ? AL_TRUE : AL_FALSE);
+ [self checkError];
+}
+
+- (BOOL)isLooping
+{
+ int v;
+ alGetSourcei(alcSource, AL_LOOPING, &v);
+ [self checkError];
+ return v;
+}
+
+- (void)setReferenceDistance:(float)d
+{
+ alSourcef(alcSource, AL_REFERENCE_DISTANCE, d);
+ [self checkError];
+}
+
+- (float)referenceDistance
+{
+ float v;
+ alGetSourcef(alcSource, AL_REFERENCE_DISTANCE, &v);
+ [self checkError];
+ return v;
+}
+
+- (void)setPoint:(ALpoint)p forParam:(ALuint)param
+{
+ alSourcefv(alcSource, param, (ALfloat *)&p);
+ [self checkError];
+}
+
+- (ALpoint)getPointForParam:(ALuint)param
+{
+ ALpoint p;
+ alGetSourcefv(alcSource, AL_POSITION, (ALfloat *)&p);
+ [self checkError];
+ return p;
+}
+
+- (void)setPosition:(ALpoint)p
+{
+ [self setPoint:p forParam:AL_POSITION];
+}
+
+- (ALpoint)position
+{
+ return [self getPointForParam:AL_POSITION];
+}
+
+- (void)setVelocity:(ALpoint)p
+{
+ [self setPoint:p forParam:AL_VELOCITY];
+}
+
+- (ALpoint)velocity
+{
+ return [self getPointForParam:AL_VELOCITY];
+}
+
+- (void)setDirection:(ALpoint)p
+{
+ [self setPoint:p forParam:AL_DIRECTION];
+}
+
+
+- (ALpoint)direction
+{
+ return [self getPointForParam:AL_DIRECTION];
+}
+
+
+- (BOOL)open
+{
+ if (!alcSource)
+ {
+ alGenSources(1, &alcSource);
+ if ([self checkError]) return NO;
+ }
+
+ return YES;
+}
+
+- (void)close
+{
+ if (alcSource)
+ {
+ alDeleteSources(1, &alcSource);
+ alcSource = 0x0;
+ [self checkError];
+ }
+}
+
+- (BOOL)play
+{
+ alSourcePlay(alcSource);
+ if ([self checkError]) return NO;
+ return YES;
+}
+
+- (void)pause
+{
+ alSourcePause(alcSource);
+ [self checkError];
+}
+
+- (void)rewind
+{
+ alSourceRewind(alcSource);
+ [self checkError];
+}
+
+
+- (void)stop
+{
+ alSourceStop(alcSource);
+ [self checkError];
+}
+
+- (int)state
+{
+ int state;
+ alGetSourcei(alcSource, AL_SOURCE_STATE, &state);
+ [self checkError];
+ return state;
+}
+
+- (BOOL)isActive
+{
+ int state = [self state];
+ return !(state == AL_INITIAL || state == AL_STOPPED);
+}
+
+- (BOOL)isInitializing
+{
+ return [self state] == AL_INITIAL;
+}
+
+- (BOOL)isPlaying
+{
+ return [self state] == AL_PLAYING;
+}
+
+- (BOOL)isPaused
+{
+ return [self state] == AL_PAUSED;
+}
+
+- (BOOL)isStopped
+{
+ return [self state] == AL_STOPPED;
+}
+
+
+@end
View
24 ALState.h
@@ -0,0 +1,24 @@
+//metadoc ALState copyright Steve Dekorte 2009
+//metadoc ALState license BSD revised
+
+#import "ALObject.h"
+
+@interface ALState : ALObject
+{
+}
+
++ (NSString *)vendor;
++ (NSString *)version;
++ (NSString *)renderer;
++ (NSString *)extensions;
+
++ (void)setDistanceModel:(ALenum)v;
++ (ALenum)distanceModel;
+
++ (void)setDopplerFactor:(float)v;
++ (float)dopplerFactor;
+
++ (void)setSpeedOfSound:(float)v;
++ (float)speedOfSound;
+
+@end
View
72 ALState.m
@@ -0,0 +1,72 @@
+#import "ALState.h"
+
+@implementation ALState
+
+/*
++ (float)dopplerFactor
+{
+ return alGetFloat(AL_DOPPLER_FACTOR);
+}
+
++ (float)speedOfSound
+{
+ return alGetFloat(AL_SPEED_OF_SOUND);
+}
+
++ (float)distanceModel
+{
+ return alGetFloat(AL_DISTANCE_MODEL);
+}
+*/
+
++ (NSString *)vendor
+{
+ return [NSString stringWithCString:alGetString(AL_VENDOR)];
+}
+
++ (NSString *)version
+{
+ return [NSString stringWithCString:alGetString(AL_VERSION)];
+}
+
++ (NSString *)renderer
+{
+ return [NSString stringWithCString:alGetString(AL_RENDERER)];
+}
+
++ (NSString *)extensions
+{
+ return [NSString stringWithCString:alGetString(AL_EXTENSIONS)];
+}
+
++ (void)setDistanceModel:(ALenum)v
+{
+ alDistanceModel(v);
+}
+
++ (ALenum)distanceModel
+{
+ return alGetFloat(AL_DISTANCE_MODEL);
+}
+
++ (void)setDopplerFactor:(float)v
+{
+ alDopplerFactor(v);
+}
+
++ (float)dopplerFactor
+{
+ return alGetFloat(AL_DOPPLER_FACTOR);
+}
+
++ (void)setSpeedOfSound:(float)v
+{
+ alSpeedOfSound(v);
+}
+
++ (float)speedOfSound
+{
+ return alGetFloat(AL_SPEED_OF_SOUND);
+}
+
+@end
View
9 README
@@ -1,3 +1,12 @@
+An Objective-C binding to OpenAL. Written for use on the iPhone, but should also work on OSX. Just drop in your project and include the following frameworks:
+ CoreAudio
+ AudioToolbox
+ AVFoundation
+ OpenAL
+Threw this together for a small iPhone game I was working on. It seems to work, but is pretty basic. Patches appreciated.
+
+- Steve Dekorte
+steve@dekorte.com

0 comments on commit 1e1fd33

Please sign in to comment.
Something went wrong with that request. Please try again.