00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <vector>
00033 #include <alc.h>
00034 #include "Exception.h"
00035 #include "config.h"
00036 #include "OggFile.h"
00037 #include "soundutil.h"
00038
00039 using namespace std;
00040
00041 namespace {
00042 const string ALNoErrorStr = "No AL error occurred";
00043 const string ALInvalidNameStr = "AL error: a bad name (ID) was passed to an OpenAL function";
00044 const string ALInvalidEnumStr = "AL error: an invalid enum value was passed to an OpenAL function";
00045 const string ALInvalidValueStr = "AL error: an invalid value was passed to an OpenAL function";
00046 const string ALInvalidOpStr = "AL error: the requested operation is not valid";
00047 const string ALOutOfMemoryStr = "AL error: the requested operation resulted in OpenAL running out of memory";
00048 const string ALOtherErrorStr = "AL error: unknown error";
00049 }
00050
00051 void pcce::InitializeAL() {
00052 ClearALError();
00053
00054 PCCE_CHECK(alcGetCurrentContext() == NULL, "AL already initialized");
00055
00056 ALCdevice* device = alcOpenDevice(NULL);
00057 PCCE_CHECK(device != NULL, "InitializeAL: Cannot open preferred device");
00058 if (alcGetError(device) != ALC_NO_ERROR) {
00059 alcCloseDevice(device);
00060 PCCE_THROW("InitializeAL: Could not open device (alc error)");
00061 }
00062
00063
00064
00065
00066
00067 ALCcontext* context = alcCreateContext(device, NULL);
00068 if (context == NULL) {
00069 alcCloseDevice(device);
00070 PCCE_THROW("InitializeAL: Could not create context");
00071 }
00072 if (alcGetError(device) != ALC_NO_ERROR) {
00073 alcDestroyContext(context);
00074 alcCloseDevice(device);
00075 PCCE_THROW("InitializeAL: Could not open device (alc error)");
00076 }
00077
00078 if (alcMakeContextCurrent(context) != ALC_TRUE) {
00079 alcDestroyContext(context);
00080 alcCloseDevice(device);
00081 PCCE_THROW("InitializeAL: Could not make context current");
00082 }
00083 if (alcGetError(device) != ALC_NO_ERROR) {
00084 alcMakeContextCurrent(NULL);
00085 alcDestroyContext(context);
00086 alcCloseDevice(device);
00087 PCCE_THROW("InitializeAL: Could not make context current (alc error)");
00088 }
00089
00090 ClearALError();
00091
00092
00093
00094
00095
00096
00097 ALfloat listenerPos[] = { 0.0, 0.0, 0.0 };
00098 ALfloat listenerVel[] = { 0.0, 0.0, 0.0 };
00099
00100
00101
00102 ALfloat listenerOri[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 };
00103
00104 alListenerfv(AL_POSITION, listenerPos);
00105 alListenerfv(AL_VELOCITY, listenerVel);
00106 alListenerfv(AL_ORIENTATION, listenerOri);
00107 if (alGetError() != AL_NO_ERROR) {
00108 ShutdownAL();
00109 PCCE_THROW("InitializeAL: Could not set listener position");
00110 }
00111
00112 }
00113
00114 void pcce::ShutdownAL() {
00115 ClearALError();
00116
00117 ALCcontext* context = alcGetCurrentContext();
00118 if (context == NULL) {
00119 PCCE_AL_CHECK();
00120 return;
00121 }
00122
00123 ALCdevice* device = alcGetContextsDevice(context);
00124 PCCE_AL_CHECK();
00125
00126 alcSuspendContext(context);
00127 PCCE_AL_CHECK();
00128 alcDestroyContext(context);
00129 PCCE_AL_CHECK();
00130 if (device != NULL) {
00131 alcCloseDevice(device);
00132 PCCE_AL_CHECK();
00133 }
00134 }
00135
00136 ALuint pcce::LoadOgg(const std::string& fileName) {
00137 ALuint buffer = AL_NONE;
00138 ALenum format;
00139 ALsizei freq;
00140 tCharVector data;
00141 OggFile f(fileName);
00142 f.Open();
00143
00144
00145 switch(f.GetChannelCount()) {
00146 case 1:
00147 format = AL_FORMAT_MONO16;
00148 break;
00149 case 2:
00150 format = AL_FORMAT_STEREO16;
00151 break;
00152 default:
00153 PCCE_THROW("Ogg file must have 1 or 2 channels");
00154 }
00155 freq = f.GetFrequency();
00156
00157 f.Read(data);
00158 f.Close();
00159
00160 ClearALError();
00161 try {
00162 alGenBuffers(1, &buffer);
00163 PCCE_CHECK(alGetError() == AL_NO_ERROR, "LoadOgg: Could not generate buffer");
00164 PCCE_CHECK(AL_NONE != buffer, "LoadOgg: Could not generate buffer");
00165
00166 alBufferData(buffer, format, &data[0], data.size(), freq);
00167 PCCE_CHECK(alGetError() == AL_NO_ERROR, "LoadOgg: Could not load buffer data");
00168
00169 return buffer;
00170 } catch (Exception& e) {
00171 if ((buffer != AL_NONE) && (alIsBuffer(buffer) == AL_TRUE)) {
00172 alDeleteBuffers(1, &buffer);
00173 }
00174 ClearALError();
00175 throw (e);
00176 }
00177 }
00178
00179
00180 namespace pcce {
00181
00182 static unsigned short readByte16(const unsigned char buffer[2]) {
00183 #if PCCE_BIG_ENDIAN
00184 return (buffer[0] << 8) + buffer[1];
00185 #else
00186 return (buffer[1] << 8) + buffer[0];
00187 #endif
00188 }
00189 static unsigned long readByte32(const unsigned char buffer[4]) {
00190 #if PCCE_BIG_ENDIAN
00191 return (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
00192 #else
00193 return (buffer[3] << 24) + (buffer[2] << 16) + (buffer[1] << 8) + buffer[0];
00194 #endif
00195 }
00196 }
00197
00198
00199
00200
00201
00202
00203
00204 ALuint pcce::LoadWav(const std::string& fileName) {
00205 const unsigned int BUFFER_SIZE = 32768;
00206 long bytes;
00207 vector <char> data;
00208 ALenum format;
00209 ALsizei freq;
00210
00211
00212 FILE *f = NULL;
00213 char *array = NULL;
00214 ALuint buffer = AL_NONE;
00215
00216 ClearALError();
00217
00218
00219 try {
00220
00221
00222 f = fopen(fileName.c_str(), "rb");
00223 if (!f)
00224 PCCE_THROW("LoadWav: Could not load wav from " + fileName);
00225
00226
00227 char magic[5];
00228 magic[4] = '\0';
00229 unsigned char buffer32[4];
00230 unsigned char buffer16[2];
00231
00232
00233 PCCE_CHECK(fread(magic,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
00234 PCCE_CHECK(std::string(magic) == "RIFF", "LoadWav: Wrong wav file format. This file is not a .wav file (no RIFF magic): "+ fileName );
00235
00236
00237 fseek(f,4,SEEK_CUR);
00238
00239
00240 PCCE_CHECK(fread(magic,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
00241 PCCE_CHECK(std::string(magic) == "WAVE", "LoadWav: Wrong wav file format. This file is not a .wav file (no WAVE format): "+ fileName );
00242
00243
00244 PCCE_CHECK(fread(magic,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
00245 PCCE_CHECK(std::string(magic) == "fmt ", "LoadWav: Wrong wav file format. This file is not a .wav file (no 'fmt ' subchunk): "+ fileName );
00246
00247
00248 PCCE_CHECK(fread(buffer32,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
00249 unsigned long subChunk1Size = readByte32(buffer32);
00250 PCCE_CHECK(subChunk1Size >= 16, "Wrong wav file format. This file is not a .wav file ('fmt ' chunk too small, truncated file?): "+ fileName );
00251
00252
00253 PCCE_CHECK(fread(buffer16,2,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
00254 unsigned short audioFormat = readByte16(buffer16);
00255 PCCE_CHECK(audioFormat == 1, "LoadWav: Wrong wav file format. This file is not a .wav file (audio format is not PCM): "+ fileName );
00256
00257
00258 PCCE_CHECK(fread(buffer16,2,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
00259 unsigned short channels = readByte16(buffer16);
00260
00261
00262 PCCE_CHECK(fread(buffer32,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
00263 unsigned long frequency = readByte32(buffer32);
00264
00265
00266 fseek(f,6,SEEK_CUR);
00267
00268
00269 PCCE_CHECK(fread(buffer16,2,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
00270 unsigned short bps = readByte16(buffer16);
00271
00272 if (channels == 1)
00273 format = (bps == 8) ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16;
00274 else
00275 format = (bps == 8) ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16;
00276
00277
00278 PCCE_CHECK(fread(magic,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
00279 PCCE_CHECK(std::string(magic) == "data", "LoadWav: Wrong wav file format. This file is not a .wav file (no data subchunk): "+ fileName );
00280
00281 PCCE_CHECK(fread(buffer32,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
00282 unsigned long subChunk2Size = readByte32(buffer32);
00283
00284
00285 freq = frequency;
00286 PCCE_CHECK(sizeof(freq) == sizeof(frequency), "LoadWav: freq and frequency different sizes");
00287
00288 array = new char[BUFFER_SIZE];
00289
00290 while (data.size() != subChunk2Size) {
00291
00292 bytes = fread(array, 1, BUFFER_SIZE, f);
00293
00294 if (bytes <= 0)
00295 break;
00296
00297 if (data.size() + bytes > subChunk2Size)
00298 bytes = subChunk2Size - data.size();
00299
00300
00301 data.insert(data.end(), array, array + bytes);
00302 };
00303
00304 delete []array;
00305 array = NULL;
00306
00307 fclose(f);
00308 f = NULL;
00309
00310 alGenBuffers(1, &buffer);
00311 PCCE_CHECK(alGetError() == AL_NO_ERROR, "LoadWav: Could not generate buffer");
00312 PCCE_CHECK(AL_NONE != buffer, "LoadWav: Could not generate buffer");
00313
00314 alBufferData(buffer, format, &data[0], data.size(), freq);
00315 PCCE_CHECK(alGetError() == AL_NO_ERROR, "LoadWav: Could not load buffer data");
00316
00317 return buffer;
00318 } catch (Exception e) {
00319 if (buffer)
00320 if (alIsBuffer(buffer) == AL_TRUE)
00321 alDeleteBuffers(1, &buffer);
00322
00323 if (array)
00324 delete []array;
00325
00326 if (f)
00327 fclose(f);
00328
00329 throw (e);
00330 }
00331 }
00332
00333 ALuint pcce::GenSource() {
00334 ALuint source;
00335 bool looping = false;
00336 ALfloat sourcePos[] = {0.0, 0.0, 0.0};
00337 ALfloat sourceVel[] = {0.0, 0.0, 0.0};
00338
00339 ClearALError();
00340
00341
00342 alGenSources(1, &source);
00343 PCCE_CHECK(alGetError() == AL_NO_ERROR, "GenSource: Could not generate source");
00344
00345 alSourcef(source, AL_PITCH, 1.0);
00346 alSourcef(source, AL_GAIN, 1.0);
00347 alSourcefv(source, AL_POSITION, sourcePos);
00348 alSourcefv(source, AL_VELOCITY, sourceVel);
00349 alSourcei(source, AL_LOOPING, looping);
00350
00351 PCCE_CHECK(alGetError() == AL_NO_ERROR, "GenSource: Could not set source attributes");
00352
00353 return source;
00354 }
00355
00356 ALuint pcce::GenSource(ALuint buffer) {
00357 ClearALError();
00358 ALuint source = GenSource();
00359 alSourcei(source, AL_BUFFER, buffer);
00360
00361 PCCE_CHECK(alGetError() == AL_NO_ERROR, "GenSource: Could not set source buffer");
00362
00363 return source;
00364 }
00365
00366 void pcce::ClearALError() {
00367 alGetError();
00368 }
00369
00370 const std::string& pcce::GetALErrorStr(const ALenum error) {
00371 switch(error) {
00372 case AL_NO_ERROR:
00373 return ALNoErrorStr;
00374 break;
00375 case AL_INVALID_NAME:
00376 return ALInvalidNameStr;
00377 break;
00378 case AL_INVALID_ENUM:
00379 return ALInvalidEnumStr;
00380 break;
00381 case AL_INVALID_VALUE:
00382 return ALInvalidValueStr;
00383 break;
00384 case AL_INVALID_OPERATION:
00385 return ALInvalidOpStr;
00386 break;
00387 case AL_OUT_OF_MEMORY:
00388 return ALOutOfMemoryStr;
00389 break;
00390 default:
00391 return ALOtherErrorStr;
00392 break;
00393 }
00394
00395 return ALOtherErrorStr;
00396 }