/* vim: sw=8 noet:
 ***************************************************************************
 *            sound.cpp
 *
 *  Fri May 13 19:02:21 2005
 *  Copyright  2005  Joe Venzon
 *  joe@venzon.net
 ****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
#include "sound.h"

//#define SOUND_DEBUG

/*void SOUNDMANAGER::LoadAllSoundFiles()
{
	if (disable)
		return;
	
	//LoadSoundFile(settings.GetDataDir() + "/sounds/engine.wav");
	LoadSoundFile(settings.GetFullDataPath("sounds/tire_squeal.wav"));
	
	string fname = settings.GetFullDataPath("cars/car_list.txt");
	ifstream cfile;
	cfile.open(fname.c_str());
	
	if (cfile)
	{
		string cftemp = utility.sGetLine(cfile);
		while (!cfile.eof())
		{
			LoadSoundFile(settings.GetFullDataPath("cars/"+cftemp+"/engine.wav"));
			//cout << "Loaded " << cftemp << endl;
			cftemp = utility.sGetLine(cfile);
		}
		cfile.close();
	}
}

void SOUNDMANAGER::SetListenerVel(VERTEX vel)
{
	if (disable)
		return;
	
	vel.Scale(VELOCITY_FACTOR);
	alListenerfv(AL_VELOCITY, vel.v3());
}

void SOUNDMANAGER::SetListenerPos(VERTEX pos)
{
	if (disable)
		return;
	
	pos.Scale(DISTANCE_FACTOR);
	alListenerfv(AL_POSITION, pos.v3());
}

void SOUNDMANAGER::SetListenerOrientation(VERTEX at, VERTEX up)
{
	if (disable)
		return;
	
	float f[6];
	f[0] = at.x;
	f[1] = at.y;
	f[2] = at.z;
	f[3] = up.x;
	f[4] = up.y;
	f[5] = up.z;
	
	alListenerfv(AL_ORIENTATION, f);
}

void SOUNDMANAGER::Load()
{
	if (disable)
		return;
	
	alutInit(NULL, 0);
	alGetError();
	
	
	// Position of the Listener.
	//ALfloat ListenerPos[] = { 0.0, 0.0, 0.0 };
	
	// Velocity of the Listener.
	//ALfloat ListenerVel[] = { 0.0, 0.0, 0.0 };
	
	// Orientation of the Listener. (first 3 elements are "at", second 3 are "up")
	// Also note that these should be units of '1'.
	//ALfloat ListenerOri[] = { 0.0, 0.0, -1.0,  0.0, 1.0, 0.0 };

	//set all sources to free
	
	buffers = new ALuint [MAX_BUFFERS];
	buf_fn = new string [MAX_BUFFERS];
	
	int i;
	for (i = 0; i < MAX_SOURCES; i++)
	{
		source_free[i] = true;
		
		buf_fn[i] = "";
	}
	
	buf_cur = 0;

	// Do another error check and return.

	//if(alGetError() == AL_NO_ERROR)
		//return AL_TRUE;

	//return AL_FALSE;

	VERTEX p;
	SetListenerPos(p);
	SetListenerVel(p);
	//alListenerfv(AL_POSITION,    ListenerPos);
	//alListenerfv(AL_VELOCITY,    ListenerVel);
	//alListenerfv(AL_ORIENTATION, ListenerOri);
	VERTEX u;
	u.y = 1;
	p.z = -1;
	SetListenerOrientation(p, u);
	
	//alSourcePlay(sources[0]);
	
	LoadAllSoundFiles();
	
	//int sid = NewSource("engine.wav");
	//PlaySource(sid);
	
	alDopplerFactor (0.002);
	alDistanceModel (AL_INVERSE_DISTANCE);
}

void SOUNDMANAGER::PlaySource(int idx)
{
	if (disable)
		return;
	
	//alSourceQueueBuffers(sources[idx], 2, buffers);
	alSourcePlay(sources[idx]);
}

SOUNDMANAGER::SOUNDMANAGER()
{
	disable = false;
	master_volume = 1.0;
}

extern bool verbose_output;
SOUNDMANAGER::~SOUNDMANAGER()
{
	if (verbose_output)
		cout << "sound deinit" << endl;
	
	if (!disable)
	{
		int i;
		
		for (i = 0; i < buf_cur; i++)
			alDeleteBuffers(1, &buffers[i]);
		
		//alDeleteBuffers(1, &buffers[0]);
		//alDeleteSources(1, &sources[0]);
		
		for (i = 0; i < MAX_SOURCES; i++)
		{
			if (!source_free[i])
			alDeleteSources(1, &sources[i]);	
		}
		
		// Destroy the sound context and device (Gentoo)
		mSoundContext = alcGetCurrentContext();
		mSoundDevice = alcGetContextsDevice( mSoundContext );
		alcDestroyContext( mSoundContext );
		if ( mSoundDevice)
			alcCloseDevice( mSoundDevice );

		alutExit();
		
		delete [] buffers;
		delete [] buf_fn;
	}
}

ALuint SOUNDMANAGER::NewSource(string buffername)
{
	if (disable)
		return 0;
	
	int i;
	for (i = 0; i < MAX_SOURCES; i++)
	{
		if (source_free[i])
		{
			source_free[i] = false;

			//cout << "old source: " << sources[i] << endl;
			
			// Bind the buffer with the source.
			alGenSources(1, &sources[i]);
			
			// Position of the source sound.
			ALfloat SourcePos[] = { 0.0, 0.0, 0.0 };
			// Velocity of the source sound.
			ALfloat SourceVel[] = { 0.0, 0.0, 0.0 };
			
			int idx, m;
			idx = -1;
			for (m = 0; m < MAX_BUFFERS; m++)
			{
				if (buf_fn[m] == buffername)
					idx = m;
			}
			
			if (idx == -1)
			{
				cout << "Cannot find sound file " << buffername << endl;
			}
			else
			{
				//cout << idx << endl;
				alSourcei (sources[i], AL_BUFFER,   buffers[idx]   );
				alSourcef (sources[i], AL_PITCH,    1.0      );
				alSourcef (sources[i], AL_GAIN,     1.0      );
				alSourcefv(sources[i], AL_POSITION, SourcePos);
				alSourcefv(sources[i], AL_VELOCITY, SourceVel);
				alSourcei (sources[i], AL_LOOPING,  AL_TRUE     );
				//alSourcei (sources[i], AL_LOOPING,  AL_FALSE     );
				
				SetGain(i, 1.0);
			}
			//cout << "new source: " << sources[i] << endl;
			PlaySource(i);
			return i;
		}
	}
	
	cout << "Out of sound sources." << endl;
	return 0;
}

void SOUNDMANAGER::LoadSoundFile(string filename)
{
	if (disable)
		return;
	
	ALenum format;
	ALsizei size;
	ALvoid* data = 0;
#ifdef OLD_OPENAL
	ALsizei freq;
	ALboolean loop;
#else
	ALfloat freq;
#endif
	
	// Load wav data into a buffer.
	

	//if(alGetError() != AL_NO_ERROR)
		//return AL_FALSE;
	
	//string sfile = settings.GetDataDir() + "/sounds/engine.wav";
	
#ifdef __APPLE__
	alutLoadWAVFile((ALbyte*)(filename).c_str(), &format, &data, &size, &freq);
#else
#ifdef OLD_OPENAL
	alutLoadWAVFile((ALbyte*)(filename).c_str(), &format, &data, &size, &freq, &loop);
#else
	data = alutLoadMemoryFromFile((ALbyte*)(filename).c_str(), &format, &size, &freq);
#endif
#endif
	//bool err = LoadWave(filename, &format, &data, &size, &freq, &loop);
	//if (filename == settings.GetDataDir() + "/sounds/engine.wav")
	{
		//cout << loop << endl;
		//cout << size << ", " << freq << endl;
	}
	if (data)
	{
		alGenBuffers(1, &buffers[buf_cur]);
		//UnloadWave(data);

#ifdef OLD_OPENAL
		alBufferData(buffers[buf_cur], format, data, size, freq);
		alutUnloadWAV(format, data, size, freq);
#else
		alBufferData(buffers[buf_cur], format, data, size, (int)freq);
#endif

		buf_fn[buf_cur] = filename;
	
		buf_cur++;
	}
	else
	{
		cerr << "Error loading sound file: " << filename << "\n";
	}
}

void SOUNDMANAGER::SetPitch(int sid, float pitch)
{
	if (disable)
		return;
	
	alSourcef (sources[sid], AL_PITCH, pitch);
}

void SOUNDMANAGER::SetGain(int sid, float gain)
{
	if (disable)
		return;

	gain *= master_volume;
	
	alSourcef (sources[sid], AL_MAX_GAIN, gain);
	alSourcef (sources[sid], AL_GAIN, gain);
	//alSourcef (sources[sid], AL_MIN_GAIN, gain);
}

void SOUNDMANAGER::SetPos(int sid, VERTEX pos)
{
	if (disable)
		return;
	
	pos.Scale(DISTANCE_FACTOR);
	//cout << sources[sid] << endl;
	if (alIsSource(sources[sid]))
	{
		alSourcefv(sources[sid], AL_POSITION, pos.v3());
	}
	else
	{
	}
}

void SOUNDMANAGER::SetVel(int sid, VERTEX vel)
{
	if (disable)
		return;
	
	vel.Scale(VELOCITY_FACTOR);
	if (alIsSource(sources[sid]))
		alSourcefv(sources[sid], AL_VELOCITY, vel.v3());
}

void SOUNDMANAGER::MuteAll()
{
	if (disable)
		return;
	
	int i;
	for (i = 0; i < MAX_SOURCES; i++)
	{
		if (!source_free[i])
		{
			SetGain(i, 0.0f);
		}
	}
}

void SOUNDMANAGER::UnMuteAll()
{
	
}

void SOUNDMANAGER::DisableAllSound()
{
	disable = true;
}

void SOUNDMANAGER::EnableAllSound()
{
	disable = false;
}

void SOUNDMANAGER::StopSource(int sid)
{
	alSourceStop(sources[sid]);
	alDeleteSources(1, &sources[sid]);
	source_free[sid] = true;
}

void SOUNDMANAGER::SetPosVel(int sid, VERTEX coord, VERTEX tvel)
{
	//cout << sid << endl;
	//coord.DebugPrint();
	SetPos(sid, coord);
	SetVel(sid, tvel);
}

void SOUNDMANAGER::SetListener(VERTEX campos, VERTEX camvel, VERTEX at, VERTEX up)
{
	//campos.DebugPrint();
	SetListenerPos(campos);
	SetListenerVel(camvel);
	SetListenerOrientation(at, up);
}*/

void SOUNDMANAGER::Init()
{
	if (disabled)
		return;
	
	if (!init)
	{
		EnumerateDevices();
		
		alutInit(NULL, 0);
		alGetError();
		
		alDopplerFactor (0.002);
		alDistanceModel (AL_INVERSE_DISTANCE);
		
		VERTEX p;
		SetListenerPos(p);
		SetListenerVel(p);
		VERTEX u;
		u.y = 1;
		p.z = -1;
		SetListenerOrientation(p, u);
		
		init = true;
	}
}

void SOUNDMANAGER::Deinit()
{
	if (disabled)
		return;
	
	if (init)
	{
		Unload();
		
		// Destroy the sound context and device (Gentoo)
		mSoundContext = alcGetCurrentContext();
		mSoundDevice = alcGetContextsDevice( mSoundContext );
		alcDestroyContext( mSoundContext );
		if ( mSoundDevice)
			alcCloseDevice( mSoundDevice );

		alutExit();
		
		init = false;
	}
}

void SOUNDMANAGER::Load()
{
	if (disabled)
		return;
	
	if (!loaded)
	{
		buffers.clear();
		sources.clear();
		
		//string car_name = state.GetCarName(0);
		string car_name;
		settings.Get( "game.selected_car", car_name );
		LoadSoundFile(settings.GetFullDataPath("sounds/tire_squeal.wav"));
		LoadSoundFile(settings.GetFullDataPath("cars/"+car_name+"/engine.wav"));
		
		loaded = true;
	}
}

void SOUNDMANAGER::Unload()
{
	if (disabled)
		return;
	
	if (loaded)
	{
		/*unsigned int i;
		for (i = 0; i < sources.size(); i++)
		{
			StopSource(i);
		}*/
		
		for (map <string, ALuint>::iterator i = buffers.begin(); i != buffers.end(); i++)
		{
			#ifdef SOUND_DEBUG
			cout << "Deleted sound " << i->first << " from buffer " << i->second << endl;
			#endif
			alDeleteBuffers(1, &(i->second));
		}
		
		for (vector <ALuint>::iterator i = sources.begin(); i != sources.end(); i++)
		{
			//alDeleteSources(1, &(*(i)));
			
			alSourceStop((*(i)));
			alDeleteSources(1, &(*(i)));
		}
		
		buffers.clear();
		sources.clear();
		source_free.clear();
		
		loaded = false;
	}
}

void SOUNDMANAGER::Reload()
{
	if (disabled)
		return;

	Unload();
	Load();
}

void SOUNDMANAGER::LoadSoundFile(string filename)
{
	if (disabled)
		return;
	
	if (buffers.find(filename) != buffers.end())
	{
		cout << "sound file already loaded: " << filename << endl;
		return;
	}
	
	ALenum format;
	ALsizei size;
	ALvoid* data = 0;
	ALsizei freq;
	bool error = 0;
	
#ifdef __BIG_ENDIAN__	 
	alutLoadWAVFile((ALbyte*)(filename).c_str(), &format, &data, &size, &freq);	 
#else
	ALboolean loop;
	error= LoadWave(filename.c_str(), &format, &data, &size, &freq, &loop);
#endif

	if (data && !error)
	{
		ALuint newbuf;
		alGenBuffers(1, &newbuf);
#ifdef __BIG_ENDIAN__	 
		alBufferData(newbuf, format, data, size, freq);	 
		alutUnloadWAV(format, data, size, freq);	 
#else
		alBufferData(newbuf, format, data, size, (int)freq);
		UnloadWave(data);
#endif
		buffers[filename] = newbuf;
		
		#ifdef SOUND_DEBUG
		cout << "Loaded sound " << filename << " into buffer " << newbuf << endl;
		#endif
	}
	else
	{
		cerr << "Error loading sound file: " << filename << "\n";
		if (!disabled)
		{
			cerr << "Disabling sound." << endl;
			disabled = true;
		}
	}
}

void SOUNDMANAGER::SetPosVel(int sid, VERTEX coord, VERTEX tvel)
{
	if (disabled)
		return;
	
	SetPos(sid, coord);
	SetVel(sid, tvel);
}

void SOUNDMANAGER::SetListener(VERTEX campos, VERTEX camvel, VERTEX at, VERTEX up)
{
	if (disabled)
		return;
	
	SetListenerPos(campos);
	SetListenerVel(camvel);
	SetListenerOrientation(at, up);
}

void SOUNDMANAGER::SetPitch(int sid, float pitch)
{
	if (disabled)
		return;
	
	//cout << "asked for source " << sid << "/" << sources.size() << endl;
	
	alSourcef (sources[sid], AL_PITCH, pitch);
}

void SOUNDMANAGER::SetGain(int sid, float gain)
{
	if (disabled)
		return;
	
	if (!loaded)
	{
		//this happens when the spinning car widget creates a car object which does a NewSource on unloaded buffers
		return;
	}

	gain *= master_volume;
	
	alSourcef (sources[sid], AL_MAX_GAIN, gain);
	alSourcef (sources[sid], AL_GAIN, gain);
}

void SOUNDMANAGER::SetPos(int sid, VERTEX pos)
{
	if (disabled)
		return;
	
	pos.Scale(DISTANCE_FACTOR);

	if (alIsSource(sources[sid]))
	{
		alSourcefv(sources[sid], AL_POSITION, pos.v3());
	}
	else
	{
	}
}

void SOUNDMANAGER::SetVel(int sid, VERTEX vel)
{
	if (disabled)
		return;
	
	vel.Scale(VELOCITY_FACTOR);
	if (alIsSource(sources[sid]))
		alSourcefv(sources[sid], AL_VELOCITY, vel.v3());
}

void SOUNDMANAGER::StopSource(int sid)
{
	if (disabled || !loaded)
		return;
	
	/*cout << "stopsource(" << sid << ")" << endl;
	
	if (source_free[sid])
		return;
	
	cout << "stopping source " << sid << " id " << sources[sid] << endl;*/
	
	alSourceStop(sources[sid]);
	alDeleteSources(1, &sources[sid]);
	source_free[sid] = true;
}

void SOUNDMANAGER::PlaySource(int idx)
{
	if (disabled || !loaded)
		return;
	
	alSourcePlay(sources[idx]);
}

ALuint SOUNDMANAGER::NewSource(string buffername)
{
	bool error;
	return NewSource(buffername, error);
}

ALuint SOUNDMANAGER::NewSource(string buffername, bool & error)
{
	if (disabled)
		return 0;
	
	if (!loaded)
	{
		//this happens when the spinning car widget creates a car object which does a NewSource on unloaded buffers
		error = true;
		return 0;
	}
	
	if (sources.size() > MAX_SOURCES)
	{
		cout << "Out of sound sources, can't create new source for buffer " << buffername << " (" << sources.size() << ")" << endl;
		error = true;
		return 0;
	}
	
	map <string, ALuint>::iterator sbuf = buffers.find(buffername);
	if (sbuf == buffers.end())
	{
		cout << "Can't find buffer " << buffername << endl;
		error = true;
		return 0;
	}
	
	ALuint newsource;
	alGenSources(1, &newsource);
	
	ALfloat SourcePos[] = { 0.0, 0.0, 0.0 };
	ALfloat SourceVel[] = { 0.0, 0.0, 0.0 };
	
	alSourcei (newsource, AL_BUFFER,   sbuf->second   );
	alSourcef (newsource, AL_PITCH,    1.0      );
	alSourcef (newsource, AL_GAIN,     1.0      );
	alSourcefv(newsource, AL_POSITION, SourcePos);
	alSourcefv(newsource, AL_VELOCITY, SourceVel);
	alSourcei (newsource, AL_LOOPING,  AL_TRUE     );
	//alSourcei (sources[i], AL_LOOPING,  AL_FALSE     );
	
	int i = sources.size();
	sources.push_back(newsource);
	
	SetGain(i, 1.0);
		
	PlaySource(i);
	
	error = false;
	
	return i;
}

void SOUNDMANAGER::SetListenerVel(VERTEX vel)
{
	if (disabled)
		return;
	
	vel.Scale(VELOCITY_FACTOR);
	alListenerfv(AL_VELOCITY, vel.v3());
}

void SOUNDMANAGER::SetListenerPos(VERTEX pos)
{
	if (disabled)
		return;
	
	pos.Scale(DISTANCE_FACTOR);
	alListenerfv(AL_POSITION, pos.v3());
}

void SOUNDMANAGER::SetListenerOrientation(VERTEX at, VERTEX up)
{
	if (disabled)
		return;
	
	float f[6];
	f[0] = at.x;
	f[1] = at.y;
	f[2] = at.z;
	f[3] = up.x;
	f[4] = up.y;
	f[5] = up.z;
	
	alListenerfv(AL_ORIENTATION, f);
}

void SOUNDMANAGER::MuteAll()
{
	if (disabled)
		return;
	
	unsigned int i;
	for (i = 0; i < sources.size(); i++)
	{
		SetGain(i, 0.0f);
	}
}

void SOUNDMANAGER::UnMuteAll()
{
	//placeholder, not yet used
}

bool SOUNDMANAGER::LoadWave(string fname, ALenum *format, ALvoid **data, ALsizei *size,
        ALsizei *freq, ALboolean *loop)
{
    FILE *fp;
        
        bool err = false;

    fp = fopen(fname.c_str(),"rb");
    if (fp)
    {
        ALbyte id[4], *sound_buffer; //four bytes to hold 'RIFF'
        
		ALint fsize; //32 bit value to hold file size
		
        ALshort format_tag; //our 16-bit signed values
		ALushort channels, block_align, bits_per_sample; //our 16-bit unsigned values
		
        ALint format_length;//our 32 signed bit values
		ALuint sample_rate, avg_bytes_sec;// data_size;//, i; //our 32 unsigned bit values
        ALint data_size;
        fsize = 0;
        fread(id, sizeof(ALbyte), 4, fp); //read in first four bytes
        //if (!strcmp((const char*)id, "RIFF"))
		if (IDMatchesString((char*) id, "RIFF"))
        { //we had 'RIFF' let's continue
            fread(&fsize, sizeof(ALint), 1, fp); //read in 32bit size value
            fread(id, sizeof(ALbyte), 4, fp); //read in 4 byte string now
            //if (!strcmp((const char*)id,"WAVE"))
			if (IDMatchesString((char*)id,"WAVE"))
            { //this is probably a wave file since it contained "WAVE"
                fread(id, sizeof(ALbyte), 4, fp); //read in 4 bytes "fmt ";
                fread(&format_length, sizeof(ALint),1,fp);
                fread(&format_tag, sizeof(ALshort), 1, fp); //check mmreg.h (i think?) for other 
                                                              // possible format tags like ADPCM
                fread(&channels, sizeof(ALshort),1,fp); //1 mono, 2 stereo
                fread(&sample_rate, sizeof(ALint), 1, fp); //like 44100, 22050, etc...
                fread(&avg_bytes_sec, sizeof(ALint), 1, fp); //probably won't need this
                fread(&block_align, sizeof(ALshort), 1, fp); //probably won't need this
                fread(&bits_per_sample, sizeof(ALshort), 1, fp); //8 bit or 16 bit file?
				
				//find data chunk
				bool found_data_chunk = false;
				long filepos = format_length + 4 + 4 + 4 + 4 + 4;
				int chunknum = 0;
				while (!found_data_chunk && chunknum < 10)
				{
					#ifdef SOUND_DEBUG
					cout << "seeking to " << filepos << endl;
					#endif
					fseek(fp, filepos, SEEK_SET); //seek to the next chunk
					fread(id, sizeof(ALbyte), 4, fp); //read in 'data'
					fread(&data_size, sizeof(ALbyte), 4, fp); //how many bytes of sound data we have
					if (IDMatchesString((char*)id, "data"))
					{
                		found_data_chunk = true;
						#ifdef SOUND_DEBUG
						cout << "Found data chunk at " << filepos << ", chunk " << chunknum << endl;
						#endif
					}
					else
					{
						#ifdef SOUND_DEBUG
						cout << "Chunk isn't data at " << filepos << ", chunk " << chunknum << endl;
						#endif
						filepos += data_size + 4 + 4;
					}
					
					chunknum++;
				}
				
				if (chunknum >= 10)
				{
					cerr << "Error: Wave file contains more than 10 chunks before the data chunk: " << fname << endl;
					*data = NULL;
					return false;
				}
				
                //sound_buffer = (BYTE *) malloc (sizeof(BYTE) * data_size); //set aside sound buffer space
				#ifdef SOUND_DEBUG
				cout << "Loading sound " << fname << ": filesize " << fsize << ", " << data_size << " samples" << endl;
				#endif
				sound_buffer = new ALbyte[data_size];
				fread(sound_buffer, sizeof(ALbyte), data_size, fp); //read in our whole sound data chunk
				
				*data = sound_buffer;
				if (bits_per_sample == 16 && channels == 2)
						*format = AL_FORMAT_STEREO16;
				else if (bits_per_sample == 8 && channels == 2)
						*format = AL_FORMAT_STEREO8;
				else if (bits_per_sample == 16 && channels == 1)
						*format = AL_FORMAT_MONO16;
				else if (bits_per_sample == 8 && channels == 1)
						*format = AL_FORMAT_MONO8;
				else
				{
					cerr << "Error: unknown bits per sample and channels in file: " << fname << endl;
					cerr << channels << " channels" << endl;
					cerr << bits_per_sample << " bits per sample" << endl;
				}
				
				*size = data_size;
				*freq = sample_rate;
				#ifdef SOUND_DEBUG
				cout << channels << " channels" << endl;
				cout << bits_per_sample << " bits per sample" << endl;
				cout << sample_rate << " Hz sample rate" << endl;
				//cout << << endl;
				#endif
            }
            else
            {
                cerr << "Error: RIFF file but not a wave file: " << fname << endl;
				err = true;
				*data = NULL;
            }
        }
        else
        {
            cerr << "Error: not a RIFF file: " << fname << endl;
			err = true;
			*data = NULL;
        }
    }
    else
    {
		cerr << "Can't find sound file: " << fname << endl;
		err = true;
		*data = NULL;
    }
	
    return err;
}

void SOUNDMANAGER::UnloadWave(ALvoid* data)
{
        delete [] (ALbyte*)data;
}

bool SOUNDMANAGER::IDMatchesString(const char * id, const char * str)
{
	bool match = true;
	for (unsigned int i = 0; i < strlen(str); i++)
	{
		if (id[i] != str[i])
			match = false;
	}
	return match;
}

void SOUNDMANAGER::EnumerateDevices()
{
	//cout << "Sound extensions: " << alGetString(AL_EXTENSIONS) << endl;
	//cout << "Sound extensions: " << alcGetString(NULL, ALC_EXTENSIONS) << endl;
	/*cout << "Sound extensions: ";
	char * extstr = (char *)alGetString(alGetEnumValue("AL_EXTENSIONS"));
	int i;
	for (i = 0; i < 100 && i != '\0'; i++)
	{
		cout << extstr[i];
	}
	cout << " (" << i << ")" << endl;*/
	/*cout << "Enumerating sound devices..." << endl;
	
	char * defaultdevice = (char *)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
	cout << "\tDefault device: " << defaultdevice << endl;
	
	ALCdevice * dev = alcOpenDevice (defaultdevice);
	
	cout << "Default device extensions: " << alcGetString(dev, alcGetEnumValue(dev, "ALC_EXTENSIONS")) << endl;
	cout << "Error: " << alcGetString(dev, alcGetError(dev)) << endl;
	
	alcCloseDevice(dev);*/
	
	/*char * defaultdevice;
	char * devicelist;
	int numdevices = 0;
	int numdefaultdevice = 0;
	int MAXDEVICES = 16;
	string devlist[MAXDEVICES];
	//if (alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE)
	if (1)
	{
		devicelist = (char *) alcGetString(NULL, ALC_DEVICE_SPECIFIER);
		cout << "\tDevice: " << devicelist << endl;
		defaultdevice = (char *)alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
		cout << "\tDefault device: " << defaultdevice << endl;
		if (strlen(devicelist))
		{
			numdevices = 1;
			for (Uint16 numdevices = 0; numdevices < 16; numdevices++)
			{
				devlist[numdevices] = devicelist;
				cout << "\tDevice " << numdevices << ": " << devicelist << endl;
				if (defaultdevice && strcmp(devicelist, defaultdevice) == 0)
					numdefaultdevice = numdevices;
				devicelist += strlen(devicelist);
				if (devicelist[0] == 0)
				{
					if (devicelist[1] == 0)
						break;
					else
					{
						numdevices++;
						devicelist++;
					}
				}
			}
		}
	}
	else
		cout << "\tNo sound device enumeration extension present." << endl;*/
}
