Scene.m
/* |
File: Scene.m |
Abstract: Scene.h |
Version: 1.2 |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple |
Inc. ("Apple") in consideration of your agreement to the following |
terms, and your use, installation, modification or redistribution of |
this Apple software constitutes acceptance of these terms. If you do |
not agree with these terms, please do not use, install, modify or |
redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and |
subject to these terms, Apple grants you a personal, non-exclusive |
license, under Apple's copyrights in this original Apple software (the |
"Apple Software"), to use, reproduce, modify and redistribute the Apple |
Software, with or without modifications, in source and/or binary forms; |
provided that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the following |
text and disclaimers in all such redistributions of the Apple Software. |
Neither the name, trademarks, service marks or logos of Apple Inc. may |
be used to endorse or promote products derived from the Apple Software |
without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or |
implied, are granted by Apple herein, including but not limited to any |
patent rights that may be infringed by your derivative works or by other |
works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. |
Copyright (C) 2012 Apple Inc. All Rights Reserved. |
*/ |
#import "Scene.h" |
#include <math.h> |
#define DEG2RAD(x) (0.0174532925 * (x)) |
#define RAD2DEG(x) (57.295779578 * (x)) |
#define kSquareSize 500 // needs to be the size of the custom NIB object |
#define kSourceCircleRadius 10.0 |
#define kListenerCircleRadius 20.0 |
#define kDefaultDistance 175.0 |
#define NUM_BUFFERS_SOURCES 5 // this test app has 4 Source Objects and 4 Buffer Objects |
#define kCaptureSamples 44100 * 5 // capture 5 seconds of data at 44k |
#define kCaptureSourceIndex 4 |
#define kCapturedAudioSampleRate 44100 |
#define kListenerIndex 5 |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Globals |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
ALCdevice *gCaptureDevice = NULL; |
UInt8* gCaptureData = NULL; |
float gListenerPos[3] = {0.0, 0.0, 0.0}; // default position is centered |
float gListenerDirection = 0; |
int gSourceDirectionOnOff[NUM_BUFFERS_SOURCES] = {0, 0, 0, 0, 0}; |
float gSourceAngle[NUM_BUFFERS_SOURCES] = {225, 315, 135, 45, 180}; // each source is now facing the center |
float gSourcePos[NUM_BUFFERS_SOURCES][3] = { {kDefaultDistance, 0.0, -kDefaultDistance}, |
{kDefaultDistance, 0.0, kDefaultDistance}, |
{-kDefaultDistance , 0.0, -kDefaultDistance}, |
{-kDefaultDistance , 0.0, kDefaultDistance}, |
{0.0 , 0.0, -kDefaultDistance} }; |
char * gSourceFile[NUM_BUFFERS_SOURCES - 1]; // only the 1st 4 sources use data from a file |
ALuint gBuffer[NUM_BUFFERS_SOURCES]; |
ALuint gSource[NUM_BUFFERS_SOURCES]; |
float gSourceInnerConeAngle[NUM_BUFFERS_SOURCES] = {90, 90, 90, 90, 90}; |
float gSourceOuterConeAngle[NUM_BUFFERS_SOURCES] = {180, 180, 180, 180, 180}; |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Extension API Procs |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
typedef ALvoid AL_APIENTRY (*alMacOSXRenderChannelCountProcPtr) (const ALint value); |
ALvoid alMacOSXRenderChannelCountProc(const ALint value) |
{ |
static alMacOSXRenderChannelCountProcPtr proc = NULL; |
if (proc == NULL) { |
proc = (alMacOSXRenderChannelCountProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alMacOSXRenderChannelCount"); |
} |
if (proc) |
proc(value); |
return; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
typedef ALvoid AL_APIENTRY (*alcMacOSXRenderingQualityProcPtr) (const ALint value); |
ALvoid alcMacOSXRenderingQualityProc(const ALint value) |
{ |
static alcMacOSXRenderingQualityProcPtr proc = NULL; |
if (proc == NULL) { |
proc = (alcMacOSXRenderingQualityProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcMacOSXRenderingQuality"); |
} |
if (proc) |
proc(value); |
return; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
typedef ALvoid AL_APIENTRY (*alcMacOSXMixerOutputRateProcPtr) (const ALdouble value); |
ALvoid alcMacOSXMixerOutputRateProc(const ALdouble value) |
{ |
static alcMacOSXMixerOutputRateProcPtr proc = NULL; |
if (proc == NULL) { |
proc = (alcMacOSXMixerOutputRateProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcMacOSXMixerOutputRate"); |
} |
if (proc) |
proc(value); |
return; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
typedef ALdouble (*alcMacOSXGetMixerOutputRateProcPtr) (); |
ALdouble alcMacOSXGetMixerOutputRateProc() |
{ |
static alcMacOSXGetMixerOutputRateProcPtr proc = NULL; |
if (proc == NULL) { |
proc = (alcMacOSXGetMixerOutputRateProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcMacOSXGetMixerOutputRate"); |
} |
if (proc) |
return proc(); |
return 0.0; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
typedef ALvoid AL_APIENTRY (*alBufferDataStaticProcPtr) (const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq); |
ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq) |
{ |
static alBufferDataStaticProcPtr proc = NULL; |
if (proc == NULL) { |
proc = (alBufferDataStaticProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alBufferDataStatic"); |
} |
if (proc) |
proc(bid, format, data, size, freq); |
return; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
typedef OSStatus (*alcASASetSourceProcPtr) (const ALuint property, ALuint source, ALvoid *data, ALuint dataSize); |
OSStatus alcASASetSourceProc(const ALuint property, ALuint source, ALvoid *data, ALuint dataSize) |
{ |
OSStatus err = noErr; |
static alcASASetSourceProcPtr proc = NULL; |
if (proc == NULL) { |
proc = (alcASASetSourceProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alcASASetSource"); |
} |
if (proc) |
err = proc(property, source, data, dataSize); |
return (err); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
typedef OSStatus (*alcASASetListenerProcPtr) (const ALuint property, ALvoid *data, ALuint dataSize); |
OSStatus alcASASetListenerProc(const ALuint property, ALvoid *data, ALuint dataSize) |
{ |
OSStatus err = noErr; |
static alcASASetListenerProcPtr proc = NULL; |
if (proc == NULL) { |
proc = (alcASASetListenerProcPtr) alcGetProcAddress(NULL, "alcASASetListener"); |
} |
if (proc) |
err = proc(property, data, dataSize); |
return (err); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
typedef ALCdevice* (*alcCaptureOpenDeviceProcPtr) (const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); |
ALCdevice* alcCaptureOpenDeviceProc(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize) |
{ |
ALCdevice* device = NULL; |
device = alcCaptureOpenDevice (devicename, frequency, format, buffersize); |
return (device); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
typedef void (*alcCaptureStartProcPtr) (ALCdevice* device); |
void alcCaptureStartProc(ALCdevice* device) |
{ |
alcCaptureStart (device); |
return; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
typedef void (*alcCaptureSamplesProcPtr) (ALCdevice *device, ALCvoid *buffer, ALCsizei samples); |
void alcCaptureSamplesProc(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) |
{ |
alcCaptureSamples (device, buffer, samples); |
return; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Initialize OpenAL -Get an Audio Device and Set Current OpenAL Context |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
ALvoid* gStaticBufferData = NULL; |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
void TeardownOpenAL() |
{ |
ALCcontext *context = NULL; |
ALCdevice *device = NULL; |
ALuint returnedNames[NUM_BUFFERS_SOURCES]; |
// Delete the Sources |
alDeleteSources(NUM_BUFFERS_SOURCES, returnedNames); |
// Delete the Buffers |
alDeleteBuffers(NUM_BUFFERS_SOURCES, returnedNames); |
//Get active context |
context = alcGetCurrentContext(); |
//Get device for active context |
device = alcGetContextsDevice(context); |
//Release context |
alcDestroyContext(context); |
//Close device |
alcCloseDevice(device); |
if (gStaticBufferData) |
free(gStaticBufferData); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
void InitializeBuffers() |
{ |
ALenum error = AL_NO_ERROR; |
ALenum format; |
ALvoid* data; |
ALsizei size; |
ALsizei freq; |
UInt32 i; |
// only the 1st 4 sources get data from a file. The 5th source gets data from capture |
for (i = 0; i < NUM_BUFFERS_SOURCES - 1; i ++) |
{ |
//Get the current path to the audio file (which is contained in the application bundle) |
NSString* fileString = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%s", gSourceFile[i]] ofType:@"wav"]; |
// get some audio data from a wave file |
CFURLRef fileURL = CFURLCreateWithString(kCFAllocatorDefault, (CFStringRef)fileString, NULL); |
data = MyGetOpenALAudioData(fileURL, &size, &format, &freq); |
CFRelease(fileURL); |
if((error = alGetError()) != AL_NO_ERROR) { |
printf("error loading %s: ", gSourceFile[i]); |
exit(1); |
} |
if (i == 0) |
{ |
// use the static buffer data API once for testing |
gStaticBufferData = (ALvoid*)malloc(size); |
memcpy(gStaticBufferData, data, size); |
alBufferDataStaticProc(gBuffer[i], format, gStaticBufferData, size, freq); |
} |
else |
{ |
// Attach Audio Data to OpenAL Buffer |
alBufferData(gBuffer[i], format, data, size, freq); |
} |
// Release the audio data |
free(data); |
if((error = alGetError()) != AL_NO_ERROR) { |
printf("error unloading %s: ", gSourceFile[i]); |
} |
} |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
void InitializeSourcesAndPlay() |
{ |
UInt32 i; |
ALenum error = AL_NO_ERROR; |
alGetError(); // Clear the error |
for (i = 0; i < NUM_BUFFERS_SOURCES; i++) |
{ |
// Turn Looping ON |
alSourcei(gSource[i], AL_LOOPING, AL_TRUE); |
// Set Source Position |
alSourcefv(gSource[i], AL_POSITION, gSourcePos[i]); |
// Set Source Reference Distance |
alSourcef(gSource[i],AL_REFERENCE_DISTANCE, 5.0f); |
// only load data and start playing the non capture sources |
if (i < NUM_BUFFERS_SOURCES-1) |
{ |
// attach OpenAL Buffer to OpenAL Source |
alSourcei(gSource[i], AL_BUFFER, gBuffer[i]); |
// Start Playing Sound |
alSourcePlay(gSource[i]); |
} |
} |
if((error = alGetError()) != AL_NO_ERROR) { |
printf("Error attaching buffer to source"); |
exit(1); |
} |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// SCENE class |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
@implementation Scene |
- (id) init |
{ |
if((self = [super init])) { |
mHasASAExtension = false; |
mHasInput = false; |
//4 WAV files in the application bundle resources |
gSourceFile[0] = "sound_engine"; |
gSourceFile[1] = "sound_voices"; |
gSourceFile[2] = "sound_bubbles"; |
gSourceFile[3] = "sound_electric"; |
mCurrentObject = -1; |
mCenterOffset = kSquareSize/2.0; |
mVelocityScaler = 0.0; |
mAngle = 0.0; |
mListenerElevation = 0.0; |
mSourceOn[0] = 1; |
mSourceOn[1] = 1; |
mSourceOn[2] = 1; |
mSourceOn[3] = 1; |
mSourceOn[4] = 0; // capture |
mSourceDirection[0] = 0.0; |
mSourceDirection[1] = 0.0; |
mSourceDirection[2] = 0.0; |
mSourceDirection[3] = 0.0; |
mSourceDirection[4] = 0.0; // capture |
mSourceVelocityScaler[0] = 0.0; |
mSourceVelocityScaler[1] = 0.0; |
mSourceVelocityScaler[2] = 0.0; |
mSourceVelocityScaler[3] = 0.0; |
mSourceVelocityScaler[4] = 0.0; // capture |
mSourceOuterConeGain[0] = 0.0; |
mSourceOuterConeGain[1] = 0.0; |
mSourceOuterConeGain[2] = 0.0; |
mSourceOuterConeGain[3] = 0.0; |
mSourceOuterConeGain[4] = 0.0; // capture |
mSourceInnerConeAngle[0] = 90.0; |
mSourceInnerConeAngle[1] = 90.0; |
mSourceInnerConeAngle[2] = 90.0; |
mSourceInnerConeAngle[3] = 90.0; |
mSourceInnerConeAngle[4] = 90.0; // capture |
mSourceOuterConeAngle[0] = 180.0; |
mSourceOuterConeAngle[1] = 180.0; |
mSourceOuterConeAngle[2] = 180.0; |
mSourceOuterConeAngle[3] = 180.0; |
mSourceOuterConeAngle[4] = 180.0; // capture |
[self initOpenAL]; |
[self setListenerOrientation:0 : NULL : NULL]; |
[self setListenerVelocity:0 : NULL : NULL]; |
[self setListenerGain:0.5]; |
} |
return self; |
} |
- (void) dealloc { |
TeardownOpenAL(); |
[super dealloc]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
//draws a simple filled circle using quick glu calls |
static void drawCircle(GLdouble x, GLdouble y, GLdouble r, GLfloat red, GLfloat grn, GLfloat blu){ |
// A GRADIENT CIRCLE - looks better |
glPushMatrix(); |
glTranslatef(x, y, 0.0); |
glBegin(GL_TRIANGLE_FAN); |
glColor3f(red, grn, blu); |
glVertex3f(0.0, 0.0, 0.0); |
{ |
UInt32 i; |
float x, y; |
float stepAngle = 20; |
double theAngle = -90; |
for (i = 0; i <= 18; i++) |
{ |
glColor3f(red/2, grn/2, blu/2); // gradient |
float rads = DEG2RAD(theAngle); |
x = cos(rads) * r; |
y = sin(rads) * r; |
glVertex3f(x, y, 0.0); |
theAngle += stepAngle; |
glColor3f(red, grn, blu); // gradient |
} |
} |
glEnd(); |
glPopMatrix(); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) drawObjects { |
// layer the objects correctly |
if (mListenerElevation > 0) |
{ |
[self drawSources]; |
[self drawListener]; |
} |
else |
{ |
[self drawListener]; |
[self drawSources]; |
} |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) drawListener { |
float elevationSizeScaler = (abs(mListenerElevation) / 200.0)/2; // -1 to 1 |
// translate that to .5 to 1.5 |
if (mListenerElevation > 0) |
elevationSizeScaler = 1 + elevationSizeScaler; |
else |
elevationSizeScaler = 1 - elevationSizeScaler; |
// draw a triangle (nose) |
glPushMatrix(); |
glTranslatef(gListenerPos[0] + mCenterOffset, -gListenerPos[2] + mCenterOffset, 0.0); |
//Rotate to show the listeners current orientation |
glRotatef(gListenerDirection, 0.0, 0.0, -1.0); |
glBegin(GL_TRIANGLES); |
glColor3f(0.0, 1.0, 0.0); |
glVertex3f(-6.0 * elevationSizeScaler, 0.0, 0.0); |
glVertex3f(6.0 * elevationSizeScaler, 0.0, 0.0); |
glColor3f(1.0, 0.0, 0.0); |
glVertex3f(0.0, 35.0 * elevationSizeScaler, 0.0); |
glEnd(); |
glPopMatrix(); |
// ears |
glPushMatrix(); |
glTranslatef(gListenerPos[0] + mCenterOffset, -gListenerPos[2] + mCenterOffset, 0.0); |
//Rotate to show the listeners current orientation |
glRotatef(gListenerDirection, 0.0, 0.0, -1.0); |
glBegin(GL_QUADS); |
glColor3f(0.0, 0.0, 0.8); |
glVertex3f(-25.0 * elevationSizeScaler, 8.0 * elevationSizeScaler, 0.0); |
glVertex3f(-25.0 * elevationSizeScaler, -8.0 * elevationSizeScaler, 0.0); |
glVertex3f(24.5 * elevationSizeScaler, -8.0 * elevationSizeScaler, 0.0); |
glVertex3f(24.5 * elevationSizeScaler, 8.0 * elevationSizeScaler, 0.0); |
glEnd(); |
glPopMatrix(); |
// minor adjustments to position circle |
drawCircle(gListenerPos[0]- .5 + mCenterOffset, -gListenerPos[2] - 1 + mCenterOffset, 20 * elevationSizeScaler, 0 , 0, 1); |
if (mListenerElevation != 0.0) |
drawCircle(gListenerPos[0] + mCenterOffset, -gListenerPos[2] + mCenterOffset, 3, 0 , 0, .6); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
#define kArcSteps 16 |
#define kInnerArcRadius 32 // larger but partially transparent |
#define kOuterArcRadius 26 // smaller with gradient |
- (void) drawSourceWithDirection :(int)inTag |
{ |
glEnable(GL_BLEND); // blend the cones so both can be seen, top cone (INNER) is partially transparent |
// bottom cone (OUTER) has a gradient |
// CONE DRAWING - OUTER |
if (gSourceDirectionOnOff[inTag]) |
{ |
float x, z; |
[self getSourceDirections:inTag : &x : &z]; |
glPushMatrix(); |
glTranslatef((gSourcePos[inTag][0] + mCenterOffset) + x, (-gSourcePos[inTag][2] + mCenterOffset) + z, 0.0); |
glRotatef(gSourceAngle[inTag], 0.0, 0.0, -1.0); |
glBegin(GL_TRIANGLE_FAN); |
glColor3f(0.0, 0.5, 0.0); |
glVertex3f(0.0, 0.0, 0.0); |
{ |
UInt32 i; |
float x, y; |
float stepAngle = mSourceOuterConeAngle[inTag]/kArcSteps; |
double theAngle = -(mSourceOuterConeAngle[inTag]/2) + 90; |
for (i = 0; i <= kArcSteps; i++) |
{ |
glColor3f(0.0, 0.2, 0.0); // gradient |
float rads = DEG2RAD(theAngle); |
x = cos(rads) * kOuterArcRadius; |
y = sin(rads) * kOuterArcRadius; |
glVertex3f(x, y, 0.0); |
theAngle += stepAngle; |
glColor3f(0.0, 0.8, 0.0); // gradient |
} |
} |
glEnd(); |
glPopMatrix(); |
} |
// CONE DRAWING - INNER |
if (gSourceDirectionOnOff[inTag]) |
{ |
float x, z; |
[self getSourceDirections:inTag : &x : &z]; |
glPushMatrix(); |
glTranslatef((gSourcePos[inTag][0] + mCenterOffset) + x, (-gSourcePos[inTag][2] + mCenterOffset) + z, 0.0); |
glRotatef(gSourceAngle[inTag], 0.0, 0.0, -1.0); |
glBegin(GL_TRIANGLE_FAN); |
glColor4f(0.0, 1.0, 0.0, .4); // transparency (.4) |
glVertex3f(0.0, 0.0, 0.0); |
{ |
UInt32 i; |
float x, y; |
float stepAngle = mSourceInnerConeAngle[inTag]/kArcSteps; |
double theAngle = -(mSourceInnerConeAngle[inTag]/2) + 90; |
for (i = 0; i <= kArcSteps; i++) |
{ |
float rads = DEG2RAD(theAngle); |
x = cos(rads) * kInnerArcRadius; |
y = sin(rads) * kInnerArcRadius; |
glVertex3f(x, y, 0.0); |
theAngle += stepAngle; |
} |
} |
glEnd(); |
glPopMatrix(); |
} |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // blend the cones |
glDisable(GL_BLEND); // blending is done |
// draw direction triangle if there is any velocity setting above zero |
if (mSourceVelocityScaler[inTag] > 0) |
{ |
float triangleLength = kSourceCircleRadius*2; |
triangleLength += (mSourceVelocityScaler[inTag]/686.0) * (kSourceCircleRadius*2); |
glPushMatrix(); |
glTranslatef(gSourcePos[inTag][0] + mCenterOffset, -gSourcePos[inTag][2] + mCenterOffset, 0.0); |
glRotatef(gSourceAngle[inTag], 0.0, 0.0, -1.0); |
glBegin(GL_TRIANGLES); |
glColor3f(0.0, 1.0, 0.0); |
glVertex3f(-4.0, 0.0, 0.0); |
glVertex3f(4.0, 0.0, 0.0); |
glColor3f(1.0, 0.0, 0.0); |
glVertex3f(0.0, triangleLength, 0.0); |
glEnd(); |
glPopMatrix(); |
} |
//minor adjustments to position circle |
if (mSourceOn[inTag] == 0) |
{ |
// draw a gray circle if source is not playing |
drawCircle(gSourcePos[inTag][0] + mCenterOffset, -gSourcePos[inTag][2] + mCenterOffset, kSourceCircleRadius, .5 , .5, .5); // capture circle is different color |
} |
else |
{ |
if (inTag == kCaptureSourceIndex) |
drawCircle(gSourcePos[inTag][0] + mCenterOffset, -gSourcePos[inTag][2] + mCenterOffset, kSourceCircleRadius, 1 , 1, 0); // capture circle is different color |
else |
drawCircle(gSourcePos[inTag][0] + mCenterOffset, -gSourcePos[inTag][2] + mCenterOffset, kSourceCircleRadius, 1 , 0, 0); |
} |
if (gSourcePos[inTag][1] != 0.0) |
drawCircle(gSourcePos[inTag][0] + mCenterOffset, -gSourcePos[inTag][2]+ mCenterOffset, 3, .5 , 0, 0); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) drawSources |
{ |
//draw sources as 4 red circles |
[self drawSourceWithDirection: 0]; |
[self drawSourceWithDirection: 1]; |
[self drawSourceWithDirection: 2]; |
[self drawSourceWithDirection: 3]; |
[self drawSourceWithDirection: kCaptureSourceIndex]; // capture |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
-(void) resetCurrentObject |
{ |
//set current object to -1 to designate no object selected. |
mCurrentObject = -1; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
-(int) selectCurrentObject:(NSPoint *)point |
{ |
//find the object (circle) that contains the point |
//return -1 if none are found |
if(mCurrentObject != -1) |
return mCurrentObject; |
if([self pointInCircle:point x:gSourcePos[0][0] + mCenterOffset y:-gSourcePos[0][2] + mCenterOffset r:kSourceCircleRadius]){ |
mCurrentObject = 0; |
}else if ([self pointInCircle:point x:gSourcePos[1][0] + mCenterOffset y:-gSourcePos[1][2] + mCenterOffset r:kSourceCircleRadius]) |
mCurrentObject = 1; |
else if ([self pointInCircle:point x:gSourcePos[2][0] + mCenterOffset y:-gSourcePos[2][2] + mCenterOffset r:kSourceCircleRadius]) |
mCurrentObject = 2; |
else if ([self pointInCircle:point x:gSourcePos[3][0] + mCenterOffset y:-gSourcePos[3][2] + mCenterOffset r:kSourceCircleRadius]) |
mCurrentObject = 3; |
else if ([self pointInCircle:point x:gSourcePos[4][0] + mCenterOffset y:-gSourcePos[4][2] + mCenterOffset r:kSourceCircleRadius]) |
mCurrentObject = kCaptureSourceIndex; // CAPTURE SOURCE |
else if ([self pointInCircle:point x:gListenerPos[0] + mCenterOffset y:-gListenerPos[2] + mCenterOffset r:kListenerCircleRadius]) |
mCurrentObject = kListenerIndex; |
return mCurrentObject; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// need to detect if point is in a source circle |
// if so, return the source pos ID |
// if not, return -1 |
- (bool) pointInCircle:(NSPoint *)point x:(float)x y:(float)y r:(float)r |
{ |
float x1 =point->x; |
float y1 = point->y; |
float dist =0; |
//calculate distance from the center of the circle to the point clcked |
dist =(((x1 - x )*(x1 - x )) + ((y1 - y)*(y1 - y))); |
//Here we can test this for each of the sources |
//if the distance is less than the radius (squared), then the point is inside the circle |
if (dist <= r*r) |
return TRUE; |
else |
return FALSE; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
-(void) setObjectPosition:(NSPoint *)point |
{ |
if(mCurrentObject < kListenerIndex){ |
[self setSourcePositionFromPoint:point]; |
} |
else if (mCurrentObject == kListenerIndex ) //listener |
{ |
[self setListenerPosition:point]; |
} |
// NOTIFY: Post a notification that object mCurrentObject has moved so the coordinate text can be updated |
[[NSNotificationCenter defaultCenter] postNotificationName: @"OALNotify" object: self]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) getCurrentObjectPosition:(int*)outCurObject : (float*) outX : (float*) outZ |
{ |
if(mCurrentObject < kListenerIndex){ |
if(outX) *outX = gSourcePos[mCurrentObject][0]; |
if(outX) *outZ = gSourcePos[mCurrentObject][2]; |
} |
else if (mCurrentObject == kListenerIndex ) //listener |
{ |
if(outX) *outX = gListenerPos[0]; |
if(outX) *outZ = gListenerPos[2]; |
} |
if(outCurObject) *outCurObject = mCurrentObject; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) getObjectPosition:(int)inObject : (float*) outX : (float*) outZ; |
{ |
if(inObject < kListenerIndex){ |
if(outX) *outX = gSourcePos[inObject][0]; |
if(outX) *outZ = gSourcePos[inObject][2]; |
} |
else if (inObject == kListenerIndex ) //listener |
{ |
if(outX) *outX = gListenerPos[0]; |
if(outX) *outZ = gListenerPos[2]; |
} |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Initialize OpenAL Context, Buffers, Listener & Sources |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) initOpenAL { |
ALenum error; |
ALCcontext *newContext = NULL; |
ALCdevice *newDevice = NULL; |
// Create a new OpenAL Device |
// Pass NULL to specify the systemÕs default output device |
newDevice = alcOpenDevice(NULL); |
if (newDevice != NULL) |
{ |
// Create a new OpenAL Context |
// The new context will render to the OpenAL Device just created |
newContext = alcCreateContext(newDevice, 0); |
if (newContext != NULL) |
{ |
// Make the new context the Current OpenAL Context |
alcMakeContextCurrent(newContext); |
// Create some OpenAL Buffer Objects |
alGenBuffers(NUM_BUFFERS_SOURCES, gBuffer); |
if((error = alGetError()) != AL_NO_ERROR) { |
printf("Error Generating Buffers: "); |
exit(1); |
} |
// Create some OpenAL Source Objects |
alGenSources(NUM_BUFFERS_SOURCES, gSource); |
if(alGetError() != AL_NO_ERROR) |
{ |
printf("Error generating sources! \n"); |
exit(1); |
} |
} |
} |
// Capture |
if (alcIsExtensionPresent( NULL, "ALC_EXT_CAPTURE" )) |
{ |
// Setup a Capture Device |
gCaptureDevice = alcCaptureOpenDeviceProc( NULL, kCapturedAudioSampleRate, AL_FORMAT_MONO16, kCaptureSamples ); |
if(gCaptureDevice) |
{ |
// Capture is supported and there is an input device |
alcCaptureStartProc(gCaptureDevice); |
mSourceOn[4] = 1; // capture |
mHasInput = true; |
} |
else |
mHasInput = false; // Capture is supported but there is no input device |
} |
else |
mHasInput = false; // Capture Not Supported by this OAL version |
// Reverb and Effects |
if (alcIsExtensionPresent( NULL, "ALC_EXT_ASA" )) |
mHasASAExtension = true; |
else |
mHasASAExtension = false; |
alGetError(); |
InitializeBuffers(); |
InitializeSourcesAndPlay(); |
} |
- (bool) hasInput |
{ |
return mHasInput; |
} |
- (bool) hasASAExtension |
{ |
return mHasASAExtension; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Orientation |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setListenerOrientation: (float) angle : (float*) outX : (float*) outZ |
{ |
mAngle = angle; |
ALenum error = AL_NO_ERROR; |
float rads = DEG2RAD(mAngle); |
float orientation[6] = { 0.0, 0.0, -1.0, // direction |
0.0, 1.0, 0.0 }; //up |
orientation[0] = cos(rads); |
orientation[1] = sin(rads); // No Change to the Z vector |
gListenerDirection = RAD2DEG(atan2(orientation[1], orientation[0])); |
// Change OpenAL Listener's Orientation |
orientation[0] = sin(rads); |
orientation[1] = 0.0; // No Change to the Y vector |
orientation[2] = -cos(rads); |
alListenerfv(AL_ORIENTATION, orientation); |
if((error = alGetError()) != AL_NO_ERROR) |
printf("Error Setting Listener Orientation"); |
// set the listener velocity as well, in this app we are always syncing the velocity to the direction that the listener is facing |
[self setListenerVelocity: mVelocityScaler : outX : outZ]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Listener Velocity Gain |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setListenerVelocity:(float) inVelocity : (float*) outX : (float*) outZ |
{ |
mVelocityScaler = inVelocity; |
ALenum error = AL_NO_ERROR; |
float rads = DEG2RAD(mAngle); |
float velocity[3] = { 0.0, 0.0, 0.0}; //up |
// Change OpenAL Listener's Orientation |
velocity[0] = sin(rads) * mVelocityScaler; |
velocity[1] = 0.0; // No Change to the Y vector |
velocity[2] = -cos(rads) * mVelocityScaler; |
if (outX) *outX = velocity[0]; |
if (outZ) *outZ = velocity[2]; |
alListenerfv(AL_VELOCITY, velocity); |
if((error = alGetError()) != AL_NO_ERROR) |
printf("Error Setting Listener Velocity"); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Position |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void)setSourcePositionFromPoint:(NSPoint *)point |
{ |
gSourcePos[mCurrentObject][0] = point->x - mCenterOffset; |
gSourcePos[mCurrentObject][2] = -point->y + mCenterOffset; // top view only in this demo! |
alSourcefv(gSource[mCurrentObject], AL_POSITION, gSourcePos[mCurrentObject]); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void)setSourcePositionX:(int) inTag : (float)inX |
{ |
gSourcePos[inTag][0] = inX; |
alSourcefv(gSource[inTag], AL_POSITION, gSourcePos[inTag]); |
[self drawSourceWithDirection :inTag]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void)setSourcePositionY:(int) inTag : (float)inY |
{ |
gSourcePos[inTag][1] = inY; |
alSourcefv(gSource[inTag], AL_POSITION, gSourcePos[inTag]); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void)setSourcePositionZ:(int) inTag : (float)inZ |
{ |
gSourcePos[inTag][2] = inZ; |
alSourcefv(gSource[inTag], AL_POSITION, gSourcePos[inTag]); |
[self drawSourceWithDirection :inTag]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setListenerPosition:(NSPoint *) point |
{ |
gListenerPos[0] = point->x - mCenterOffset; |
gListenerPos[1] = mListenerElevation; |
gListenerPos[2] = -point->y + mCenterOffset; // top view only in this demo! |
alListenerfv(AL_POSITION, gListenerPos); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setListenerElevation: (float)elevation |
{ |
mListenerElevation = elevation; |
gListenerPos[1] = mListenerElevation; |
// do not change x or z |
alListenerfv(AL_POSITION, gListenerPos); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void)setListenerPositionX: (float)inX |
{ |
gListenerPos[0] = inX; |
alListenerfv(AL_POSITION, gListenerPos); |
[self drawListener]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void)setListenerPositionZ: (float)inX |
{ |
gListenerPos[2] = inX; |
alListenerfv(AL_POSITION, gListenerPos); |
[self drawListener]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourcePlayState:(int)inTag :(int)inCheckBoxValue |
{ |
if (mSourceOn[inTag] == inCheckBoxValue) |
return; |
mSourceOn[inTag] = inCheckBoxValue; |
if (mSourceOn[inTag]) |
alSourcePlay(gSource[inTag]); |
else |
alSourceStop(gSource[inTag]); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Pitch |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourcePitch:(int)inTag :(float)inPitch |
{ |
alSourcef(gSource[inTag], AL_PITCH, inPitch); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Source Gain |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceGain:(int)inTag :(float)inGain |
{ |
alSourcef(gSource[inTag], AL_GAIN, inGain); |
// alSourcef (gSource[inTag], AL_SEC_OFFSET, 1.0); // quick way to test the set offset API until controls can be added to UI |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Source Rolloff |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceRolloffFactor:(int)inTag :(float)inRolloff |
{ |
alSourcef(gSource[inTag], AL_ROLLOFF_FACTOR, inRolloff); |
} |
- (float) getSourceRolloffFactor:(int)inTag |
{ |
float ro; |
alGetSourcef(gSource[inTag], AL_ROLLOFF_FACTOR, &ro); |
return ro; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Source Reference Distance |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceReferenceDistance:(int)inTag :(float)inReferenceDistance |
{ |
alSourcef(gSource[inTag], AL_REFERENCE_DISTANCE, inReferenceDistance); |
} |
- (float) getSourceReferenceDistance:(int)inTag |
{ |
float rd; |
alGetSourcef(gSource[inTag], AL_REFERENCE_DISTANCE, &rd); |
return rd; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Source Max Distance |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceMaxDistance:(int)inTag :(float)inMaxDistance |
{ |
alSourcef(gSource[inTag], AL_MAX_DISTANCE, inMaxDistance); |
} |
- (float) getSourceMaxDistance:(int)inTag |
{ |
float md; |
alGetSourcef(gSource[inTag], AL_MAX_DISTANCE, &md); |
return md; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Source Direction & Velocity |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceVelocity:(int)inTag :(float) inVelocity |
{ |
mSourceVelocityScaler[inTag] = inVelocity; |
float velocities[3]; |
velocities[1] = 0; // No Change to the Y vector |
[self getSourceVelocities: inTag : &velocities[0] : &velocities[2]]; |
alSourcefv(gSource[inTag], AL_VELOCITY, velocities); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceDirection:(int)inTag |
{ |
float directions[3]; |
directions[1] = 0; // No Change to the Y vector |
if (gSourceDirectionOnOff[inTag] == false) |
{ |
directions[0] = 0; |
directions[2] = 0; |
alSourcefv(gSource[inTag], AL_DIRECTION, directions); |
alSourcef(gSource[inTag], AL_CONE_INNER_ANGLE, 360.0); |
alSourcef(gSource[inTag], AL_CONE_OUTER_ANGLE, 360.0); |
alSourcef(gSource[inTag], AL_CONE_OUTER_GAIN, 0.0); |
} |
else |
{ |
[self getSourceDirections: inTag : &directions[0] : &directions[2]]; |
alSourcefv(gSource[inTag], AL_DIRECTION, directions); |
alSourcef(gSource[inTag], AL_CONE_INNER_ANGLE, 90 ); |
alSourcef(gSource[inTag], AL_CONE_OUTER_ANGLE, 180); |
alSourcef(gSource[inTag], AL_CONE_OUTER_GAIN, mSourceOuterConeGain[inTag] ); |
} |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceOuterConeGain:(int)inTag :(float) inGain |
{ |
mSourceOuterConeGain[inTag] = inGain; |
alSourcef(gSource[inTag], AL_CONE_OUTER_GAIN, mSourceOuterConeGain[inTag]); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceInnerConeAngle:(int)inTag :(float) inAngle |
{ |
mSourceInnerConeAngle[inTag] = inAngle; |
alSourcef(gSource[inTag], AL_CONE_INNER_ANGLE, mSourceInnerConeAngle[inTag]); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceOuterConeAngle:(int)inTag :(float) inAngle |
{ |
mSourceOuterConeAngle[inTag] = inAngle; |
alSourcef(gSource[inTag], AL_CONE_OUTER_ANGLE, mSourceOuterConeAngle[inTag]); |
[self drawSourceWithDirection :inTag]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceDirectionOnOff:(int)inTag :(int)inCheckBoxValue |
{ |
if (gSourceDirectionOnOff[inTag] == inCheckBoxValue) |
return; |
gSourceDirectionOnOff[inTag] = inCheckBoxValue; |
[self setSourceDirection: inTag]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceAngle:(int)inTag :(float)inAngle |
{ |
gSourceAngle[inTag] = inAngle; |
[self setSourceVelocity: inTag : mSourceVelocityScaler[inTag]]; |
[self setSourceDirection: inTag]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) getSourceVelocities:(int)inTag : (float*) outX : (float*) outZ |
{ |
float rads = DEG2RAD(gSourceAngle[inTag]); |
if (outX) *outX = sin(rads) * mSourceVelocityScaler[inTag]; |
if (outZ) *outZ = -cos(rads) * mSourceVelocityScaler[inTag]; |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) getSourceDirections:(int)inTag : (float*) outX : (float*) outZ |
{ |
float rads = DEG2RAD(gSourceAngle[inTag]); |
if (outX) *outX = sin(rads); |
if (outZ) *outZ = -cos(rads); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Listener Gain |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setListenerGain:(float)inGain |
{ |
alListenerf(AL_GAIN, inGain); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Render Channels |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setRenderChannels:(int)inCheckBoxValue |
{ |
// Global Setting: |
// Used to Force OpenAL to render to stereo, even if the user's default audio hw is multichannel |
UInt32 setting = (inCheckBoxValue == 0) ? alcGetEnumValue(NULL, "ALC_RENDER_CHANNEL_COUNT_MULTICHANNEL") : alcGetEnumValue(NULL, "ALC_RENDER_CHANNEL_COUNT_STEREO"); |
alMacOSXRenderChannelCountProc((const ALint) setting); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Render Quality |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setRenderQuality:(int)inCheckBoxValue |
{ |
// Global Setting: |
// Used to turn on HRTF Rendering when OpenAL is rendering to stereo |
UInt32 setting = (inCheckBoxValue == 0) ? alcGetEnumValue(NULL, "ALC_SPATIAL_RENDERING_QUALITY_LOW") : alcGetEnumValue(NULL, "ALC_SPATIAL_RENDERING_QUALITY_HIGH"); |
alcMacOSXRenderingQualityProc((const ALint) setting); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Source Reverb Level |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceReverb:(int)inTag :(float)inReverbSendLevel |
{ |
ALfloat level = inReverbSendLevel; |
alcASASetSourceProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_SEND_LEVEL"), gSource[inTag], &level, sizeof(level)); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Source Reverb Level |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceOcclusion:(int)inTag :(float)inLevel |
{ |
ALfloat level = inLevel; |
alcASASetSourceProc(alcGetEnumValue(NULL, "ALC_ASA_OCCLUSION"), gSource[inTag], &level, sizeof(level)); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Source Reverb Level |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSourceObstruction:(int)inTag :(float)inReverbSendLevel |
{ |
ALfloat level = inReverbSendLevel; |
alcASASetSourceProc(alcGetEnumValue(NULL, "ALC_ASA_OBSTRUCTION"), gSource[inTag], &level, sizeof(level)); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Global Reverb Level |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setGlobalReverb :(float)inReverbLevel |
{ |
ALfloat level = inReverbLevel; |
alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_GLOBAL_LEVEL"), &level, sizeof(level)); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Reverb ON |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setReverbOn:(int)inCheckBoxValue |
{ |
UInt32 setting = (inCheckBoxValue == 0) ? 0 : 1; |
alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_ON"), &setting, sizeof(setting)); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setReverbEQGain:(float)inLevel |
{ |
ALfloat level = inLevel; |
alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_EQ_GAIN"), &level, sizeof(level)); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setReverbEQBandwidth:(float)inLevel |
{ |
ALfloat level = inLevel; |
alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_EQ_BANDWITH"), (ALvoid *) &level, sizeof(level)); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setReverbEQFrequency:(float)inLevel |
{ |
ALfloat level = inLevel; |
alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_EQ_FREQ"), &level, sizeof(level)); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setReverbRoomType:(int)inTag controlIndex:(int) inIndex title:(NSString*) inTitle |
{ |
UInt32 roomtype = inTag; |
UInt32 roomIndex = inIndex; |
if (roomIndex < 12) |
{ |
// the 1st 12 menu items have the proper reverb constant in the tag value |
alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_ROOM_TYPE"), &roomtype, sizeof(roomtype)); |
} |
else |
{ |
const char *fullPathToFile; |
fullPathToFile =[[[NSBundle mainBundle] pathForResource:inTitle ofType:@"aupreset" inDirectory:@"ReverbPresets"]UTF8String]; |
alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_PRESET"), (void *) fullPathToFile, strlen(fullPathToFile)); |
} |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setReverbQuality:(int)inTag |
{ |
UInt32 quality = inTag; |
alcASASetListenerProc(alcGetEnumValue(NULL, "ALC_ASA_REVERB_QUALITY"), &quality, sizeof(quality)); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Distance Model |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setDistanceModel:(int)inTag |
{ |
alDistanceModel(inTag); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Doppler Factor |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setDopplerFactor :(float)inValue |
{ |
alDopplerFactor(inValue); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// Speed Of Sound |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) setSpeedOfSound :(float)inValue |
{ |
alSpeedOfSound(inValue); |
} |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
// CAPTURE |
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- (void) captureSamples :(int*)outValue |
{ |
if (!gCaptureData) |
{ |
gCaptureData = (UInt8*) calloc(1, kCaptureSamples * 2); // 1 second of 44k mono 16 bit data |
} |
alGetError(); // reset |
alcGetIntegerv( gCaptureDevice, ALC_CAPTURE_SAMPLES, 1, outValue ); |
// get some new sample, free gCaptureData if this fails |
alcCaptureSamplesProc( gCaptureDevice, gCaptureData, *outValue ); |
UInt32 err = alGetError(); |
if (err) |
return; |
alSourceStop(gSource[4]); |
alSourcei(gSource[4], AL_BUFFER, AL_NONE); |
ALint count = 1; |
while (count > 0) |
alGetSourcei(gSource[4], AL_BUFFERS_QUEUED, &count); |
alBufferData(gBuffer[4], AL_FORMAT_MONO16, gCaptureData, *outValue * 2, kCapturedAudioSampleRate); |
alSourcei(gSource[4], AL_BUFFER, gBuffer[4]); |
alSourcePlay(gSource[4]); |
} |
@end |
Copyright © 2012 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2012-08-19