/*=============================================================================

	oalImp.cpp
	al_osx
	
	Created by Bob Aron on Mon Oct 13 2003.
	Copyright (c) 2003 Apple Computer Inc. All rights reserved.
 
 	$Log: oalImp.cpp,v $
 	Revision 1.33.2.1  2005/10/21 21:34:27  baron
 	Make sure 16 bit data stays in native endian at runtime (4307588).
 	
 	Revision 1.33  2005/01/11 21:41:55  baron
 	Tweaks and some added logging.
 	
 	Revision 1.32  2004/11/08 22:42:46  baron
 	Add alHint method.
 	
 	Revision 1.31  2004/09/27 21:40:24  baron
 	Make the OALSource object thread safe by using two bufferQ lists and mutexes. Don't dereference NULL ptr. [3791105, 3791120]
 	
 	Revision 1.30  2004/09/02 22:33:21  baron
 	Clean up some code.
 	
 	Revision 1.29  2004/09/02 20:25:19  baron
 	Do not return an error for a positive value for alDopplerVelocity() [3724224].
 	
 	Revision 1.28  2004/09/02 20:20:07  baron
 	Add workaround for DistanceParameter problem in the 2.0 3DMixer. Allow Doppler to be turned ON. Allow OAL Distance Model to be AL_NONE.
 	
 	Revision 1.27  2004/03/19 22:51:16  baron
 	Add BSD License and clean up comments before submitting to Open Source (Creative).
 	
 	Revision 1.26  2004/03/11 19:42:23  baron
 	Add extension to clamp rendering to stereo (ALC_RENDER_CHANNEL_COUNT). Merge the OAL3DGraph and OALDevice classes. General clean up.
 	
 	Revision 1.25  2004/03/09 18:36:45  baron
 	Add some try/catches and always check that global maps are initialized before dereferencing to prevent potential crashes when calls are made in an incorrect order.
 	
 	Revision 1.24  2004/02/25 20:51:55  baron
 	Check version of 3DMixer component and fail if pre-Panther version. Use playback rate parameter to adjust sample rates if 3DMixer is not 2.0 or >, else use stream format property to change sample rates on the mixer busses.
 	
 	Revision 1.23  2004/02/13 23:13:55  baron
 	Add Spatial Rendering and Mixer Output Rate extensions.
 	
 	Revision 1.22  2004/02/13 17:39:12  baron
 	Clean up comments and temporarily stop supporting NONE as a valid DistanceModel.
 	
 	Revision 1.21  2004/02/13 02:34:50  baron
 	Check for NANs. Add 3DMixer Distance Params support. Partial Min/Max Gain changes. Everything builds and works, some commented code needs to be clean up still.
 	
 	Revision 1.20  2004/02/11 18:14:13  baron
 	Remove warning.
 	
 	Revision 1.19  2004/01/29 22:12:43  baron
 	Remove ALC_MIXING_SAMPLE_RATE.
 	
 	Revision 1.18  2004/01/29 22:02:58  baron
 	Remove ALC_SPEAKER_CONFIGURATION property and add ALC_RENDER_QUALITY property.
 	
 	Revision 1.17  2004/01/27 23:24:18  baron
 	Do not pre convert the sound data be default.
 	
 	Revision 1.16  2004/01/23 06:14:15  baron
 	Remember the original size and format of audio data when it gets converted on the way into OAL. Fix try/catch types.
 	
 	Revision 1.15  2004/01/20 02:05:28  baron
 	free the Buffer memory when the alDeleteBuffer is called.
 	
 	Revision 1.14  2004/01/20 00:50:19  baron
 	Convert data before placing in memory turned on by default. Use realloc when changing the data in the buffer's memory.
 	
 	Revision 1.13  2004/01/09 18:35:06  baron
 	Remove calloc from Render Proc and other potential blocking code. Add several build flags and logging code.
 	
 	Revision 1.12  2003/12/23 01:44:00  baron
 	Remove duplicate method for finding QLength..
 	
 	Revision 1.11  2003/12/19 22:24:41  baron
 	Some cleanup.
 	
 	Revision 1.10  2003/12/17 18:30:46  baron
 	Add Speaker Configuration support.
 	
 	Revision 1.9  2003/12/17 00:19:23  baron
 	Add support for a internal mix sample rate. Dependent on enhancements to the 3DMixer.
 	
 	Revision 1.8  2003/12/11 23:02:00  baron
 	Add support to allow buffer data to be converted to the mixer format when it is given to the library. As OAL extension for this implementation will have to be added for it to be accessible.
 	
 	Revision 1.7  2003/12/10 17:56:14  baron
 	Add some profiling code and make 8bit pcm data work.
 	
 	Revision 1.6  2003/12/09 01:26:21  baron
 	more cleanup.
 	
 	Revision 1.5  2003/12/03 23:17:09  baron
 	Add some doppler support and clean up comments
 	
 	Revision 1.4  2003/12/02 18:59:50  baron
 	Add check-in comment logging.
 	
	
	$NoKeywords: $

=============================================================================*/

/**********************************************************************************************************************************
*
*   OpenAL cross platform audio library
*   Copyright © 2004, Apple Computer, Inc. All rights reserved.
*
*   Redistribution and use in source and binary forms, with or without modification, are permitted provided 
*   that the following conditions are met:
*
*   1.  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
*   2.  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
*       disclaimer in the documentation and/or other materials provided with the distribution. 
*   3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of its contributors may be used to endorse or promote 
*       products derived from this software without specific prior written permission. 
*
*   THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
*   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS 
*   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
*   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
*   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
*   USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
**********************************************************************************************************************************/

/*
	This source file contains all the entry points into the oal state via the defined OpenAL API set. 
*/

#include "oalImp.h"
#include "oalContext.h"
#include "oalDevice.h"
#include "oalSource.h"
#include "oalBuffer.h"

// ~~~~~~~~~~~~~~~~~~~~~~
// development build flags
#define		LOG_API_USAGE	0
#define		LOG_EXTRAS		0
#define		LOG_ERRORS		0

// ~~~~~~~~~~~~~~~~~~~~~~

// AL_STATE info
const char *alVendor="Any";
const char *alVersion="OpenAL 1.2";
const char *alRenderer="Software";
const char *alExtensions="";

const char *alNoError="No Error";
const char *alErrInvalidName="Invalid Name";
const char *alErrInvalidEnum="Invalid Enum";
const char *alErrInvalidValue="Invalid Enum Value";
const char *alErrInvalidOp="Invalid Operation";
const char *alErrOutOfMemory="Out of Memory";

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// globals
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// globals
UInt32		gCurrentContext = 0;                                    // token for the current context
UInt32		gCurrentDevice = 0;                                     // token for the device of the current context
UInt32      gMaximumMixerBusCount = kDefaultMaximumMixerBusCount;   // use gMaximumMixerBusCount for settinmg the bus count when a device is opened

// At this time, only mono CBR formats would work - no problem as only pcm formats are currently valid
// The feature is turned on using ALC_CONVERT_DATA_UPON_LOADING and the alEnable()/alDisable() APIs
bool        gConvertBufferNow = false;                              // do not convert data into mixer format by default

// global object maps
OALDeviceMap*				gOALDeviceMap = NULL;					// this map will be created upon the first call to alcOpenDevice()
OALBufferMap*				gOALBufferMap = NULL;					// this map will be created upon the first call to alcGenBuffers()
OALContextMap*				gOALContextMap = NULL;					// this map will be created upon the first call to alcCreateContext()

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// utility functions
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

// Use this for getting a unique token when creating all new sources, contexts, devices and buffers
UInt32	GetNewToken (void)
{
	static	UInt32	currentToken = 1;
	UInt32	returnedToken;
	
	returnedToken = currentToken;
	currentToken++;
	
	return (returnedToken);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void	InitializeBufferMap()
{
	if (gOALBufferMap == NULL)
	{
		gOALBufferMap = new OALBufferMap ();					// create the buffer map since there isn't one yet
		
		// add the NONE buffer
		OALBuffer	newBuffer;
		
		newBuffer.mData = NULL;
		newBuffer.mDataSize = 0;
		newBuffer.mAttachedCount = 0;
										
		gOALBufferMap->Add(0, &newBuffer);						// add the new buffer to the buffer map
	}
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// walk through the context map and find the ones that are linked to this device
void	DeleteContextsOfThisDevice(UInt32 inDeviceToken)
{
	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

		for (UInt32	i = 0; i < gOALContextMap->Size(); i++)
		{
			UInt32		contextToken = 0;
			OALContext	*oalContext = gOALContextMap->GetContextByIndex(i, contextToken);
			
            if (oalContext == NULL)
                throw ((OSStatus) AL_INVALID_OPERATION);

			if (oalContext->GetDeviceToken() == inDeviceToken)
			{
				// delete this context, it belongs to the device that is going away
				if (contextToken == gCurrentContext)
				{
					// this context is the current context, so remove it as the current context first
					alcMakeContextCurrent(NULL);
				}
				
				delete (oalContext);
				i--; //try this index again since it was just deleted
			}
		}
	}
	catch (OSStatus     result) {
		alSetError(result);
	}
	catch (...) {
		alSetError(AL_INVALID_VALUE);
	}
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStatus	FillInASBD(CAStreamBasicDescription &inASBD, UInt32	inFormatID, UInt32 inSampleRate)
{
	OSStatus	err = noErr;
	
	switch (inFormatID)
	{
		case AL_FORMAT_STEREO16:
			inASBD.mSampleRate = inSampleRate * 1.0;			
			inASBD.mFormatID = kAudioFormatLinearPCM;
			inASBD.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
			inASBD.mBytesPerPacket = 4;
			inASBD.mBytesPerFrame = 4;
			inASBD.mFramesPerPacket = 1;
			inASBD.mBitsPerChannel = 16;
			inASBD.mChannelsPerFrame = 2;
			inASBD.mReserved = 0;
			break;
		case AL_FORMAT_MONO16: 
			inASBD.mSampleRate = inSampleRate * 1.0;			
			inASBD.mFormatID = kAudioFormatLinearPCM;
			inASBD.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
			inASBD.mBytesPerPacket = 2;
			inASBD.mBytesPerFrame = 2;
			inASBD.mFramesPerPacket = 1;
			inASBD.mBitsPerChannel = 16;
			inASBD.mChannelsPerFrame = 1;
			inASBD.mReserved = 0;
			break;
		case AL_FORMAT_STEREO8:
			inASBD.mSampleRate = inSampleRate * 1.0;			
			inASBD.mFormatID = kAudioFormatLinearPCM;
			inASBD.mFormatFlags = kAudioFormatFlagIsPacked;
			inASBD.mBytesPerPacket = 2;
			inASBD.mBytesPerFrame = 2;
			inASBD.mFramesPerPacket = 1;
			inASBD.mBitsPerChannel = 8;
			inASBD.mChannelsPerFrame = 2;
			inASBD.mReserved = 0;
			break;
		case AL_FORMAT_MONO8 : 
			inASBD.mSampleRate = inSampleRate * 1.0;			
			inASBD.mFormatID = kAudioFormatLinearPCM;
			inASBD.mFormatFlags = kAudioFormatFlagIsPacked;
			inASBD.mBytesPerPacket = 1;
			inASBD.mBytesPerFrame = 1;
			inASBD.mFramesPerPacket = 1;
			inASBD.mBitsPerChannel = 8;
			inASBD.mChannelsPerFrame = 1;
			inASBD.mReserved = 0;
			break;
		default: 
			err = AL_INVALID_VALUE;
			break;
	}
	return (err);	
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// This currently will only work for cbr formats
OSStatus ConvertDataForBuffer(OALBuffer	*inOALBuffer, void *inData, UInt32 inDataSize, UInt32	inDataFormat, UInt32 inDataSampleRate)
{
	OSStatus					result = noErr;

    try {

        AudioConverterRef			converter;
        CAStreamBasicDescription	destFormat;
        UInt32						framesOfSource = 0;

        if ((inOALBuffer == NULL) || (inData == NULL))
            throw ((OSStatus) AL_INVALID_OPERATION);
        
        result = FillInASBD(inOALBuffer->mPreConvertedDataFormat, inDataFormat, inDataSampleRate);
            THROW_RESULT

        // we only should be here for mono sounds for now...
        if (inOALBuffer->mPreConvertedDataFormat.NumberChannels() == 1)
            inOALBuffer->mPreConvertedDataFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved; 
                    
        destFormat.mChannelsPerFrame = inOALBuffer->mPreConvertedDataFormat.NumberChannels();
        destFormat.mSampleRate = inOALBuffer->mPreConvertedDataFormat.mSampleRate;
        destFormat.mFormatID = kAudioFormatLinearPCM;
        
        if (inOALBuffer->mPreConvertedDataFormat.NumberChannels() == 1)
            destFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;
        else
            destFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; // leave stereo data interleaved, and an AC will be used for deinterleaving later on
        
        destFormat.mFramesPerPacket = 1;	
        destFormat.mBitsPerChannel = sizeof (Float32) * 8;	
        destFormat.mBytesPerPacket = sizeof (Float32) * destFormat.NumberChannels();	
        destFormat.mBytesPerFrame = sizeof (Float32) * destFormat.NumberChannels();
        
        result = FillInASBD(inOALBuffer->mDataFormat, inDataFormat, UInt32(destFormat.mSampleRate));
            THROW_RESULT
            
        result = AudioConverterNew(&inOALBuffer->mPreConvertedDataFormat, &destFormat, &converter);
            THROW_RESULT

        framesOfSource = inDataSize / inOALBuffer->mPreConvertedDataFormat.mBytesPerFrame; // THIS ONLY WORKS FOR CBR FORMATS
        
        UInt32		dataSize = framesOfSource * sizeof(Float32) * destFormat.NumberChannels();
        inOALBuffer->mDataSize = (UInt32) dataSize;

        if (inOALBuffer->mData != NULL)
        {
            if (inOALBuffer->mDataSize != dataSize)
            {
                inOALBuffer->mDataSize = dataSize;
                void *newDataPtr = realloc(inOALBuffer->mData, inOALBuffer->mDataSize);
                if (newDataPtr == NULL)
                    throw ((OSStatus) AL_INVALID_OPERATION);
                    
                inOALBuffer->mData = (char *) newDataPtr;
            }		
        }
        else
        {
            inOALBuffer->mDataSize = dataSize;
            inOALBuffer->mData = (char *) malloc (inOALBuffer->mDataSize);
            if (inOALBuffer->mData == NULL)
                throw ((OSStatus) AL_INVALID_OPERATION);
        }

        if (inOALBuffer->mData != NULL)
        {
            result = AudioConverterConvertBuffer(converter, inDataSize, inData, &inOALBuffer->mDataSize, inOALBuffer->mData);
            if (result == noErr)
            {
                inOALBuffer->mDataFormat.SetFrom(destFormat);
                if (inOALBuffer->mPreConvertedDataFormat.NumberChannels() == 1)
                    inOALBuffer->mDataHasBeenConverted = true;
                else
                    inOALBuffer->mDataHasBeenConverted = false;				
            }
        }
        
        AudioConverterDispose(converter);
    }
    catch (OSStatus     result) {
        return (result);
    }
    catch (...) {
        result = (OSStatus) AL_INVALID_OPERATION;
    }
    
	return (result);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ALC Methods
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ***** ALC - METHODS *****

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Device APIs
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ***** Devices *****

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(ALCubyte *deviceName)
{
	UInt32		newDeviceToken = 0;
	OALDevice	*newDevice = NULL;

#if LOG_API_USAGE
	DebugMessage("alcOpenDevice called");
#endif
	
	try {
		if (gOALDeviceMap == NULL)
			gOALDeviceMap = new OALDeviceMap ();                                        // create the device map if there isn't one yet
		        
        newDeviceToken = GetNewToken();                                                 // get a unique token
        newDevice = new OALDevice((const char *) deviceName, newDeviceToken, gMaximumMixerBusCount);	// create a new device object
        if (newDevice != NULL)
            gOALDeviceMap->Add(newDeviceToken, &newDevice);                             // add the new device to the device map
	}
	catch (OSStatus result) {
		DebugMessageN1("alcOpenDevice Failed - err = %ld\n", result);
		if (newDevice) 
			delete (newDevice);
		newDeviceToken = 0;
		alSetError(result);
    }
	catch (...) {
		DebugMessage("alcOpenDevice Failed");
		if (newDevice) 
			delete (newDevice);
		newDeviceToken = 0;
		alSetError(AL_INVALID_OPERATION);
	}
	
	return ((ALCdevice *) newDeviceToken);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALCvoid    ALCAPIENTRY alcCloseDevice(ALCdevice *device)
{
#if LOG_API_USAGE
	DebugMessage("alcCloseDevice called");
#endif

	try {										
        if (gOALDeviceMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALDevice		*oalDevice = gOALDeviceMap->Get((UInt32) device);	// get the requested oal device
        if (oalDevice == NULL) 
            throw ((OSStatus) AL_INVALID_VALUE);                            // make sure it is a valid device token

        gOALDeviceMap->Remove((UInt32) device);                             // remove the device from the map
        
        DeleteContextsOfThisDevice((UInt32) device);
        delete (oalDevice);                                                 // destruct the device object
        
        if (gOALDeviceMap->Empty())
        {
            // there are no more devices in the map, so delete the map and create again later if needed
            delete (gOALDeviceMap);
            gOALDeviceMap = NULL;
        }
	}
	catch (OSStatus   result) {
		DebugMessageN1("alcCloseDevice Failed - err = %ld\n", result);
        alSetError(result);
	}
    catch (...) {
		DebugMessage("alcCloseDevice Failed");
        alSetError(AL_INVALID_OPERATION);
	}

	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALCenum  ALCAPIENTRY alcGetError(ALCdevice *device)
{
#if LOG_API_USAGE
	DebugMessage("alcGetError called");
#endif
	// NOTE: Ignore device parameter for now as this has been the common implementation so far
	return (alGetError ());
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Context APIs
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ***** Contexts *****

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// There is no attribute support yet
ALCAPI ALCcontext* 	ALCAPIENTRY alcCreateContext(ALCdevice *device,	ALCint *attrList)
{
	UInt32			newContextToken = 0;
	OALContext		*newContext = NULL;

#if LOG_API_USAGE
	DebugMessage("alcCreateContext called");
#endif
	
	try {
        if (gOALDeviceMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALDevice		*oalDevice = gOALDeviceMap->Get((UInt32) device);
        if (oalDevice == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);           // invalid device has been passed

		// create the context map if there isn't one yet
		if (gOALContextMap == NULL)
			gOALContextMap = new OALContextMap();
	
		newContextToken = GetNewToken();
		newContext = new OALContext(newContextToken, oalDevice);
		
		gOALContextMap->Add(newContextToken, &newContext);	
	}
	catch (OSStatus     result){
		DebugMessageN1("alcCreateContext Failed - err = %ld\n", result);
		if (newContext) 
            delete (newContext);
		alSetError(result);
		return (NULL);
	}
    catch (...) {
		DebugMessage("alcCreateContext Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return ((ALCcontext *) newContextToken);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALCboolean  ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context)
{
#if LOG_API_USAGE
	DebugMessage("alcMakeContextCurrent called");
#endif

	if ((UInt32 ) context == gCurrentContext)
		return AL_TRUE;								// no change necessary, already using this context

	try {	
        if (gOALDeviceMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

		OALContext		*currentContext = NULL;
		// get the current context if there is one
		if (gCurrentContext != 0)
			currentContext = gOALContextMap->Get(gCurrentContext);
			
		if (context == 0)
		{
			// caller passed NULL, which means no context should be current
			gCurrentDevice = 0;
			gCurrentContext = 0;
			// disable the current context if there is one
			if (currentContext != NULL)
				currentContext->DisableContext();
		}
		else
		{
			// find the device that owns this context
			UInt32		newCurrentDeviceToken = gOALContextMap->GetDeviceTokenForContext((UInt32) context);
			if (newCurrentDeviceToken != 0)
			{
				OALContext		*oalContext = gOALContextMap->Get((UInt32) context);
				if (oalContext == NULL)
                    throw ((OSStatus) AL_INVALID_VALUE);    // fail because the context is invalid

                // new context is obtained so disable the old one now
                if (currentContext)
                    currentContext->DisableContext();
            
                // store the new current context and device
                gCurrentDevice = newCurrentDeviceToken;
                gCurrentContext = (UInt32) context;
			}
		}
		
		return AL_TRUE;
	}
	catch (OSStatus result) {
		DebugMessageN1("alcMakeContextCurrent Failed - err = %ld\n", result);
        alSetError(result);
	}
    catch (...) {
		DebugMessage("alcMakeContextCurrent Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return AL_FALSE;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALCvoid	  ALCAPIENTRY alcProcessContext(ALCcontext *context)
{
#if LOG_API_USAGE
	DebugMessage("alcProcessContext called");
#endif

	try {
        if (gOALDeviceMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALContext		*oalContext = gOALContextMap->Get((UInt32) context);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
        
        oalContext->ProcessContext();
    }
    catch (OSStatus result) {
		DebugMessageN1("alcProcessContext Failed - err = %ld\n", result);
        alSetError(result);        
    }
    catch (...) {
		DebugMessage("alcProcessContext Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
    return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALCcontext* ALCAPIENTRY alcGetCurrentContext(ALCvoid)
{
#if LOG_API_USAGE
	DebugMessage("alcGetCurrentContext called");
#endif

	return ((ALCcontext *) gCurrentContext);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// find out what device the context uses
ALCAPI ALCdevice*  ALCAPIENTRY alcGetContextsDevice(ALCcontext *context)
{
	UInt32	returnValue = 0;

#if LOG_API_USAGE
	DebugMessage("alcGetContextsDevice called");
#endif
	
	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
        
        returnValue = gOALContextMap->GetDeviceTokenForContext((UInt32) context);
    }
    catch (OSStatus result) {
		DebugMessageN1("alcGetContextsDevice Failed - err = %ld\n", result);
        alSetError(result);
    }
    catch (...) {
		DebugMessage("alcGetContextsDevice Failed");
        alSetError(AL_INVALID_OPERATION);
	}
    
	return ((ALCdevice*) returnValue);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALCvoid	  ALCAPIENTRY alcSuspendContext(ALCcontext *context)
{
#if LOG_API_USAGE
	DebugMessage("alcSuspendContext called");
#endif

    try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
        
        OALContext		*oalContext = gOALContextMap->Get((UInt32) context);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);
            
        oalContext->SuspendContext();
    }
    catch (OSStatus     result) {
		DebugMessageN1("alcSuspendContext Failed - err = %ld\n", result);
        alSetError(result);
    }
    catch (...) {
		DebugMessage("alcSuspendContext Failed");
        alSetError(AL_INVALID_OPERATION);
	}
    
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALCvoid	ALCAPIENTRY alcDestroyContext (ALCcontext *context)
{
#if LOG_API_USAGE
	DebugMessage("alcDestroyContext called");
#endif

	try {
		if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
        
        // make sure it is a valid device token
		OALContext		*oalContext = gOALContextMap->Get((UInt32) context);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);
            
        // if this was the current context, set current context to NULL
        if (gCurrentContext == (UInt32) context)
            alcMakeContextCurrent(NULL);

        gOALContextMap->Remove((UInt32) context);	// remove from the map
	}
	catch (OSStatus     result) {
		DebugMessageN1("alcDestroyContext Failed - err = %ld\n", result);
        alSetError (result);
	}
    catch (...) {
		DebugMessage("alcDestroyContext Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Other APIs
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ***** Other *****

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALCubyte*   ALCAPIENTRY alcGetString(ALCdevice *device, ALCenum param)
{
#if LOG_API_USAGE
	DebugMessage("alcGetString called");
#endif

	switch (param)
	{
		default:
			break;
	}
	return NULL;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALCvoid     ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALCsizei size,ALCint *data)
{	
#if LOG_API_USAGE
	DebugMessage("alcGetIntegerv called");
#endif

	switch (param)
	{
		default:
			break;
	}

	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALboolean  ALCAPIENTRY alcIsExtensionPresent(ALCdevice *device, ALubyte *extName)
{
#if LOG_API_USAGE
	DebugMessage("alcIsExtensionPresent called");
#endif

	return AL_FALSE;    // no extensions present in this implementation
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALvoid  *  ALCAPIENTRY alcGetProcAddress(ALCdevice *device, ALubyte *funcName)
{
#if LOG_API_USAGE
	DebugMessage("alcGetProcAddress called");
#endif

	return 0;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALenum  ALCAPIENTRY alcGetEnumValue(ALCdevice *device, ALubyte *enumName)
{
#if LOG_API_USAGE
	DebugMessage("alcGetEnumValue called");
#endif

	// since the device name is ignored by always using the default output AU,
    // alGetEnumValue() should return the same thing
    return (alGetEnumValue (enumName));
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetIntegerv (ALenum pname, ALint *data)
{
#if LOG_API_USAGE
	DebugMessage("alGetIntegerv called");
#endif

	try {
		if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

		OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        switch (pname)
        {
            case AL_DISTANCE_MODEL:
                *data = oalContext->GetDistanceModel();
                break;
                
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus     result) {
		DebugMessageN1("alGetIntegerv Failed - err = %ld\n", result);
        alSetError(result);
    }
    catch (...) {
		DebugMessage("alGetIntegerv Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid	ALAPIENTRY alHint( ALenum target, ALenum mode )
{
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// AL Methods
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ***** AL - METHODS *****

UInt32		gCurrentError = 0;				// globally stored error code

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALenum ALAPIENTRY alGetError ()
{
    ALenum	error = AL_NO_ERROR;

#if LOG_API_USAGE
	DebugMessage("alGetError called");
#endif

	if (gCurrentError != AL_NO_ERROR)
    {
#if LOG_ERRORS
		DebugMessageN1("alGetError: error = %ld\n", gCurrentError);
#endif
		error = gCurrentError;
		gCurrentError = AL_NO_ERROR;
	}
	
	return (error);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSetError (ALenum errorCode)
{

#if LOG_API_USAGE
	DebugMessage("alSetError called");
#endif

#if LOG_ERRORS
	DebugMessageN1("alSetError called: error #  %ld\n", errorCode);
#endif

    // only set an error if we are in a no error state
    if (gCurrentError == AL_NO_ERROR)
		gCurrentError = errorCode;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Buffer APIs
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ***** Buffers *****

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGenBuffers(ALsizei n, ALuint *buffers)
{
#if LOG_API_USAGE
	DebugMessage("alGenBuffers called");
#endif

	UInt32		newBufferToken = 0;
	
	try {
        InitializeBufferMap();
        if (gOALBufferMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
		if ((n + gOALBufferMap->Size() > AL_MAXBUFFERS) || (n > AL_MAXBUFFERS))
            throw ((OSStatus) AL_INVALID_VALUE);
		
        for (UInt32	i = 0; i < n; i++)
        {
            OALBuffer	newBuffer;
            
            // initialize some of the fields, others will be explicitly set later
            newBuffer.mData = NULL;
            newBuffer.mDataSize = 0;
            newBuffer.mAttachedCount = 0;
            newBuffer.mDataHasBeenConverted = false;
            
            newBufferToken = GetNewToken(); 						// get a unique token
                                    
            gOALBufferMap->Add(newBufferToken, &newBuffer);			// add the new buffer to the buffer map
            buffers[i] = newBufferToken;
        }
	}
	catch (OSStatus     result) {
		DebugMessageN1("alGenBuffers Failed - err = %ld\n", result);
        alSetError (result);
	}
    catch (...) {
		DebugMessage("alGenBuffers Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetBufferf (ALuint buffer, ALenum pname, ALfloat *value)
{
#if LOG_API_USAGE
	DebugMessage("alGetBufferf called");
#endif

    try {
        if (gOALBufferMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALBuffer	*oalBuffer = gOALBufferMap->Get((UInt32) buffer);
        if (oalBuffer == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);
        
        switch (pname)
        {
            case AL_FREQUENCY:
                *value = oalBuffer->mDataFormat.mSampleRate;
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
    }
    catch (OSStatus result) {
		DebugMessageN1("alGetBufferf Failed - err = %ld\n", result);
        alSetError(result);
    }
    catch (...) {
		DebugMessage("alGetBufferf Failed");
        alSetError(AL_INVALID_OPERATION);
	}
    
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetBufferi(ALuint buffer, ALenum pname, ALint *value)
{
#if LOG_API_USAGE
	DebugMessage("alGetBufferi called");
#endif

    try {
        if (gOALBufferMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALBuffer	*oalBuffer = gOALBufferMap->Get((UInt32) buffer);
        if (oalBuffer == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);

        switch (pname)
        {
            case AL_FREQUENCY:
                *value = (UInt32) oalBuffer->mDataFormat.mSampleRate;
                break;
            case AL_BITS:
                *value = oalBuffer->mPreConvertedDataFormat.mBitsPerChannel;
                break;
            case AL_CHANNELS:
                *value = oalBuffer->mDataFormat.NumberChannels();
                break;
            case AL_SIZE:
                *value = oalBuffer->mPreConvertedDataSize;
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }        
    }
    catch (OSStatus result) {
		DebugMessageN1("alGetBufferi Failed - err = %ld\n", result);
		alSetError(result);
    }
    catch (...) {
		DebugMessage("alGetBufferi Failed");
        alSetError(AL_INVALID_OPERATION);
	}
    
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alDeleteBuffers(ALsizei n, ALuint *buffers)
{
#if LOG_API_USAGE
	DebugMessage("alDeleteBuffers called");
#endif

	try {
        if (gOALBufferMap == NULL)
        {
            DebugMessage("alDeleteBuffers: gOALBufferMap == NULL");
            throw ((OSStatus) AL_INVALID_OPERATION);   
        }
        
        if (gOALBufferMap->Empty())
            return; // nothing to do
            
        if (n > gOALBufferMap->Size() - 1)
        {
            DebugMessage("alDeleteBuffers: n > gOALBufferMap->Size() - 1");
            throw ((OSStatus) AL_INVALID_VALUE);   
        }
        else
        {
            UInt32	i;
            // see if any of the buffers are attached to a source or are invalid names
            for (i = 0; i < n; i++)
            {
                // don't bother verifying the NONE buffer, it won't be deleted anyway
                if (buffers[i] != AL_NONE)
                {
                    OALBuffer	*oalBuffer = gOALBufferMap->Get(buffers[i]);
                    if (oalBuffer == NULL)
                    {
                        DebugMessage("alDeleteBuffers: oalBuffer == NULL");
                        throw ((OSStatus) AL_INVALID_VALUE);    // the buffer is invalid
                    }
                    else if (oalBuffer->mAttachedCount > 0)
                    {
                        DebugMessageN1("alDeleteBuffers: oalBuffer->mAttachedCount = %ld\n", oalBuffer->mAttachedCount);
                        throw ((OSStatus) AL_INVALID_VALUE);    // the buffer is attached to a source so set an error and bail
                    }
                }
            }
        
            // All the buffers are OK'd for deletion, so delete them now
            for (i = 0; i < n; i++)
            {
                // do not delete the NONE buffer at the beginning of the map
                if (buffers[i] != AL_NONE)
                {
                    OALBuffer	*buffer = gOALBufferMap->Get((UInt32) buffers[i]);
                    if (buffer != NULL)
                    {
   	                	if (buffer->mData != NULL)
                        	free(buffer->mData);
                    }
	            	gOALBufferMap->Remove((UInt32) buffers[i]);
	            }
            }
        }
    }
    catch (OSStatus     result) {
		DebugMessageN1("alDeleteBuffers Failed - err = %ld\n", result);
        alSetError(result);
    }
    catch (...) {
		DebugMessage("alDeleteBuffers Failed");
        alSetError(AL_INVALID_OPERATION);
	}
    
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alBufferData(ALuint buffer, ALenum format, ALvoid *data, ALsizei size, ALsizei freq)
{
#if LOG_API_USAGE
	DebugMessage("alBufferData called");
#endif

	try {
        if (gOALBufferMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);   

        OALBuffer	*oalBuffer = gOALBufferMap->Get((UInt32) buffer);
        if ((oalBuffer == NULL) || !IsFormatSupported(format))
            throw ((OSStatus) AL_INVALID_VALUE);   // this is not a valid buffer token or is an invalid format
	
        // don't allow if the buffer is in a queue
        if (oalBuffer->mAttachedCount > 0)
        {
            DebugMessage("alBufferData ATTACHMENT > 0");
            throw ((OSStatus) AL_INVALID_OPERATION);   
        }
		
        oalBuffer->mPreConvertedDataSize = (UInt32) size;
        // do not pre-convert stereo sounds, let the AC do the deinterleaving	
        OSStatus    result = noErr;
        if (!gConvertBufferNow || ((format == AL_FORMAT_STEREO16) || (format == AL_FORMAT_STEREO8)))
        {
            if (oalBuffer->mData != NULL)
            {
                if (oalBuffer->mDataSize != (UInt32) size)
                {
                    oalBuffer->mDataSize = (UInt32) size;
                    void *newDataPtr = realloc(oalBuffer->mData, oalBuffer->mDataSize);
                    oalBuffer->mData = (char *) newDataPtr;
                }		
            }
            else
            {
                oalBuffer->mDataSize = (UInt32) size;
                oalBuffer->mData = (char *) malloc (oalBuffer->mDataSize);
            }
            
            if (oalBuffer->mData)
            {
                result = FillInASBD(oalBuffer->mDataFormat, format, freq);
                    THROW_RESULT
                
                oalBuffer->mPreConvertedDataFormat.SetFrom(oalBuffer->mDataFormat); //  make sure they are the same so original format info can be returned to caller
                memcpy (oalBuffer->mData, data, oalBuffer->mDataSize);		
            }
        }
        else
        {
    #if LOG_EXTRAS		
        DebugMessage("alBufferData called: Converting Data Now");
    #endif
            result = ConvertDataForBuffer(oalBuffer, data, size, format, freq);	// convert the data to the mixer's format and copy to the buffer
                THROW_RESULT
        }
    }
    catch (OSStatus     result) {
		DebugMessageN1("alBufferData Failed - err = %ld\n", result);
        alSetError(result);
    }
    catch (...) {
		DebugMessage("alBufferData Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALboolean ALAPIENTRY alIsBuffer(ALuint buffer)
{
#if LOG_API_USAGE
	DebugMessage("alIsBuffer called");
#endif

    try {
        if (gOALBufferMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);   

        OALBuffer	*oalBuffer = gOALBufferMap->Get((UInt32) buffer);

        if (oalBuffer != NULL)
            return AL_TRUE;
        else
            return AL_FALSE;
    }
    catch (OSStatus     result) {
		DebugMessageN1("alIsBuffer Failed - err = %ld\n", result);
        alSetError(result);
    }
    catch (...) {
		DebugMessage("alIsBuffer Failed");
        alSetError(AL_INVALID_OPERATION);
	}

    return AL_FALSE;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Source APIs
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma mark ***** Sources *****

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALvoid  ALAPIENTRY alGenSources(ALsizei n, ALuint *sources)
{
#if LOG_API_USAGE
	DebugMessage("alGenSources called");
#endif

	if (n == 0)
		return; // NOP

	UInt32      i = 0,
                count = 0;
	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        if ((n > AL_MAXSOURCES) || (sources == NULL))
            throw ((OSStatus) AL_INVALID_VALUE);
        
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        for (i = 0; i < n; i++)
        {
            UInt32	newToken = GetNewToken();		// get a unique token
            
            oalContext->AddSource(newToken);		// add this source to the context
            sources[i] = newToken; 					// return the source token
            count++;
        }
	}
	catch (OSStatus     result){
		DebugMessageN1("alGenSources Failed - err = %ld\n", result);
		// some of the sources could not be created, so delete the ones that were and return none
		alSetError(result);
		alDeleteSources(i, sources);
		for (i = 0; i < count; i++)
			sources[i] = 0;
	}
    catch (...) {
		DebugMessage("alGenSources Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALvoid ALAPIENTRY alDeleteSources (ALsizei n, ALuint *sources)
{
#if LOG_API_USAGE
	DebugMessage("alDeleteSources called");
#endif

	if (n == 0)
		return; // NOP

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

		OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        if (n > oalContext->GetSourceCount())
            throw ((OSStatus) AL_INVALID_VALUE);
        
        for (UInt32 i = 0; i < n; i++)
        {
            oalContext->RemoveSource(sources[i]);
        }
	}
	catch (OSStatus     result) {
		DebugMessageN1("alDeleteSources Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alDeleteSources Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALCAPI ALboolean  ALAPIENTRY alIsSource(ALuint source)
{
#if LOG_API_USAGE
	DebugMessage("alIsSource called");
#endif

	ALboolean	returnValue = AL_FALSE;
	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

		OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
        if (oalSource != NULL)
            return AL_TRUE;
        else
            return AL_FALSE;
	}
	catch (OSStatus     result) {
		DebugMessageN1("alIsSource Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alIsSource Failed");
        alSetError(AL_INVALID_OPERATION);
	}

	return (returnValue);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourcef (ALuint source, ALenum pname, ALfloat value)
{
#if LOG_API_USAGE
	DebugMessage("alSourcef called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

		OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);

        switch (pname) 
        {
            case AL_CONE_INNER_ANGLE:
                oalSource->SetConeInnerAngle(value, false);
                break;
            case AL_CONE_OUTER_ANGLE:
                oalSource->SetConeOuterAngle(value, false);
                break;
            case AL_CONE_OUTER_GAIN:
                if (value >= 0.0 && value <= 1.0)
                    oalSource->SetConeOuterGain(value, false);
                break;
            case AL_PITCH:
                if (value < 0.0f)
                    throw ((OSStatus) AL_INVALID_VALUE);
                oalSource->SetPitch(value, false);
                break;
            case AL_GAIN:
                oalSource->SetGain(value, false);
                break;
            case AL_MAX_DISTANCE:
                oalSource->SetMaxDistance(value, false);
                break;
            case AL_MIN_GAIN:
                if ((value < 0.0f) && (value > 1.0f))
                    throw ((OSStatus) AL_INVALID_VALUE);
                oalSource->SetMinGain(value, false);
                break;
            case AL_MAX_GAIN:
                if ((value < 0.0f) && (value > 1.0f))
                    throw ((OSStatus) AL_INVALID_VALUE);
                oalSource->SetMaxGain(value, false);
                break;
            case AL_ROLLOFF_FACTOR:
                if (value < 0.0f) 
                    throw ((OSStatus) AL_INVALID_VALUE);
                oalSource->SetRollOffFactor(value, false);
                break;
            case AL_REFERENCE_DISTANCE:
                if (value <= 0.0f)
                    throw ((OSStatus) AL_INVALID_VALUE);
                oalSource->SetReferenceDistance(value, false);
                break;
            default:
                alSetError(AL_INVALID_OPERATION);
                break;
        }
	}
	catch (OSStatus     result) {
		DebugMessageN1("alSourcef Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourcef Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourcefv (ALuint source, ALenum pname, ALfloat *values)
{
#if LOG_API_USAGE
	DebugMessage("alSourcefv called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);

        switch(pname) 
        {
            case AL_POSITION:
                if (isnan(values[0]) || isnan(values[1]) || isnan(values[2]))
                    throw ((OSStatus) AL_INVALID_VALUE);
                oalSource->SetPosition(values[0], values[1], values[2], false);
                break;
            case AL_DIRECTION:
                oalSource->SetDirection(values[0], values[1], values[2], false);
                break;
            case AL_VELOCITY:
                oalSource->SetVelocity(values[0], values[1], values[2], false);
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch(OSStatus      result) {
		DebugMessageN1("alSourcefv Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourcefv Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSource3f (ALuint source, ALenum pname, ALfloat v1, ALfloat v2, ALfloat v3)
{
#if LOG_API_USAGE
	DebugMessage("alSource3f called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);

        switch (pname) 
        {
            case AL_POSITION:
                if (isnan(v1) || isnan(v2) || isnan(v3))
                    throw ((OSStatus) AL_INVALID_VALUE);
                oalSource->SetPosition(v1, v2, v3, false);
                break;
            case AL_VELOCITY:
                oalSource->SetVelocity(v1, v2, v3, false);
                break;
            case AL_DIRECTION:
                oalSource->SetDirection(v1, v2, v3, false);
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus      result) {
		DebugMessageN1("alSource3f Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSource3f Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourcei (ALuint source, ALenum pname, ALint value)
{
#if LOG_API_USAGE
	DebugMessage("alSourcei called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);

        switch (pname) 
        {
            case AL_CONE_INNER_ANGLE:
                oalSource->SetConeInnerAngle(value, false);
                break;
            case AL_CONE_OUTER_ANGLE:
                oalSource->SetConeOuterAngle(value, false);
                break;
            case AL_CONE_OUTER_GAIN:
                if (value >= 0 && value <= 1)
                    oalSource->SetConeOuterGain(value, false);
                break;
            case AL_LOOPING:
                oalSource->SetLooping(value, false);
                break;
            case AL_BUFFER:
                if ((oalSource->GetState() == AL_STOPPED) || (oalSource->GetState() == AL_INITIAL))
                {
                    if (gOALBufferMap == NULL)
                        throw ((OSStatus) AL_INVALID_OPERATION);   

                    if ((alIsBuffer(value)) || (value == 0))
                        oalSource->SetBuffer(value, gOALBufferMap->Get((UInt32) value));
                    else
                        throw ((OSStatus) AL_INVALID_OPERATION);
                } 
                else
                    throw ((OSStatus) AL_INVALID_OPERATION);
    
                break;
            case AL_SOURCE_RELATIVE:
                if ((value == AL_FALSE) || (value == AL_TRUE))
                    oalSource->SetSourceRelative(value, false);
                else
                    throw ((OSStatus) AL_INVALID_VALUE);
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus      result) {
		DebugMessageN1("alSourcei Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourcei Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetSourcef (ALuint source, ALenum pname, ALfloat *value)
{
#if LOG_API_USAGE
	DebugMessage("alGetSourcef called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);

        switch (pname) 
        {
            case AL_CONE_INNER_ANGLE:
                *value = oalSource->GetConeInnerAngle();
                break;
            case AL_CONE_OUTER_ANGLE:
                *value = oalSource->GetConeOuterAngle();
                break;
            case AL_CONE_OUTER_GAIN:
                *value = oalSource->GetConeOuterGain();
                break;
            case AL_PITCH:
                *value = oalSource->GetPitch();
                break;
            case AL_GAIN:
                *value = oalSource->GetGain();
                break;
            case AL_MAX_DISTANCE:
                *value = oalSource->GetMaxDistance();
                break;
            case AL_MIN_GAIN:
                *value = oalSource->GetMinGain();
                break;
            case AL_MAX_GAIN:
                *value = oalSource->GetMaxGain();
                break;
            case AL_ROLLOFF_FACTOR:
                *value = oalSource->GetRollOffFactor();
                break;
            case AL_REFERENCE_DISTANCE:
                *value = oalSource->GetReferenceDistance();
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus      result) {
		DebugMessageN1("alGetSourcef Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alGetSourcef Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetSource3f (ALuint source, ALenum pname, ALfloat *v1, ALfloat *v2, ALfloat *v3)
{
#if LOG_API_USAGE
	DebugMessage("alGetSource3f called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);

        switch (pname) 
        {
            case AL_POSITION:
                oalSource->GetPosition(*v1, *v2, *v3, false);
                break;
            case AL_DIRECTION:
                oalSource->GetDirection(*v1, *v2, *v3, false);
                break;
            case AL_VELOCITY:
                oalSource->GetVelocity(*v1, *v2, *v3, false);
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus      result) {
		DebugMessageN1("alGetSource3f Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alGetSource3f Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetSourcefv (ALuint source, ALenum pname, ALfloat *values)
{
#if LOG_API_USAGE
	DebugMessage("alGetSourcefv called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);

        switch(pname) 
        {
            case AL_POSITION:
                oalSource->GetPosition(values[0], values[1], values[2], false);
                break;
            case AL_VELOCITY:
                oalSource->GetVelocity(values[0], values[1], values[2], false);
                break;
            case AL_DIRECTION:
                oalSource->GetDirection(values[0], values[1], values[2], false);
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus      result) {
		DebugMessageN1("alGetSourcefv Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alGetSourcefv Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetSourcei (ALuint source, ALenum pname, ALint *value)
{
#if LOG_API_USAGE
	DebugMessage("alGetSourcei called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);

        switch (pname) 
        {
            case AL_CONE_INNER_ANGLE:
                *value = (UInt32) oalSource->GetConeInnerAngle();
                break;
            case AL_CONE_OUTER_ANGLE:
                *value = (UInt32) oalSource->GetConeOuterAngle();
                break;
            case AL_CONE_OUTER_GAIN:
                *value = (UInt32) oalSource->GetConeOuterGain();
                break;
            case AL_LOOPING:
                *value = oalSource->GetLooping();
                break;
            case AL_BUFFER:
                *value = oalSource->GetBuffer();
                break;
            case AL_SOURCE_RELATIVE:
                *value = oalSource->GetSourceRelative();
                break;
            case AL_SOURCE_STATE:
                *value = oalSource->GetState();
                break;
            case AL_BUFFERS_QUEUED:
                *value = oalSource->GetQLength();
                break;
            case AL_BUFFERS_PROCESSED:
                *value = oalSource->GetBuffersProcessed();
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus      result) {
		DebugMessageN1("alGetSourcei Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alGetSourcei Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourcePlay(ALuint source)
{	
#if LOG_API_USAGE
	DebugMessage("alSourcePlay called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_NAME);

        if (oalSource->GetQLength() != 0)
        {
            UInt32		state = oalSource->GetState();
            switch (state)
            {
                case AL_INITIAL:
                    oalSource->Play();					// start playing the queue
                    break;
                case AL_PLAYING:
                    oalSource->Stop();					// stop playing the queue
                    oalSource->Play();					// start playing the queue
                    break;
                case AL_PAUSED:
                    oalSource->Resume();				// continue playing again from somewhere in the buffer queue
                    break;
                case AL_STOPPED:
                    oalSource->Play();					// start playing the queue
                    break;
                default:
                    break;
            }
        }		
	}
	catch (OSStatus      result) {
		DebugMessageN1("alSourcePlay Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourcePlay Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourcePause (ALuint source)
{
#if LOG_API_USAGE
	DebugMessage("alSourcePause called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_NAME);

        oalSource->Pause();
	}
	catch (OSStatus      result) {
		DebugMessageN1("alSourcePause Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourcePause Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourceStop (ALuint source)
{
#if LOG_API_USAGE
	DebugMessage("alSourceStop called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_NAME);

        oalSource->Stop();
	}
	catch (OSStatus      result) {
		DebugMessageN1("alSourceStop Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourceStop Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourceRewind (ALuint source)
{
#if LOG_API_USAGE
	DebugMessage("alSourceRewind called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_NAME);

        oalSource->Stop();
        oalSource->Play();
	}
	catch (OSStatus      result) {
		DebugMessageN1("alSourceRewind Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourceRewind Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourcePlayv(ALsizei n, ALuint *ID)
{
#if LOG_API_USAGE
	DebugMessage("alSourcePlayv called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        for (UInt32	i = 0; i < n; i++)
            alSourcePlay(ID[i]);
    }
	catch (OSStatus      result) {
		DebugMessageN1("alSourcePlayv Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourcePlayv Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourcePausev(ALsizei n, ALuint *ID)
{
#if LOG_API_USAGE
	DebugMessage("alSourcePausev called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        for (UInt32	i = 0; i < n; i++)
            alSourcePause(ID[i]);
    }
	catch (OSStatus      result) {
		DebugMessageN1("alSourcePausev Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourcePausev Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourceStopv(ALsizei n, ALuint *ID)
{
#if LOG_API_USAGE
	DebugMessage("alSourceStopv called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        for (UInt32	i = 0; i < n; i++)
            alSourceStop(ID[i]);
    }
	catch (OSStatus      result) {
		DebugMessageN1("alSourceStopv Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourceStopv Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourceRewindv (ALsizei n, ALuint *ID)
{
#if LOG_API_USAGE
	DebugMessage("alSourceRewindv called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        for (UInt32	i = 0; i < n; i++)
            alSourceRewind(ID[i]);
    }
	catch (OSStatus      result) {
		DebugMessageN1("alSourceRewindv Failed - err = %ld\n", result);
		alSetError(result);
	}
    catch (...) {
		DebugMessage("alSourceRewindv Failed");
        alSetError(AL_INVALID_OPERATION);
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers (ALuint source, ALsizei n, ALuint *buffers)
{
#if LOG_API_USAGE
	DebugMessage("alSourceQueueBuffers called");
#endif

	if (n == 0)
		return;	// no buffers were actually requested for queueing
		
	try {
        if (gOALBufferMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);   

        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_NAME);
                        
        // verify that buffers provided are valid before queueing them.
        for (UInt32	i = 0; i < n; i++)
        {
            if (buffers[i] != AL_NONE)
            {
                // verify that this is a valid buffer
                OALBuffer *oalBuffer = gOALBufferMap->Get(buffers[i]);
                if (oalBuffer == NULL)
                    throw ((OSStatus) AL_INVALID_VALUE);				// an invalid buffer id has been provided
            }
            else
            {
                // NONE is a valid buffer parameter - do nothing it's valid
            }
        }

        // all valid buffers, so append them to the queue
        for (UInt32	i = 0; i < n; i++)
        {
            oalSource->AppendBufferToQueue(buffers[i], gOALBufferMap->Get(buffers[i]));
        }
	}
	catch (OSStatus		result) {
		DebugMessageN1("alSourceQueueBuffers Failed - err = %ld\n", result);
		alSetError(result);
	}
	catch (...) {
		DebugMessage("alSourceQueueBuffers Failed");
        alSetError(AL_INVALID_OPERATION);
	}

	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers (ALuint source, ALsizei n, ALuint *buffers)
{
#if LOG_API_USAGE
	DebugMessage("alSourceUnqueueBuffers called");
#endif

	if (n == 0)
		return;

	try {
        if (buffers == NULL)
            throw ((OSStatus) AL_INVALID_VALUE);   

        if (gOALBufferMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);   

        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
		
        OALContext		*oalContext = gOALContextMap->Get((UInt32) gCurrentContext);
		if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALSource	*oalSource = oalContext->GetSource((UInt32) source);
		if (oalSource == NULL)
            throw ((OSStatus) AL_INVALID_NAME);

        if (oalSource->GetQLength() < n)
            throw (OSStatus) AL_INVALID_VALUE;				// n is greater than the source's Q length
        
        oalSource->RemoveBuffersFromQueue(n, (UInt32 *) buffers);

	}
	catch (OSStatus		result) {
		DebugMessageN1("alSourceUnqueueBuffers Failed - err = %ld\n", result);
		// reinitialize the elements in the buffers array
		if (buffers)
		{
			for (UInt32	i = 0; i < n; i++)
				buffers[i] = 0;
		}
		// this would be real bad, as now we have a buffer queue in an unknown state
		alSetError(result);
	}
	catch (...){
		DebugMessage("alSourceUnqueueBuffers Failed");
        alSetError(AL_INVALID_OPERATION);
	}

	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY	alDistanceModel (ALenum value)
{
#if LOG_API_USAGE
	DebugMessage("alDistanceModel called");
#endif

	try {
        switch (value)
        {
            case AL_NONE:			
            case AL_INVERSE_DISTANCE:
            case AL_INVERSE_DISTANCE_CLAMPED:
            {
                if (gOALContextMap == NULL)
                    throw ((OSStatus) AL_INVALID_OPERATION);
                    
                OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
                if (oalContext == NULL)
                    throw ((OSStatus) AL_INVALID_OPERATION);

                oalContext->SetDistanceModel(value);
            } 
            break;
            
            default:
                alSetError(AL_INVALID_VALUE);
                break;
        }
    }
	catch (OSStatus		result) {
		DebugMessageN1("alDistanceModel Failed - err = %ld\n", result);
        alSetError(result);
    }
    catch (...) {
		DebugMessage("alDistanceModel Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
    }
    return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alDopplerFactor (ALfloat value)
{	
#if LOG_API_USAGE
	DebugMessage("alDopplerFactor called");
#endif

	try {
        if (value < 0.0f)
            throw ((OSStatus) AL_INVALID_VALUE);

        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        oalContext->SetDopplerFactor(value, false);
	}
	catch (OSStatus		result) {
		DebugMessageN1("alDopplerFactor Failed - err = %ld\n", result);
        alSetError(result);
    }
    catch (...) {
		DebugMessage("alDopplerFactor Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
    }
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alDopplerVelocity (ALfloat value)
{
#if LOG_API_USAGE
	DebugMessage("alDopplerVelocity called");
#endif

	try {
        if (value <= 0.0f)
            throw ((OSStatus) AL_INVALID_VALUE);

        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        oalContext->SetDopplerVelocity(value, false);
	}
	catch (OSStatus		result) {
		DebugMessageN1("alDopplerVelocity Failed - err = %ld\n", result);
        alSetError(result);
    }
    catch (...) {
		DebugMessage("alDopplerVelocity Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
    }
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetListenerf( ALenum pname, ALfloat* value )
{
#if LOG_API_USAGE
	DebugMessage("alGetListenerf called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        switch(pname) 
        {
            case AL_GAIN:
                *value = oalContext->GetListenerGain();
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus		result) {
		DebugMessageN1("alGetListenerf Failed - err = %ld\n", result);
        alSetError(result);
    }
	catch (...) {
		DebugMessage("alGetListenerf Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetListener3f( ALenum pname, ALfloat* v1, ALfloat* v2, ALfloat* v3 )
{
#if LOG_API_USAGE
	DebugMessage("alGetListener3f called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        switch(pname) 
        {
            case AL_POSITION:
                oalContext->GetListenerPosition(v1, v2, v3);
                break;
            case AL_VELOCITY:
                oalContext->GetListenerVelocity(v1, v2, v3);
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus		result) {
		DebugMessageN1("alGetListener3f Failed - err = %ld\n", result);
        alSetError(result);
    }
	catch (...) {
		DebugMessage("alGetListener3f Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetListenerfv( ALenum pname, ALfloat* values )
{
#if LOG_API_USAGE
	DebugMessage("alGetListenerfv called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        switch (pname) 
        {
            case AL_POSITION:
                oalContext->GetListenerPosition(&values[0], &values[1], &values[2]);
                break;
            case AL_VELOCITY:
                oalContext->GetListenerVelocity(&values[0], &values[1], &values[2]);
                break;
            case AL_ORIENTATION:
                oalContext->GetListenerOrientation( &values[0], &values[1], &values[2],
                                                    &values[3], &values[4], &values[5]);
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus		result) {
		DebugMessageN1("alGetListenerfv Failed - err = %ld\n", result);
        alSetError(result);
    }
	catch (...) {
		DebugMessage("alGetListenerfv Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alListener3f (ALenum pname, ALfloat v1, ALfloat v2, ALfloat v3)
{
#if LOG_API_USAGE
	DebugMessage("alListener3f called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        switch (pname) 
        {
            case AL_POSITION:
                if (isnan(v1) || isnan(v2) || isnan(v3))
                    throw ((OSStatus) AL_INVALID_VALUE);
                oalContext->SetListenerPosition(v1, v2, v3);
                break;
            case AL_VELOCITY:
                oalContext->SetListenerVelocity(v1, v2, v3);
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus		result) {
		DebugMessageN1("alListener3f Failed - err = %ld\n", result);
        alSetError(result);
    }
	catch (...) {
		DebugMessage("alListener3f Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alListenerfv (ALenum pname, ALfloat *values)
{
#if LOG_API_USAGE
	DebugMessage("alListenerfv called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        switch(pname) 
        {
            case AL_POSITION:
				#if LOG_API_USAGE
					DebugMessage("          AL_POSITION");
				#endif
                if (isnan(values[0]) || isnan(values[1]) || isnan(values[2]))
                    throw ((OSStatus) AL_INVALID_VALUE);                        
                oalContext->SetListenerPosition(values[0], values[1], values[2]);
                break;
            case AL_VELOCITY:
				#if LOG_API_USAGE
					DebugMessage("          AL_VELOCITY");
				#endif
                oalContext->SetListenerVelocity(values[0], values[1], values[2]);
                break;
            case AL_ORIENTATION:
				#if LOG_API_USAGE
					DebugMessage("          AL_ORIENTATION");
				#endif
                oalContext->SetListenerOrientation(	values[0], values[1], values[2],
                                                    values[3], values[4], values[5]);
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus		result) {
 		DebugMessageN1("alListenerfv Failed - err = %ld\n", result);
       alSetError(result);
    }
	catch (...) {
 		DebugMessage("alListenerfv Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alListenerf (ALenum pname, ALfloat value)
{
#if LOG_API_USAGE
	DebugMessage("alListenerf called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        switch (pname) 
        {
            case AL_GAIN:
                oalContext->SetListenerGain((Float32) value);     //gListener.Gain=value;
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus		result) {
 		DebugMessageN1("alListenerf Failed - err = %ld\n", result);
        alSetError(result);
    }
	catch (...) {
 		DebugMessage("alListenerf Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetFloatv (ALenum pname, ALfloat *data)
{
#if LOG_API_USAGE
	DebugMessage("alGetFloatv called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        switch(pname)
        {
            case AL_DOPPLER_FACTOR:
                *data = oalContext->GetDopplerFactor();
                break;
            case AL_DOPPLER_VELOCITY:
                *data = oalContext->GetDopplerVelocity();
                break;
            default:
                alSetError(AL_INVALID_ENUM);
                break;
        }
	}
	catch (OSStatus		result) {
 		DebugMessageN1("alGetFloatv Failed - err = %ld\n", result);
        alSetError(result);
    }
	catch (...) {
 		DebugMessage("alGetFloatv Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
	}
	
    return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ALAPI ALenum ALAPIENTRY alGetEnumValue (ALubyte *ename)
{
#if LOG_API_USAGE
	DebugMessageN1("alGetEnumValue called", *ename);
#endif

	if (strcmp("AL_INVALID", (const char *)ename) == 0) { return AL_INVALID; }
	if (strcmp("ALC_INVALID", (const char *)ename) == 0) { return ALC_INVALID; }
	if (strcmp("AL_NONE", (const char *)ename) == 0) { return AL_NONE; }
	if (strcmp("AL_FALSE", (const char *)ename) == 0) { return AL_FALSE; }
	if (strcmp("ALC_FALSE", (const char *)ename) == 0) { return ALC_FALSE; }
	if (strcmp("AL_TRUE", (const char *)ename) == 0) { return AL_TRUE; }
	if (strcmp("ALC_TRUE", (const char *)ename) == 0) { return ALC_TRUE; }
	if (strcmp("AL_SOURCE_RELATIVE", (const char *)ename) == 0) { return AL_SOURCE_RELATIVE; }
	if (strcmp("AL_CONE_INNER_ANGLE", (const char *)ename) == 0) { return AL_CONE_INNER_ANGLE; }
	if (strcmp("AL_CONE_OUTER_ANGLE", (const char *)ename) == 0) { return AL_CONE_OUTER_ANGLE; }
	if (strcmp("AL_PITCH", (const char *)ename) == 0) { return AL_PITCH; }
	if (strcmp("AL_POSITION", (const char *)ename) == 0) { return AL_POSITION; }
	if (strcmp("AL_DIRECTION", (const char *)ename) == 0) { return AL_DIRECTION; }
	if (strcmp("AL_VELOCITY", (const char *)ename) == 0) { return AL_VELOCITY; }
	if (strcmp("AL_LOOPING", (const char *)ename) == 0) { return AL_LOOPING; }
	if (strcmp("AL_BUFFER", (const char *)ename) == 0) { return AL_BUFFER; }
	if (strcmp("AL_GAIN", (const char *)ename) == 0) { return AL_GAIN; }
	if (strcmp("AL_MIN_GAIN", (const char *)ename) == 0) { return AL_MIN_GAIN; }
	if (strcmp("AL_MAX_GAIN", (const char *)ename) == 0) { return AL_MAX_GAIN; }
	if (strcmp("AL_ORIENTATION", (const char *)ename) == 0) { return AL_ORIENTATION; }
	if (strcmp("AL_REFERENCE_DISTANCE", (const char *)ename) == 0) { return AL_REFERENCE_DISTANCE; }
	if (strcmp("AL_ROLLOFF_FACTOR", (const char *)ename) == 0) { return AL_ROLLOFF_FACTOR; }
	if (strcmp("AL_CONE_OUTER_GAIN", (const char *)ename) == 0) { return AL_CONE_OUTER_GAIN; }
	if (strcmp("AL_MAX_DISTANCE", (const char *)ename) == 0) { return AL_MAX_DISTANCE; }
	if (strcmp("AL_SOURCE_STATE", (const char *)ename) == 0) { return AL_SOURCE_STATE; }
	if (strcmp("AL_INITIAL", (const char *)ename) == 0) { return AL_INITIAL; }
	if (strcmp("AL_PLAYING", (const char *)ename) == 0) { return AL_PLAYING; }
	if (strcmp("AL_PAUSED", (const char *)ename) == 0) { return AL_PAUSED; }
	if (strcmp("AL_STOPPED", (const char *)ename) == 0) { return AL_STOPPED; }
	if (strcmp("AL_BUFFERS_QUEUED", (const char *)ename) == 0) { return AL_BUFFERS_QUEUED; }
	if (strcmp("AL_BUFFERS_PROCESSED", (const char *)ename) == 0) { return AL_BUFFERS_PROCESSED; }
	if (strcmp("AL_FORMAT_MONO8", (const char *)ename) == 0) { return AL_FORMAT_MONO8; }
	if (strcmp("AL_FORMAT_MONO16", (const char *)ename) == 0) { return AL_FORMAT_MONO16; }
	if (strcmp("AL_FORMAT_STEREO8", (const char *)ename) == 0) { return AL_FORMAT_STEREO8; }
	if (strcmp("AL_FORMAT_STEREO16", (const char *)ename) == 0) { return AL_FORMAT_STEREO16; }
	if (strcmp("AL_FREQUENCY", (const char *)ename) == 0) { return AL_FREQUENCY; }
	if (strcmp("AL_SIZE", (const char *)ename) == 0) { return AL_SIZE; }
	if (strcmp("AL_UNUSED", (const char *)ename) == 0) { return AL_UNUSED; }
	if (strcmp("AL_PENDING", (const char *)ename) == 0) { return AL_PENDING; }
	if (strcmp("AL_PROCESSED", (const char *)ename) == 0) { return AL_PROCESSED; }
	if (strcmp("ALC_MAJOR_VERSION", (const char *)ename) == 0) { return ALC_MAJOR_VERSION; }
	if (strcmp("ALC_MINOR_VERSION", (const char *)ename) == 0) { return ALC_MINOR_VERSION; }
	if (strcmp("ALC_ATTRIBUTES_SIZE", (const char *)ename) == 0) { return ALC_ATTRIBUTES_SIZE; }
	if (strcmp("ALC_ALL_ATTRIBUTES", (const char *)ename) == 0) { return ALC_ALL_ATTRIBUTES; }
	if (strcmp("ALC_DEFAULT_DEVICE_SPECIFIER", (const char *)ename) == 0) { return ALC_DEFAULT_DEVICE_SPECIFIER; }
	if (strcmp("ALC_DEVICE_SPECIFIER", (const char *)ename) == 0) { return ALC_DEVICE_SPECIFIER; }
	if (strcmp("ALC_EXTENSIONS", (const char *)ename) == 0) { return ALC_EXTENSIONS; }
	if (strcmp("ALC_FREQUENCY", (const char *)ename) == 0) { return ALC_FREQUENCY; }
	if (strcmp("ALC_REFRESH", (const char *)ename) == 0) { return ALC_REFRESH; }
	if (strcmp("ALC_SYNC", (const char *)ename) == 0) { return ALC_SYNC; }
	if (strcmp("AL_NO_ERROR", (const char *)ename) == 0) { return AL_NO_ERROR; }
	if (strcmp("AL_INVALID_NAME", (const char *)ename) == 0) { return AL_INVALID_NAME; }
	if (strcmp("AL_INVALID_ENUM", (const char *)ename) == 0) { return AL_INVALID_ENUM; }
	if (strcmp("AL_INVALID_VALUE", (const char *)ename) == 0) { return AL_INVALID_VALUE; }
	if (strcmp("AL_INVALID_OPERATION", (const char *)ename) == 0) { return AL_INVALID_OPERATION; }
	if (strcmp("AL_OUT_OF_MEMORY", (const char *)ename) == 0) { return AL_OUT_OF_MEMORY; }
	if (strcmp("ALC_NO_ERROR", (const char *)ename) == 0) { return ALC_NO_ERROR; }
	if (strcmp("ALC_INVALID_DEVICE", (const char *)ename) == 0) { return ALC_INVALID_DEVICE; }
	if (strcmp("ALC_INVALID_CONTEXT", (const char *)ename) == 0) { return ALC_INVALID_CONTEXT; }
	if (strcmp("ALC_INVALID_ENUM", (const char *)ename) == 0) { return ALC_INVALID_ENUM; }
	if (strcmp("ALC_INVALID_VALUE", (const char *)ename) == 0) { return ALC_INVALID_VALUE; }
	if (strcmp("ALC_OUT_OF_MEMORY", (const char *)ename) == 0) { return ALC_OUT_OF_MEMORY; }
	if (strcmp("AL_VENDOR", (const char *)ename) == 0) { return AL_VENDOR; }
	if (strcmp("AL_VERSION", (const char *)ename) == 0) { return AL_VERSION; }
	if (strcmp("AL_RENDERER", (const char *)ename) == 0) { return AL_RENDERER; }
	if (strcmp("AL_EXTENSIONS", (const char *)ename) == 0) { return AL_EXTENSIONS; }
	if (strcmp("AL_DOPPLER_FACTOR", (const char *)ename) == 0) { return AL_DOPPLER_FACTOR; }
	if (strcmp("AL_DOPPLER_VELOCITY", (const char *)ename) == 0) { return AL_DOPPLER_VELOCITY; }
	if (strcmp("AL_DISTANCE_MODEL", (const char *)ename) == 0) { return AL_DISTANCE_MODEL; }
	if (strcmp("AL_INVERSE_DISTANCE", (const char *)ename) == 0) { return AL_INVERSE_DISTANCE; }
	if (strcmp("AL_INVERSE_DISTANCE_CLAMPED", (const char *)ename) == 0) { return AL_INVERSE_DISTANCE_CLAMPED; }
	
	return -1;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALubyte * ALAPIENTRY alGetString (ALenum pname)
{
#if LOG_API_USAGE
	DebugMessage("alGetString called");
#endif

	switch (pname)
	{
		case AL_VENDOR:
			return (ALubyte *)alVendor;
		case AL_VERSION:
			return (ALubyte *)alVersion;
		case AL_RENDERER:
			return (ALubyte *)alRenderer;
		case AL_EXTENSIONS:
			return (ALubyte *)alExtensions;
		case AL_NO_ERROR:
			return (ALubyte *)alNoError;
		case AL_INVALID_NAME:
			return (ALubyte *)alErrInvalidName;
		case AL_INVALID_ENUM:
			return (ALubyte *)alErrInvalidEnum;
		case AL_INVALID_VALUE:
			return (ALubyte *)alErrInvalidValue;
		case AL_INVALID_OPERATION:
			return (ALubyte *)alErrInvalidOp;
		case AL_OUT_OF_MEMORY:
			return (ALubyte *)alErrOutOfMemory;
		default:
			alSetError(AL_INVALID_ENUM);
			break;
	}
	return NULL;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALfloat ALAPIENTRY alGetFloat (ALenum pname)
{
	Float32			returnValue = 0.0f;

#if LOG_API_USAGE
	DebugMessage("alGetFloat called");
#endif

	try {
        if (gOALContextMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);
            
        OALContext		*oalContext = gOALContextMap->Get(gCurrentContext);
        if (oalContext == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        switch (pname)
        {
            case AL_DOPPLER_FACTOR:
                returnValue = oalContext->GetDopplerFactor();
                break;
            case AL_DOPPLER_VELOCITY:
                returnValue = oalContext->GetDopplerVelocity();
                break;
            default:
                break;
        }
	}
	catch (OSStatus		result) {
 		DebugMessageN1("alGetFloat Failed - err = %ld\n", result);
        alSetError(result);
    }
	catch (...) {
 		DebugMessage("alGetFloat Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
	}
	
	return (returnValue);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALboolean ALAPIENTRY alIsExtensionPresent(ALubyte *extName)
{
#if LOG_API_USAGE
	DebugMessage("alIsExtensionPresent called");
#endif

    return AL_FALSE;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ALAPI ALvoid ALAPIENTRY alDeleteEnvironmentIASIG (ALsizei n, ALuint *environments)
{
#if LOG_API_USAGE
	DebugMessage("***** alDeleteEnvironmentIASIG called");
#endif
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alDisable (ALenum capability)
{
#if LOG_API_USAGE
	DebugMessage("***** alDisable called");
#endif
	switch (capability)
	{
		case ALC_CONVERT_DATA_UPON_LOADING:
			gConvertBufferNow = false;
			break;
		default:
			alSetError(AL_INVALID_VALUE);
			break;
	}
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alDistanceScale (ALfloat value)
{
#if LOG_API_USAGE
	DebugMessage("***** alDistanceScale called");
#endif

	if (value > 0.0f)
	{
		// gDistanceScale = value;
	} 
    else
	{
		alSetError(AL_INVALID_VALUE);
	}
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alEnable (ALenum capability)
{
#if LOG_API_USAGE
	DebugMessage("***** alEnable called");
#endif
	switch(capability)
	{
		case ALC_CONVERT_DATA_UPON_LOADING:
			gConvertBufferNow = true;
			break;
		default:
			alSetError(AL_INVALID_VALUE);
			break;
	}
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alEnviromentiIASIG (ALuint environment, ALenum pname, ALint value)
{
#if LOG_API_USAGE
	DebugMessage("***** alEnviromentiIASIG called");
#endif
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alEnvironmentfIASIG (ALuint environment, ALenum pname, ALfloat value)
{
#if LOG_API_USAGE
	DebugMessage("***** alEnvironmentfIASIG called");
#endif
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALsizei ALAPIENTRY alGenEnvironmentIASIG (ALsizei n, ALuint *environments)
{
#if LOG_API_USAGE
	DebugMessage("***** alGenEnvironmentIASIG called");
#endif
	return 0;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALboolean ALAPIENTRY alGetBoolean (ALenum pname)
{
#if LOG_API_USAGE
	DebugMessage("***** alGetBoolean called");
#endif
	return AL_FALSE;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetBooleanv (ALenum pname, ALboolean *data)
{
#if LOG_API_USAGE
	DebugMessage("***** alGetBooleanv called");
#endif
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALdouble ALAPIENTRY alGetDouble (ALenum pname)
{
#if LOG_API_USAGE
	DebugMessage("***** alGetDouble called");
#endif

    double      returnValue = 0.0;

	try {
        if (gOALDeviceMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALDevice	*oalDevice = gOALDeviceMap->Get(gCurrentDevice);
        if (oalDevice == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

		switch (pname)
		{			
			case ALC_MIXER_OUTPUT_RATE:
				returnValue = (ALdouble) oalDevice->GetMixerRate();
				break;
			
			default:
				alSetError(AL_INVALID_VALUE);
				break;
		}
	}
	catch (OSStatus		result) {
 		DebugMessageN1("alGetDouble Failed - err = %ld\n", result);
        alSetError(result);
    }
	catch (...) {
 		DebugMessage("alGetDouble Failed");
        alSetError(AL_INVALID_OPERATION);   // by default
	}
	
	return (returnValue);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetDoublev (ALenum pname, ALdouble *data)
{
#if LOG_API_USAGE
	DebugMessage("***** alGetDoublev called");
#endif
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSetInteger (ALenum pname, ALint value)
{	
#if LOG_API_USAGE
	DebugMessage("***** alSetIntegeri called");
#endif
	try {
        if (gOALDeviceMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALDevice	*oalDevice = gOALDeviceMap->Get(gCurrentDevice);
        if (oalDevice == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

		switch(pname)
		{			
			case ALC_SPATIAL_RENDERING_QUALITY:
				oalDevice->SetRenderQuality ((UInt32) value);
				break;

			case ALC_RENDER_CHANNEL_COUNT:
				oalDevice->SetRenderChannelCount ((UInt32) value);
				break;

            case ALC_MIXER_MAXIMUM_BUSSES:
                gMaximumMixerBusCount = value;
                break;
			
			default:
				alSetError(AL_INVALID_VALUE);
				break;
		}
	}
	catch (OSStatus		result) {
 		DebugMessageN1("alSetInteger Failed - err = %ld\n", result);
        alSetError(result);
    }
	catch (...) {
 		DebugMessage("alSetInteger Failed");
		alSetError(AL_INVALID_OPERATION); 
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alSetDouble (ALenum pname, ALdouble value)
{	
#if LOG_API_USAGE
	DebugMessage("***** alSetDouble called");
#endif
	try {
        if (gOALDeviceMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALDevice	*oalDevice = gOALDeviceMap->Get(gCurrentDevice);
        if (oalDevice == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

		switch (pname)
		{			
			case ALC_MIXER_OUTPUT_RATE:
				oalDevice->SetMixerRate ((Float64) value);
				break;
			
			default:
				alSetError(AL_INVALID_VALUE);
				break;
		}
	}
	catch (OSStatus		result) {
 		DebugMessageN1("alSetDouble Failed - err = %ld\n", result);
        alSetError(result);
    }
	catch (...) {
 		DebugMessage("alSetDouble Failed");
		alSetError(AL_INVALID_OPERATION); 
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALint ALAPIENTRY alGetInteger (ALenum pname)
{
#if LOG_API_USAGE
	DebugMessage("***** alGetInteger called");
#endif

	UInt32		returnValue	= 0;

	try {
        if (gOALDeviceMap == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

        OALDevice	*oalDevice = gOALDeviceMap->Get(gCurrentDevice);
        if (oalDevice == NULL)
            throw ((OSStatus) AL_INVALID_OPERATION);

		switch (pname)
		{
			case ALC_SPATIAL_RENDERING_QUALITY:
                returnValue = oalDevice->GetRenderQuality();
				break;

			case ALC_RENDER_CHANNEL_COUNT:
                returnValue = oalDevice->GetRenderChannelCount();
				break;
                
            case ALC_MIXER_MAXIMUM_BUSSES:
                returnValue = oalDevice->GetBusCount();
                break;
			
			default:
				alSetError(AL_INVALID_VALUE);
				break;
		}
	}
	catch (OSStatus		result) {
 		DebugMessageN1("alGetInteger Failed - err = %ld\n", result);
        // special case this property for now, it can return a valid value if there is no device open
        if (pname == ALC_MIXER_MAXIMUM_BUSSES)
            returnValue = gMaximumMixerBusCount;
        else
			alSetError(AL_INVALID_OPERATION); // not available yet as the device is not setup
    }
	catch (...) {
 		DebugMessage("alGetInteger Failed");
        // special case this property for now, it can return a valid value if there is no device open
        if (pname == ALC_MIXER_MAXIMUM_BUSSES)
            returnValue = gMaximumMixerBusCount;
        else
			alSetError(AL_INVALID_OPERATION); // not available yet as the device is not setup
	}
	
	return (returnValue);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alGetListeneri( ALenum pname, ALint* value )
{
#if LOG_API_USAGE
	DebugMessage("***** alGetListeneri called");
#endif

	*value = 0;

	try {
		switch (pname)
		{
			default:
				alSetError(AL_INVALID_VALUE);
				break;
		}
	}
	catch (...) {
 		DebugMessage("alGetListeneri Failed");
        alSetError(AL_INVALID_OPERATION); // not available yet as the device is not setup
	}
	
	return;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid * ALAPIENTRY alGetProcAddress(ALubyte *fname)
{
#if LOG_API_USAGE
	DebugMessage("***** alGetProcAddress called");
#endif
	return NULL;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALboolean ALAPIENTRY alIsEnabled(ALenum capability)
{
#if LOG_API_USAGE
	DebugMessage("***** alIsEnabled called");
#endif
	switch(capability)
	{
		case ALC_CONVERT_DATA_UPON_LOADING:
			return (gConvertBufferNow);
			break;
		default:
			break;
	}
	return (false);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALboolean ALAPIENTRY alIsEnvironmentIASIG (ALuint environment)
{
#if LOG_API_USAGE
	DebugMessage("***** alIsEnvironmentIASIG called");
#endif
	return AL_FALSE;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alListeneri (ALenum pname, ALint value)
{		
#if LOG_API_USAGE
	DebugMessage("***** alListeneri called");
#endif
	alSetError(AL_INVALID_ENUM);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alPropagationSpeed (ALfloat value)
{
#if LOG_API_USAGE
	DebugMessage("***** alPropagationSpeed called");
#endif
	if (value > 0.0f)
	{
		// gPropagationSpeed = value;
	} 
    else
	{
        alSetError(AL_INVALID_VALUE);
	}
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alQueuef (ALuint source, ALenum param, ALfloat value)
{
#if LOG_API_USAGE
	DebugMessage("***** alQueuef called");
#endif
	if (alIsSource(source))
	{
		switch(param) 
		{
			case AL_PITCH:
				if ((value>=0.5f)&&(value<=2.0f))
				{	
					// ***** gSource[source].pitch = value;
				}
				else
					alSetError(AL_INVALID_VALUE);
				break;
			case AL_GAIN:
				if (value <= 1.0f)
				{
					// ***** smSetSourceVolume (source, (value * kFullVolume), (value * kFullVolume));
				}	
				break;
			default:
				alSetError(AL_INVALID_OPERATION);
				break;
		}
	} 
    else
	{
		alSetError(AL_INVALID_NAME);
	}
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ALAPI ALvoid ALAPIENTRY alQueuei (ALuint source, ALenum param, ALint value)
{
#if LOG_API_USAGE
	DebugMessage("***** alQueuei called");
#endif
}