00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdopenal.h"
00027
00028 #include "buffer_al.h"
00029 #include "listener_al.h"
00030
00031 using namespace std;
00032
00033
00034 namespace NLSOUND {
00035
00036
00037 #ifdef EAX_AVAILABLE
00038
00039 EAXSet EAXSetProp = NULL;
00040
00041
00042 EAXGet EAXGetProp = NULL;
00043 #endif
00044
00045
00046
00047
00048 #ifdef NL_OS_UNIX
00049 #define AL_INVALID_ENUM AL_ILLEGAL_ENUM
00050 #define AL_INVALID_OPERATION AL_ILLEGAL_COMMAND
00051 #endif
00052
00053
00054 #ifdef NL_DEBUG
00055
00056 void TestALError()
00057 {
00058 ALuint errcode = alGetError();
00059 switch( errcode )
00060 {
00061 case AL_NO_ERROR : break;
00062 case AL_INVALID_NAME : nlerror( "OpenAL: Invalid name" );
00063 case AL_INVALID_ENUM : nlerror( "OpenAL: Invalid enum" );
00064 case AL_INVALID_VALUE : nlerror( "OpenAL: Invalid value" );
00065 case AL_INVALID_OPERATION : nlerror( "OpenAL: Invalid operation" );
00066 case AL_OUT_OF_MEMORY : nlerror( "OpenAL: Out of memory" );
00067
00068 }
00069 }
00070 #endif
00071
00072
00073 #define INITIAL_BUFFERS 8
00074 #define INITIAL_SOURCES 8
00075 #define BUFFER_ALLOC_RATE 8
00076 #define SOURCE_ALLOC_RATE 8
00077
00078 #define ROLLOFF_FACTOR_DEFAULT 1.0f
00079
00080
00081
00082
00083 #ifdef NL_OS_WINDOWS
00084
00085 __declspec(dllexport) ISoundDriver *NLSOUND_createISoundDriverInstance()
00086 {
00087 CSoundDriverAL *driver = new CSoundDriverAL();
00088 driver->init();
00089 return driver;
00090 }
00091
00092 __declspec(dllexport) uint32 NLSOUND_interfaceVersion ()
00093 {
00094 return ISoundDriver::InterfaceVersion;
00095 }
00096
00097 #elif defined (NL_OS_UNIX)
00098
00099 extern "C"
00100 {
00101 ISoundDriver* NLSOUND_createISoundDriverInstance ()
00102 {
00103 CSoundDriverAL *driver = new CSoundDriverAL();
00104 driver->init();
00105 return driver;
00106 }
00107
00108 uint32 NLSOUND_interfaceVersion ()
00109 {
00110 return ISoundDriver::InterfaceVersion;
00111 }
00112 }
00113
00114 #endif // NL_OS_UNIX
00115
00116
00117
00118 CSoundDriverAL *CSoundDriverAL::_Instance = NULL;
00119
00120
00121
00122
00123
00124 CSoundDriverAL::CSoundDriverAL() :
00125 ISoundDriver(), _NbExpBuffers( 0 ), _NbExpSources( 0 ), _RolloffFactor( 1.0f )
00126 {
00127 if ( _Instance == NULL )
00128 {
00129 _Instance = this;
00130 }
00131 else
00132 {
00133 nlerror( "Sound driver singleton instanciated twice" );
00134 }
00135 }
00136
00137
00138
00139
00140
00141 CSoundDriverAL::~CSoundDriverAL()
00142 {
00143
00144 alDeleteSources( compactAliveNames( _Sources, alIsSource ), &*_Sources.begin() );
00145 alDeleteBuffers( compactAliveNames( _Buffers, alIsBuffer ), &*_Buffers.begin() );
00146
00147
00148 alutExit();
00149
00150 _Instance = NULL;
00151 }
00152
00153
00154
00155
00156
00157 bool CSoundDriverAL::init()
00158 {
00159
00160 alutInit( NULL, NULL );
00161
00162
00163 const ALubyte *alversion, *alrenderer, *alvendor, *alext;
00164 alversion = alGetString( AL_VERSION );
00165 alrenderer = alGetString( AL_RENDERER );
00166 alvendor = alGetString( AL_VENDOR );
00167 alext = alGetString( AL_EXTENSIONS );
00168 TestALError();
00169 nlinfo( "Loading OpenAL lib: %s, %s, %s", alversion, alrenderer, alvendor );
00170 nlinfo( "Listing extensions: %s", alext );
00171
00172 #ifdef EAX_AVAILABLE
00173
00174 if ( alIsExtensionPresent((ALubyte *)"EAX") == AL_TRUE )
00175 {
00176 nlinfo( "Initializing EAX" );
00177 EAXSetProp = (EAXSet)alGetProcAddress((ALubyte*)"EAXSet");
00178 EAXGetProp = (EAXGet)alGetProcAddress((ALubyte*)"EAXGet");
00179 if ( EAXSetProp != NULL )
00180 {
00181 unsigned long ulEAXVal;
00182 long lGlobalReverb;
00183 lGlobalReverb = 0;
00184 EAXSetProp( &DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ROOM, 0, &lGlobalReverb, sizeof(unsigned long) );
00185 ulEAXVal = EAX_ENVIRONMENT_GENERIC;
00186 EAXSetProp( &DSPROPSETID_EAX_ListenerProperties, DSPROPERTY_EAXLISTENER_ENVIRONMENT, 0, &ulEAXVal, sizeof(unsigned long) );
00187 }
00188 }
00189 else
00190 #endif
00191 {
00192 nlinfo( "EAX not available" );
00193 }
00194
00195
00196 alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED );
00197 TestALError();
00198
00199
00200 allocateNewItems( alGenBuffers, alIsBuffer, _Buffers, _NbExpBuffers, INITIAL_BUFFERS );
00201 allocateNewItems( alGenSources, alIsSource, _Sources, _NbExpSources, INITIAL_SOURCES );
00202
00203 return true;
00204 }
00205
00206
00207
00208
00209
00210 void CSoundDriverAL::allocateNewItems( TGenFunctionAL algenfunc, TTestFunctionAL altestfunc,
00211 vector<ALuint>& names, uint index, uint nb )
00212 {
00213 nlassert( index == names.size() );
00214 names.resize( index + nb );
00215 generateItems( algenfunc, altestfunc, nb, &(names[index]) );
00216 }
00217
00218
00219
00220
00221
00222 void ThrowGenException( TGenFunctionAL algenfunc )
00223 {
00224 if ( algenfunc == alGenBuffers )
00225 throw ESoundDriverGenBuf();
00226 else if ( algenfunc == alGenSources )
00227 throw ESoundDriverGenSrc();
00228 else
00229 nlstop;
00230 }
00231
00232
00233
00234
00235 void CSoundDriverAL::generateItems( TGenFunctionAL algenfunc, TTestFunctionAL altestfunc, uint nb, ALuint *array )
00236 {
00237 algenfunc( nb, array );
00238
00239
00240 if ( alGetError() != AL_NO_ERROR )
00241 {
00242 ThrowGenException( algenfunc );
00243 }
00244
00245
00246 uint i;
00247 for ( i=0; i!=nb; i++ )
00248 {
00249 if ( ! altestfunc( array[i] ) )
00250 {
00251 ThrowGenException( algenfunc );
00252 }
00253 }
00254 }
00255
00256
00257
00258
00259
00260 IBuffer *CSoundDriverAL::createBuffer()
00261 {
00262 return new CBufferAL( createItem( alGenBuffers, alIsBuffer, _Buffers, _NbExpBuffers, BUFFER_ALLOC_RATE ) );
00263 }
00264
00265
00266
00267
00268
00269 ISource *CSoundDriverAL::createSource()
00270 {
00271 CSourceAL *sourceal = new CSourceAL( createItem( alGenSources, alIsSource, _Sources, _NbExpSources, SOURCE_ALLOC_RATE ) );
00272 if ( _RolloffFactor != ROLLOFF_FACTOR_DEFAULT )
00273 {
00274 alSourcef( sourceal->sourceName(), AL_ROLLOFF_FACTOR, _RolloffFactor );
00275 }
00276 return sourceal;
00277 }
00278
00279
00280
00281
00282
00283 ALuint CSoundDriverAL::createItem( TGenFunctionAL algenfunc, TTestFunctionAL altestfunc,
00284 vector<ALuint>& names, uint& index, uint allocrate )
00285 {
00286 nlassert( index <= names.size() );
00287 if ( index == names.size() )
00288 {
00289
00290 uint nbalive = compactAliveNames( names, altestfunc );
00291 if ( nbalive == names.size() )
00292 {
00293
00294 allocateNewItems( algenfunc, altestfunc, names, index, allocrate );
00295 }
00296 else
00297 {
00298
00299 nlassert( nbalive < names.size() );
00300 index = nbalive;
00301 generateItems( algenfunc, altestfunc, names.size() - nbalive, &(names[nbalive]) );
00302 }
00303 }
00304
00305
00306 nlassert( index < names.size() );
00307 ALuint itemname = names[index];
00308 index++;
00309 return itemname;
00310 }
00311
00312
00313
00314
00315
00316 uint CSoundDriverAL::compactAliveNames( vector<ALuint>& names, TTestFunctionAL altestfunc )
00317 {
00318 vector<ALuint>::iterator iball, ibcompacted;
00319 for ( iball=names.begin(), ibcompacted=names.begin(); iball!=names.end(); ++iball )
00320 {
00321
00322
00323 if ( altestfunc( *iball ) )
00324 {
00325 *ibcompacted = *iball;
00326 ++ibcompacted;
00327 }
00328 }
00329 nlassert( ibcompacted <= names.end() );
00330 return ibcompacted - names.begin();
00331 }
00332
00333
00334
00335
00336
00337 void CSoundDriverAL::removeBuffer( IBuffer *buffer )
00338 {
00339 nlassert( buffer != NULL );
00340 CBufferAL *bufferAL = dynamic_cast<CBufferAL*>(buffer);
00341 if ( ! deleteItem( bufferAL->bufferName(), alDeleteBuffers, _Buffers ) )
00342 {
00343 nlwarning( "Deleting buffer: name not found" );
00344 }
00345 }
00346
00347
00348
00349
00350
00351 void CSoundDriverAL::removeSource( ISource *source )
00352 {
00353 nlassert( source != NULL );
00354 CSourceAL *sourceAL = dynamic_cast<CSourceAL*>(source);
00355 if ( ! deleteItem( sourceAL->sourceName(), alDeleteSources, _Sources ) )
00356 {
00357 nlwarning( "Deleting source: name not found" );
00358 }
00359 }
00360
00361
00362
00363
00364
00365 bool CSoundDriverAL::deleteItem( ALuint name, TGenFunctionAL aldeletefunc, vector<ALuint>& names )
00366 {
00367 vector<ALuint>::iterator ibn = find( names.begin(), names.end(), name );
00368 if ( ibn == names.end() )
00369 {
00370 return false;
00371 }
00372 aldeletefunc( 1, &*ibn );
00373 *ibn = AL_NONE;
00374 TestALError();
00375 return true;
00376 }
00377
00378
00379
00380
00381
00382 IListener *CSoundDriverAL::createListener()
00383 {
00384 nlassert( CListenerAL::instance() == NULL );
00385 return new CListenerAL();
00386 }
00387
00388
00389
00390
00391
00392 void CSoundDriverAL::applyRolloffFactor( float f )
00393 {
00394 _RolloffFactor = f;
00395 vector<ALuint>::iterator ibn;
00396 for ( ibn=_Sources.begin(); ibn!=_Sources.end(); ++ibn )
00397 {
00398 alSourcef( *ibn, AL_ROLLOFF_FACTOR, _RolloffFactor );
00399 }
00400 TestALError();
00401 }
00402
00403
00404
00405
00406
00407 TSampleFormat ALtoNLSoundFormat( ALenum alformat )
00408 {
00409 switch ( alformat )
00410 {
00411 case AL_FORMAT_MONO8 : return Mono8;
00412 case AL_FORMAT_MONO16 : return Mono16;
00413 case AL_FORMAT_STEREO8 : return Stereo8;
00414 case AL_FORMAT_STEREO16 : return Stereo16;
00415 default : nlstop; return Mono8;
00416 }
00417 }
00418
00419
00420
00421
00422
00423 bool CSoundDriverAL::loadWavFile( IBuffer *destbuffer, const char *filename )
00424 {
00425
00426 #ifdef NL_OS_WINDOWS
00427 ALsizei size,freq;
00428 ALenum format;
00429 ALvoid *data;
00430 ALboolean loop;
00431 alutLoadWAVFile( const_cast<char*>(filename), &format, &data, &size, &freq, &loop );
00432 #else
00433 ALsizei bits;
00434 ALsizei size,freq;
00435 ALsizei format;
00436 ALvoid *data;
00437 alutLoadWAV( const_cast<char*>(filename), &data, &format, &size, &bits, &freq );
00438 #endif
00439 if ( data == NULL )
00440 {
00441 return false;
00442 }
00443 destbuffer->setFormat( ALtoNLSoundFormat(format), freq );
00444 destbuffer->fillBuffer( data, size );
00445 #ifdef NL_OS_WINDOWS
00446 alutUnloadWAV(format,data,size,freq);
00447 #endif
00448 return true;
00449 }
00450
00451
00452 }