/*
 * OpenAL Test
 *
 * Copyright (C) 1999-2000 by authors.
 * This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the
 *  Free Software Foundatio n, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA  02111-1307, USA.
 * Or go to http://www.gnu.org/copyleft/lgpl.html
 */

/** notes for gendocs.py
 OpenAL Test Notes

 If there are any core OpenAL API shortcomings exposed by these
 tests at the code level, they are marked in this codebase by
 a comment string "*** API Issue ***".

 There are three classes of tests supported by this program:

    1) Fully Automated Testing
         These tests run entirely by themseves and require no
       user input.
    2) Semi-Automated Testing
         These tests require some analysis by the user. 
    3) Interactive Testing
         These tests allow a user to create their own OpenAL
       scenarios.

 To find the menu in the code, search for the string 
 "*** Main Menu ***".
  */

#define INITGUID
#define OPENAL

#define TEST_VORBIS 0	// enable for ogg vorbis testing
//#define TEST_EAX	1   // enable for EAX testing

#ifdef _WIN32
#include <windows.h>	// For timeGetTime()
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <al/al.h>
#include <al/alc.h>
#include <al/alut.h>
#endif // _WIN32

#ifdef LINUX
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <memory.h>
#include <math.h>
#ifndef __USE_BSD
#define __USE_BSD
#endif
#include <unistd.h>
#include <sys/stat.h>

#ifdef OSX_FRAMEWORK
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#include <OpenAL/alut.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alut.h>
#endif

#ifndef AL_INVALID_ENUM
#define AL_INVALID_ENUM AL_ILLEGAL_ENUM
#endif

#ifndef AL_INVALID_OPERATION
#define AL_INVALID_OPERATION AL_ILLEGAL_COMMAND
#endif

#endif // LINUX

#ifdef __MACOS__
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <memory.h>
#include <math.h>
#include <string.h>
#include <al.h>
#include <alc.h>
#include <alut.h>
#include <eax.h>
#include <Timer.h>
#define SWAPBYTES
#endif // MACOS

#ifdef MAC_OS_X
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <memory.h>
#include <math.h>
#include <string.h>
#include <openal/al.h>
#include <openal/alc.h>
#include <openal/alut.h>
#include <unistd.h>
#define SWAPBYTES
#endif // MAC_OS_X

#if TEST_VORBIS
#include <AL/alext.h>
#include <AL/alexttypes.h>
#endif

#if TEST_EAX
#include <eax.h>
#endif

#define NUM_BUFFERS 8	// Number of buffers to be Generated

#ifndef LINUX
#ifndef MAC_OS_X
#pragma pack (push,1) 							/* Turn off alignment */
#endif
#endif

typedef struct
{
	ALchar		riff[4];		// 'RIFF'
	ALsizei		riffSize;
	ALchar		wave[4];		// 'WAVE'
	ALchar		fmt[4];			// 'fmt '
	ALuint		fmtSize;
	ALushort	Format;                              
	ALushort	Channels;
	ALuint		SamplesPerSec;
	ALuint		BytesPerSec;
	ALushort	BlockAlign;
	ALushort	BitsPerSample;
	ALchar		data[4];		// 'data'
	ALuint		dataSize;
} WAVE_Struct;

#pragma pack (push,1)
typedef struct
{
	char			szRIFF[4];
	long			lRIFFSize;
	char			szWave[4];
	char			szFmt[4];
	long			lFmtSize;
	WAVEFORMATEX	wfex;
	char			szData[4];
	long			lDataSize;
} WAVEHEADER;
#pragma pack (pop)

#define QUEUEBUFFERSIZE		2048
#define QUEUEBUFFERCOUNT	4

typedef struct ALenum_struct
{
	ALchar		*enumName;
	ALenum		value;
} ALenums;

#ifndef LINUX
#ifndef MAC_OS_X
#pragma pack (pop)   
#endif
#endif

// Global variables
ALuint	g_Buffers[NUM_BUFFERS];		// Array of Buffers

#if TEST_EAX
EAXSet	eaxSet;						// EAXSet function, retrieved if EAX Extension is supported
EAXGet	eaxGet;						// EAXGet function, retrieved if EAX Extension is supported
ALboolean g_bEAX;					// Boolean variable to indicate presence of EAX Extension 
#endif
#if TEST_VORBIS
#define AL_FORMAT_VORBIS_EXT 0x10003
unsigned int g_ovSize;
#endif

static ALenums enumeration[]={
	// Types
	{ (ALchar *)"AL_INVALID",                           AL_INVALID                          },
	{ (ALchar *)"ALC_INVALID",						    ALC_INVALID							},
	{ (ALchar *)"AL_NONE",							    AL_NONE								},
	{ (ALchar *)"AL_FALSE",							    AL_FALSE							},
	{ (ALchar *)"ALC_FALSE",						    ALC_FALSE							},
	{ (ALchar *)"AL_TRUE",							    AL_TRUE								},
	{ (ALchar *)"ALC_TRUE",							    ALC_TRUE							},
	
	// Source and Listener Properties
	{ (ALchar *)"AL_SOURCE_RELATIVE",				    AL_SOURCE_RELATIVE					},
	{ (ALchar *)"AL_CONE_INNER_ANGLE",				    AL_CONE_INNER_ANGLE					},
	{ (ALchar *)"AL_CONE_OUTER_ANGLE",				    AL_CONE_OUTER_ANGLE					},
	{ (ALchar *)"AL_PITCH",							    AL_PITCH							},
	{ (ALchar *)"AL_POSITION",						    AL_POSITION							},
	{ (ALchar *)"AL_DIRECTION",						    AL_DIRECTION						},
	{ (ALchar *)"AL_VELOCITY",						    AL_VELOCITY							},
	{ (ALchar *)"AL_LOOPING",						    AL_LOOPING							},
	{ (ALchar *)"AL_BUFFER",						    AL_BUFFER							},
	{ (ALchar *)"AL_GAIN",							    AL_GAIN								},
	{ (ALchar *)"AL_MIN_GAIN",						    AL_MIN_GAIN							},
	{ (ALchar *)"AL_MAX_GAIN",						    AL_MAX_GAIN							},
	{ (ALchar *)"AL_ORIENTATION",					    AL_ORIENTATION						},
	{ (ALchar *)"AL_REFERENCE_DISTANCE",			    AL_REFERENCE_DISTANCE				},
	{ (ALchar *)"AL_ROLLOFF_FACTOR",				    AL_ROLLOFF_FACTOR					},
	{ (ALchar *)"AL_CONE_OUTER_GAIN",				    AL_CONE_OUTER_GAIN					},
	{ (ALchar *)"AL_MAX_DISTANCE",					    AL_MAX_DISTANCE						},
	{ (ALchar *)"AL_SEC_OFFSET",                        AL_SEC_OFFSET                       },
	{ (ALchar *)"AL_SAMPLE_OFFSET",                     AL_SAMPLE_OFFSET                    },
	{ (ALchar *)"AL_BYTE_OFFSET",                       AL_BYTE_OFFSET                      },
	{ (ALchar *)"AL_SOURCE_TYPE",                       AL_SOURCE_TYPE                      },
	{ (ALchar *)"AL_STATIC",                            AL_STATIC                           },
	{ (ALchar *)"AL_STREAMING",                         AL_STREAMING                        },
	{ (ALchar *)"AL_UNDETERMINED",                      AL_UNDETERMINED                     },

	// Source State information
	{ (ALchar *)"AL_SOURCE_STATE",					    AL_SOURCE_STATE						},
	{ (ALchar *)"AL_INITIAL",						    AL_INITIAL							},
	{ (ALchar *)"AL_PLAYING",						    AL_PLAYING							},
	{ (ALchar *)"AL_PAUSED",						    AL_PAUSED							},
	{ (ALchar *)"AL_STOPPED",						    AL_STOPPED							},

	// Queue information
	{ (ALchar *)"AL_BUFFERS_QUEUED",				    AL_BUFFERS_QUEUED					},
	{ (ALchar *)"AL_BUFFERS_PROCESSED",				    AL_BUFFERS_PROCESSED				},
	
	// Buffer Formats
	{ (ALchar *)"AL_FORMAT_MONO8",					    AL_FORMAT_MONO8						},
	{ (ALchar *)"AL_FORMAT_MONO16",					    AL_FORMAT_MONO16					},
	{ (ALchar *)"AL_FORMAT_STEREO8",				    AL_FORMAT_STEREO8					},
	{ (ALchar *)"AL_FORMAT_STEREO16",				    AL_FORMAT_STEREO16					},

	// Buffer attributes
	{ (ALchar *)"AL_FREQUENCY",						    AL_FREQUENCY						},
	{ (ALchar *)"AL_BITS",						        AL_BITS								},
	{ (ALchar *)"AL_CHANNELS",					        AL_CHANNELS							},
	{ (ALchar *)"AL_SIZE",							    AL_SIZE								},
	{ (ALchar *)"AL_DATA",						        AL_DATA								},

	// Buffer States (not supported yet)
	{ (ALchar *)"AL_UNUSED",						    AL_UNUSED							},
	{ (ALchar *)"AL_PENDING",						    AL_PENDING							},
	{ (ALchar *)"AL_PROCESSED",						    AL_PROCESSED						},

	// ALC Properties
	{ (ALchar *)"ALC_MAJOR_VERSION",				    ALC_MAJOR_VERSION					},
	{ (ALchar *)"ALC_MINOR_VERSION",				    ALC_MINOR_VERSION					},
	{ (ALchar *)"ALC_ATTRIBUTES_SIZE",				    ALC_ATTRIBUTES_SIZE					},
	{ (ALchar *)"ALC_ALL_ATTRIBUTES",				    ALC_ALL_ATTRIBUTES					},
	{ (ALchar *)"ALC_DEFAULT_DEVICE_SPECIFIER",		    ALC_DEFAULT_DEVICE_SPECIFIER		},
	{ (ALchar *)"ALC_DEVICE_SPECIFIER",				    ALC_DEVICE_SPECIFIER				},
	{ (ALchar *)"ALC_EXTENSIONS",					    ALC_EXTENSIONS						},
	{ (ALchar *)"ALC_FREQUENCY",					    ALC_FREQUENCY						},
	{ (ALchar *)"ALC_REFRESH",						    ALC_REFRESH							},
	{ (ALchar *)"ALC_SYNC",							    ALC_SYNC							},
	{ (ALchar *)"ALC_MONO_SOURCES",                     ALC_MONO_SOURCES                    },
	{ (ALchar *)"ALC_STEREO_SOURCES",                   ALC_STEREO_SOURCES                  },
	{ (ALchar *)"ALC_CAPTURE_DEVICE_SPECIFIER",         ALC_CAPTURE_DEVICE_SPECIFIER        },
	{ (ALchar *)"ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER", ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER },
    { (ALchar *)"ALC_CAPTURE_SAMPLES",                  ALC_CAPTURE_SAMPLES                 },

	// AL Error Messages
	{ (ALchar *)"AL_NO_ERROR",						    AL_NO_ERROR							},
	{ (ALchar *)"AL_INVALID_NAME",					    AL_INVALID_NAME						},
	{ (ALchar *)"AL_INVALID_ENUM",					    AL_INVALID_ENUM						},
	{ (ALchar *)"AL_INVALID_VALUE",					    AL_INVALID_VALUE					},
	{ (ALchar *)"AL_INVALID_OPERATION",				    AL_INVALID_OPERATION				},
	{ (ALchar *)"AL_OUT_OF_MEMORY",					    AL_OUT_OF_MEMORY					},
	
	// ALC Error Message
	{ (ALchar *)"ALC_NO_ERROR",						    ALC_NO_ERROR						},
	{ (ALchar *)"ALC_INVALID_DEVICE",				    ALC_INVALID_DEVICE					},
	{ (ALchar *)"ALC_INVALID_CONTEXT",				    ALC_INVALID_CONTEXT					},
	{ (ALchar *)"ALC_INVALID_ENUM",					    ALC_INVALID_ENUM					},
	{ (ALchar *)"ALC_INVALID_VALUE",				    ALC_INVALID_VALUE					},
	{ (ALchar *)"ALC_OUT_OF_MEMORY",				    ALC_OUT_OF_MEMORY					},

	// Context strings
	{ (ALchar *)"AL_VENDOR",						    AL_VENDOR							},
	{ (ALchar *)"AL_VERSION",						    AL_VERSION							},
	{ (ALchar *)"AL_RENDERER",						    AL_RENDERER							},
	{ (ALchar *)"AL_EXTENSIONS",					    AL_EXTENSIONS						},
	
	// Global states
	{ (ALchar *)"AL_DOPPLER_FACTOR",				    AL_DOPPLER_FACTOR					},
	{ (ALchar *)"AL_DOPPLER_VELOCITY",				    AL_DOPPLER_VELOCITY					},
	{ (ALchar *)"AL_DISTANCE_MODEL",				    AL_DISTANCE_MODEL					},
	{ (ALchar *)"AL_SPEED_OF_SOUND",                    AL_SPEED_OF_SOUND                   },
	
	// Distance Models
	{ (ALchar *)"AL_INVERSE_DISTANCE",				    AL_INVERSE_DISTANCE					},
	{ (ALchar *)"AL_INVERSE_DISTANCE_CLAMPED",		    AL_INVERSE_DISTANCE_CLAMPED			},
	{ (ALchar *)"AL_LINEAR_DISTANCE",				    AL_LINEAR_DISTANCE					},
	{ (ALchar *)"AL_LINEAR_DISTANCE_CLAMPED",		    AL_LINEAR_DISTANCE_CLAMPED			},
	{ (ALchar *)"AL_EXPONENT_DISTANCE",				    AL_EXPONENT_DISTANCE			    },
	{ (ALchar *)"AL_EXPONENT_DISTANCE_CLAMPED",		    AL_EXPONENT_DISTANCE_CLAMPED	    },

	// Default
	{ (ALchar *)NULL,								(ALenum  ) 0 						} };

// Function prototypes
void delay_ms(unsigned int ms);
ALvoid DisplayALError(ALbyte *szText, ALint errorcode);

#ifdef LINUX
ALvoid DisplayALError(const char *text, ALint errorcode);
#endif

char getUpperCh(void);
int CRToContinue(void);
void CRForNextTest(void);
int ContinueOrSkip(void);
ALvoid FullAutoTests(ALvoid);
ALvoid SemiAutoTests(ALvoid);

#ifdef __MACOS__
void ALTestSwapWords(unsigned int *puint);
void ALTestSwapBytes(unsigned short *pshort);
#endif
#ifdef MAC_OS_X
void ALTestSwapWords(unsigned int *puint);
void ALTestSwapBytes(unsigned short *pshort);
#endif

// Test Function prototypes
ALvoid I_PositionTest(ALvoid);
ALvoid I_LoopingTest(ALvoid);
ALvoid I_QueueTest(ALvoid);
ALvoid I_BufferTest(ALvoid);
ALvoid I_FreqTest(ALvoid);
ALvoid I_StereoTest(ALvoid);
ALvoid I_GainTest(ALvoid);
ALvoid I_StreamingTest(ALvoid);
ALvoid I_MultipleSourcesTest(ALvoid);
ALvoid I_SourceRelativeTest(ALvoid);
ALvoid I_SourceRolloffTest(ALvoid);
ALvoid I_ADPCMTest(ALvoid);
ALvoid I_VelocityTest(ALvoid);
ALvoid I_GetSourceOffsetTest(ALvoid);
ALvoid I_SetSourceOffsetTest(ALvoid);
ALvoid I_DistanceModelTest(ALvoid);
ALvoid I_CaptureTest(ALvoid);
ALvoid I_CaptureAndPlayTest(ALvoid);
ALvoid FA_RequestObjectNames(ALvoid);
ALvoid FA_ReleaseObjectNames(ALvoid);
ALvoid FA_ValidateObjectNames(ALvoid);
ALvoid FA_StateTransition(ALvoid);
ALvoid FA_VectorStateTransition(ALvoid);
ALvoid FA_GetBufferProperties(ALvoid);
ALvoid FA_EnumerationValue(ALvoid);
ALvoid FA_QueuingUnderrunStates(ALvoid);
ALvoid SA_StringQueries(ALvoid);
ALvoid SA_SourceGain(ALvoid);
ALvoid SA_ListenerGain(ALvoid);
ALvoid SA_Position(ALvoid);
ALvoid SA_SourceRelative(ALvoid);
ALvoid SA_ListenerOrientation(ALvoid);
ALvoid SA_SourceCone(ALvoid);
ALvoid SA_MinMaxGain(ALvoid);
ALvoid SA_ReferenceDistance(ALvoid);
ALvoid SA_RolloffFactor(ALvoid);
ALvoid SA_DistanceModel(ALvoid);
ALvoid SA_Doppler(ALvoid);
ALvoid SA_Frequency(ALvoid);
ALvoid SA_Stereo(ALvoid);
ALvoid SA_Streaming(ALvoid);
ALvoid SA_QueuingUnderrunPerformance(ALvoid);

#if TEST_VORBIS
ALvoid I_VorbisTest(ALvoid);
#endif

#if TEST_EAX
ALvoid I_EAXTest(ALvoid);
#endif

/*
	delay_ms -- delay by given number of milliseconds
*/
void delay_ms(unsigned int ms)
{
#ifdef __MACOS__
	UnsignedWide endTime, currentTime;
	
	Microseconds(&currentTime);
	endTime = currentTime;
	endTime.lo += ms * 1000;
	
	while (endTime.lo > currentTime.lo)
	{
		Microseconds(&currentTime);
	}
#endif
#ifdef MAC_OS_X
	usleep(ms * 1000);
#endif
#ifdef LINUX
	usleep(ms * 1000);
#endif   
#ifdef _WIN32
	int startTime;
	startTime = timeGetTime();
	while ((startTime + ms) > timeGetTime());
#endif
}

/*
	Display AL Error message
*/
ALvoid DisplayALError(ALchar *szText, ALint errorcode)
{
	printf("%s%s\n",szText,alGetString(errorcode));
	return;
}

/*
	Loads the wave file into the given Buffer ID
*/
ALboolean LoadWave(char *szWaveFile, ALuint BufferID)
{
	ALint	error;
	ALsizei size,freq;
	ALenum	format;
	ALvoid	*data;
	ALboolean loop;

	if (!szWaveFile)
		return AL_FALSE;

	alutLoadWAVFile(szWaveFile,&format,&data,&size,&freq,&loop);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		printf("Failed to load %s\n", szWaveFile);
		DisplayALError("alutLoadWAVFile : ", error);
		return AL_FALSE;
	}

	// Copy data into ALBuffer
	alBufferData(BufferID,format,data,size,freq);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError("alBufferData : ", error);
		return AL_FALSE;
	}

	// Unload wave file
	alutUnloadWAV(format,data,size,freq);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError("alutUnloadWAV : ", error);
		return AL_FALSE;
	}

	return AL_TRUE;
}

/*
	Main application - Initializes Open AL, Sets up Listener, Generates Buffers, and loads in audio data.
	Displays Test Menu and calls appropriate Test functions.  On exit, buffers are destroyed and Open AL
	is shutdown.

	Each Test function is responsible for creating and destroying whatever Sources they require. All test
	applications use the same set of Buffers (created in this function).
*/
int main(int argc, char* argv[])
{
	ALbyte	ch;
	ALint	error;
#ifndef LINUX
    ALCcontext *Context;
#else
    ALvoid *Context;
#endif
	ALCdevice *Device;
	ALfloat listenerPos[]={0.0,0.0,0.0};
	ALfloat listenerVel[]={0.0,0.0,0.0};
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};	// Listener facing into the screen

#if TEST_EAX
	ALchar szFnName[128];
	ALchar szEAX[] = "EAX";
#endif	


	printf("OpenAL Test Application\n");
	printf("=======================\n\n");

	// Initialize Open AL manually
	//Open device
	char deviceName[256];
	char *defaultDevice;
	char *deviceList;
	char *devices[12];
	int numDevices, numDefaultDevice, i;

	strcpy(deviceName, "");
	if (alcIsExtensionPresent(NULL, (ALchar*)"ALC_ENUMERATION_EXT") == AL_TRUE) { // try out enumeration extension
		defaultDevice = (char *)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
		if (defaultDevice != NULL) {
			deviceList = (char *)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
			if (deviceList != NULL) {
				for (numDevices = 0; numDevices < 12; numDevices++) {devices[numDevices] = NULL;}
				for (numDevices = 0; numDevices < 12; numDevices++) {
					devices[numDevices] = deviceList;
					if (strcmp(devices[numDevices], defaultDevice) == 0) {
						numDefaultDevice = numDevices;
					}
					deviceList += strlen(deviceList);
					if (deviceList[0] == 0) {
						if (deviceList[1] == 0) {
							break;
						} else {
							deviceList += 1;
						}
					}
				}
				if (devices[numDevices] != NULL) {
					numDevices++;
					printf("\nEnumeration extension found -- select an output device:\n");
					printf("0. NULL Device (Default)\n");
					for (i = 0; i < numDevices; i++) {
						printf("%d. %s\n", i + 1, devices[i]);
					}
					printf("\n\n");
					do {
						ch = getUpperCh();
						i = atoi((char *)&ch);
					} while ((i < 0) || (i > numDevices));
					if ((i != 0) && (strlen(devices[i-1]) < 256)) {
						strcpy(deviceName, devices[i-1]);
					}
				}
			}
		}
	}

	if (strlen(deviceName) == 0) {
		Device = alcOpenDevice(NULL); // this is supposed to select the "preferred device"
	} else {
		Device = alcOpenDevice((ALchar*)deviceName); // have a name from enumeration process above, so use it...
	}
	//Create context(s)
	Context=alcCreateContext(Device,NULL);
	//Set active context
	alcMakeContextCurrent(Context);

	// Clear Error Codes
	alGetError();
	alcGetError(Device);

	// Check what version of Open AL we are using
	ALint major, minor;
	alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major);
	alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor);
	printf("\nOpen AL Version %d.%d\n", major, minor);

	// Check for all the AL 1.1 Extensions (they may be present on AL 1.0 implementations too)
	ALboolean bOffsetExt = alIsExtensionPresent("al_ext_offset");
	if (bOffsetExt)
		printf("AL_EXT_OFFSET support found !\n");

	ALboolean bNewDistModels = AL_TRUE;
	bNewDistModels &= alIsExtensionPresent("AL_EXT_LINEAR_DISTANCE");
	bNewDistModels &= alIsExtensionPresent("AL_EXT_EXPONENT_DISTANCE");
	if (bNewDistModels)
		printf("AL_EXT_LINEAR_DISTANCE and AL_EXT_EXPONENT_DISTANCE support found !\n");
	
	ALboolean bCaptureExt = alcIsExtensionPresent(Device, "alc_EXT_capTure");
	if (bCaptureExt)
		printf("ALC_EXT_CAPTURE support found !\n");

	// Set Listener attributes

	// Position ...
	alListenerfv(AL_POSITION,listenerPos);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alListenerfv POSITION : ", error);
		exit(-1);
	}

	// Velocity ...
	alListenerfv(AL_VELOCITY,listenerVel);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alListenerfv VELOCITY : ", error);
		exit(-1);
	}

	// Orientation ...
	alListenerfv(AL_ORIENTATION,listenerOri);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alListenerfv ORIENTATION : ", error);
		exit(-1);
	}

	// Generate Buffers
	alGenBuffers(NUM_BUFFERS, g_Buffers);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alGenBuffers :", error);
		exit(-1);
	}

	// Load in samples to be used by Test functions
	if ((!LoadWave("footsteps.wav", g_Buffers[0])) ||
		(!LoadWave("ding.wav", g_Buffers[1])) ||
		(!LoadWave("wave1.wav", g_Buffers[2])) ||
		(!LoadWave("wave2.wav", g_Buffers[3])) ||
		(!LoadWave("wave3.wav", g_Buffers[4])) ||
		(!LoadWave("wave4.wav", g_Buffers[5])) ||
		(!LoadWave("stereo.wav", g_Buffers[6])))
	{
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

#if TEST_VORBIS
	void *ovdata;	

	FILE *fh;
	fh = fopen("boom.ogg", "rb");
	if (fh != NULL) {
#ifndef _WIN32
		struct stat sbuf;
		if (stat("boom.ogg", &sbuf) != -1) {
#else
		struct _stat sbuf;
		if (_fstat(fh->_file, &sbuf) != -1) {
#endif
			g_ovSize = sbuf.st_size;
			ovdata = malloc(g_ovSize);

		        if (ovdata != NULL) {
				fread(ovdata, 1, g_ovSize, fh);

			        // Copy boom.ogg data into AL Buffer 7
				alGetError();
				alBufferData(g_Buffers[7], AL_FORMAT_VORBIS_EXT, ovdata, g_ovSize, freq);
				error = alGetError();
				if (error != AL_NO_ERROR) {
					DisplayALError((ALbyte *) "alBufferData buffer 7 : ", error);
				}
			        free(ovdata);
			}				 
			fclose(fh);
		}	   
	}
#endif

#if TEST_EAX
	// Check for EAX extension
	g_bEAX = alIsExtensionPresent(szEAX);

        if (g_bEAX)
		printf("EAX Extensions available\n");

	sprintf((char*)szFnName, "EAXSet");

	eaxSet = (EAXSet)alGetProcAddress(szFnName);

	if (eaxSet == NULL)
		g_bEAX = false;

	sprintf((char*)szFnName,"EAXGet");

	eaxGet = (EAXGet)alGetProcAddress(szFnName);

	if (eaxGet == NULL)
		g_bEAX = false;
#endif

	/* *** Main Menu *** */
	do
	{
		printf("\n\n\nAutomated Test Series:\n\n");
		printf("A) Run Fully Automated Tests\n");
		printf("B) Run Semi-Automated Tests\n");
		printf("\nInteractive Tests:\n\n");
		printf("1) Position Test\n");
		printf("2) Looping Test\n");
		printf("3) Queue Test\n");
		printf("4) Buffer Test\n");
		printf("5) Frequency Test\n");
		printf("6) Stereo Test\n");
		printf("7) Gain Test\n");
		printf("8) Streaming Test\n");
		printf("9) Multiple Sources Test\n");
		printf("C) Source Relative Test\n");
		printf("D) Source Rolloff Test\n");
		printf("E) ADPCM Play Test\n");
		printf("F) Velocity Test\n");
		printf("G) Get Source Offset Test\n");
		printf("H) Set Source Offset Test\n");
		printf("I) Distance Model Test\n");
		printf("J) Capture Test\n");
		printf("K) Capture and Play Test\n");
#if TEST_EAX
		printf("L) EAX Test\n");
#endif
#if TEST_VORBIS
		printf("M) Ogg Vorbis Test\n");
#endif
		printf("\nQ) to quit\n\n\n");

		ch = getUpperCh();

		switch (ch)
		{
			case 'A':
				FullAutoTests();
				break;
			case 'B':
				SemiAutoTests();
				break;
			case '1':
				I_PositionTest();
				break;
			case '2':
				I_LoopingTest();
				break;
			case '3':
				I_QueueTest();
				break;
			case '4':
				I_BufferTest();
				break;
			case '5':
				I_FreqTest();
				break;
			case '6':
				I_StereoTest();
				break;
			case '7':
				I_GainTest();
				break;
			case '8':
				I_StreamingTest();
				break;
			case '9':
				I_MultipleSourcesTest();
				break;
    		case 'C':
	    		I_SourceRelativeTest();
		    	break;
    		case 'D':
 	    		I_SourceRolloffTest();
		    	break;
    		case 'E':
	    		I_ADPCMTest();
		    	break;
    		case 'F':
	    		I_VelocityTest();
		    	break;
    		case 'G':
	    		I_GetSourceOffsetTest();
		    	break;
    		case 'H':
	    		I_SetSourceOffsetTest();
		    	break;
    		case 'I':
	    		I_DistanceModelTest();
		    	break;
    		case 'J':
	    		I_CaptureTest();
		    	break;
    		case 'K':
	    		I_CaptureAndPlayTest();
		    	break;
#if TEST_EAX
			case 'L':
				if (g_bEAX)
					I_EAXTest();
				break;
#endif
#if TEST_VORBIS
		    case 'M':
		        I_VorbisTest();
		        break;
#endif
			default:
				break;
		}
	} while (ch != 'Q');

	alGetError(); // clear error state
	alDeleteBuffers(NUM_BUFFERS, g_Buffers);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alDeleteBuffers : ", error);
		exit(-1);
	}

	//Get active context
	Context=alcGetCurrentContext();
	//Get device for active context
	Device=alcGetContextsDevice(Context);
	//Release context(s)
	alcDestroyContext(Context);
	//Close device
	alcCloseDevice(Device);

	printf("\nProgram Terminated\n");
	
	return 0;
}


/*
 	Fully Automatic Tests
*/
ALvoid FullAutoTests(ALvoid)
{	
	FA_RequestObjectNames();  // Request Object Names
	FA_ReleaseObjectNames();  // Release Object Names
	FA_ValidateObjectNames();  // Validating Object Names
	FA_StateTransition();  // State Transistion Testing
	FA_VectorStateTransition();  // Vector State Transistion Testing
	FA_GetBufferProperties();  // Get Buffer Properties
	FA_EnumerationValue(); // Enumeration Value Test
	FA_QueuingUnderrunStates(); // test underrun while queuing

	printf("\n\n");
	delay_ms(1000);
}

char getUpperCh(void)
{
	char ch;
	
#ifdef _WIN32
	ch = _getch();
#else
	int bs;
	ch = '\0';
	bs = getchar();
	while (bs != 10)
	{
		ch = bs;
		bs = getchar();
	}
#endif

 	ch = toupper(ch);
 		
 	return ch;
 }

int CRToContinue()
{
	ALchar ch = 0;
	ALchar lastchar = 0;
	
	do 
	{ 
		lastchar = ch;
		ch = getchar(); 
	} while (ch != 10);
	
	return lastchar;
}

void CRForNextTest()
{   
	printf("\nPress Return to continue on to the next test.\n");	

	CRToContinue();
}

int ContinueOrSkip()
{
    ALchar ch;
    
	printf("\nPress Return to run this test, or 'S' to skip:\n");	

	while (1)
	{
		ch = CRToContinue();
		if ((ch == 'S') || (ch == 's'))
		{
			return 0;
		} 
		if (ch == 0)
		{
			return 1;
		}
	}
}

/*
 	Semi Automatic Tests
*/
ALvoid SemiAutoTests(ALvoid)
{
	SA_StringQueries();  // String Queries Test
	SA_SourceGain();  // Source Gain Test
	SA_ListenerGain();  // Listener Gain Test
	SA_Position();  // Position Test
	SA_SourceRelative();  // Source Relative Test
	SA_ListenerOrientation();  // Listener Orientation Test
	SA_SourceCone();  // Source Cone Test
	SA_MinMaxGain();  // MIN/MAX Gain Test
	SA_ReferenceDistance();  // Reference Distance Test
	SA_RolloffFactor();  // Rolloff Factor Test
	SA_DistanceModel();  // Distance Model Test
	SA_Doppler();  // Doppler Test
	SA_Frequency();  // Frequency Test
	SA_Stereo();  // Stereo Test
	SA_Streaming(); // Streaming Test
	SA_QueuingUnderrunPerformance(); // test underrun performance

	printf("\nDone with this series of tests. Going back to the main menu...");
	delay_ms(1000);
}


/** used by gendocs.py
$SECTION Fully Automatic Tests
$SUBTITLE Request Object Names
This test checks that OpenAL responds correctly to the creation of either
zero or -1 objects.  The two object types are Buffers and Sources.  When
zero objects are requested, the call should be the equivalent of a NOP.
when -1 objects are requested, an AL_INVALID_VALUE error should be generated.
*/
ALvoid FA_RequestObjectNames(ALvoid)
{
	bool localResultOK;
	ALuint testSources[4], testBuffers[4];
	ALint error;

	printf("\nRequest Object Names Test. ");
	alGetError(); // clear error state
	localResultOK = true;
	alGenBuffers(0, testBuffers); // should be equivalent to NOP
	error = alGetError();
	if (error != AL_NO_ERROR)
	{
		localResultOK = false;
	}
	alGenSources(0, testSources); // should be equivalent to NOP
	error = alGetError();
	if (error != AL_NO_ERROR)
	{
		localResultOK = false;
	}
	alGenBuffers((ALuint)-1, testBuffers); // invalid -- make sure error code comes back
	error = alGetError();
	if (error == AL_NO_ERROR)
	{
		localResultOK = false;
	}
	alGenSources((ALuint)-1, testSources); // invalid -- make sure error code comes back
	error = alGetError();
	if (error == AL_NO_ERROR)
	{
		localResultOK = false;
	}
	if (localResultOK == true)
	{
		printf("PASSED.");
	} else
	{
		printf("FAILED.");
	}
}

/** used by gendocs.py
$SECTION Fully Automatic Tests
$SUBTITLE Release Object Names
This test checks that OpenAL responds correctly to the deletion of -1 objects.
The two object types are Buffers and Sources.  When -1 objects are requested, an
AL_INVALID_VALUE error should be generated.
*/
ALvoid FA_ReleaseObjectNames (ALvoid)
{
	bool localResultOK;
	ALuint testSources[4], testBuffers[4];
	ALint error;

	printf("\nReleasing Object Names Test. ");
	alGetError();
	localResultOK = true;
	alDeleteBuffers((ALuint)-1, testBuffers); // invalid -- make sure error code comes back
	error = alGetError();
	if (error == AL_NO_ERROR)
	{
		localResultOK = false;
	}
	alDeleteSources((ALuint)-1, testSources); // invalid -- make sure error code comes back
	error = alGetError();
	if (error == AL_NO_ERROR)
	{
		localResultOK = false;
	}
	if (localResultOK == true)
	{
		printf("PASSED.");
	} else
	{
		printf("FAILED.");
	}
}
	
/** used by gendocs.py
$SECTION Fully Automatic Tests
$SUBTITLE Validating Object Names
This test checks that OpenAL can test the validity of a source or buffer.  A
check is made on valid objects for a positive result, and a check is made on
invalid objects to confirm a negative result.
*/
ALvoid FA_ValidateObjectNames (ALvoid)
{
	bool localResultOK;
	ALuint testSources[4], testBuffers[4];
	ALint error;

	printf("\nValidating Object Names Test. ");
	alGetError();
	localResultOK = true;
	alGenBuffers(1, testBuffers);
	alGenSources(1, testSources);
	error = alGetError();
	if (error != AL_NO_ERROR)
	{
		localResultOK = false;
	} else
	{
		if (alIsBuffer(testBuffers[0]) == AL_FALSE) // this buffer should test as valid
		{
			localResultOK = false;
		}
		if (alIsSource(testSources[0]) == AL_FALSE) // this source should test as valid
		{
			localResultOK = false;
		}
		if (alIsBuffer(testBuffers[0] + 1) == AL_TRUE) // this buffer should be invalid
		{
			localResultOK = false;
		}
		if (alIsSource(testSources[0] + 1) == AL_TRUE) // this source should be invalid
		{
			localResultOK = false;
		}
		alDeleteBuffers(1, testBuffers);
		alDeleteSources(1, testSources);
	}
	if (localResultOK == true)
	{
		printf("PASSED.");
	} else
	{
		printf("FAILED.");
	}
}

/** used by gendocs.py
$SECTION Fully Automatic Tests
$SUBTITLE State Transition Testing
This test checks that OpenAL can monitor the state of a source properly.  The
source is tested to make sure it can run through all its possible states --
AL_INITIAL, AL_PLAYING, AL_PAUSED, and AL_STOPPED.
*/
ALvoid FA_StateTransition (ALvoid)
{
	bool localResultOK;
	ALuint testSources[4];

	printf("\nState Transition Test. ");
	alGetError();
	localResultOK = true;
	alGenSources(1, testSources);
	alSourcei(testSources[0], AL_BUFFER, g_Buffers[0]);
	alSourcei(testSources[0], AL_LOOPING, AL_TRUE);
	ALint sourceState;
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_INITIAL)
	{
		localResultOK = false;
	}
	alSourcePlay(testSources[0]);
	delay_ms(500);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_PLAYING)
	{
		localResultOK = false;
	}
	alSourcePause(testSources[0]);
	delay_ms(500);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_PAUSED)
	{
		localResultOK = false;
	}
	alSourcePlay(testSources[0]);
	delay_ms(500);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_PLAYING)
	{
		localResultOK = false;
	}
	alSourceStop(testSources[0]);
	delay_ms(500);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_STOPPED)
	{
		localResultOK = false;
	}
	if (localResultOK == true)
	{
		printf("PASSED.");
	} else
	{
		printf("FAILED.");
	}
	alDeleteSources(1, testSources);
}

/** used by gendocs.py
$SECTION Fully Automatic Tests
$SUBTITLE Vector State Transition Testing
This test checks that OpenAL can monitor the state of multiple sources which
are being controlled using vectors.  The sources are tested to make sure
they properly run through all its possible states -- AL_INITIAL, AL_PLAYING,
AL_PAUSED, and AL_STOPPED.
*/	
ALvoid FA_VectorStateTransition (ALvoid)
{
	bool localResultOK;
	ALuint testSources[4];
	ALenum sourceState;

	printf("\nVector State Transition Test. ");
	alGetError();
	localResultOK = true;
	alGenSources(2, testSources);
	alSourcei(testSources[0], AL_BUFFER, g_Buffers[0]);
	alSourcei(testSources[1], AL_BUFFER, g_Buffers[1]);
	alSourcei(testSources[0], AL_LOOPING, AL_TRUE);
	alSourcei(testSources[1], AL_LOOPING, AL_TRUE);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_INITIAL)
	{
		localResultOK = false;
		printf("FAILED -- AL_INITIAL 0");
	}
	alGetSourcei(testSources[1], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_INITIAL)
	{
		localResultOK = false;
		printf("FAILED -- AL_INITIAL 1");
	}
	alSourcePlayv(2, &testSources[0]);
	delay_ms(500);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_PLAYING)
	{
		localResultOK = false;
		printf("FAILED -- AL_PLAYING 0");
	}
	alGetSourcei(testSources[1], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_PLAYING)
	{
		localResultOK = false;
		printf("FAILED -- AL_PLAYING 1");
	}
	alSourcePausev(2, &testSources[0]);
	delay_ms(500);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_PAUSED)
	{
		localResultOK = false;
		printf("FAILED -- AL_PAUSED 0");
	}
	alGetSourcei(testSources[1], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_PAUSED)
	{
		localResultOK = false;
		printf("FAILED -- AL_PAUSED 1");
	}
	alSourcePlayv(2, &testSources[0]);
	delay_ms(500);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_PLAYING)
	{
		localResultOK = false;
		printf("FAILED -- AL_PLAYING 0A");
	}
	alGetSourcei(testSources[1], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_PLAYING)
	{
		localResultOK = false;
		printf("FAILED -- AL_PLAYING 1A");
	}
	alSourceStopv(2, &testSources[0]);
	delay_ms(500);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_STOPPED)
	{
		localResultOK = false;
		printf("FAILED -- AL_STOPPED 0");
	}
	alGetSourcei(testSources[1], AL_SOURCE_STATE, &sourceState);
	if (sourceState != AL_STOPPED)
	{
		localResultOK = false;
		printf("FAILED -- AL_STOPPED 1");
	}
	if (localResultOK == true)
	{
		printf("PASSED.");
	} else
	{
		printf("FAILED.");
	}
	alDeleteSources(2, testSources);
}


/** used by gendocs.py
$SECTION Fully Automatic Tests
$SUBTITLE Get Buffer Properties Test
This test checks that OpenAL can retrieve buffer properties properly.
*/
ALvoid FA_GetBufferProperties(ALvoid)
{
	ALint freq, size;
	ALboolean passNULL;

	printf("\nGet Buffer Properties Test. ");
	alGetBufferi(g_Buffers[0], AL_FREQUENCY, &freq);
	alGetBufferi(g_Buffers[0], AL_SIZE, &size);
	
	passNULL = alIsBuffer(0);  // the NULL buffer should cause alIsBuffer to be TRUE (non-annotated 1.0 spec, pg 26)

	if ((freq == 44100) && (size == 282626) && (passNULL == AL_TRUE))
	{
		printf("PASSED.");
	} else
	{
		printf("FAILED.");
	}
}


/** used by gendocs.py
$SECTION Fully Automatic Tests
$SUBTITLE Enumeration Value Test
This test checks that the implementation's enumeration values are correct.
*/
ALvoid FA_EnumerationValue(ALvoid)
{
	bool result = true;
	int i = 0;
	int getVal;

	printf("\nEnumeration Value Test. ");

	while (enumeration[i].enumName)
	{
		getVal = alGetEnumValue(enumeration[i].enumName);
		if (getVal != enumeration[i].value)
		{
			printf("\n%s has an invalid enum value.", enumeration[i].enumName);
			result = false;
		}
		i++;
	}
	
	if (result == true)
	{
		printf("PASSED.");
	} else
	{
		printf("FAILED.");
	}
}


/** used by gendocs.py
$SECTION Fully Automatic Tests
$SUBTITLE Queuing Underrun States
This test checks that OpenAL handles state progressions properly during a streaming underrun.
*/
ALvoid FA_QueuingUnderrunStates(ALvoid)
{
	ALuint testSources[1];
	ALuint bufferName;
	ALuint error;
	ALint tempInt;
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};
	bool localResultOK;

	printf("\nQueuing Underrun States Test. ");
	localResultOK = true;
	alGetError();
	alGenSources(1, testSources);
	alSourcei(testSources[0], AL_BUFFER, 0);
	alSourcei(testSources[0], AL_LOOPING, AL_FALSE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "Init error : ", error);
	alSourceQueueBuffers(testSources[0], 1, &g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR) localResultOK = false;
	alSourcePlay(testSources[0]);
	delay_ms(1000);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &tempInt);
	if (tempInt != AL_STOPPED) localResultOK = false;
	alGetSourcei(testSources[0], AL_BUFFERS_PROCESSED, &tempInt);
	if (tempInt != 1)
	{
		localResultOK = false;
	} else
	{
		alSourceUnqueueBuffers(testSources[0], tempInt, &bufferName);
	}
	alSourceQueueBuffers(testSources[0], 1, &g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR) localResultOK = false;
	alSourcePlay(testSources[0]);
	delay_ms(100);
	alGetSourcei(testSources[0], AL_SOURCE_STATE, &tempInt);
	if (tempInt != AL_PLAYING) localResultOK = false;
		
	// cleanup
	alSourcei(testSources[0], AL_BUFFER, 0);
	alDeleteSources(1, testSources);
	
	// display result
	if (localResultOK == true)
	{
		printf("PASSED.");
	} else
	{
		printf("FAILED.");
	}
}



/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE String Queries Test
This test outputs the renderer, version #, vendor, and extensions string so that
the user can confirm that the string values are correct.
*/	
ALvoid SA_StringQueries(ALvoid)
{
	printf("String Queries Test:");
	if (ContinueOrSkip())
	{
		printf("Check that the following values are reasonable:\n");

		const ALchar *tempString;

		ALCcontext* pContext;
		ALCdevice* pDevice;
		pContext = alcGetCurrentContext();
		pDevice = alcGetContextsDevice(pContext);
		tempString = alcGetString(pDevice, ALC_DEVICE_SPECIFIER);
		printf("OpenAL Context Device Specifier is '%s'\n", tempString);
		tempString = alGetString(AL_RENDERER);
		printf("OpenAL Renderer is '%s'\n", tempString);
		tempString = alGetString(AL_VERSION);
		printf("OpenAL Version is '%s'\n", tempString);
		tempString = alGetString(AL_VENDOR);
		printf("OpenAL Vendor is '%s'\n", tempString);
		tempString = alGetString(AL_EXTENSIONS);
		printf("OpenAL Extensions supported are :\n%s\n", tempString);
		printf("\nError Codes are :-\n");
		printf("AL_NO_ERROR : '%s'\n", tempString = alGetString(AL_NO_ERROR));

#ifdef LINUX
		printf("AL_ILLEGAL_ENUM : '%s'\n", tempString = alGetString(AL_ILLEGAL_ENUM));
#else
// ***** FIXME ***** warning: Check the spec: pretty sure INVALID_ENUM changed to ILLEGAL_ENUM
		printf("AL_INVALID_ENUM : '%s'\n", tempString = alGetString(AL_INVALID_ENUM));
#endif
		printf("AL_INVALID_VALUE : '%s'\n", tempString = alGetString(AL_INVALID_VALUE));

#ifdef LINUX
		printf("AL_ILLEGAL_COMMAND: '%s'\n", tempString = alGetString(AL_ILLEGAL_COMMAND));
#else
// ***** FIXME ***** warning Check the spec: pretty sure INVALID_OPERATION changed to ILLEGAL_COMMAND
		printf("AL_INVALID_OPERATION : '%s'\n", tempString = alGetString(AL_INVALID_OPERATION));
#endif
		printf("AL_OUT_OF_MEMORY : '%s'\n", tempString = alGetString(AL_OUT_OF_MEMORY));
		CRForNextTest();
	}
}



/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Source Gain Test
This test outputs a source at multiple gain values for testing by the user.
*/	
ALvoid SA_SourceGain(ALvoid)
{
	ALuint testSources[2];
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("Source Gain Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("The following sound effect will be played at full source gain (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0],AL_GAIN,1.0f);
		alSourcePlay(testSources[0]);
		printf("The following sound effect will be played at half source gain (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0],AL_GAIN,0.5f);
		alSourcePlay(testSources[0]);
		printf("The following sound effect will be played at quarter source gain (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0],AL_GAIN,0.25f);
		alSourcePlay(testSources[0]);
		printf("The following sound effect will be played at 1/20th source gain (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0],AL_GAIN,0.05f);
		alSourcePlay(testSources[0]);
		CRForNextTest();
		alSourcef(testSources[0],AL_GAIN,1.0f); 
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	}
}



/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Listener Gain Test
This test outputs a source at a fixed gain level, and tests various listener gain levels.
*/
ALvoid SA_ListenerGain(ALvoid)
{	
	ALuint testSources[2];
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("Listener Gain Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("The following sound effect will be played at full listener gain (Press Return):\n");
		CRToContinue();
		alListenerf(AL_GAIN,1.0f);
		alSourcePlay(testSources[0]);
		printf("The following sound effect will be played at half listener gain (Press Return):\n");
		CRToContinue();
		alListenerf(AL_GAIN,0.5f);
		alSourcePlay(testSources[0]);
		printf("The following sound effect will be played at quarter listener gain (Press Return):\n");
		CRToContinue();
		alListenerf(AL_GAIN,0.25f);
		alSourcePlay(testSources[0]);
		printf("The following sound effect will be played at 1/20th listener gain (Press Return):\n");
		CRToContinue();
		alListenerf(AL_GAIN,0.05f);
		alSourcePlay(testSources[0]);
		CRForNextTest();
		alListenerf(AL_GAIN,1.0f);
		float f;
		alGetListenerf(AL_GAIN, &f);
		if (f != 1.0) { printf("ERROR:  alGetListenerf failed.\n"); }
		alSourceStop(testSources[0]);
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	} 
}
	

/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Position Test
This tests various source/listener positions, as well as the AL_POSITION get functions.
*/	
ALvoid SA_Position(ALvoid)
{
	ALuint testSources[2];
	int i;
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};
	ALfloat tempFVect[6];

	printf("Position Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, 0.0);
	
		printf("Trying Left-to-Right sweep by moving listener(Press Return):\n");
		CRToContinue();
		alSourcei(testSources[0], AL_LOOPING, true);
		alListener3f(AL_POSITION, 100.0, 0.0, 0.0);
		alGetListener3f(AL_POSITION, &tempFVect[0], &tempFVect[1], &tempFVect[2]);
		if ((tempFVect[0] != 100.0) || (tempFVect[1] != 0.0) || (tempFVect[2] != 0.0))
		{
			printf("ERROR: alGetListener3f(AL_POSITION, ...).\n");
		}
		alGetListenerfv(AL_POSITION, tempFVect);
		if ((tempFVect[0] != 100.0) || (tempFVect[1] != 0.0) || (tempFVect[2] != 0.0))
		{
			printf("ERROR: alGetListenerfv(AL_POSITION, ...).\n");
		}
		alSourcePlay(testSources[0]);
		for (i = -100; i < 100; i++)
		{
			alListener3f(AL_POSITION, (float) -i, 0.0, 0.0);		
			delay_ms(100);
		}
		alListener3f(AL_POSITION, 0.0, 0.0, 0.0);
		alSourceStop(testSources[0]);
		printf("Trying Left-to-Right sweep by moving source (Press Return):\n");
		CRToContinue();
		alSourcei(testSources[0], AL_LOOPING, true);
		alSource3f(testSources[0], AL_POSITION, -100.0, 0.0, 0.0);
		alSourcePlay(testSources[0]);
		for (i = -100; i < 100; i++)
		{
			alSource3f(testSources[0], AL_POSITION, (float) i, 0.0, 0.0);		
			delay_ms(100);
		}
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, 0.0);
		alSourceStop(testSources[0]);
		printf("Trying Back-to-Front sweep (Press Return):\n");
		CRToContinue();
		alSourcei(testSources[0], AL_LOOPING, true);
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -100.0);
		alGetSource3f(testSources[0], AL_POSITION, &tempFVect[0], &tempFVect[1], &tempFVect[2]);
		if ((tempFVect[0] != 0.0) || (tempFVect[1] != 0.0) || (tempFVect[2] != -100.0))
		{
			printf("ERROR: alGetSource3f(..., AL_POSITION, ...).\n");
		}
		alGetSourcefv(testSources[0], AL_POSITION, tempFVect);
		if ((tempFVect[0] != 0.0) || (tempFVect[1] != 0.0) || (tempFVect[2] != -100.0))
		{
			printf("ERROR: alGetSourcefv(..., AL_POSITION, ...).\n");
		}
		alSourcePlay(testSources[0]);
		for (i = -100; i < 100; i++)
		{
			alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, (float) -i);		
			delay_ms(100);
		}
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, 0.0);
		alSourceStop(testSources[0]);
		CRForNextTest(); 
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	}
}
	

/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Source Relative Test
This tests the source relative mode.
*/	
ALvoid SA_SourceRelative(ALvoid)
{
	ALuint testSources[2];
	int i;
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("Source Relative Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
		
		printf("Placing Listener at (100, 0, 0) and sweeping source from (0, 0, 0) to (100, 0, 0).  The sound should pan from left to center (Press Return):\n");
		CRToContinue();
		alListener3f(AL_POSITION, 100.0, 0.0, 0.0);
		alListenerfv(AL_ORIENTATION, listenerOri);
		alSourcei(testSources[0], AL_LOOPING, true);
		alSource3f(testSources[0], AL_POSITION, -10.0, 0.0, 0.0);
		alSourcePlay(testSources[0]);
		for (i = 00; i < 100; i++)
		{
			alSource3f(testSources[0], AL_POSITION, (float) i, 0.0, 0.0);
			delay_ms(100);
		}
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, 0.0);
		alSourceStop(testSources[0]);

		printf("Turning on source relative mode, placing Listener at (100, 0, 0), and sweeping source from (0, 0, 0) to (100, 0, 0).  The sound should pan from center to right (Press Return):\n");
		CRToContinue();
		alSourcei(testSources[0], AL_SOURCE_RELATIVE, AL_TRUE);
		alSourcei(testSources[0], AL_LOOPING, true);
		alSource3f(testSources[0], AL_POSITION, -100.0, 0.0, 0.0);
		alSourcePlay(testSources[0]);
		for (i = 0; i < 100; i++)
		{
			alSource3f(testSources[0], AL_POSITION, (float) i, 0.0, 0.0);
			delay_ms(100);
		}

		alListener3f(AL_POSITION, 0.0, 0.0, 0.0);
		alSourcei(testSources[0], AL_SOURCE_RELATIVE, AL_FALSE);
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, 0.0);
		alSourceStop(testSources[0]);
		CRForNextTest(); 
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	}
}


/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Listener Orientation Test
This test moves and orients the listener around a fixed source.
*/
ALvoid SA_ListenerOrientation (ALvoid)
{	
	ALuint testSources[2];
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("Listener Orientation Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("The listener will be placed at (1, 0, 0) and will face the -X direction.  The sound should be centered. (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, 0.0);
		alListenerf(AL_GAIN,1.0f);
		float f;
		alGetSourcef(testSources[0], AL_GAIN, &f);
		if (f != 1.0) { printf("ERROR: alGetSourcef(..., AL_GAIN, ...).\n"); }
		alListener3f(AL_POSITION, 1.0, 0.0, 0.0);
		listenerOri[0]=-1.0;
		listenerOri[1]=0.0;
		listenerOri[2]=0.0;
		listenerOri[3]=0.0;
		listenerOri[4]=1.0;
		listenerOri[5]=0.0;
		alListenerfv(AL_ORIENTATION, listenerOri);
		alSourcei(testSources[0], AL_LOOPING, true);
		alSourcePlay(testSources[0]);
		delay_ms(4000);
		alSourceStop(testSources[0]);
		
		printf("The listener will now be oriented down the -Z axis.  The sound should be to the left. (Press Return):\n");
		CRToContinue();
		listenerOri[0]=0.0;
		listenerOri[1]=0.0;
		listenerOri[2]=-1.0;
		listenerOri[3]=0.0;
		listenerOri[4]=1.0;
		listenerOri[5]=0.0;
		alListenerfv(AL_ORIENTATION, listenerOri);
		alSourcePlay(testSources[0]);
		delay_ms(4000);
		alSourceStop(testSources[0]);
		
		printf("The listener will now be turned upside-down (the 'up' direction will be (0, -1, 0)).  The sound should be to the right. (Press Return):\n");
		CRToContinue();
		listenerOri[0]=0.0;
		listenerOri[1]=0.0;
		listenerOri[2]=-1.0;
		listenerOri[3]=0.0;
		listenerOri[4]=-1.0;
		listenerOri[5]=0.0;
		alListenerfv(AL_ORIENTATION, listenerOri);
		alSourcePlay(testSources[0]);
		delay_ms(4000);
		alSourceStop(testSources[0]);
		
		printf("The listener will now be oriented down the +Z axis (and the 'up' direction is now (0, 1, 0) again).  The sound should be to the right. (Press Return):\n");
		CRToContinue();
		listenerOri[0]=0.0;
		listenerOri[1]=0.0;
		listenerOri[2]=1.0;
		listenerOri[3]=0.0;
		listenerOri[4]=1.0;
		listenerOri[5]=0.0;
		alListenerfv(AL_ORIENTATION, listenerOri);
		alSourcePlay(testSources[0]);
		delay_ms(4000);
		alSourceStop(testSources[0]);

	        printf("The listener will now be oriented down the +Y axis and with a +Z 'up' vector.  The sound should be to the left. (Press Return):\n");
		CRToContinue();
		listenerOri[0]=0.0;
		listenerOri[1]=1.0;
		listenerOri[2]=0.0;
		listenerOri[3]=0.0;
		listenerOri[4]=0.0;
		listenerOri[5]=1.0;
		alListenerfv(AL_ORIENTATION, listenerOri);
		alSourcePlay(testSources[0]);
		delay_ms(4000);
		alSourceStop(testSources[0]);

	        printf("The listener will now be oriented down the -Y axis and with a +Z 'up' vector.  The sound should be to the right. (Press Return):\n");
		CRToContinue();
		listenerOri[0]=0.0;
		listenerOri[1]=-1.0;
		listenerOri[2]=0.0;
		listenerOri[3]=0.0;
		listenerOri[4]=0.0;
		listenerOri[5]=1.0;
		alListenerfv(AL_ORIENTATION, listenerOri);
		alSourcePlay(testSources[0]);
		delay_ms(4000);
		alSourceStop(testSources[0]);

		CRForNextTest();
		alListenerf(AL_GAIN,1.0f);
		alListener3f(AL_POSITION, 0.0, 0.0, 0.0);
		listenerOri[0]=0.0;
		listenerOri[1]=0.0;
		listenerOri[2]=-1.0;
		listenerOri[3]=0.0;
		listenerOri[4]=1.0;
		listenerOri[5]=0.0;
		alListenerfv(AL_ORIENTATION, listenerOri);
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	} 
}


/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Source Cone Test
This test exercises source cones.
*/
ALvoid SA_SourceCone (ALvoid)
{	
	ALuint testSources[2];
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};
	ALfloat	sourceDir[]={0.0,0.0,1.0};
	ALfloat	sourceDir2[]={1.0,0.0,1.0};
	ALfloat	sourceDir3[]={0.0,0.0,-1.0};

	printf("Source Cone Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("The listener will be at (0,0,0).  The source will be at (0,0,-1).  The source will be directly facing the listener and should be loud. (Press Return):\n");
		CRToContinue();
		alListener3f(AL_POSITION, 0.0, 0.0, 0.0);
		alListenerfv(AL_ORIENTATION, listenerOri);
		alSourcef(testSources[0], AL_CONE_INNER_ANGLE, 10.0);
		alSourcef(testSources[0], AL_CONE_OUTER_ANGLE, 270.0);
		alSourcef(testSources[0], AL_CONE_OUTER_GAIN, (float)0.01);
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -1.0);
		alSourcefv(testSources[0], AL_DIRECTION, sourceDir);
		alSourcePlay(testSources[0]);
		
		printf("The source will now point between the inner and outer cones, and should be at medium volume. (Press Return):\n");
		CRToContinue();
		alSourcefv(testSources[0], AL_DIRECTION, sourceDir2);
		alSourcePlay(testSources[0]);

		printf("The source will now point behind the outer cone and will be at low volume. (Press Return):\n");
		CRToContinue();
		alSourcefv(testSources[0], AL_DIRECTION, sourceDir3);
		alSourcePlay(testSources[0]);
		
		CRForNextTest();
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	} 
}


/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE MIN/MAX Gain Test
This test checks if minimum and maximum gain settings are working.
*/
ALvoid SA_MinMaxGain(ALvoid)
{	
	ALuint testSources[2];
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("MIN/MAX Gain Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("The source will be played at GAIN 1.0 with MAX gain set to 1.0. This should be high volume. (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0], AL_GAIN, 1.0);
		alSourcef(testSources[0], AL_MAX_GAIN, 1.0);
		alSourcei(testSources[0], AL_LOOPING, false);
		alSourcePlay(testSources[0]);

		printf("The source will be played at GAIN 0.1 with MIN gain set to 0.6.  This should be at medium volume. (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0], AL_GAIN, (float) 0.1);
		alSourcef(testSources[0], AL_MIN_GAIN, (float) 0.6);
		alSourcePlay(testSources[0]);
		
		printf("The source will be played at GAIN 1.0 with MAX gain set to 0.1.  This should be low volume. (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0], AL_GAIN, 1.0);
		alSourcef(testSources[0], AL_MAX_GAIN, (float) 0.1);
		alSourcePlay(testSources[0]);
		
		printf("The source will be played at GAIN 0.1 with MIN gain set to 0.0.  This should be low volume. (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0], AL_GAIN, (float) 0.1);
		alSourcef(testSources[0], AL_MIN_GAIN, 0.0);
		alSourcePlay(testSources[0]);

		printf("The source will be played at GAIN 1.0 with MAX gain set to 0.0.  This should be zero volume. (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0], AL_GAIN, (float) 1.0);
		alSourcef(testSources[0], AL_MAX_GAIN, 0.0);
		alSourcePlay(testSources[0]);
		
		CRForNextTest();
		alSourcef(testSources[0], AL_GAIN, 1.0);
		alSourcef(testSources[0], AL_MAX_GAIN, 1.0);
		alSourcef(testSources[0], AL_MIN_GAIN, 0.0);
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	} 
}
		

/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Reference Distance Test
This test exercises a source's reference distance.
*/
ALvoid SA_ReferenceDistance(ALvoid)
{
	ALuint testSources[2];
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("Reference Distance Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("The source will be placed at (0, 0, -10), and the reference distance set at 1.0. This should be low volume. (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -10.0);
		alSourcef(testSources[0], AL_REFERENCE_DISTANCE, 1.0);
		alSourcei(testSources[0], AL_LOOPING, false);
		alSourcePlay(testSources[0]);
		
		printf("The source will be played with the reference distance set to 3.0.  This should be medium volume. (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0], AL_REFERENCE_DISTANCE, 3.0);
		alSourcePlay(testSources[0]);
		
		printf("The source will be played with the reference distance set to 10.0.  This should be high volume. (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0], AL_REFERENCE_DISTANCE, 10.0);
		alSourcePlay(testSources[0]);
		
		CRForNextTest();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, 0.0);
		alSourcef(testSources[0], AL_REFERENCE_DISTANCE, 1.0);
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	} 
}
	

/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Rolloff Factor Test
This test exercises a source's rolloff factor.
*/	
ALvoid SA_RolloffFactor(ALvoid)
{
	ALuint testSources[2];
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("Rolloff Factor Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("The source will be played with the rolloff factor set to 0.0.  This should be high volume. (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -10.0);
		alSourcei(testSources[0], AL_LOOPING, false);
		alSourcef(testSources[0], AL_ROLLOFF_FACTOR, 0.0);
		alSourcePlay(testSources[0]);

		printf("The source will be placed at (0, 0, -10), and the rolloff factor set at 1.0. This should be medium volume. (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0], AL_ROLLOFF_FACTOR, 1.0);
		alSourcePlay(testSources[0]);
		
		printf("The source will be played with the rolloff factor set to 3.0.  This should be low volume. (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0], AL_ROLLOFF_FACTOR, 3.0);
		alSourcePlay(testSources[0]);
		
		printf("The source will be played with the rolloff factor set to 10.0.  This should be very low volume. (Press Return):\n");
		CRToContinue();
		alSourcef(testSources[0], AL_ROLLOFF_FACTOR, 10.0);
		alSourcePlay(testSources[0]);
		
		CRForNextTest();
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	} 
}
	

/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Distance Model Test
This test exercises the three distance models.
*/
ALvoid SA_DistanceModel(ALvoid)
{	
	ALuint testSources[2];
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("Distance Model Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("The source will be placed at (0, 0, -10). This should be low volume. (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -10.0);
		alDistanceModel(AL_INVERSE_DISTANCE);
		alSourcei(testSources[0], AL_LOOPING, false);
		alSourcePlay(testSources[0]);
		
		printf("The source will be placed at (0, 0, -1). This should be high volume. (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -1.0);
		alSourcePlay(testSources[0]);
		
		printf("The source will be placed at (0, 0, -10) and the distance model will be set to AL_NONE. This should be high volume. (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -10.0);
		alDistanceModel(AL_NONE);
		alSourcePlay(testSources[0]);
		
		printf("The source will be placed at (0, 0, -100) and the distance model will remain AL_NONE. This should be high volume. (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -100.0);
		alSourcePlay(testSources[0]);
		
		printf("The source will be placed at (0, 0, -100) and the distance model will be AL_INVERSE_DISTANCE_CLAMPED. AL_MAX_DISTANCE will be set to 100.0.  This should be low volume. (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -100.0);
		alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
		alSourcef(testSources[0], AL_MAX_DISTANCE, 100.0);
		alSourcePlay(testSources[0]);
		
		printf("The source will be placed at (0, 0, -100) and the distance model will be AL_INVERSE_DISTANCE_CLAMPED. AL_MAX_DISTANCE will be set to 20.0.  This should be louder. (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -100.0);
		alSourcef(testSources[0], AL_MAX_DISTANCE, 20.0);
		alSourcePlay(testSources[0]);
		
		printf("The source will be placed at (0, 0, -100) and the distance model will be AL_INVERSE_DISTANCE_CLAMPED. AL_MAX_DISTANCE will be set to 5.0.  This should be high volume. (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, -100.0);
		alSourcef(testSources[0], AL_MAX_DISTANCE, 5.0);
		alSourcePlay(testSources[0]);
		
		CRForNextTest();
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, 0.0);
		alDistanceModel(AL_INVERSE_DISTANCE);
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	} 
}


/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Doppler Test
This tests doppler shift capability.
*/
ALvoid SA_Doppler(ALvoid)
{	
	ALuint testSources[2];
	int i;
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};
	ALfloat	sourceDir[]={1.0,0.0,0.0};

	printf("Doppler Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("Trying Left-to-Right sweep with doppler shift, and the speed of sound at its default setting (Press Return):\n");
		CRToContinue();
		alListenerfv(AL_ORIENTATION, listenerOri);
		alSourcei(testSources[0], AL_LOOPING, true);
		alSource3f(testSources[0], AL_POSITION, -100.0, 0.0, 0.0);
		alSource3f(testSources[0], AL_VELOCITY, 10.0, 0.0, 0.0);
		alSourcefv(testSources[0], AL_DIRECTION, sourceDir);
		alSourcePlay(testSources[0]);
		for (i = -100; i < 100; i++)
		{
			alSource3f(testSources[0], AL_POSITION, (float) i, 0.0, 0.0);		
			delay_ms(100);
		}
		alSourceStop(testSources[0]);
		printf("Trying Left-to-Right sweep with the speed of sound set to 171.7 (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, -100.0, 0.0, 0.0);
		alSource3f(testSources[0], AL_VELOCITY, 10.0, 0.0, 0.0);
		alSpeedOfSound(171.7f);
		if (alGetFloat(AL_SPEED_OF_SOUND) != 171.7f) { printf(" alGetFloat(AL_SPEED_OF_SOUND) error.\n"); }
		alSourcePlay(testSources[0]);
		for (i = -100; i < 100; i++)
		{
			alSource3f(testSources[0], AL_POSITION, (float) i, 0.0, 0.0);		
			delay_ms(100);
		}
		alSourceStop(testSources[0]);
		alDopplerFactor(1.0);
		printf("Trying Left-to-Right sweep with the speed of sound set to 686.6 (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, -100.0, 0.0, 0.0);
		alSource3f(testSources[0], AL_VELOCITY, 10.0, 0.0, 0.0);
		alSpeedOfSound(686.6f);
		if (alGetFloat(AL_SPEED_OF_SOUND) != 686.6f) { printf(" alGetFloat(AL_SPEED_OF_SOUND) error.\n"); }
		alSourcePlay(testSources[0]);
		for (i = -100; i < 100; i++)
		{
			alSource3f(testSources[0], AL_POSITION, (float) i, 0.0, 0.0);		
			delay_ms(100);
		}
		alSourceStop(testSources[0]);
		alDopplerFactor(2.0);
		printf("Trying Left-to-Right sweep with the speed of sound set to 686.6 and doppler factor set to 2.0 (Press Return):\n");
		CRToContinue();
		alSource3f(testSources[0], AL_POSITION, -100.0, 0.0, 0.0);
		alSource3f(testSources[0], AL_VELOCITY, 10.0, 0.0, 0.0);
		alSpeedOfSound(686.6f);
		alSourcePlay(testSources[0]);
		for (i = -100; i < 100; i++)
		{
			alSource3f(testSources[0], AL_POSITION, (float) i, 0.0, 0.0);		
			delay_ms(100);
		}
		alSpeedOfSound(343.3f);
		alDopplerFactor(1.0f);
		alSource3f(testSources[0], AL_POSITION, 0.0, 0.0, 0.0);
		alSourceStop(testSources[0]);
		CRForNextTest();
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	} 
}


/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Frequency Test
This test alters the frequency of a playing source.
*/
ALvoid SA_Frequency(ALvoid)
{	
	ALuint testSources[2];
	float root12 = (float)(pow (2, 1/12.0));
	float increments[15] = { -12, -10, -8, -7, -5, -3, -1, 0,
				 2, 4, 5, 7, 9, 11, 12 };
	int i;
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("Frequency Test:");
	if (ContinueOrSkip())
	{
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("A source will be played fifteen times -- going from one-half to double it's native frequency (Press Return):\n");
		CRToContinue();
		alSourcei(testSources[0], AL_LOOPING, false);
		for (i = 0; i < 15; i++)
		{
			alSourcef(testSources[0], AL_PITCH,
				  (float) (pow (root12, increments[i])));
			alSourcePlay(testSources[0]);
			delay_ms(2000);
		}
		alSourceStop(testSources[0]);
		alSourcef(testSources[0], AL_PITCH, 1.0);
		CRForNextTest();
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	} 
}
	

/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Stereo Test
This test plays a stereo buffer.
*/
ALvoid SA_Stereo(ALvoid)
{	
	ALuint testSources[2];
	ALuint error;
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("Stereo Test:");
	if (ContinueOrSkip())
	{
		// clear error state
		alGetError();
	
		// load up sources
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, g_Buffers[1]);
	
		printf("A stereo buffer will play twice in succession (Press Return):\n");
		CRToContinue();
		alSourcei(testSources[0], AL_BUFFER, 0);
		alSourcei(testSources[0], AL_LOOPING, AL_FALSE);
		if ((error = alGetError()) != AL_NO_ERROR)
			DisplayALError((ALbyte *) "Init error : ", error);
		alSourceQueueBuffers(testSources[0], 1, &g_Buffers[6]);
		if ((error = alGetError()) != AL_NO_ERROR)
			DisplayALError((ALbyte *) "alSourceQueueBuffers 1 (stereo) : ", error);
		alSourceQueueBuffers(testSources[0], 1, &g_Buffers[6]);
		if ((error = alGetError()) != AL_NO_ERROR)
			DisplayALError((ALbyte *) "alSourceQueueBuffers 1 (stereo) : ", error);
		alSourcePlay(testSources[0]);
		CRForNextTest();
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	}
}
		

/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Streaming Test
This test streams audio from a file.
*/
ALvoid SA_Streaming(ALvoid)
{
	printf("Streaming Test:");
	if (ContinueOrSkip())
	{
		printf("A stereo audio file will now be streamed from a file (Press Return):\n");
		CRToContinue();
		I_StreamingTest();
		CRForNextTest();
	}
}


/** used by gendocs.py
$SECTION Semi Automatic Tests
$SUBTITLE Queuing Underrun Performance
This test checks the performance of OpenAL during a buffer underrun.
*/
ALvoid SA_QueuingUnderrunPerformance(ALvoid)
{	
	ALuint testSources[1];
	ALuint bufferName;
	ALuint error;
	ALint tempInt;
	ALfloat	listenerOri[]={0.0,0.0,-1.0, 0.0,1.0,0.0};

	printf("Queuing Underrun Performance Test:");
	if (ContinueOrSkip())
	{
		printf("A stereo buffer will play once, there will be a brief pause, and then the buffer will play again (Press Return):\n");
		CRToContinue();
		alGetError();
		alGenSources(1, testSources);
		alSourcei(testSources[0], AL_BUFFER, 0);
		alSourcei(testSources[0], AL_LOOPING, AL_FALSE);
		if ((error = alGetError()) != AL_NO_ERROR)
			DisplayALError((ALbyte *) "Init error : ", error);
		alSourceQueueBuffers(testSources[0], 1, &g_Buffers[6]);
		if ((error = alGetError()) != AL_NO_ERROR)
			DisplayALError((ALbyte *) "alSourceQueueBuffers 1 (stereo) : ", error);
		alSourcePlay(testSources[0]);
		delay_ms(4000);
		alGetSourcei(testSources[0], AL_SOURCE_STATE, &tempInt);
		if (tempInt != AL_STOPPED)
		    printf("Wrong underrun state -- should be AL_STOPPED. ");
		alGetSourcei(testSources[0], AL_BUFFERS_PROCESSED, &tempInt);
		if (tempInt != 1)
		{
		    printf("Wrong underrun state -- should have one buffer processed. ");
		} else
		{
			alSourceUnqueueBuffers(testSources[0], tempInt, &bufferName);
		}
		alSourceQueueBuffers(testSources[0], 1, &g_Buffers[6]);
		if ((error = alGetError()) != AL_NO_ERROR)
			DisplayALError((ALbyte *) "alSourceQueueBuffers 1 (stereo) : ", error);
		alSourcePlay(testSources[0]);
		delay_ms(3000);
		printf("The stereo buffer will now play twice with no pause (Press Return):\n");
		CRToContinue();
		alSourceQueueBuffers(testSources[0], 1, &g_Buffers[6]);
		alSourcePlay(testSources[0]);
		delay_ms(4000);
		CRForNextTest();
		
		// dispose of sources
		alSourcei(testSources[0], AL_BUFFER, 0);
		alDeleteSources(1, testSources);
	}
}


// Buffer Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Buffer Test
This test allows the user to dynamically attach and unattach different buffers
to a single source.
*/
ALvoid I_BufferTest(ALvoid)
{
	ALuint	source[1];
	ALint	error;
	char ch;

	ALfloat source0Pos[]={ 1.0, 0.0,-1.0};	// Front and right of the listener
	ALfloat source0Vel[]={ 0.0, 0.0, 0.0};
	
	alGenSources(1,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alGenSources 2 : ", error);
		return;
	}

	alSourcef(source[0],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_PITCH : \n", error);

	alSourcef(source[0],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN : \n", error);
	
	alSourcefv(source[0],AL_POSITION,source0Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_POSITION : \n", error);
	
	alSourcefv(source[0],AL_VELOCITY,source0Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_VELOCITY : \n", error);

	alSourcei(source[0],AL_LOOPING,AL_FALSE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING true: \n", error);

	printf("Buffer Test\n");
	printf("Press '1' to play buffer 0 on source 0\n");
	printf("Press '2' to play buffer 1 on source 0\n");
	printf("Press '3' to stop source 0\n");
	printf("Press 'q' to quit\n");

	do
	{
		ch = getUpperCh();
 		
		switch (ch)
		{
			case '1':
				// Stop source
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop 0 : ", error);
				// Attach buffer 0 to source
				alSourcei(source[0], AL_BUFFER, g_Buffers[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei AL_BUFFER 0 : ", error);
				// Play
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay 0 : ", error);
				break;
			case '2':
				// Stop source
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop 0 : ", error);
				// Attach buffer 0 to source
				alSourcei(source[0], AL_BUFFER, g_Buffers[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei AL_BUFFER 1 : ", error);
				// Play
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay 0 : ", error);
				break;
			case '3':
				// Stop source
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop 0 : ", error);
				break;
		}
	} while (ch != 'Q');

	// Release resources
	alSourceStopv(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourceStopv 1 : ", error);

	alDeleteSources(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alDeleteSources 1 : ", error);

	return;
}


// Position Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Position Test
This test creates 2 Sources - one to the front right of the listener, and one to
the rear left of the listener
*/
ALvoid I_PositionTest(ALvoid)
{	
	ALint	error;
	
	ALuint	source[2];
	ALbyte	ch;

	ALfloat source0Pos[]={ -1.0, 0.0, 1.0};	// Behind and to the left of the listener
	ALfloat source0Vel[]={ 0.0, 0.0, 0.0};

	ALfloat source1Pos[]={ 1.0, 0.0,-1.0};	// Front and right of the listener
	ALfloat source1Vel[]={ 0.0, 0.0, 0.0};

	alGenSources(2,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alGenSources 2 : ", error);
		return;
	}
	
	alSourcef(source[0],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_PITCH : \n", error);

	alSourcef(source[0],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN : \n", error);
	
	alSourcefv(source[0],AL_POSITION,source0Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_POSITION : \n", error);
	
	alSourcefv(source[0],AL_VELOCITY,source0Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_VELOCITY : \n", error);

	alSourcei(source[0],AL_BUFFER, g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_BUFFER buffer 0 : \n", error);

	alSourcei(source[0],AL_LOOPING,AL_TRUE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING true: \n", error);


	alSourcef(source[1],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 1 AL_PITCH : \n", error);

	alSourcef(source[1],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 1 AL_GAIN : \n", error);

	alSourcefv(source[1],AL_POSITION,source1Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 1 AL_POSITION : \n", error);

	alSourcefv(source[1],AL_VELOCITY,source1Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 1 AL_VELOCITY : \n", error);

	alSourcei(source[1],AL_BUFFER, g_Buffers[1]); 
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 1 AL_BUFFER buffer 1 : \n", error);

	alSourcei(source[1],AL_LOOPING,AL_FALSE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 1 AL_LOOPING false: \n", error);

	printf("Position Test\n");
	printf("Press '1' to play source 0 (looping) rear left of listener\n");
	printf("Press '2' to play source 1 once (single shot) front right of listener\n");
	printf("Press '3' to stop source 0\n");
	printf("Press '4' to stop source 1\n");
	printf("Press 'q' to quit\n");

	do
	{
		ch = getUpperCh();
 		
		switch (ch)
		{
			case '1':
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 0 : ", error);
				break;
			case '2':
				alSourcePlay(source[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 1 : ", error);
				break;
			case '3':
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop source 0 : ", error);
				break;
			case '4':
				alSourceStop(source[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop source 1 : ", error);
				break;
		}
	} while (ch != 'Q');

	// Release resources
	alSourceStopv(2, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourceStopv 2 : ", error);

	alDeleteSources(2, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alDeleteSources 2 : ", error);

	return;
}


// Looping Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Looping Test
This test checks the ability to switch Looping ON and OFF for a particular source, either before
or during Playback.  (If looping is switched off during playback, the buffer should finish playing
until the end of the sample.)
*/
ALvoid I_LoopingTest(ALvoid)
{
	ALint	error;
	ALuint	source[2];
	ALbyte	ch;
	ALboolean bLooping0 = AL_FALSE;
	ALboolean bLooping1 = AL_FALSE;

	ALfloat source0Pos[]={ -1.0, 0.0, -1.0};	// Front left of the listener
	ALfloat source0Vel[]={ 0.0, 0.0, 0.0};

	ALfloat source1Pos[]={ 1.0, 0.0, -1.0};		// Front right of the listener
	ALfloat source1Vel[]={ 0.0, 0.0, 0.0};

	// Clear Error Code
	alGetError();

	alGenSources(2,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alGenSources 1 : ", error);
		return;
	}
	
	alSourcef(source[0],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_PITCH : \n", error);

	alSourcef(source[0],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN : \n", error);
	
	alSourcefv(source[0],AL_POSITION,source0Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_POSITION : \n", error);
	
	alSourcefv(source[0],AL_VELOCITY,source0Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_VELOCITY : \n", error);

	alSourcei(source[0],AL_BUFFER, g_Buffers[0]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_BUFFER buffer 0 : \n", error);

	alSourcei(source[0],AL_LOOPING,AL_FALSE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING false : \n", error);


	alSourcef(source[1],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 1 AL_PITCH : \n", error);

	alSourcef(source[1],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 1 AL_GAIN : \n", error);

	alSourcefv(source[1],AL_POSITION,source1Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 1 AL_POSITION : \n", error);

	alSourcefv(source[1],AL_VELOCITY,source1Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 1 AL_VELOCITY : \n", error);

	alSourcei(source[1],AL_BUFFER, g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 1 AL_BUFFER buffer 1 : \n", error);

	alSourcei(source[1],AL_LOOPING,AL_FALSE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 1 AL_LOOPING false: \n", error);

	printf("Looping Test\n");
	printf("Press '1' to play source 0 once (single shot)\n");
	printf("Press '2' to toggle looping on source 0\n");
	printf("Press '3' to play source 1 once (single shot)\n");
	printf("Press '4' to toggle looping on source 1\n");
	printf("Press 'q' to quit\n");
	printf("\nSource 0 : Not looping Source 1 : Not looping\n");
	do
	{
		ch = getUpperCh();
 		
		switch (ch)
		{
			case '1':
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 0 : ", error);
				break;
			case '2':
				if (bLooping0 == AL_FALSE)
				{
					bLooping0 = AL_TRUE;
					if (bLooping1)
						printf("Source 0 : Looping     Source 1 : Looping    \n");
					else
						printf("Source 0 : Looping     Source 1 : Not looping\n");
				}
				else
				{
					bLooping0 = AL_FALSE;
					if (bLooping1)
						printf("Source 0 : Not looping Source 1 : Looping    \n");
					else
						printf("Source 0 : Not looping Source 1 : Not looping\n");
				}
				alSourcei(source[0], AL_LOOPING, bLooping0);
				break;
			case '3':
				alSourcePlay(source[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 1 : ", error);
				break;
			case '4':
				if (bLooping1 == AL_FALSE)
				{
					bLooping1 = AL_TRUE;
					if (bLooping0)
						printf("Source 0 : Looping     Source 1 : Looping    \n");
					else
						printf("Source 0 : Not looping Source 1 : Looping    \n");
				}
				else
				{
					bLooping1 = AL_FALSE;
					if (bLooping0)
						printf("Source 0 : Looping     Source 1 : Not looping\n");
					else
						printf("Source 0 : Not looping Source 1 : Not looping\n");
				}
				alSourcei(source[1], AL_LOOPING, bLooping1);
				break;
		}
	} while (ch != 'Q');

	printf("\n");

	// Release resources
	alSourceStop(source[0]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourceStop source 1 : ", error);

	alDeleteSources(2, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alDeleteSources 1 : ", error);

	return;
}

#if TEST_EAX
// EAX Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE EAX Test
This test Uses 2 Sources to test out EAX 2.0 Reverb, Occlusion and Obstruction.  Also tests the use
of the DEFERRED flag in EAX.
*/
ALvoid I_EAXTest(ALvoid)
{
        ALint	error;
	ALuint	source[2];
	ALbyte	ch;
	ALuint	Env;
	ALint	Room;
	ALint	Occlusion;
	ALint	Obstruction;
	EAXBUFFERPROPERTIES eaxBufferProp0;

	ALfloat source0Pos[]={ -1.0, 0.0, 1.0};	// Behind and to the left of the listener
	ALfloat source0Vel[]={ 0.0, 0.0, 0.0};

	ALfloat source1Pos[]={ 1.0, 0.0,-1.0};	// Front and right of the listener
	ALfloat source1Vel[]={ 0.0, 0.0, 0.0};

	// Clear Error Code
	alGetError();

	alGenSources(2,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alGenSources 2 : ", error);
		return;
	}
	
	alSourcef(source[0],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_PITCH : \n", error);

	alSourcef(source[0],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN : \n", error);
	
	alSourcefv(source[0],AL_POSITION,source0Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_POSITION : \n", error);
	
	alSourcefv(source[0],AL_VELOCITY,source0Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_VELOCITY : \n", error);

	alSourcei(source[0],AL_BUFFER, g_Buffers[0]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_BUFFER buffer 0 : \n", error);

	alSourcei(source[0],AL_LOOPING,AL_TRUE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING true: \n", error);


	alSourcef(source[1],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 1 AL_PITCH : \n", error);

	alSourcef(source[1],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 1 AL_GAIN : \n", error);

	alSourcefv(source[1],AL_POSITION,source1Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 1 AL_POSITION : \n", error);

	alSourcefv(source[1],AL_VELOCITY,source1Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 1 AL_VELOCITY : \n", error);

	alSourcei(source[1],AL_BUFFER, g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 1 AL_BUFFER buffer 1 : \n", error);

	alSourcei(source[1],AL_LOOPING,AL_FALSE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 1 AL_LOOPING false: \n", error);

	printf("EAX Test\n\n");
	printf("Press '1' to play source 0 (looping)\n");
	printf("Press '2' to play source 1 once (single shot)\n");
	printf("Press '3' to stop source 0\n");
	printf("Press '4' to stop source 1\n");
	printf("Press '5' to add Hangar reverb (DEFERRED)\n");
	printf("Press '6' to remove reverb (DEFERRED)\n");
	printf("Press '7' to occlude source 0 (DEFERRED)\n");
	printf("Press '8' to remove occlusion from source 0 (DEFERRED)\n");
	printf("Press '9' to obstruct source 1 (IMMEDIATE)\n");
	printf("Press '0' to remove obstruction from source 1 (IMMEDIATE)\n");
	printf("Press 'c' to COMMIT EAX settings\n");
	printf("Press 'q' to quit\n\n");

	do
	{
		ch = getUpperCh();
 		
		switch (ch)
		{
			case '1':
				alSourcePlay(source[0]);
				break;
			case '2':
				alSourcePlay(source[1]);
				break;
			case '3':
				alSourceStop(source[0]);
				break;
			case '4':
				alSourceStop(source[1]);
				break;

			case '5':
				Env = EAX_ENVIRONMENT_HANGAR;
				eaxSet(&DSPROPSETID_EAX20_ListenerProperties, DSPROPERTY_EAXLISTENER_ENVIRONMENT | DSPROPERTY_EAXLISTENER_DEFERRED,
					NULL, &Env, sizeof(ALuint));
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "eaxSet EAXLISTENER_ENVIRONMENT | EAXLISTENER_DEFERRED : \n", error);
				break;

			case '6':
				Room = -10000;
				eaxSet(&DSPROPSETID_EAX20_ListenerProperties, DSPROPERTY_EAXLISTENER_ROOM | DSPROPERTY_EAXLISTENER_DEFERRED, NULL,
					&Room, sizeof(ALint));
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "eaxSet EAXLISTENER_ROOM | EAXLISTENER_DEFERRED : \n", error);
				break;

			case '7':
				eaxGet(&DSPROPSETID_EAX20_BufferProperties, DSPROPERTY_EAXBUFFER_ALLPARAMETERS, source[0],
					&eaxBufferProp0, sizeof(EAXBUFFERPROPERTIES));
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "eaxGet EAXBUFFER_ALLPARAMETERS : \n", error);
				eaxBufferProp0.lOcclusion = -5000;
				eaxSet(&DSPROPSETID_EAX20_BufferProperties, DSPROPERTY_EAXBUFFER_ALLPARAMETERS | DSPROPERTY_EAXBUFFER_DEFERRED, source[0],
					&eaxBufferProp0, sizeof(EAXBUFFERPROPERTIES));
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "eaxSet EAXBUFFER_ALLPARAMETERS | EAXBUFFER_DEFERRED : \n", error);
				break;

			case '8':
				Occlusion = 0;
				eaxSet(&DSPROPSETID_EAX20_BufferProperties, DSPROPERTY_EAXBUFFER_OCCLUSION | DSPROPERTY_EAXBUFFER_DEFERRED, source[0],
					&Occlusion, sizeof(ALint));
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "eaxSet EAXBUFFER_OCCLUSION | EAXBUFFER_DEFERRED : \n", error);
				break;

			case '9':
				Obstruction = -5000;
				eaxSet(&DSPROPSETID_EAX20_BufferProperties, DSPROPERTY_EAXBUFFER_OBSTRUCTION, source[1],
					&Obstruction, sizeof(ALint));
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "eaxSet EAXBUFFER_OBSTRUCTION : \n", error);
				break;

			case '0':
				Obstruction = 0;
				eaxSet(&DSPROPSETID_EAX20_BufferProperties, DSPROPERTY_EAXBUFFER_OBSTRUCTION, source[1],
					&Obstruction, sizeof(ALint));
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "eaxSet EAXBUFFER_OBSTRUCTION : \n", error);
				break;

			case 'C':
				// Commit settings on source 0
				eaxSet(&DSPROPSETID_EAX20_BufferProperties, DSPROPERTY_EAXBUFFER_COMMITDEFERREDSETTINGS,
					source[0], NULL, 0);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "eaxSet EAXBUFFER_COMMITDEFERREDSETTINGS : \n", error);

				// Commit Listener settings
				eaxSet(&DSPROPSETID_EAX20_ListenerProperties, DSPROPERTY_EAXLISTENER_COMMITDEFERREDSETTINGS,
					NULL, NULL, 0);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "eaxSet EAXLISTENER_COMMITDEFERREDSETTINGSENVIRONMENT : \n", error);
				break;
		}
	} while (ch != 'Q');

	// reset EAX level
	Room = -10000;
	eaxSet(&DSPROPSETID_EAX20_ListenerProperties, DSPROPERTY_EAXLISTENER_ROOM, NULL, &Room, sizeof(ALint));
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "eaxSet EAXLISTENER_ROOM : \n", error);

	// Release resources
	alSourceStopv(2, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourceStopv 2 : ", error);

	alDeleteSources(2, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alDeleteSources 2 : ", error);
	return;
}
#endif


// Queue Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Queue Test
This test checks the ability to queue and unqueue a sequence of buffers on a Source. (Buffers
can only be	unqueued if they have been PROCESSED by a Source.)
*/
ALvoid I_QueueTest(ALvoid)
{
	ALint	error;
	ALuint	source[1];
	ALbyte	ch;
	ALuint  buffers[5];
	ALuint  *buffersremoved;
	ALboolean bLooping;
	ALint	BuffersInQueue, BuffersProcessed;
	ALfloat source0Pos[]={ 0.0, 0.0, -1.0};	// Immediately in front of listener
	ALfloat source0Vel[]={ 0.0, 0.0, 0.0};
	ALuint	Buffer;
	ALint	i;

	// Clear Error Code
	alGetError();

	alGenSources(1,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError("alGenSources 1 : ", error);
		return;
	}
	
	alSourcef(source[0],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcef 0 AL_PITCH : ", error);

	alSourcef(source[0],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcef 0 AL_GAIN : ", error);
	
	alSourcefv(source[0],AL_POSITION,source0Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcefv 0 AL_POSITION : ", error);
	
	alSourcefv(source[0],AL_VELOCITY,source0Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcefv 0 AL_VELOCITY : ", error);

	alSourcei(source[0],AL_LOOPING,AL_FALSE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcei 0 AL_LOOPING false: ", error);

	bLooping = false;

	printf("Queue Test\n\n");
	printf("Press '1' to start playing source 0\n");
	printf("Press '2' to stop source 0\n");
	printf("Press '3' to toggle looping on source 0\n");
	printf("Press '4' to queue 4 buffers on source 0\n");
	printf("Press '5' to queue 1st buffer on source 0\n");
	printf("Press '6' to queue 2nd buffer on source 0\n");
	printf("Press '7' to queue 3rd buffer on source 0\n");
	printf("Press '8' to queue 4th buffer on source 0\n");
	printf("Press '9' to queue 5th buffer (Buffer 0) on source 0\n");
	printf("Press '0' to display stats\n");

	printf("Press 'a' to unqueue first Buffer\n");
	printf("Press 'b' to unqueue first 2 Buffers\n");
	printf("Press 'c' to unqueue first 3 Buffers\n");
	printf("Press 'd' to unqueue first 4 Buffers\n");
	printf("Press 'e' to unqueue first 5 Buffers\n");
	printf("Press 'f' to unqueue all buffers\n");

	printf("Press 'q' to quit\n");

	printf("Source 0 not looping\n");

	buffers[0] = g_Buffers[2];
	buffers[1] = g_Buffers[3];
	buffers[2] = g_Buffers[4];
	buffers[3] = g_Buffers[5];
	buffers[4] = 0;
	
	do
	{
		ch = getUpperCh();
		switch (ch)
		{
			case '1':
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourcePlay source 0 : ", error);
				break;
			case '2':
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourceStop source 0 : ", error);
				break;
			case '3':
				if (bLooping == AL_TRUE)
				{
					bLooping = AL_FALSE;
					printf("Source 0 not looping\n");
				}
				else
				{
					bLooping = AL_TRUE;
					printf("Source 0 looping    \n");
				}
				alSourcei(source[0], AL_LOOPING, bLooping);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourcei AL_LOOPING : ", error);
				break;
			case '4':
				alSourceQueueBuffers(source[0], 4, buffers);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourceQueueBuffers 4 : ", error);
				break;
			case '5':
				alSourceQueueBuffers(source[0], 1, &buffers[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourceQueueBuffers 1 : ", error);
				break;
			case '6':
				alSourceQueueBuffers(source[0], 1, &buffers[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourceQueueBuffers 1 : ", error);
				break;
			case '7':
				alSourceQueueBuffers(source[0], 1, &buffers[2]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourceQueueBuffers 1 : ", error);
				break;
			case '8':
				alSourceQueueBuffers(source[0], 1, &buffers[3]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourceQueueBuffers 1 : ", error);
				break;
			case '9':
				// Queue buffer 0
				alSourceQueueBuffers(source[0], 1, &buffers[4]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourceQueueBuffers 1 (buffer 0) : ", error);
				break;
			case 'A':
				// Unqueue first Buffer
				buffersremoved = new ALuint[1];
				alSourceUnqueueBuffers(source[0], 1, buffersremoved);
				
				if ((error = alGetError()) != AL_NO_ERROR)
				{
					DisplayALError("alSourceUnqueueBuffers 1 : ", error);
				} else
				{
					if (buffersremoved[0] == buffers[0])
						buffersremoved[0] = 1;
					else if (buffersremoved[0] == buffers[1])
						buffersremoved[0] = 2;
					else if (buffersremoved[0] == buffers[2])
						buffersremoved[0] = 3;
					else if (buffersremoved[0] == buffers[3])
						buffersremoved[0] = 4;
					else
						buffersremoved[0] = 0;
				
					printf("\nRemoved Buffer %d from queue\n", buffersremoved[0]);
				}
				
				delete buffersremoved;
				break;
			case 'B':
				// Unqueue first 2 Buffers
				buffersremoved = new ALuint[2];
				alSourceUnqueueBuffers(source[0], 2, buffersremoved);
				
				if ((error = alGetError()) != AL_NO_ERROR)
				{
					DisplayALError("alSourceUnqueueBuffers 2 : ", error);
				} else
				{
					for (i = 0; i < 2; i++)
					{
						if (buffersremoved[i] == buffers[0])
							buffersremoved[i] = 1;
						else if (buffersremoved[i] == buffers[1])
							buffersremoved[i] = 2;
						else if (buffersremoved[i] == buffers[2])
							buffersremoved[i] = 3;
						else if (buffersremoved[i] == buffers[3])
							buffersremoved[i] = 4;
						else
							buffersremoved[i] = 0;
					}

					printf("\nRemoved Buffers %d and %d from queue\n", buffersremoved[0], buffersremoved[1]);
				}

				delete buffersremoved;
				break;
			case 'C':
				// Unqueue first 3 Buffers
				buffersremoved = new ALuint[3];
				alSourceUnqueueBuffers(source[0], 3, buffersremoved);
				if ((error = alGetError()) != AL_NO_ERROR)
				{
					DisplayALError("alSourceUnqueueBuffers 3 : ", error);
				} else
				{
					for (i = 0; i < 3; i++)
					{
						if (buffersremoved[i] == buffers[0])
							buffersremoved[i] = 1;
						else if (buffersremoved[i] == buffers[1])
							buffersremoved[i] = 2;
						else if (buffersremoved[i] == buffers[2])
							buffersremoved[i] = 3;
						else if (buffersremoved[i] == buffers[3])
							buffersremoved[i] = 4;
						else
							buffersremoved[i] = 0;
					}

					printf("\nRemoved Buffers %d, %d and %d from queue\n", buffersremoved[0], buffersremoved[1],
						buffersremoved[2]);
				}

				delete buffersremoved;
				break;
			case 'D':
				// Unqueue first 4 Buffers
				buffersremoved = new ALuint[4];
				alSourceUnqueueBuffers(source[0], 4, buffersremoved);
				
				if ((error = alGetError()) != AL_NO_ERROR)
				{
					DisplayALError("alSourceUnqueueBuffers 1 : ", error);
				} else
				{
					for (i = 0; i < 4; i++)
					{
						if (buffersremoved[i] == buffers[0])
							buffersremoved[i] = 1;
						else if (buffersremoved[i] == buffers[1])
							buffersremoved[i] = 2;
						else if (buffersremoved[i] == buffers[2])
							buffersremoved[i] = 3;
						else if (buffersremoved[i] == buffers[3])
							buffersremoved[i] = 4;
						else
							buffersremoved[i] = 0;
					}

					printf("\nRemoved Buffers %d, %d, %d and %d from queue\n", buffersremoved[0], buffersremoved[1],
						buffersremoved[2], buffersremoved[3]);
				}

				delete buffersremoved;
				break;
			case 'E':
				// Unqueue first 5 Buffers
				buffersremoved = new ALuint[5];
				alSourceUnqueueBuffers(source[0], 5, buffersremoved);
				
				if ((error = alGetError()) != AL_NO_ERROR)
				{
					DisplayALError("alSourceUnqueueBuffers 1 : ", error);
				} else
				{
					for (i = 0; i < 5; i++)
					{
						if (buffersremoved[i] == buffers[0])
							buffersremoved[i] = 1;
						else if (buffersremoved[i] == buffers[1])
							buffersremoved[i] = 2;
						else if (buffersremoved[i] == buffers[2])
							buffersremoved[i] = 3;
						else if (buffersremoved[i] == buffers[3])
							buffersremoved[i] = 4;
						else
							buffersremoved[i] = 0;
					}

					printf("\nRemoved Buffers %d, %d, %d, %d and %d from queue\n", buffersremoved[0], buffersremoved[1],
						buffersremoved[2], buffersremoved[3], buffersremoved[4]);
				}

				delete buffersremoved;
				break;
			case 'F':
				alSourcei(source[0], AL_BUFFER, 0);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSource AL_BUFFER NULL : ", error);
				break;
			case '0':
				// Retrieve number of buffers in queue
#ifndef LINUX
		        alGetSourcei(source[0], AL_BUFFERS_QUEUED, &BuffersInQueue);
#else
		        alGetSourceiv(source[0], AL_BUFFERS_QUEUED, &BuffersInQueue);
#endif
				// Retrieve number of processed buffers
#ifndef LINUX
		        alGetSourcei(source[0], AL_BUFFERS_PROCESSED, &BuffersProcessed);
#else
		       alGetSourceiv(source[0], AL_BUFFERS_PROCESSED, &BuffersProcessed);
#endif
				// Retrieve current buffer
#ifndef LINUX
		        alGetSourcei(source[0], AL_BUFFER, (ALint*)&Buffer);
#else
		       alGetSourceiv(source[0], AL_BUFFER, (ALint*)&Buffer);
#endif
				if (Buffer == buffers[0])
					Buffer = 1;
				else if (Buffer == buffers[1])
					Buffer = 2;
				else if (Buffer == buffers[2])
					Buffer = 3;
				else if (Buffer == buffers[3])
					Buffer = 4;
				else
					Buffer = 0;
				
				printf("Current Buffer is %d, %d Buffers in queue, %d Processed\n", Buffer, BuffersInQueue, BuffersProcessed);
				
				break;
		}
	} while (ch != 'Q');

	// Release resources
	alSourceStop(source[0]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourceStop : ", error);

	alDeleteSources(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alDeleteSources 1 : ", error);

	return;
}

// Frequency Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Frequency Test
This test exercises AL_PITCH functionality
*/
ALvoid I_FreqTest(ALvoid)
{
	ALint	error;
	ALuint	source[1];
	ALbyte	ch;
	ALfloat source0Pos[]={ 1.0, 0.0,-1.0};	// Front and right of the listener
	ALfloat source0Vel[]={ 0.0, 0.0, 0.0};


	alGenSources(1,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alGenSources 1 : ", error);
		return;
	}
	
	alSourcef(source[0],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_PITCH : \n", error);

	alSourcef(source[0],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN : \n", error);
	
	alSourcefv(source[0],AL_POSITION,source0Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_POSITION : \n", error);
	
	alSourcefv(source[0],AL_VELOCITY,source0Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_VELOCITY : \n", error);

	alSourcei(source[0],AL_BUFFER, g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_BUFFER buffer 1 : \n", error);

	alSourcei(source[0],AL_LOOPING,AL_TRUE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING true: \n", error);

	printf("Frequency Test\n");
	printf("Press '1' to play source 0 (looping)\n");
	printf("Press '2' to Double Frequency\n");
	printf("Press '3' to Halve Frequency\n");
	printf("Press 'q' to quit\n");

	do
	{
		ch = getUpperCh();
 		
		switch (ch)
		{
			case '1':
				alSourcef(source[0], AL_PITCH, 1.0f);
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 0 : ", error);
				break;
			case '2':
				alSourcef(source[0], AL_PITCH, 2.0f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcef source 0 AL_PITCH 2.0 : ", error);
				break;
			case '3':
				alSourcef(source[0], AL_PITCH, 0.5f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcef source 0 AL PITCH 0.5: ", error);
				break;
		}
	} while (ch != 'Q');

	// Release resources
	alSourceStopv(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourceStopv 2 : ", error);

	alDeleteSources(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alDeleteSources 2 : ", error);
	
	return;
}


// Stereo Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Stereo Test
This test plays a stereo buffer.
*/
ALvoid I_StereoTest(ALvoid)
{
	ALint	error;
	ALuint	source[1];
	ALuint  buffers[2];
	ALuint	Buffer;
	ALint	BuffersInQueue, BuffersProcessed;
	ALbyte	ch;
	ALboolean bLoop = true;
	ALfloat source0Pos[]={ 1.0, 0.0,-1.0};	// Front and right of the listener
	ALfloat source0Vel[]={ 0.0, 0.0, 0.0};

	alGenSources(1,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alGenSources 1 : ", error);
		return;
	}

	buffers[0] = g_Buffers[6];
	buffers[1] = g_Buffers[6];

	printf("Stereo Test\n");
	printf("Press '1' to play a stereo buffer on source 0 (looping)\n");
	printf("Press '2' to play a mono buffer on source 0 (looping)\n");
	printf("Press '3' to stop source 0\n");
	printf("Press '4' to queue 2 stereo buffers on source 0 and start playing\n");
	printf("Press '5' to unqueue the 2 stereo buffers on source 0\n");
	printf("Press '6' to toggle looping on / off\n");
	printf("Press '0' to display stats\n");
	printf("Press 'q' to quit\n");
	printf("Looping is on\n");

	do
	{
		ch = getUpperCh();
 		
		switch (ch)
		{
			case '1':
				// Stop source
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop source 0 : ", error);

				// Attach new buffer
				alSourcei(source[0],AL_BUFFER, g_Buffers[6]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei 0 AL_BUFFER buffer 6 (stereo) : \n", error);

				// Set volume
				alSourcef(source[0],AL_GAIN,0.5f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN : \n", error);

				// Set looping
				alSourcei(source[0],AL_LOOPING,bLoop);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING true: \n", error);

				// Play source
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 0 : ", error);
				
				break;
			case '2':
				// Stop source
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop source 0 : ", error);

				// Attach new buffer
				alSourcei(source[0],AL_BUFFER, g_Buffers[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei 0 AL_BUFFER buffer 0 (mono) : \n", error);

				// Set 3D position
				alSourcefv(source[0],AL_POSITION,source0Pos);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcefv 0 AL_POSITION : \n", error);
	
				// Set 3D velocity
				alSourcefv(source[0],AL_VELOCITY,source0Vel);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcefv 0 AL_VELOCITY : \n", error);

				// Set volume to full
				alSourcef(source[0],AL_GAIN,1.0f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN : \n", error);

				// Set Looping
				alSourcei(source[0],AL_LOOPING,bLoop);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING : \n", error);

				// Play source
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 0 : ", error);
				break;
			case '3':
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop source 0 : ", error);
				break;
			case '4':
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop Source 0 : ", error);

				// Attach NULL buffer to source to clear everything
				alSourcei(source[0], AL_BUFFER, 0);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei AL_BUFFER (NULL) : ", error);

				alSourceQueueBuffers(source[0], 2, buffers);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceQueueBuffers 2 (stereo) : ", error);

				// Set Looping
				alSourcei(source[0],AL_LOOPING,bLoop);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING : \n", error);

				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay Source 0 : ", error);
				break;
			case '5':
				alSourceUnqueueBuffers(source[0], 2, buffers);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceUnqueueBuffers 2 (stereo) : ", error);
				break;
			case '6':
				if (bLoop)
				{
					printf("Looping is off\n");
					bLoop = AL_FALSE;
				}
				else
				{
					printf("Looping is on  \n");
					bLoop = AL_TRUE;
				}
				alSourcei(source[0], AL_LOOPING, bLoop);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING : \n", error);
				break;
			case '0':
#ifndef LINUX
		                // Retrieve number of buffers in queue
				alGetSourcei(source[0], AL_BUFFERS_QUEUED, &BuffersInQueue);
				// Retrieve number of processed buffers
				alGetSourcei(source[0], AL_BUFFERS_PROCESSED, &BuffersProcessed);
				// Retrieve current buffer
				alGetSourcei(source[0], AL_BUFFER, (ALint*)&Buffer);
#else
		                // Retrieve number of buffers in queue
				alGetSourceiv(source[0], AL_BUFFERS_QUEUED, &BuffersInQueue);
				// Retrieve number of processed buffers
				alGetSourceiv(source[0], AL_BUFFERS_PROCESSED, &BuffersProcessed);
				// Retrieve current buffer
				alGetSourceiv(source[0], AL_BUFFER, (ALint*)&Buffer);
		   
#endif
		                if (Buffer == buffers[0])
					Buffer = 6;
				else if (Buffer == buffers[1])
					Buffer = 6;
				else
					Buffer = 0;
				
				printf("Current Buffer is %d, %d Buffers in queue, %d Processed\n", Buffer, BuffersInQueue, BuffersProcessed);
				
				break;
		}
	} while (ch != 'Q');

	// Release resources
	alSourceStop(source[0]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourceStop : ", error);

	alDeleteSources(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alDeleteSources 2 : ", error);
	
	return;
}


// Gain Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Gain Test
This test plays two sources, allowing the control of source and listener gain.
*/
ALvoid I_GainTest(ALvoid)
{
	ALint	error;
	ALuint	source[2];
	ALbyte	ch;

	ALfloat source0Pos[]={ 1.0, 0.0,-1.0};	// Front and right of the listener
	ALfloat source0Vel[]={ 0.0, 0.0, 0.0};

	ALfloat source1Pos[]={-1.0, 0.0,-1.0};
	ALfloat source1Vel[]={ 0.0, 0.0, 0.0};

	alGenSources(2,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alGenSources 2 : ", error);
		return;
	}

	alSourcef(source[0],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_PITCH : \n", error);

	alSourcef(source[0],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN : \n", error);
	
	alSourcefv(source[0],AL_POSITION,source0Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_POSITION : \n", error);
	
	alSourcefv(source[0],AL_VELOCITY,source0Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 0 AL_VELOCITY : \n", error);

	alSourcei(source[0],AL_BUFFER, g_Buffers[0]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_BUFFER buffer 0 : \n", error);

	alSourcei(source[0],AL_LOOPING,AL_TRUE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING true: \n", error);


	alSourcef(source[1],AL_PITCH,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 1 AL_PITCH : \n", error);

	alSourcef(source[1],AL_GAIN,1.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcef 1 AL_GAIN : \n", error);

	alSourcefv(source[1],AL_POSITION,source1Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 1 AL_POSITION : \n", error);

	alSourcefv(source[1],AL_VELOCITY,source1Vel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcefv 1 AL_VELOCITY : \n", error);

	alSourcei(source[1],AL_BUFFER, g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 1 AL_BUFFER buffer 1 : \n", error);

	alSourcei(source[1],AL_LOOPING,AL_TRUE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourcei 1 AL_LOOPING true: \n", error);

	printf("Gain Test\n");
	printf("Press '1' to play source 0 (looping)\n");
	printf("Press '2' to play source 1 (looping)\n");
	printf("Press '3' to stop source 0\n");
	printf("Press '4' to stop source 1\n");
	printf("Press '5' to set source 0 gain to 1.0\n");
	printf("Press '6' to set source 0 gain to 0.5\n");
	printf("Press '7' to set source 0 gain to 0.25\n");
	printf("Press '8' to set source 0 gain to 0\n");
	printf("Press 'a' to set Listener Gain to 1.0\n");
	printf("Press 'b' to set Listener Gain to 0.5\n");
	printf("Press 'c' to set Listener Gain to 0.25\n");
	printf("Press 'd' to set Listener Gain to 0.0\n");
	printf("Press 'q' to quit\n");

	do
	{
		ch = getUpperCh();
 		
		switch (ch)
		{
			case '1':
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 0 : ", error);
				break;
			case '2':
				alSourcePlay(source[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 1 : ", error);
				break;
			case '3':
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop source 0 : \n", error);
				break;
			case '4':
				alSourceStop(source[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop source 1 : \n", error);
				break;
			case '5':
				alSourcef(source[0],AL_GAIN,1.0f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN 1.0 : \n", error);
				break;
			case '6':
				alSourcef(source[0],AL_GAIN,0.5f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN 0.5 : \n", error);
				break;
			case '7':
				alSourcef(source[0],AL_GAIN,0.25f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN 0.25 : \n", error);
				break;
			case '8':
				alSourcef(source[0],AL_GAIN,0.0f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN 0.0 : \n", error);
				break;
			case 'A':
				alListenerf(AL_GAIN,1.0f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alListenerf AL_GAIN 1.0 : \n", error);
				break;
			case 'B':
				alListenerf(AL_GAIN,0.5f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alListenerf AL_GAIN 0.5 : \n", error);
				break;
			case 'C':
				alListenerf(AL_GAIN,0.25f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alListenerf AL_GAIN 0.25 : \n", error);
				break;
			case 'D':
				alListenerf(AL_GAIN,0.0f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alListenerf AL_GAIN 0.0 : \n", error);
				break;
		}
	} while (ch != 'Q');

	// Reset & Release resources
	alListenerf(AL_GAIN,1.0f);
	alSourceStopv(2,source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourceStop : ", error);

	alDeleteSources(2, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alDeleteSources 2 : ", error);
	
	return;
}

#ifdef __MACOS__
void ALTestSwapWords(unsigned int *puint)
{
    unsigned int tempint;
	char *pChar1, *pChar2;
	
	tempint = *puint;
	pChar2 = (char *)&tempint;
	pChar1 = (char *)puint;
	
	pChar1[0]=pChar2[3];
	pChar1[1]=pChar2[2];
	pChar1[2]=pChar2[1];
	pChar1[3]=pChar2[0];
}

void ALTestSwapBytes(unsigned short *pshort)
{
    unsigned short tempshort;
    char *pChar1, *pChar2;
    
    tempshort = *pshort;
    pChar2 = (char *)&tempshort;
    pChar1 = (char *)pshort;
    
    pChar1[0]=pChar2[1];
    pChar1[1]=pChar2[0];
}
#endif
#ifdef MAC_OS_X
void ALTestSwapWords(unsigned int *puint)
{
    unsigned int tempint;
	char *pChar1, *pChar2;
	
	tempint = *puint;
	pChar2 = (char *)&tempint;
	pChar1 = (char *)puint;
	
	pChar1[0]=pChar2[3];
	pChar1[1]=pChar2[2];
	pChar1[2]=pChar2[1];
	pChar1[3]=pChar2[0];
}

void ALTestSwapBytes(unsigned short *pshort)
{
    unsigned short tempshort;
    char *pChar1, *pChar2;
    
    tempshort = *pshort;
    pChar2 = (char *)&tempshort;
    pChar1 = (char *)pshort;
    
    pChar1[0]=pChar2[1];
    pChar1[1]=pChar2[0];
}
#endif

#define BSIZE 20000
#define NUMBUFFERS	4


// Streaming Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Streaming Test
This test streams a long stereo wave file from harddisc - using AL Queuing
*/
ALvoid I_StreamingTest(ALvoid)
{
	FILE			*fp;
	WAVE_Struct		wave;
	ALbyte			data[BSIZE];
	ALuint			SourceID;
	ALuint			BufferID[NUMBUFFERS];
	ALuint			TempBufferID;
	ALuint			ulBuffersAvailable;
	ALuint			ulUnqueueCount, ulQueueCount, ulDataSize, ulDataToRead;
	ALint			error, lProcessed, lPlaying, lLoop;

	printf("Streaming Test\n");

	fp = fopen("stereo.wav", "rb");
	if (fp == NULL)
	{
		printf("Failed to open stereo.wav\n");
		return;
	}

	// Read in WAVE Header
	if (fread(&wave, 1, sizeof(WAVE_Struct), fp) != sizeof(WAVE_Struct))
	{
		printf("Invalid wave file\n");
		fclose(fp);
		return;
	}

#ifdef SWAPBYTES
    ALTestSwapWords(&wave.dataSize);
    ALTestSwapBytes(&wave.Channels);
    ALTestSwapWords(&wave.SamplesPerSec);
#endif

	// Generate a number of buffers to be used to queue data on to Source
	alGenBuffers(NUMBUFFERS, BufferID);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError("alGenBuffers : ", error);
		fclose(fp);
		return;
	}

	// Generate a Source
	alGenSources(1, &SourceID);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError("alGenSources 1 : ", error);
		alDeleteBuffers(NUMBUFFERS, BufferID);
		fclose(fp);
		return;
	}

	ulUnqueueCount = 0;
	ulQueueCount = 0;
	ulBuffersAvailable = NUMBUFFERS;
	ulDataSize = wave.dataSize;

	while (!_kbhit())
	{
		// Check how many Buffers have been processed
		alGetSourcei(SourceID, AL_BUFFERS_PROCESSED, &lProcessed);
		while (lProcessed)
		{
			// Unqueue the buffer
			alSourceUnqueueBuffers(SourceID, 1, &TempBufferID);

			// Update unqueue count
			if (++ulUnqueueCount == NUMBUFFERS)
				ulUnqueueCount = 0;

			// Increment buffers available
			ulBuffersAvailable++;

			// Decrement lProcessed count
			lProcessed--;
		}

		// If there is more data to read, and available buffers ... read in more data and fill the buffers !
		if ((ulDataSize) && (ulBuffersAvailable))
		{
			ulDataToRead = (ulDataSize > BSIZE) ? BSIZE : ulDataSize;

			fread(data, ulDataToRead, 1, fp);
			ulDataSize -= ulDataToRead;

			// Copy to Buffer
#ifdef SWAPBYTES
    		for (int i = 0; i < BSIZE; i=i+2)
    		{
    			ALTestSwapBytes((unsigned short *)(data+i));
    		}
#endif
			alBufferData(BufferID[ulQueueCount], AL_FORMAT_STEREO16, data, ulDataToRead, wave.SamplesPerSec);

			// Queue the buffer
			alSourceQueueBuffers(SourceID, 1, &BufferID[ulQueueCount]);

			if (++ulQueueCount == NUMBUFFERS)
				ulQueueCount = 0;

			// Decrement buffers available
			ulBuffersAvailable--;
		}

		// If all the Buffers are available then we must have finished
		if (ulBuffersAvailable == NUMBUFFERS)
			break;

		// If the Source has stopped (been starved of data) it will need to be restarted
		alGetSourcei(SourceID, AL_SOURCE_STATE, &lPlaying);
		if (lPlaying != AL_PLAYING)
		{	
			// If the Source has stopped prematurely, all the processed buffers must be unqueued
			// before re-playing (otherwise they will be heard twice).
			// Any buffers queued after the Source stopped will not be processed, so they won't
			// be unqueued by this step
			alGetSourcei(SourceID, AL_BUFFERS_PROCESSED, &lProcessed);
			while (lProcessed)
			{
				alSourceUnqueueBuffers(SourceID, 1, &TempBufferID);
				if (++ulUnqueueCount == NUMBUFFERS)
					ulUnqueueCount = 0;
				ulBuffersAvailable++;
				lProcessed--;
			}

			alSourcePlay(SourceID);
		}
	}

	// Clean-up
	alSourceStop(SourceID);

	alDeleteSources(1, &SourceID);

	for (lLoop = 0; lLoop < NUMBUFFERS; lLoop++)
		alDeleteBuffers(1, &BufferID[lLoop]);
}


// Multiple Sources Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Multiple Sources Test
This test generates a large number of sources, positions, and plays them.
*/
ALvoid I_MultipleSourcesTest()
{
	ALuint	numSources = 0;
	ALuint	Sources[64] = { 0 };
	ALint	error;
	ALuint	i;
	char	ch;
	ALfloat radius;
	double anglestep;
	ALfloat pos[3];

	// Generate as many sources as possible (up to 64)
	for (i = 0; i < 64; i++)
	{
		alGenSources(1, &Sources[i]);
		if ((error = alGetError()) != AL_NO_ERROR)
			break;
		else
			numSources++;
	}

	printf("Multiple Sources Test\n\n");
	printf("Generated %d Sources\n", numSources);

	// Set sources to located in a circle around the listener

	anglestep = (2 * 3.1416) / (ALfloat)numSources;
	radius = 2.0f;

	for (i = 0; i < numSources; i++)
	{
		// Attach buffer
		alSourcei(Sources[i], AL_BUFFER, g_Buffers[0]);

		// Set position
		pos[0] = (float)(cos(anglestep*i) * radius);
		pos[1] = 0.0f;
		pos[2] = (float)(sin(anglestep*i) * radius);
		alSourcefv(Sources[i], AL_POSITION, pos);
		printf("Source %d at %.3f, %.3f, %.3f\n", i, pos[0], pos[1], pos[2]);

		// Enable looping
		alSourcei(Sources[i], AL_LOOPING, AL_TRUE);
	}


	printf("Press '1' to start playing Sources seperately\n");
	printf("Press '2' to stop playing Sources seperately\n");
	printf("Press 'q' to quit\n");

	do
	{
		ch = getUpperCh();
		switch (ch)
		{
			case '1':
				for (i = 0; i < numSources; i++)
				{
					alSourcePlay(Sources[i]);
					if ((error = alGetError()) != AL_NO_ERROR)
						DisplayALError("alSourcePlay : ", error);

					// Delay a little
					delay_ms(100);
				}
				break;
			case '2':
				alSourceStopv(numSources, Sources);
					if ((error = alGetError()) != AL_NO_ERROR)
						DisplayALError("alSourceStopv : ", error);
				break;
		}
	} while (ch != 'Q');

	// Delete the Sources
	alDeleteSources(numSources, Sources);
}

// Source Relative Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Source Relative Test
*/
ALvoid I_SourceRelativeTest()
{
	ALuint	source[1];
	ALint	error;
	ALbyte	ch;
	ALboolean bRelative = AL_FALSE;

	alGenSources(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError("alGenSources 1 : ", error);
		return;
	}

	alSourcei(source[0],AL_BUFFER, g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcei 0 AL_BUFFER buffer 0 : ", error);

	alSourcei(source[0],AL_LOOPING,AL_TRUE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcei 0 AL_LOOPING true: ", error);

	alSourcei(source[0], AL_SOURCE_RELATIVE, AL_FALSE);	
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcei 0 AL_SOURCE_RELATIVE AL_FALSE : ", error);

	printf("Source Relative Test\n");
	printf("Press '1' to play source 0 at 1, 0, 0\n");
	printf("Press '2' to move listener  to 2, 0, 0\n");
	printf("Press '3' to toggle SOURCE RELATIVE Mode\n");
	printf("Press 'q' to quit\n");

	do
	{
		ch = getUpperCh();  
		switch (ch)
		{
		case '1':
			alSource3f(source[0],AL_POSITION,1.0f,0.0f,0.0f);
			if ((error = alGetError()) != AL_NO_ERROR)
				DisplayALError("alSourcefv 0 AL_POSITION : ", error);
			
			alSourcePlay(source[0]);
			if ((error = alGetError()) != AL_NO_ERROR)
				DisplayALError("alSourcePlay source 0 : ", error);
			break;
		case '2':
			alListener3f(AL_POSITION,2.0f,0.0f,0.0f);
			if ((error = alGetError()) != AL_NO_ERROR)
				DisplayALError("alListenerfv  AL_POSITION : ", error);
			break;
		case '3':
			if (bRelative)
			{
				printf("Source Relative == FALSE\r");
				alSourcei(source[0], AL_SOURCE_RELATIVE, AL_FALSE);
				bRelative = AL_FALSE;
			}
			else
			{
				alSourcei(source[0], AL_SOURCE_RELATIVE, AL_TRUE);
				printf("Source Relative == TRUE \r");
				bRelative = AL_TRUE;
			}
			if ((error = alGetError()) != AL_NO_ERROR)
				DisplayALError("alSourcei source 0 AL_SOURCE_RELATIVE : ", error);
			break;
		}
	} while (ch != 'Q');

	// Release resources
	alSourceStopv(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourceStopv 1 : ", error);

	alDeleteSources(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alDeleteSources 1 : ", error);

	// Restore Listener Position
	alListener3f(AL_POSITION,0.0f,0.0f,0.0f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alListenerfv  AL_POSITION : ", error);

	return;
}

// Source Rolloff Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Source Rolloff Test
*/
ALvoid I_SourceRolloffTest()
{
	ALint	error;
	
	ALuint	source[2];
	ALbyte	ch;

	ALfloat source0Pos[]={-4.0, 0.0,  4.0};	// Behind and to the left of the listener
	ALfloat source1Pos[]={ 4.0, 0.0, -4.0};	// Front and to the right of the listener

	alGenSources(2,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError("alGenSources 2 : ", error);
		return;
	}

	alSourcefv(source[0],AL_POSITION,source0Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcefv 0 AL_POSITION : ", error);
	
	alSourcei(source[0],AL_BUFFER, g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcei 0 AL_BUFFER buffer 0 : ", error);

	alSourcei(source[0],AL_LOOPING,AL_TRUE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcei 0 AL_LOOPING true: ", error);

	alSourcefv(source[1],AL_POSITION,source1Pos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcefv 1 AL_POSITION : ", error);

	alSourcei(source[1],AL_BUFFER, g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcei 1 AL_BUFFER buffer 1 : ", error);

	alSourcei(source[1],AL_LOOPING,AL_TRUE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcei 1 AL_LOOPING false: ", error);

	printf("Source Roll-off Test\n");
	printf("Press '1' to play source 0 rear left of listener\n");
	printf("Press '2' to stop source 0\n");
	printf("Press '3' to play source 1 front right of listener\n");
	printf("Press '4' to stop source 1\n");
	printf("Press '5' to set Source 0 Roff-off Factor to 0.5\n");
	printf("Press '6' to set Source 0 Roll-off Factor to 1.0\n");
	printf("Press '7' to set Source 0 Roll-off Factor to 2.0\n");
	printf("Press '8' to set Source 1 Roff-off Factor to 0.5\n");
	printf("Press '9' to set Source 1 Roll-off Factor to 1.0\n");
	printf("Press 'A' to set Source 1 Roll-off Factor to 2.0\n");

	printf("Press 'q' to quit\n");

	do
	{
		ch = getUpperCh();  
		switch (ch)
		{
			case '1':
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourcePlay source 0 : ", error);
				break;
			case '2':
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourceStop source 0 : ", error);
				break;
			case '3':
				alSourcePlay(source[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourcePlay source 1 : ", error);
				break;
			case '4':
				alSourceStop(source[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourceStop source 1 : ", error);
				break;
			case '5':
				alSourcef(source[0], AL_ROLLOFF_FACTOR, 0.5f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourcef ROLLOFF_FACTOR 0.5 : ", error);
				break;
			case '6':
				alSourcef(source[0], AL_ROLLOFF_FACTOR, 1.0f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourcef ROLLOFF_FACTOR 1.0 : ", error);
				break;
			case '7':
				alSourcef(source[0], AL_ROLLOFF_FACTOR, 2.0f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourcef ROLLOFF_FACTOR 2.0 : ", error);
				break;
			case '8':
				alSourcef(source[1], AL_ROLLOFF_FACTOR, 0.5f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourcef ROLLOFF_FACTOR 0.5 : ", error);
				break;
			case '9':
				alSourcef(source[1], AL_ROLLOFF_FACTOR, 1.0f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourcef ROLLOFF_FACTOR 1.0 : ", error);
				break;
			case 'A':
				alSourcef(source[1], AL_ROLLOFF_FACTOR, 2.0f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alSourcef ROLLOFF_FACTOR 2.0 : ", error);
				break;
		}
	} while (ch != 'Q');

	// Release resources
	alSourceStopv(2, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourceStopv 2 : ", error);

	alDeleteSources(2, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alDeleteSources 2 : ", error);

	return;
}

// ADPCM Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE ADPCM Test
*/
ALvoid I_ADPCMTest()
{
	ALuint uiSourceID, uiBufferID;
	ALenum eMonoADPCM = 0, eStereoADPCM = 0;
	ALsizei size,freq;
	ALenum	format;
	ALvoid	*data;
	ALboolean loop;
	char ch;

	// Check for support for ADPCM
	eMonoADPCM = alGetEnumValue("AL_FORMAT_MONO_IMA4");
	eStereoADPCM = alGetEnumValue("AL_FORMAT_STEREO_IMA4");

	if (eMonoADPCM && eStereoADPCM)
	{
		// Load footadpcm.wav
		alutLoadWAVFile("footadpcm.wav",&format,&data,&size,&freq,&loop);
		if (alGetError() != AL_NO_ERROR)
		{
			printf("Failed to load footadpcm.wav\n");
			return;
		}

		alGetError();

		// Generate an AL Buffer and an AL Source
		alGenBuffers(1, &uiBufferID);
		// Copy data to AL buffer
		alBufferData(uiBufferID,format,data,size,freq);
		// Release wave data
		alutUnloadWAV(format,data,size,freq);

		if (alGetError() != AL_NO_ERROR)
		{
			printf("Failed to generate and copy data to buffer\n");
			return;
		}

		// Generate a Source
		alGenSources(1, &uiSourceID);
		// Attach buffer to Source
		alSourcei(uiSourceID, AL_BUFFER, uiBufferID);
		// Enable Looping
		alSourcei(uiSourceID, AL_LOOPING, AL_TRUE);
		// Play Source
		alSourcePlay(uiSourceID);

		printf("Press a key to stop test\n");
		ch = getUpperCh();

		// Stop the Source
		alSourceStop(uiSourceID);
		// Attach NULL Buffer
		alSourcei(uiSourceID, AL_BUFFER, 0);
		// Delete Source
		alDeleteSources(1, &uiSourceID);
		// Delete Buffer
		alDeleteBuffers(1, &uiBufferID);
	}
	else
	{
		printf("No ADPCM support found !\n");
	}
}

// Velocity Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Velocity Test
*/
ALvoid I_VelocityTest()
{
	ALint	error;

	ALuint	source;
	ALbyte	ch;

	ALfloat sourcePos[] = { 1.0, 0.0, 0.0};
	ALfloat sourceVel[] = { 0.0, 0.0, 0.0};

	ALfloat listenerPos[]={ 0.0, 0.0, 0.0};
	ALfloat listenerVel[]={ 0.0, 0.0, 0.0};

	ALCcontext *context = alcGetCurrentContext();
	ALCdevice *device = alcGetContextsDevice(context);
	ALint major, minor;
    alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
    alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);

	alGenSources(1,&source);

	alSourcefv(source,AL_POSITION,sourcePos);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcefv 0 AL_POSITION : \n", error);

	alSourcefv(source,AL_VELOCITY,sourceVel);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcefv 0 AL_VELOCITY : \n", error);

	alSourcei(source,AL_BUFFER, g_Buffers[1]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcei 0 AL_BUFFER buffer 0 : \n", error);

	alSourcei(source,AL_LOOPING,AL_TRUE);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcei 0 AL_LOOPING true: \n", error);

	alListenerfv(AL_POSITION, listenerPos);
	alListenerfv(AL_VELOCITY, listenerVel);

	alSourcePlay(source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcePlay source 0 : ", error);

	printf("Velocity Test\n");
	printf("Press '1' to increase source X velocity by 50 units / second\n");
	printf("Press '2' to decrease source X velocity by 50 units / second\n");
	printf("Press '3' to increase listener X velocity by 50 units / second\n");
	printf("Press '4' to decrease listener X velocity by 50 units / second\n");
	printf("Press '5' to set Speed Of Sound to 343.3\n");
	printf("Press '6' to set Speed Of Sound to 686.6\n");
	printf("Press '7' to set Speed Of Sound to 171.6\n");
	printf("Press '8' to set Doppler Factor to 1\n");
	printf("Press '9' to set Doppler Factor to 2\n");
	printf("Press '0' to set Doppler Factor to 4\n");
	printf("Press 'q' to quit\n");

	do
	{
		printf("Source %.1f Listener %.1f\r", sourceVel[0], listenerVel[0]);

		ch = getUpperCh();  
		switch (ch)
		{
			case '1':
				sourceVel[0] += 50.0f;
				break;
			case '2':
				sourceVel[0] -= 50.0f;
				break;
			case '3':
				listenerVel[0] += 50.0f;
				break;
			case '4':
				listenerVel[0] -= 50.0f;
				break;
		case '5':
				if ((major > 1) || ((major == 1) && (minor >= 1)))
					alSpeedOfSound(343.3f);
				break;
		case '6':
				if ((major > 1) || ((major == 1) && (minor >= 1)))
					alSpeedOfSound(686.6f);
				break;
		case '7':
				if ((major > 1) || ((major == 1) && (minor >= 1)))
					alSpeedOfSound(171.6f);
				break;
			case '8':
				alDopplerFactor(1.0);
				break;
			case '9':
				alDopplerFactor(2.0);
				break;
			case '0':
				alDopplerFactor(4.0);
				break;
			default:
				break;
		}

		alSourcefv(source,AL_VELOCITY,sourceVel);
		alListenerfv(AL_VELOCITY, listenerVel);
	} while (ch != 'Q');

	// Release resources
	alSourceStopv(1, &source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourceStopv 2 : ", error);

	alDeleteSources(1, &source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alDeleteSources 2 : ", error);

	return;
}

// Get Source Offset Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Get Source Offset Test
*/
ALvoid I_GetSourceOffsetTest()
{
	ALuint Source;
	char ch, oldch;
	ALint lOffset;
	ALfloat flOffset;

	alGenSources(1, &Source);
	alSourcei(Source, AL_BUFFER, g_Buffers[6]);

	printf("Get Source Offset Test\n");
	printf("Press 1 to Play Stereo.wav\n");
	printf("Press 2 to Use AL_BYTE_OFFSET (int) to track progress\n");
	printf("Press 3 to Use AL_SAMPLE_OFFSET (int) to track progress\n");
	printf("Press 4 to Use AL_SEC_OFFSET (int) to track progress\n");
	printf("Press 5 to Use AL_BYTE_OFFSET (float) to track progress\n");
	printf("Press 6 to Use AL_SAMPLE_OFFSET (float) to track progress\n");
	printf("Press 7 to Use AL_SEC_OFFSET (float) to track progress\n");
	printf("Press Q to quit\n");
	while (1)
	{
		if (_kbhit())
		{
			ch = getUpperCh();   

			if (ch == '1')
			{
				alSourcePlay(Source);
				ch = oldch;
			}
			else if (ch == 'Q')
			{
				break;
			}

			oldch = ch;
		}
		else
		{
			switch (ch)
			{
			case '2':
			default:
				alGetSourcei(Source, AL_BYTE_OFFSET, &lOffset);
				printf("ByteOffset is %d                   \r", lOffset);
				break;
			case '3':
				alGetSourcei(Source, AL_SAMPLE_OFFSET, &lOffset);
				printf("SampleOffset is %d                 \r", lOffset);
				break;
			case '4':
				alGetSourcei(Source, AL_SEC_OFFSET, &lOffset);
				printf("SecondOffset is %d                 \r", lOffset);
				break;
			case '5':
				alGetSourcef(Source, AL_BYTE_OFFSET, &flOffset);
				printf("ByteOffset is %.3f                 \r", flOffset);
				break;
			case '6':
				alGetSourcef(Source, AL_SAMPLE_OFFSET, &flOffset);
				printf("SampleOffset is %.3f               \r", flOffset);
				break;
			case '7':
				alGetSourcef(Source, AL_SEC_OFFSET, &flOffset);
				printf("SecondOffset is %.3f               \r", flOffset);
				break;
			}
		}
	}

	alSourceStop(Source);
	alDeleteSources(1, &Source);
}

// Set Source Offset Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Set Source Offset Test
*/
ALvoid I_SetSourceOffsetTest()
{
	ALuint Source;
	char ch;
	ALint lOffset = 0;
	ALfloat flOffset = 0.0f;
	ALint error;
	ALint iType = 0;

	alGenSources(1, &Source);
	alSourcei(Source, AL_BUFFER, g_Buffers[0]);

	printf("Set Source Offset Test\n");
	printf("Press 1 to Stop and Play 1 Footstep\n");
	printf("Press 2 to Stop and Play 2 Footsteps\n");
	printf("Press 3 to Stop and Play 3 Footsteps\n");
	printf("Press 4 to Stop and Play 4 Footsteps\n");
	printf("Press 5 to Stop and Play with bad offset\n");
	printf("Press 6 to Set Offset to play 1 Footstep\n");
	printf("Press 7 to Set Offset to play 2 Footsteps\n");
	printf("Press 8 to Set Offset to play 3 Footsteps\n");
	printf("Press 9 to Set Offset to play 4 Footsteps\n");
	printf("Press 0 to Set Offset to bad offset\n");
	printf("Press A to Play complete footstep sample\n");
	printf("Press B to Play (Looping) complete footstep sample\n");
	printf("Press C to Pause Source\n");
	printf("Press D to Stop Source\n");
	printf("Press E to Rewind Source\n");
	printf("Press F to toggle Bytes, Samples, Seconds\n");
	printf("Press Q to quit\n");

	while (1)
	{
		if (_kbhit())
		{
			ch = getUpperCh();   

			switch(ch)
			{
			case '1':
				alSourceStop(Source);
				if (iType == 0)
					alSourcei(Source, AL_BYTE_OFFSET, 216000);
				else if (iType == 1)
					alSourcei(Source, AL_SAMPLE_OFFSET, 108000);
				else if (iType == 2)
					alSourcef(Source, AL_SEC_OFFSET, 2.440f);
				alSourcePlay(Source);
				break;

			case '2':
				alSourceStop(Source);
				if (iType == 0)
					alSourcei(Source, AL_BYTE_OFFSET, 144000);
				else if (iType == 1)
					alSourcei(Source, AL_SAMPLE_OFFSET, 72000);
				else if (iType == 2)
					alSourcef(Source, AL_SEC_OFFSET, 1.640f);
				alSourcePlay(Source);
				break;

			case '3':
				alSourceStop(Source);
				if (iType == 0)
					alSourcei(Source, AL_BYTE_OFFSET, 75000);
				else if (iType == 1)
					alSourcei(Source, AL_SAMPLE_OFFSET, 37500);
				else if (iType == 2)
					alSourcef(Source, AL_SEC_OFFSET, 0.840f);
				alSourcePlay(Source);
				break;

			case '4':
				alSourceStop(Source);
				if (iType == 0)
					alSourcei(Source, AL_BYTE_OFFSET, 1000);
				else if (iType == 1)
					alSourcei(Source, AL_SAMPLE_OFFSET, 500);
				else if (iType == 2)
					alSourcef(Source, AL_SEC_OFFSET, 0.015f);
				alSourcePlay(Source);
				break;

			case '5':
				alSourceStop(Source);
				if (iType == 0)
					alSourcei(Source, AL_BYTE_OFFSET, 400000);
				else if (iType == 1)
					alSourcei(Source, AL_SAMPLE_OFFSET, 200000);
				else if (iType == 2)
					alSourcef(Source, AL_SEC_OFFSET, 5.000f);
				alSourcePlay(Source);
				break;

			case '6':
				if (iType == 0)
					alSourcei(Source, AL_BYTE_OFFSET, 216000);
				else if (iType == 1)
					alSourcei(Source, AL_SAMPLE_OFFSET, 108000);
				else if (iType == 2)
					alSourcef(Source, AL_SEC_OFFSET, 2.440f);
				break;

			case '7':
				if (iType == 0)
					alSourcei(Source, AL_BYTE_OFFSET, 144000);
				else if (iType == 1)
					alSourcei(Source, AL_SAMPLE_OFFSET, 72000);
				else if (iType == 2)
					alSourcef(Source, AL_SEC_OFFSET, 1.640f);
				break;

			case '8':
				if (iType == 0)
					alSourcei(Source, AL_BYTE_OFFSET, 75000);
				else if (iType == 1)
					alSourcei(Source, AL_SAMPLE_OFFSET, 37500);
				else if (iType == 2)
					alSourcef(Source, AL_SEC_OFFSET, 0.840f);
				break;

			case '9':
				if (iType == 0)
					alSourcei(Source, AL_BYTE_OFFSET, 1000);
				else if (iType == 1)
					alSourcei(Source, AL_SAMPLE_OFFSET, 500);
				else if (iType == 2)
					alSourcef(Source, AL_SEC_OFFSET, 0.015f);
				break;

			case '0':
				if (iType == 0)
					alSourcei(Source, AL_BYTE_OFFSET, 400000);
				else if (iType == 1)
					alSourcei(Source, AL_SAMPLE_OFFSET, 200000);
				else if (iType == 2)
					alSourcef(Source, AL_SEC_OFFSET, 5.000f);
				break;

			case 'A':
				alSourcei(Source, AL_LOOPING, AL_FALSE);
				alSourcePlay(Source);
				break;

			case 'B':
				alSourcei(Source, AL_LOOPING, AL_TRUE);
				alSourcePlay(Source);
				break;

			case 'C':
				alSourcePause(Source);
				break;

			case 'D':
				alSourceStop(Source);
				break;

			case 'E':
				alSourceRewind(Source);
				break;

			case 'F':
				iType = (++iType % 3);
				break;
			}

			if (ch == 'Q')
				break;
		}
		else
		{
			switch (iType)
			{
			case 0:
				alGetSourcei(Source, AL_BYTE_OFFSET, &lOffset);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alGetSourcei AL_BYTE_OFFSET : ", error);
				else
					printf("ByteOffset is %d                  \r", lOffset);
				break;

			case 1:
				alGetSourcei(Source, AL_SAMPLE_OFFSET, &lOffset);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alGetSourcei AL_SAMPLE_OFFSET : ", error);
				else
					printf("SampleOffset is %d                \r", lOffset);
				break;

			case 2:
				alGetSourcef(Source, AL_SEC_OFFSET, &flOffset);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError("alGetSourcef AL_SEC_OFFSET : ", error);
				else
					printf("Seconds Offset is %.3f            \r", flOffset);
				break;
			}
		}
	}

	alSourceStop(Source);
	alDeleteSources(1, &Source);
}

// Distance Model Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Distance Model Test
*/
ALvoid I_DistanceModelTest()
{
	ALuint	source[1];
	ALint	error;
	ALint	lLoop;

	alGenSources(1,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError("alGenSources 2 : ", error);
		return;
	}

	alSourcei(source[0], AL_BUFFER, g_Buffers[0]);
	alSourcei(source[0], AL_LOOPING, AL_TRUE);
	alSourcePlay(source[0]);

	printf("Distance Model Test\n");

	for (lLoop = 0; lLoop < 7; lLoop++)
	{
		switch (lLoop)
		{
		case 0:
			printf("Distance Model is AL_NONE\n");
			alDistanceModel(AL_NONE);
			break;
		case 1:
			printf("Distance Model is AL_INVERSE_DISTANCE\n");
			alDistanceModel(AL_INVERSE_DISTANCE);
			break;
		case 2:
			printf("Distance Model is AL_INVERSE_DISTANCE_CLAMPED\n");
			alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
			break;
		case 3:
			printf("Distance Model is AL_LINEAR_DISTANCE\n");
			alDistanceModel(AL_LINEAR_DISTANCE);
			break;
		case 4:
			printf("Distance Model is AL_LINEAR_DISTANCE_CLAMPED\n");
			alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
			break;
		case 5:
			printf("Distance Model is AL_EXPONENT_DISTANCE\n");
			alDistanceModel(AL_EXPONENT_DISTANCE);
			break;
		case 6:
			printf("Distance Model is AL_EXPONENT_DISTANCE_CLAMPED\n");
			alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
			break;
		}

		printf("Distance is 16\n");
		alSource3f(source[0], AL_POSITION, 0.0f, 0.0f, -16.0f);
		printf("Ref Distance is 8\n");
		alSourcef(source[0], AL_REFERENCE_DISTANCE, 8.0f);
		printf("Max Distance is 32\n");
		alSourcef(source[0], AL_MAX_DISTANCE, 32.0f);

		Sleep(2000);

		printf("Distance is 64\n");
		alSource3f(source[0], AL_POSITION, 0.0f, 0.0f, -64.0f);
		printf("Ref Distance is 8\n");
		alSourcef(source[0], AL_REFERENCE_DISTANCE, 8.0f);
		printf("Max Distance is 32\n");
		alSourcef(source[0], AL_MAX_DISTANCE, 32.0f);

		Sleep(2000);
	}

	printf("Restoring INVERSE_DISTANCE_CLAMPED model\n");
	alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
	Sleep(50);

	alSourceStopv(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourceStopv : ", error);

	alDeleteSources(1, source);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alDeleteSources 1 : ", error);

	return;
}

// Capture Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Capture Test
*/
ALvoid I_CaptureTest()
{
	ALCdevice *pCaptureDevice;
	const ALCchar *szDefaultCaptureDevice;
	ALint lSamplesAvailable;
	ALchar ch;
	FILE *pFile;
	ALchar Buffer[4000];
	WAVEHEADER waveHeader;
	ALint lDataSize = 0;
	ALint lSize;

	// NOTE : This code does NOT setup the Wave Device's Audio Mixer to select a recording input
	// or recording level.

	// Get list of available Capture Devices
	const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
	if (pDeviceList)
	{
		printf("Available Capture Devices are:-\n");

		while (*pDeviceList)
		{
			printf("%s\n", pDeviceList);
			pDeviceList += strlen(pDeviceList) + 1;
		}
	}

	szDefaultCaptureDevice = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
	printf("\nDefault Capture Device is '%s'\n\n", szDefaultCaptureDevice);

	pCaptureDevice = alcCaptureOpenDevice(szDefaultCaptureDevice, 22050, AL_FORMAT_STEREO16, 22050);
	if (pCaptureDevice)
	{
		printf("Opened '%s' Capture Device\n\n", alcGetString(pCaptureDevice, ALC_CAPTURE_DEVICE_SPECIFIER));

		printf("Press 1 to Start Recording\n");
		printf("Press 2 to Stop Recording\n");
		printf("Press Q to quit\n");

		pFile = fopen("recording.wav", "wb");

		sprintf(waveHeader.szRIFF, "RIFF");
		waveHeader.lRIFFSize = 0;
		sprintf(waveHeader.szWave, "WAVE");
		sprintf(waveHeader.szFmt, "fmt ");
		waveHeader.lFmtSize = sizeof(WAVEFORMATEX);		
		waveHeader.wfex.nChannels = 2;
		waveHeader.wfex.wBitsPerSample = 16;
		waveHeader.wfex.wFormatTag = WAVE_FORMAT_PCM;
		waveHeader.wfex.nSamplesPerSec = 22050;
		waveHeader.wfex.nBlockAlign = waveHeader.wfex.nChannels * waveHeader.wfex.wBitsPerSample / 8;
		waveHeader.wfex.nAvgBytesPerSec = waveHeader.wfex.nSamplesPerSec * waveHeader.wfex.nBlockAlign;
		waveHeader.wfex.cbSize = 0;
		sprintf(waveHeader.szData, "data");
		waveHeader.lDataSize = 0;

		fwrite(&waveHeader, sizeof(WAVEHEADER), 1, pFile);

		while (1)
		{
			if (_kbhit())
			{
				ch = getUpperCh();   

				switch(ch)
				{
				case '1':
					alcCaptureStart(pCaptureDevice);
					break;

				case '2':
					alcCaptureStop(pCaptureDevice);
					break;
				}

				if (ch == 'Q')
				{
					alcCaptureStop(pCaptureDevice);
					break;
				}
			}
			else
			{
				alcGetIntegerv(pCaptureDevice, ALC_CAPTURE_SAMPLES, 1, &lSamplesAvailable);
				printf("Samples available is %d\r", lSamplesAvailable);

				// When we have enough data to fill our 4000 byte buffer, grab the samples
				if (lSamplesAvailable > (4000 / waveHeader.wfex.nBlockAlign))
				{
					// Consume Samples
					alcCaptureSamples(pCaptureDevice, Buffer, 4000 / waveHeader.wfex.nBlockAlign);

					// Write the audio data to a file
					fwrite(Buffer, 4000, 1, pFile);

					// Record total amount of data recorded
					lDataSize += 4000;
				}
			}
		}

		// Check if any Samples haven't been captured yet
		alcGetIntegerv(pCaptureDevice, ALC_CAPTURE_SAMPLES, 1, &lSamplesAvailable);
		while (lSamplesAvailable)
		{
			if (lSamplesAvailable > (4000 / waveHeader.wfex.nBlockAlign))
			{
				alcCaptureSamples(pCaptureDevice, Buffer, 4000 / waveHeader.wfex.nBlockAlign);
				fwrite(Buffer, 4000, 1, pFile);
				lSamplesAvailable -= (4000 / waveHeader.wfex.nBlockAlign);
				lDataSize += 4000;
			}
			else
			{
				alcCaptureSamples(pCaptureDevice, Buffer, lSamplesAvailable);
				fwrite(Buffer, lSamplesAvailable * waveHeader.wfex.nBlockAlign, 1, pFile);
				lSamplesAvailable = 0;
				lDataSize += lSamplesAvailable * waveHeader.wfex.nBlockAlign;
			}
		}

		// Fill in Size information in Wave Header
		fseek(pFile, 4, SEEK_SET);
		lSize = lDataSize + sizeof(WAVEHEADER) - 8;
		fwrite(&lSize, 4, 1, pFile);
		fseek(pFile, 42, SEEK_SET);
		fwrite(&lDataSize, 4, 1, pFile);

		fclose(pFile);

		alcCaptureCloseDevice(pCaptureDevice);
	}
}

// Capture And Play Test
/** used by gendocs.py
$SECTION Interactive Tests
$SUBTITLE Capture And Play Test
*/
ALvoid I_CaptureAndPlayTest()
{
	ALCdevice		*pCaptureDevice;
	const			ALCchar *szDefaultCaptureDevice;
	ALint			lSamplesAvailable;
	ALchar			ch;
	ALchar			Buffer[QUEUEBUFFERSIZE];
	ALuint			SourceID, TempBufferID;
	ALuint			BufferID[QUEUEBUFFERCOUNT];
	ALuint			ulBuffersAvailable = QUEUEBUFFERCOUNT;
	ALuint			ulUnqueueCount, ulQueueCount;
	ALint			lLoop, lFormat, lFrequency, lBlockAlignment, lProcessed, lPlaying;
	ALboolean		bPlaying = AL_FALSE;
	ALboolean		bPlay = AL_FALSE;
#ifdef TEST_EAX
	ALint			lEnv, lDirect, lRoom;
#endif

	// NOTE : This code does NOT setup the Wave Device's Audio Mixer to select a recording input
	// or recording level.

	// Generate a Source and QUEUEBUFFERCOUNT Buffers for Queuing
	alGetError();
	alGenSources(1, &SourceID);

	for (lLoop = 0; lLoop < QUEUEBUFFERCOUNT; lLoop++)
		alGenBuffers(1, &BufferID[lLoop]);

	if (alGetError() != AL_NO_ERROR)
	{
		printf("Failed to generate Source and / or Buffers\n");
		return;
	}

	ulUnqueueCount = 0;
	ulQueueCount = 0;

	// Get list of available Capture Devices
	const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
	if (pDeviceList)
	{
		printf("Available Capture Devices are:-\n");

		while (*pDeviceList)
		{
			printf("%s\n", pDeviceList);
			pDeviceList += strlen(pDeviceList) + 1;
		}
	}

	szDefaultCaptureDevice = alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
	printf("\nDefault Capture Device is '%s'\n\n", szDefaultCaptureDevice);

	// The next call can fail if the WaveDevice does not support the requested format, so the application
	// should be prepared to try different formats in case of failure

	lFormat = AL_FORMAT_MONO16;
	lFrequency = 22050;
	lBlockAlignment = 2;

	pCaptureDevice = alcCaptureOpenDevice(szDefaultCaptureDevice, lFrequency, lFormat, lFrequency);
	if (pCaptureDevice)
	{
		printf("Opened '%s' Capture Device\n\n", alcGetString(pCaptureDevice, ALC_CAPTURE_DEVICE_SPECIFIER));

		printf("Press 1 to Start Recording and Playing\n");
		printf("Press 2 to Stop Recording\n");
#ifdef TEST_EAX
		printf("Press 3 to Apply EAX Reverb\n");
		printf("Press 4 to Remove EAX Reverb\n");
#endif
		printf("Press Q to quit\n");

		while (1)
		{
			if (_kbhit())
			{
				ch = getUpperCh();   

				switch(ch)
				{
				case '1':
					alcCaptureStart(pCaptureDevice);
					bPlay = AL_TRUE;
					break;

				case '2':
					alcCaptureStop(pCaptureDevice);
					break;
#ifdef TEST_EAX
				case '3':
					// Mute Direct path
					lDirect = -10000;
					eaxSet(&DSPROPSETID_EAX20_BufferProperties, DSPROPERTY_EAXBUFFER_DIRECT,
						NULL, &lDirect, sizeof(ALint));

					// Apply a Reverb Preset
					lEnv = EAX_ENVIRONMENT_HANGAR;
					eaxSet(&DSPROPSETID_EAX20_ListenerProperties, DSPROPERTY_EAXLISTENER_ENVIRONMENT,
						NULL, &lEnv, sizeof(ALint));

					lRoom = 0;
					eaxSet(&DSPROPSETID_EAX20_ListenerProperties, DSPROPERTY_EAXLISTENER_ROOM,
						NULL, &lRoom, sizeof(ALint));
					break;

				case '4':
					// Un-mute Direct path
					lDirect = 0;
					eaxSet(&DSPROPSETID_EAX20_BufferProperties, DSPROPERTY_EAXBUFFER_DIRECT,
						NULL, &lDirect, sizeof(ALint));

					// Mute Reverb Preset
					lRoom = -10000;
					eaxSet(&DSPROPSETID_EAX20_ListenerProperties, DSPROPERTY_EAXLISTENER_ROOM,
						NULL, &lRoom, sizeof(ALint));
					break;
#endif
				}

				if (ch == 'Q')
				{
					alcCaptureStop(pCaptureDevice);
					break;
				}
			}
			else
			{
				alcGetIntegerv(pCaptureDevice, ALC_CAPTURE_SAMPLES, 1, &lSamplesAvailable);
				printf("Samples available is %d\r", lSamplesAvailable);

				// If the Source is (or should be) playing, get number of buffers processed
				// and check play status
				if (bPlaying)
				{
					alGetSourcei(SourceID, AL_BUFFERS_PROCESSED, &lProcessed);
					while (lProcessed)
					{
						// Unqueue the buffer
						alSourceUnqueueBuffers(SourceID, 1, &TempBufferID);

						// Update unqueue count
						if (++ulUnqueueCount == QUEUEBUFFERCOUNT)
							ulUnqueueCount = 0;

						// Increment buffers available
						ulBuffersAvailable++;

						lProcessed--;
					}

					// If the Source has stopped (been starved of data) it will need to be
					// restarted
					alGetSourcei(SourceID, AL_SOURCE_STATE, &lPlaying);
					if (lPlaying == AL_STOPPED)
						bPlay = AL_TRUE;
				}

				// When we have enough data to fill our QUEUEBUFFERSIZE byte buffer, grab the samples
				if ((lSamplesAvailable > (QUEUEBUFFERSIZE / lBlockAlignment)) && (ulBuffersAvailable))
				{
					// Consume Samples
					alcCaptureSamples(pCaptureDevice, Buffer, QUEUEBUFFERSIZE / lBlockAlignment);

					alBufferData(BufferID[ulQueueCount], lFormat, Buffer, QUEUEBUFFERSIZE, lFrequency);

					// Queue the buffer, and mark buffer as queued
					alSourceQueueBuffers(SourceID, 1, &BufferID[ulQueueCount]);

					if (++ulQueueCount == QUEUEBUFFERCOUNT)
						ulQueueCount = 0;

					// Decrement buffers available
					ulBuffersAvailable--;

					// If we need to start the Source do it now IF AND ONLY IF we have queued at least 2 buffers
					if ((bPlay) && (ulBuffersAvailable <= (QUEUEBUFFERCOUNT - 2)))
					{
						alSourcePlay(SourceID);
						bPlaying = AL_TRUE;
						bPlay = AL_FALSE;
					}
				}
			}
		}

		alcCaptureCloseDevice(pCaptureDevice);
	}
	else
	{
		printf("WaveDevice is unavailable, or does not supported the request format\n");
	}

	alSourceStop(SourceID);
	alDeleteSources(1, &SourceID);
	for (lLoop = 0; lLoop < QUEUEBUFFERCOUNT; lLoop++)
		alDeleteBuffers(1, &BufferID[lLoop]);
}

#if TEST_VORBIS
// Vorbis Test
/** used by gendocs.pyp
$SECTION Interactive Tests
$SUBTITLE Vorbis Test
This test exercises Ogg Vorbis playback functionality.
*/
ALvoid I_VorbisTest()
{
      ALint error;
      ALbyte *data;
      ALuint source[3];
      ALuint tempBuffers[4];
      ALbyte ch;
      ALboolean bLoop = false;

      alGetError(); // reset error state

      if (alIsExtensionPresent((ALchar *)"AL_EXT_vorbis") == AL_TRUE) {
	alGenSources(3,source);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alGenSources 3 : ", error);
		return;
	}
	 
	// create buffers for queueing
	alGenBuffers(4, tempBuffers);

	printf("Vorbis Test\n");
	printf("Press '1' to play an Ogg Vorbis buffer on source 0\n");
	printf("Press '2' to toggle looping on / off for source 0\n");
        printf("Press '3' to play an Ogg Vorbis buffer on source 1\n");
        printf("Press '4' to stream an Ogg Vorbis buffer on source 2\n");
	printf("Press 'q' to quit\n");
	printf("Looping is off\n");

	do
	{
		ch = getUpperCh();
 		
		switch (ch)
		{
			case '1':
				// Stop source
				alSourceStop(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop source 0 : ", error);

				// Attach new buffer
				alSourcei(source[0],AL_BUFFER, g_Buffers[7]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei 0 AL_BUFFER buffer 7 : \n", error);

				// Set volume
				alSourcef(source[0],AL_GAIN,0.5f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcef 0 AL_GAIN : \n", error);

				// Set looping
				alSourcei(source[0],AL_LOOPING,bLoop);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING true: \n", error);

				// Play source
				alSourcePlay(source[0]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 0 : ", error);
		   				
				break;
			case '2':
				if (bLoop)
				{
					printf("Looping is off\n");
					bLoop = AL_FALSE;
				}
				else
				{
					printf("Looping is on  \n");
					bLoop = AL_TRUE;
				}
				alSourcei(source[0], AL_LOOPING, bLoop);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei 0 AL_LOOPING : \n", error);
				break;
			case '3':
				// Stop source
				alSourceStop(source[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourceStop source 1 : ", error);

				// Attach new buffer
				alSourcei(source[1],AL_BUFFER, g_Buffers[7]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcei 1 AL_BUFFER buffer 7 : \n", error);

				// Set volume
				alSourcef(source[1],AL_GAIN,0.5f);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcef 1 AL_GAIN : \n", error);

				// Play source
				alSourcePlay(source[1]);
				if ((error = alGetError()) != AL_NO_ERROR)
					DisplayALError((ALbyte *) "alSourcePlay source 1 : ", error);
		   				
				break;
			case '4':
				// Stop source
				alSourceStop(source[2]);
				if ((error = alGetError()) != AL_NO_ERROR) DisplayALError((ALbyte *) "alSourceStop source 2 : ", error);
                alSourcei(source[2], AL_BUFFER, 0);
		   
                // Queue buffers
				FILE *fp;
		        fp = fopen("boom.ogg", "rb");
		        if (fp == NULL) {
					printf("Failed to open boom.ogg\n");
					break;
				}
		   
		        alGetError(); // clear error state
		   
		        int actual;
				data = (ALbyte *)malloc(((g_ovSize / 4) + 1));
				if (data != 0) {
		        for (int loop = 0; loop < 4; loop++) {
						actual = fread(data, 1, ((g_ovSize / 4) + 1), fp);
						alBufferData(tempBuffers[loop], AL_FORMAT_VORBIS_EXT, data, actual, 0);
					}
					alSourceQueueBuffers(source[2], 4, tempBuffers);
			   
					fclose(fp);

					// Set volume
					alSourcef(source[2],AL_GAIN,0.5f);
					if ((error = alGetError()) != AL_NO_ERROR) DisplayALError((ALbyte *) "alSourcef 2 AL_GAIN : \n", error);

					// Play source
					alSourcePlay(source[2]);
					if ((error = alGetError()) != AL_NO_ERROR) DisplayALError((ALbyte *) "alSourcePlay source 2 : ", error);

					free((void *)data);
				} else {
					printf("Failed memory allocation.\n");
				}
		   				
				break;
		}
	} while (ch != 'Q');

	// Release resources
	alSourceStop(source[0]);
	alSourceStop(source[1]);
	alSourceStop(source[2]);
	alDeleteBuffers(4, tempBuffers);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError((ALbyte *) "alSourceStop : ", error);

	alDeleteSources(3, source);
	if ((error = alGetError()) != AL_NO_ERROR)
  	  DisplayALError((ALbyte *) "alDeleteSources 3 : ", error);    
      } else { // Ogg Vorbis extension not present
	printf("\nOgg Vorbis extension not available.\n");
      }
	
      return;
}
#endif
