/**
 * 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 Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA  02111-1307, USA.
 * Or go to http://www.gnu.org/copyleft/lgpl.html
 */

#define INITGUID
#define OPENAL

#ifdef _WIN32
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <memory.h>
#include <al/al.h>
#include <al/alc.h>
#include <al/alut.h>
#include <al/eax.h>
#endif

#ifdef LINUX
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <memory.h>
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alut.h>
#endif

#ifdef __MACOS__
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <memory.h>
#include <string.h>
#include <al.h>
#include <alc.h>
#include <alut.h>
#include <eax.h>
#endif

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

#pragma pack (push,1) 							/* Turn off alignment */

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


// Global variables

#ifndef LINUX
EAXSet	eaxSet;						// EAXSet function, retrieved if EAX Extension is supported
EAXGet	eaxGet;						// EAXGet function, retrieved if EAX Extension is supported
#endif
ALboolean g_bEAX;					// Boolean variable to indicate presence of EAX Extension 
ALuint	g_Buffers[NUM_BUFFERS];		// Array of Buffer IDs

// Function prototypes
ALvoid DisplayALError(ALbyte *szText, ALint errorcode);

// Test Function prototypes
ALvoid PositionTest(ALvoid);
ALvoid LoopingTest(ALvoid);
ALvoid EAXTest(ALvoid);
ALvoid QueueTest(ALvoid);
ALvoid BufferTest(ALvoid);
ALvoid FreqTest(ALvoid);
ALvoid StereoTest(ALvoid);
ALvoid GainTest(ALvoid);
ALvoid StreamingTest(ALvoid);

/*
	Display AL Error message
*/
ALvoid DisplayALError(ALbyte *szText, ALint errorcode)
{
	printf((const char *) szText);
	switch (errorcode)
	{
		case AL_INVALID_NAME:
			printf("AL_INVALID_NAME\n");
			break;
#ifndef LINUX
	        case AL_INVALID_ENUM:
			printf("AL_INVALID_ENUM\n");
			break;
#endif
		case AL_INVALID_VALUE:
			printf("AL_INVALID_VALUE\n");
			break;
#ifndef LINUX
	        case AL_INVALID_OPERATION:
			printf("AL_INVALID_OPERATION\n");
			break;
#endif
		case AL_OUT_OF_MEMORY:
			printf("AL_OUT_OF_MEMORY\n");
			break;
		default:
			printf("UNDEFINED ERROR\n");
			break;
	}
	return;
}

/*
	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[])
{
	ALubyte szEAX[] = "EAX";
	ALubyte szFnName[128];
	ALbyte	ch, bs;
	ALint	error;
	ALsizei size,freq;
	ALenum	format;
	ALvoid	*data;
	ALboolean loop;
#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

	printf("OpenAL Test application\n\n");

	// Initialize Open AL manually

#ifdef _WIN32
	//Open device
 	Device=alcOpenDevice((ALubyte*)"DirectSound3D");
	//Create context(s)
	Context=alcCreateContext(Device,NULL);
	//Set active context
	alcMakeContextCurrent(Context);
#else
    alutInit(NULL, 0);
#endif

	// Clear Error Code
	alGetError();

	// 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
	// Load footsteps.wav
#ifdef LINUX
        ALsizei bits;
        alutLoadWAV("Footsteps.wav", &data, &format, &size, & bits, &freq);
#endif
#ifdef _WIN32
	alutLoadWAVFile("footsteps.wav",&format,&data,&size,&freq,&loop);
#endif
#ifdef __MACOS__
	alutLoadWAVFile((char *) "footsteps.wav",&format,&data,&size,&freq);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutLoadWAVFile footsteps.wav : ", error);
		// Delete Buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Copy footsteps.wav data into AL Buffer 0
	alBufferData(g_Buffers[0],format,data,size,freq);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alBufferData buffer 0 : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Unload footsteps.wav
#ifndef LINUX
        alutUnloadWAV(format,data,size,freq);
#else
        free(data);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutUnloadWAV : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Load ding.wav
#ifdef LINUX
        alutLoadWAV("ding.wav", &data, &format, &size, & bits, &freq);
#endif
#ifdef _WIN32
	alutLoadWAVFile("ding.wav",&format,&data,&size,&freq,&loop);
#endif
#ifdef __MACOS__
	alutLoadWAVFile((char *) "ding.wav",&format,&data,&size,&freq);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutLoadWAVFile ding.wav : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit (-1);
	}

	// Copy ding.wav audio data into AL Buffer 1
	alBufferData(g_Buffers[1],format,data,size,freq);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alBufferData buffer 1 : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}
	
	// Unload ding.wav
#ifndef LINUX
        alutUnloadWAV(format,data,size,freq);
#else
        free(data);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutUnloadWAV : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

		// Load wave1.wav
#ifdef LINUX
        alutLoadWAV("Wave1.WAV", &data, &format, &size, & bits, &freq);
#endif
#ifdef _WIN32
	alutLoadWAVFile("wave1.wav",&format,&data,&size,&freq,&loop);
#endif
#ifdef __MACOS__
	alutLoadWAVFile((char *) "wave1.wav",&format,&data,&size,&freq);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutLoadWAVFile wave1.wav : ", error);
		// Delete Buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Copy wave1.wav data into AL Buffer 2
	alBufferData(g_Buffers[2],format,data,size,freq);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alBufferData buffer 2 : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Unload wave1.wav
#ifndef LINUX
        alutUnloadWAV(format,data,size,freq);
#else
        free(data);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutUnloadWAV : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

		// Load wave2.wav
#ifdef LINUX
        alutLoadWAV("Wave2.WAV", &data, &format, &size, & bits, &freq);
#endif
#ifdef _WIN32
	alutLoadWAVFile("wave2.wav",&format,&data,&size,&freq,&loop);
#endif
#ifdef __MACOS__
	alutLoadWAVFile((char *) "wave2.wav",&format,&data,&size,&freq);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutLoadWAVFile wave2.wav : ", error);
		// Delete Buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Copy wave2.wav data into AL Buffer 3
	alBufferData(g_Buffers[3],format,data,size,freq);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alBufferData buffer 3 : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Unload wave2.wav
#ifndef LINUX
        alutUnloadWAV(format,data,size,freq);
#else
        free(data);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutUnloadWAV : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

		// Load wave3.wav
#ifdef LINUX
        alutLoadWAV("Wave3.WAV", &data, &format, &size, & bits, &freq);
#endif
#ifdef _WIN32
	alutLoadWAVFile("wave3.wav",&format,&data,&size,&freq,&loop);
#endif
#ifdef __MACOS__
	alutLoadWAVFile((char *) "wave3.wav",&format,&data,&size,&freq);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutLoadWAVFile wave3.wav : ", error);
		// Delete Buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Copy wave3.wav data into AL Buffer 4
	alBufferData(g_Buffers[4],format,data,size,freq);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alBufferData buffer 4 : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Unload wave3.wav
#ifndef LINUX
        alutUnloadWAV(format,data,size,freq);
#else
        free(data);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutUnloadWAV : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Load wave4.wav
#ifdef LINUX
        alutLoadWAV("Wave4.WAV", &data, &format, &size, & bits, &freq);
#endif
#ifdef _WIN32
	alutLoadWAVFile("wave4.wav",&format,&data,&size,&freq,&loop);
#endif
#ifdef __MACOS__
	alutLoadWAVFile((char *) "wave4.wav",&format,&data,&size,&freq);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutLoadWAVFile wave4.wav : ", error);
		// Delete Buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Copy wave4.wav data into AL Buffer 5
	alBufferData(g_Buffers[5],format,data,size,freq);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alBufferData buffer 5 : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Unload wave4.wav
#ifndef LINUX
        alutUnloadWAV(format,data,size,freq);
#else
        free(data);
#endif
        if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutUnloadWAV : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Load stereo.wav
#ifdef LINUX
        alutLoadWAV("stereo.wav", &data, &format, &size, & bits, &freq);
#endif
#ifdef _WIN32
	alutLoadWAVFile("stereo.wav",&format,&data,&size,&freq,&loop);
#endif
#ifdef __MACOS__
	alutLoadWAVFile((char *) "stereo.wav",&format,&data,&size,&freq);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutLoadWAVFile stereo.wav : ", error);
		// Delete Buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Copy stereo.wav data into AL Buffer 6
	alBufferData(g_Buffers[6],format,data,size,freq);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alBufferData buffer 6 : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

	// Unload stereo.wav
#ifndef LINUX
        alutUnloadWAV(format,data,size,freq);
#else
        free(data);
#endif
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError((ALbyte *) "alutUnloadWAV : ", error);
		// Delete buffers
		alDeleteBuffers(NUM_BUFFERS, g_Buffers);
		exit(-1);
	}

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

#ifndef LINUX
        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

	do
	{
		printf("\nSelect a test from the following options\n\n");
		printf("1 Position Test\n");
		printf("2 Looping Test\n");
		printf("3 EAX 2.0 Test\n");
		printf("4 Queue Test\n");
		printf("5 Buffer Test\n");
		printf("6 Frequency Test\n");
		printf("7 Stereo Test\n");
		printf("8 Gain Test\n");
		printf("9 Streaming Test\n");
		printf("Q to quit\n\n\n");

#ifdef _WIN32
		ch = _getch();
#else
		ch = getchar();
#endif
 		ch = toupper(ch);

		switch (ch)
		{
			case '1':
				PositionTest();
				break;
			case '2':
				LoopingTest();
				break;
			case '3':
				if (g_bEAX)
					EAXTest();
				break;
			case '4':
				QueueTest();
				break;
			case '5':
				BufferTest();
				break;
			case '6':
				FreqTest();
				break;
			case '7':
				StereoTest();
				break;
			case '8':
				GainTest();
				break;
			case '9':
				StreamingTest();
				break;
			default:
				break;
		}
#ifndef _WIN32
	bs = getchar(); // grab newline
#endif 
	} while (ch != 'Q');

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

#ifdef _WIN32
	//Get active context
	Context=alcGetCurrentContext();
	//Get device for active context
	Device=alcGetContextsDevice(Context);
	//Release context(s)
	alcDestroyContext(Context);
	//Close device
	alcCloseDevice(Device);
#else
    alutExit();
#endif

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


/*
	Buffer Test
	Dynamically attach and unattach different buffers to a single Source
*/
ALvoid BufferTest(ALvoid)
{
	ALuint	source[1];
	ALint	error;
	char ch;

	ALfloat source0Pos[]={ 2.0, 0.0,-2.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
	{
#ifdef _WIN32
		ch = _getch();
#else
		ch = getchar();
#endif
 		ch = toupper(ch);
 		
		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
	Creates 2 Sources - one to the front right of the listener, and one to the rear left of the listener
*/
ALvoid PositionTest(ALvoid)
{	
	ALint	error;
	
	ALuint	source[2];
	ALbyte	ch;

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

	ALfloat source1Pos[]={ 2.0, 0.0,-2.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
	{
#ifdef _WIN32
		ch = _getch();
#else
		ch = getchar();
#endif
 		ch = toupper(ch);
 		
		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
	Tests 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 LoopingTest(ALvoid)
{
	ALint	error;
	ALuint	source[2];
	ALbyte	ch;
	ALboolean bLooping0 = AL_FALSE;
	ALboolean bLooping1 = AL_FALSE;

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

	ALfloat source1Pos[]={ 2.0, 0,0, -2.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
	{
#ifdef _WIN32
		ch = _getch();
#else
		ch = getchar();
#endif
 		ch = toupper(ch);
 		
		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;
}

/*
	EAXTest (Only runs if the EAX Extension is present)
	Uses 2 Sources to test out EAX 2.0 Reverb, Occlusion and Obstruction.  Also tests the use of the
	DEFERRED flag in EAX.
*/
ALvoid EAXTest(ALvoid)
{
#ifndef LINUX
        ALint	error;
	ALuint	source[2];
	ALbyte	ch;
	ALuint	Env;
	ALint	Room;
	ALint	Occlusion;
	ALint	Obstruction;
	EAXBUFFERPROPERTIES eaxBufferProp0;

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

	ALfloat source1Pos[]={ 2.0, 0.0,-2.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
	{
#ifdef _WIN32
		ch = _getch();
#else
		ch = getchar();
#endif
 		ch = toupper(ch);
 		
		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');

	// 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);

#endif // ifdef LINUX
	return;
}

/*
	QueueTest
	Tests 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 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, -2.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("EAX 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] = NULL;
	
	do
	{
#ifdef _WIN32
		ch = _getch();
#else
		ch = getchar();
#endif
		ch = toupper( ch );
		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);

				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);

				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);

				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);

				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);

				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, NULL);
				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;
}

/*
	FreqTest
	Test AL_PITCH functionality
*/
ALvoid FreqTest(ALvoid)
{
	ALint	error;
	ALuint	source[1];
	ALbyte	ch;
	ALfloat source0Pos[]={ 2.0, 0.0,-2.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
	{
#ifdef _WIN32
		ch = _getch();
#else
		ch = getchar();
#endif
 		ch = toupper(ch);
 		
		switch (ch)
		{
			case '1':
				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
	Plays a stereo buffer
*/
ALvoid StereoTest(ALvoid)
{
	ALint	error;
	ALuint	source[1];
	ALuint  buffers[2];
	ALuint	Buffer;
	ALint	BuffersInQueue, BuffersProcessed;
	ALbyte	ch;
	ALboolean bLoop = true;
	ALfloat source0Pos[]={ 2.0, 0.0,-2.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
	{
#ifdef _WIN32
		ch = _getch();
#else
		ch = getchar();
#endif
 		ch = toupper(ch);
 		
		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;
}

/*
	GainTest
	Play 2 Sources - control gain of each, and control Listener Gain
*/
ALvoid GainTest(ALvoid)
{
	ALint	error;
	ALuint	source[2];
	ALbyte	ch;

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

	ALfloat source1Pos[]={-2.0, 0.0,-2.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
	{
#ifdef _WIN32
		ch = _getch();
#else
		ch = getchar();
#endif
 		ch = toupper(ch);
 		
		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');

	// Release resources
	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 SwapWords(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 SwapBytes(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
	Stream a long stereo wave file from harddisc - using AL Queuing 
*/
ALvoid StreamingTest(ALvoid)
{
	FILE			*fp;
	WAVE_Struct		wave;

	ALbyte			data[BSIZE];
	ALuint			Buffers[NUMBUFFERS];
	ALuint			BufferID;
	ALuint			Sources[1];
	ALint			error;
	ALuint			DataSize;
	ALuint			DataToRead;
	ALubyte			ch;
	ALint			processed;
	ALboolean		bFinished = AL_FALSE;
	ALuint			Format;
	ALuint			loop;

	printf("Streaming Test\n");

#ifndef __MACOS__
	fp = fopen("stereo.wav", "rb");
#else
	fp = fopen("STEREO.WAV", "rb"); // not sure why this is needed on MacOS -- the file isn't really in upper-case
#endif

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

	// We are going to be queuing x buffers on our source

	// To start, fill all the buffers with audio data from the wave file

	// Read in WAVE Header
	if (fread(&wave, 1, sizeof(WAVE_Struct), fp) != sizeof(WAVE_Struct))
	{
		printf("Invalid wave file\n");
		fclose(fp);
		return;
	}
	
#ifdef __MACOS__
    SwapWords(&wave.dataSize);
    SwapBytes(&wave.Channels);
    SwapWords(&wave.SamplesPerSec);
#endif

	DataSize = wave.dataSize;

	if (wave.Channels == 1)
		Format = AL_FORMAT_MONO16;
	else
		Format = AL_FORMAT_STEREO16;

	alGenBuffers(NUMBUFFERS, Buffers);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError("alGenBuffers : ", error);
		fclose(fp);
		return;
	}

	for (loop = 0; loop < NUMBUFFERS; loop++)
	{
		fread(data, 1, BSIZE, fp);
		DataSize -= BSIZE;
#ifndef __MACOS__
		alBufferData(Buffers[loop], Format, data, BSIZE, wave.SamplesPerSec);
#else
		for (int i = 0; i < BSIZE; i=i+2)
		{
			SwapBytes((unsigned short *)(data+i));
		}
		alBufferData(Buffers[loop], (ALenum) Format, data, BSIZE, wave.SamplesPerSec);
#endif
		if ((error = alGetError()) != AL_NO_ERROR)
			DisplayALError("alBufferData : ", error);
	}

	alGenSources(1, Sources);
	if ((error = alGetError()) != AL_NO_ERROR)
	{
		DisplayALError("alGenSources 1 : ", error);
		alDeleteBuffers(NUMBUFFERS, Buffers);
		fclose(fp);
		return;
	}

	alSourcef(Sources[0], AL_GAIN, 0.5f);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcef AL_GAIN : ", error);

	// Queue the buffers on the source
	alSourceQueueBuffers(Sources[0], NUMBUFFERS, Buffers);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourceQueueBuffers : ", error);

	alSourcei(Sources[0], AL_LOOPING, AL_FALSE);

	// Start playing source
	alSourcePlay(Sources[0]);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alSourcePlay source 0 : ", error);

	printf("Press a key to quit\n");

	ALuint count = 0;
	ALuint buffersreturned = 0;
	ALboolean bFinishedPlaying = AL_FALSE;
	ALuint buffersinqueue = NUMBUFFERS;

#ifdef _WIN32
	while (!_kbhit() && !bFinishedPlaying)
#else
    while (!bFinishedPlaying)
#endif
	{
		// Get status
#ifndef LINUX
	        alGetSourcei(Sources[0], AL_BUFFERS_PROCESSED, &processed);
#else
	        alGetSourceiv(Sources[0], AL_BUFFERS_PROCESSED, &processed);
#endif

		// If some buffers have been played, unqueue them and load new audio into them, then add them to the queue
		if (processed > 0)
		{
			buffersreturned += processed;
			printf("Buffers Completed is %d\n", buffersreturned);

			// Pseudo code for Streaming a buffer with Open AL
			// while (processed)
			//		Unqueue a buffer
			//		Load audio data into buffer (returned by UnQueueBuffers)
			//		if successful
			//			Queue buffer
			//			processed--
			//		else
			//			buffersinqueue--
			//			if buffersinqueue == 0
			//				finished playing !

			while (processed)
			{
				alSourceUnqueueBuffers(Sources[0], 1, &BufferID);
				if ((error = alGetError()) != AL_NO_ERROR)
				{
					DisplayALError("alSourceUnqueueBuffers 1 : ", error);
				}

				if (!bFinished)
				{
					DataToRead = (DataSize > BSIZE) ? BSIZE : DataSize;

					if (DataToRead == DataSize)
						bFinished = AL_TRUE;
					
					fread(data, 1, DataToRead, fp);
					DataSize -= DataToRead;
					
					if (bFinished == AL_TRUE)
					{
						memset(data + DataToRead, 0, BSIZE - DataToRead);
					}

#ifndef __MACOS__				
					alBufferData(BufferID, Format, data, DataToRead, wave.SamplesPerSec);
#else
					for (int i = 0; i < DataToRead; i = i+2)
					{
						SwapBytes((unsigned short *)(data+i));
					}
					alBufferData(BufferID, (ALenum) Format, (void *) data, DataToRead, wave.SamplesPerSec);
#endif
					if ((error = alGetError()) != AL_NO_ERROR)
						DisplayALError("alBufferData : ", error);

					// Queue buffer
					alSourceQueueBuffers(Sources[0], 1, &BufferID);
					if ((error = alGetError()) != AL_NO_ERROR)
						DisplayALError("alSourceQueueBuffers 1 : ", error);

					processed--;
				}
				else
				{
					buffersinqueue--;
					processed--;

					if (buffersinqueue == 0)
					{
						bFinishedPlaying = true;
						break;
					}
				}
			}
		}
	}

#ifdef _WIN32
	if (!bFinishedPlaying)
		ch = getch();
#endif

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

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

	alDeleteBuffers(NUMBUFFERS, Buffers);
	if ((error = alGetError()) != AL_NO_ERROR)
		DisplayALError("alDeleteBuffers : ", error);

	fclose(fp);

	return;
}
