Blender V2.61 - r43446

AUD_OpenALDevice.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * Copyright 2009-2011 Jörg Hermann Müller
00005  *
00006  * This file is part of AudaSpace.
00007  *
00008  * Audaspace is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * AudaSpace is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with Audaspace; if not, write to the Free Software Foundation,
00020  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00030 #include "AUD_OpenALDevice.h"
00031 #include "AUD_IFactory.h"
00032 #include "AUD_IReader.h"
00033 #include "AUD_ConverterReader.h"
00034 
00035 #include <cstring>
00036 #include <limits>
00037 
00038 #ifdef WIN32
00039 #include <windows.h>
00040 #else
00041 #include <unistd.h>
00042 #endif
00043 
00044 /*struct AUD_OpenALBufferedFactory
00045 {
00047     AUD_IFactory* factory;
00048 
00050     ALuint buffer;
00051 };*/
00052 
00053 //typedef std::list<AUD_OpenALBufferedFactory*>::iterator AUD_BFIterator;
00054 
00055 
00056 /******************************************************************************/
00057 /*********************** AUD_OpenALHandle Handle Code *************************/
00058 /******************************************************************************/
00059 
00060 static const char* genbuffer_error = "AUD_OpenALDevice: Buffer couldn't be "
00061                                      "generated.";
00062 static const char* gensource_error = "AUD_OpenALDevice: Source couldn't be "
00063                                      "generated.";
00064 static const char* queue_error = "AUD_OpenALDevice: Buffer couldn't be "
00065                                  "queued to the source.";
00066 static const char* bufferdata_error = "AUD_OpenALDevice: Buffer couldn't be "
00067                                       "filled with data.";
00068 
00069 AUD_OpenALDevice::AUD_OpenALHandle::AUD_OpenALHandle(AUD_OpenALDevice* device, ALenum format, AUD_Reference<AUD_IReader> reader, bool keep) :
00070     m_isBuffered(false), m_reader(reader), m_keep(keep), m_format(format), m_current(0),
00071     m_eos(false), m_loopcount(0), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING),
00072     m_device(device)
00073 {
00074     AUD_DeviceSpecs specs = m_device->m_specs;
00075     specs.specs = m_reader->getSpecs();
00076 
00077     // OpenAL playback code
00078     alGenBuffers(CYCLE_BUFFERS, m_buffers);
00079     if(alGetError() != AL_NO_ERROR)
00080         AUD_THROW(AUD_ERROR_OPENAL, genbuffer_error);
00081 
00082     try
00083     {
00084         m_device->m_buffer.assureSize(m_device->m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
00085         int length;
00086         bool eos;
00087 
00088         for(int i = 0; i < CYCLE_BUFFERS; i++)
00089         {
00090             length = m_device->m_buffersize;
00091             reader->read(length, eos, m_device->m_buffer.getBuffer());
00092             alBufferData(m_buffers[i], m_format, m_device->m_buffer.getBuffer(),
00093                          length * AUD_DEVICE_SAMPLE_SIZE(specs),
00094                          specs.rate);
00095             if(alGetError() != AL_NO_ERROR)
00096                 AUD_THROW(AUD_ERROR_OPENAL, bufferdata_error);
00097         }
00098 
00099         alGenSources(1, &m_source);
00100         if(alGetError() != AL_NO_ERROR)
00101             AUD_THROW(AUD_ERROR_OPENAL, gensource_error);
00102 
00103         try
00104         {
00105             alSourceQueueBuffers(m_source, CYCLE_BUFFERS,
00106                                  m_buffers);
00107             if(alGetError() != AL_NO_ERROR)
00108                 AUD_THROW(AUD_ERROR_OPENAL, queue_error);
00109         }
00110         catch(AUD_Exception&)
00111         {
00112             alDeleteSources(1, &m_source);
00113             throw;
00114         }
00115     }
00116     catch(AUD_Exception&)
00117     {
00118         alDeleteBuffers(CYCLE_BUFFERS, m_buffers);
00119         throw;
00120     }
00121     alSourcei(m_source, AL_SOURCE_RELATIVE, 1);
00122 }
00123 
00124 bool AUD_OpenALDevice::AUD_OpenALHandle::pause()
00125 {
00126     if(m_status)
00127     {
00128         m_device->lock();
00129 
00130         if(m_status == AUD_STATUS_PLAYING)
00131         {
00132             m_device->m_playingSounds.remove(this);
00133             m_device->m_pausedSounds.push_back(this);
00134 
00135             alSourcePause(m_source);
00136 
00137             m_status = AUD_STATUS_PAUSED;
00138             m_device->unlock();
00139 
00140             return true;
00141         }
00142 
00143         m_device->unlock();
00144     }
00145 
00146     return false;
00147 }
00148 
00149 bool AUD_OpenALDevice::AUD_OpenALHandle::resume()
00150 {
00151     if(m_status)
00152     {
00153         m_device->lock();
00154 
00155         if(m_status == AUD_STATUS_PAUSED)
00156         {
00157             m_device->m_pausedSounds.remove(this);
00158             m_device->m_playingSounds.push_back(this);
00159 
00160             m_device->start();
00161             m_status = AUD_STATUS_PLAYING;
00162             m_device->unlock();
00163             return true;
00164         }
00165 
00166         m_device->unlock();
00167     }
00168 
00169     return false;
00170 }
00171 
00172 bool AUD_OpenALDevice::AUD_OpenALHandle::stop()
00173 {
00174     if(!m_status)
00175         return false;
00176 
00177     m_device->lock();
00178 
00179     // AUD_XXX Create a reference of our own object so that it doesn't get
00180     // deleted before the end of this function
00181     AUD_Reference<AUD_OpenALHandle> This = this;
00182 
00183     if(m_status == AUD_STATUS_PLAYING)
00184         m_device->m_playingSounds.remove(This);
00185     else
00186         m_device->m_pausedSounds.remove(This);
00187 
00188     m_device->unlock();
00189 
00190     alDeleteSources(1, &m_source);
00191     if(!m_isBuffered)
00192         alDeleteBuffers(CYCLE_BUFFERS, m_buffers);
00193 
00194     m_status = AUD_STATUS_INVALID;
00195     return true;
00196 }
00197 
00198 bool AUD_OpenALDevice::AUD_OpenALHandle::getKeep()
00199 {
00200     if(m_status)
00201         return m_keep;
00202 
00203     return false;
00204 }
00205 
00206 bool AUD_OpenALDevice::AUD_OpenALHandle::setKeep(bool keep)
00207 {
00208     if(!m_status)
00209         return false;
00210 
00211     m_device->lock();
00212 
00213     m_keep = keep;
00214 
00215     m_device->unlock();
00216 
00217     return true;
00218 }
00219 
00220 bool AUD_OpenALDevice::AUD_OpenALHandle::seek(float position)
00221 {
00222     if(!m_status)
00223         return false;
00224 
00225     m_device->lock();
00226 
00227     if(m_isBuffered)
00228         alSourcef(m_source, AL_SEC_OFFSET, position);
00229     else
00230     {
00231         m_reader->seek((int)(position * m_reader->getSpecs().rate));
00232         m_eos = false;
00233 
00234         ALint info;
00235 
00236         alGetSourcei(m_source, AL_SOURCE_STATE, &info);
00237 
00238         if(info != AL_PLAYING)
00239         {
00240             if(info == AL_PAUSED)
00241                 alSourceStop(m_source);
00242 
00243             alSourcei(m_source, AL_BUFFER, 0);
00244             m_current = 0;
00245 
00246             ALenum err;
00247             if((err = alGetError()) == AL_NO_ERROR)
00248             {
00249                 int length;
00250                 AUD_DeviceSpecs specs = m_device->m_specs;
00251                 specs.specs = m_reader->getSpecs();
00252                 m_device->m_buffer.assureSize(m_device->m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
00253 
00254                 for(int i = 0; i < CYCLE_BUFFERS; i++)
00255                 {
00256                     length = m_device->m_buffersize;
00257                     m_reader->read(length, m_eos, m_device->m_buffer.getBuffer());
00258                     alBufferData(m_buffers[i], m_format, m_device->m_buffer.getBuffer(),
00259                                  length * AUD_DEVICE_SAMPLE_SIZE(specs), specs.rate);
00260 
00261                     if(alGetError() != AL_NO_ERROR)
00262                         break;
00263                 }
00264 
00265                 if(m_loopcount != 0)
00266                     m_eos = false;
00267 
00268                 alSourceQueueBuffers(m_source, CYCLE_BUFFERS, m_buffers);
00269             }
00270 
00271             alSourceRewind(m_source);
00272         }
00273     }
00274 
00275     m_device->unlock();
00276 
00277     return true;
00278 }
00279 
00280 float AUD_OpenALDevice::AUD_OpenALHandle::getPosition()
00281 {
00282     if(!m_status)
00283         return 0.0f;
00284 
00285     m_device->lock();
00286 
00287     float position = 0.0f;
00288 
00289     alGetSourcef(m_source, AL_SEC_OFFSET, &position);
00290 
00291     if(!m_isBuffered)
00292     {
00293         AUD_Specs specs = m_reader->getSpecs();
00294         position += (m_reader->getPosition() - m_device->m_buffersize *
00295                      CYCLE_BUFFERS) / (float)specs.rate;
00296     }
00297 
00298     m_device->unlock();
00299 
00300     return position;
00301 }
00302 
00303 AUD_Status AUD_OpenALDevice::AUD_OpenALHandle::getStatus()
00304 {
00305     return m_status;
00306 }
00307 
00308 float AUD_OpenALDevice::AUD_OpenALHandle::getVolume()
00309 {
00310     float result = std::numeric_limits<float>::quiet_NaN();
00311 
00312     if(!m_status)
00313         return result;
00314 
00315     m_device->lock();
00316 
00317     alGetSourcef(m_source, AL_GAIN, &result);
00318 
00319     m_device->unlock();
00320 
00321     return result;
00322 }
00323 
00324 bool AUD_OpenALDevice::AUD_OpenALHandle::setVolume(float volume)
00325 {
00326     if(!m_status)
00327         return false;
00328 
00329     m_device->lock();
00330 
00331     alSourcef(m_source, AL_GAIN, volume);
00332 
00333     m_device->unlock();
00334 
00335     return true;
00336 }
00337 
00338 float AUD_OpenALDevice::AUD_OpenALHandle::getPitch()
00339 {
00340     float result = std::numeric_limits<float>::quiet_NaN();
00341 
00342     if(!m_status)
00343         return result;
00344 
00345     m_device->lock();
00346 
00347     alGetSourcef(m_source, AL_PITCH, &result);
00348 
00349     m_device->unlock();
00350 
00351     return result;
00352 }
00353 
00354 bool AUD_OpenALDevice::AUD_OpenALHandle::setPitch(float pitch)
00355 {
00356     if(!m_status)
00357         return false;
00358 
00359     m_device->lock();
00360 
00361     alSourcef(m_source, AL_PITCH, pitch);
00362 
00363     m_device->unlock();
00364 
00365     return true;
00366 }
00367 
00368 int AUD_OpenALDevice::AUD_OpenALHandle::getLoopCount()
00369 {
00370     if(!m_status)
00371         return 0;
00372     return m_loopcount;
00373 }
00374 
00375 bool AUD_OpenALDevice::AUD_OpenALHandle::setLoopCount(int count)
00376 {
00377     if(!m_status)
00378         return false;
00379     m_loopcount = count;
00380     return true;
00381 }
00382 
00383 bool AUD_OpenALDevice::AUD_OpenALHandle::setStopCallback(stopCallback callback, void* data)
00384 {
00385     if(!m_status)
00386         return false;
00387 
00388     m_device->lock();
00389 
00390     m_stop = callback;
00391     m_stop_data = data;
00392 
00393     m_device->unlock();
00394 
00395     return true;
00396 }
00397 
00398 /******************************************************************************/
00399 /********************* AUD_OpenALHandle 3DHandle Code *************************/
00400 /******************************************************************************/
00401 
00402 AUD_Vector3 AUD_OpenALDevice::AUD_OpenALHandle::getSourceLocation()
00403 {
00404     AUD_Vector3 result = AUD_Vector3(0, 0, 0);
00405 
00406     if(!m_status)
00407         return result;
00408 
00409     m_device->lock();
00410 
00411     ALfloat p[3];
00412     alGetSourcefv(m_source, AL_POSITION, p);
00413 
00414     m_device->unlock();
00415 
00416     result = AUD_Vector3(p[0], p[1], p[2]);
00417 
00418     return result;
00419 }
00420 
00421 bool AUD_OpenALDevice::AUD_OpenALHandle::setSourceLocation(const AUD_Vector3& location)
00422 {
00423     if(!m_status)
00424         return false;
00425 
00426     m_device->lock();
00427 
00428     alSourcefv(m_source, AL_POSITION, (ALfloat*)location.get());
00429 
00430     m_device->unlock();
00431 
00432     return true;
00433 }
00434 
00435 AUD_Vector3 AUD_OpenALDevice::AUD_OpenALHandle::getSourceVelocity()
00436 {
00437     AUD_Vector3 result = AUD_Vector3(0, 0, 0);
00438 
00439     if(!m_status)
00440         return result;
00441 
00442     m_device->lock();
00443 
00444     ALfloat v[3];
00445     alGetSourcefv(m_source, AL_VELOCITY, v);
00446 
00447     m_device->unlock();
00448 
00449     result = AUD_Vector3(v[0], v[1], v[2]);
00450 
00451     return result;
00452 }
00453 
00454 bool AUD_OpenALDevice::AUD_OpenALHandle::setSourceVelocity(const AUD_Vector3& velocity)
00455 {
00456     if(!m_status)
00457         return false;
00458 
00459     m_device->lock();
00460 
00461     alSourcefv(m_source, AL_VELOCITY, (ALfloat*)velocity.get());
00462 
00463     m_device->unlock();
00464 
00465     return true;
00466 }
00467 
00468 AUD_Quaternion AUD_OpenALDevice::AUD_OpenALHandle::getSourceOrientation()
00469 {
00470     return m_orientation;
00471 }
00472 
00473 bool AUD_OpenALDevice::AUD_OpenALHandle::setSourceOrientation(const AUD_Quaternion& orientation)
00474 {
00475     if(!m_status)
00476         return false;
00477 
00478     ALfloat direction[3];
00479     direction[0] = -2 * (orientation.w() * orientation.y() +
00480                          orientation.x() * orientation.z());
00481     direction[1] = 2 * (orientation.x() * orientation.w() -
00482                         orientation.z() * orientation.y());
00483     direction[2] = 2 * (orientation.x() * orientation.x() +
00484                         orientation.y() * orientation.y()) - 1;
00485     m_device->lock();
00486 
00487     alSourcefv(m_source, AL_DIRECTION, direction);
00488 
00489     m_device->unlock();
00490 
00491     m_orientation = orientation;
00492 
00493     return true;
00494 }
00495 
00496 bool AUD_OpenALDevice::AUD_OpenALHandle::isRelative()
00497 {
00498     int result;
00499 
00500     if(!m_status)
00501         return false;
00502 
00503     m_device->lock();
00504 
00505     alGetSourcei(m_source, AL_SOURCE_RELATIVE, &result);
00506 
00507     m_device->unlock();
00508 
00509     return result;
00510 }
00511 
00512 bool AUD_OpenALDevice::AUD_OpenALHandle::setRelative(bool relative)
00513 {
00514     if(!m_status)
00515         return false;
00516 
00517     m_device->lock();
00518 
00519     alSourcei(m_source, AL_SOURCE_RELATIVE, relative);
00520 
00521     m_device->unlock();
00522 
00523     return true;
00524 }
00525 
00526 float AUD_OpenALDevice::AUD_OpenALHandle::getVolumeMaximum()
00527 {
00528     float result = std::numeric_limits<float>::quiet_NaN();
00529 
00530     if(!m_status)
00531         return result;
00532 
00533     m_device->lock();
00534 
00535     alGetSourcef(m_source, AL_MAX_GAIN, &result);
00536 
00537     m_device->unlock();
00538 
00539     return result;
00540 }
00541 
00542 bool AUD_OpenALDevice::AUD_OpenALHandle::setVolumeMaximum(float volume)
00543 {
00544     if(!m_status)
00545         return false;
00546 
00547     m_device->lock();
00548 
00549     alSourcef(m_source, AL_MAX_GAIN, volume);
00550 
00551     m_device->unlock();
00552 
00553     return true;
00554 }
00555 
00556 float AUD_OpenALDevice::AUD_OpenALHandle::getVolumeMinimum()
00557 {
00558     float result = std::numeric_limits<float>::quiet_NaN();
00559 
00560     if(!m_status)
00561         return result;
00562 
00563     m_device->lock();
00564 
00565     alGetSourcef(m_source, AL_MIN_GAIN, &result);
00566 
00567     m_device->unlock();
00568 
00569     return result;
00570 }
00571 
00572 bool AUD_OpenALDevice::AUD_OpenALHandle::setVolumeMinimum(float volume)
00573 {
00574     if(!m_status)
00575         return false;
00576 
00577     m_device->lock();
00578 
00579     alSourcef(m_source, AL_MIN_GAIN, volume);
00580 
00581     m_device->unlock();
00582 
00583     return true;
00584 }
00585 
00586 float AUD_OpenALDevice::AUD_OpenALHandle::getDistanceMaximum()
00587 {
00588     float result = std::numeric_limits<float>::quiet_NaN();
00589 
00590     if(!m_status)
00591         return result;
00592 
00593     m_device->lock();
00594 
00595     alGetSourcef(m_source, AL_MAX_DISTANCE, &result);
00596 
00597     m_device->unlock();
00598 
00599     return result;
00600 }
00601 
00602 bool AUD_OpenALDevice::AUD_OpenALHandle::setDistanceMaximum(float distance)
00603 {
00604     if(!m_status)
00605         return false;
00606 
00607     m_device->lock();
00608 
00609     alSourcef(m_source, AL_MAX_DISTANCE, distance);
00610 
00611     m_device->unlock();
00612 
00613     return true;
00614 }
00615 
00616 float AUD_OpenALDevice::AUD_OpenALHandle::getDistanceReference()
00617 {
00618     float result = std::numeric_limits<float>::quiet_NaN();
00619 
00620     if(!m_status)
00621         return result;
00622 
00623     m_device->lock();
00624 
00625     alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &result);
00626 
00627     m_device->unlock();
00628 
00629     return result;
00630 }
00631 
00632 bool AUD_OpenALDevice::AUD_OpenALHandle::setDistanceReference(float distance)
00633 {
00634     if(!m_status)
00635         return false;
00636 
00637     m_device->lock();
00638 
00639     alSourcef(m_source, AL_REFERENCE_DISTANCE, distance);
00640 
00641     m_device->unlock();
00642 
00643     return true;
00644 }
00645 
00646 float AUD_OpenALDevice::AUD_OpenALHandle::getAttenuation()
00647 {
00648     float result = std::numeric_limits<float>::quiet_NaN();
00649 
00650     if(!m_status)
00651         return result;
00652 
00653     m_device->lock();
00654 
00655     alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &result);
00656 
00657     m_device->unlock();
00658 
00659     return result;
00660 }
00661 
00662 bool AUD_OpenALDevice::AUD_OpenALHandle::setAttenuation(float factor)
00663 {
00664     if(!m_status)
00665         return false;
00666 
00667     m_device->lock();
00668 
00669     alSourcef(m_source, AL_ROLLOFF_FACTOR, factor);
00670 
00671     m_device->unlock();
00672 
00673     return true;
00674 }
00675 
00676 float AUD_OpenALDevice::AUD_OpenALHandle::getConeAngleOuter()
00677 {
00678     float result = std::numeric_limits<float>::quiet_NaN();
00679 
00680     if(!m_status)
00681         return result;
00682 
00683     m_device->lock();
00684 
00685     alGetSourcef(m_source, AL_CONE_OUTER_ANGLE, &result);
00686 
00687     m_device->unlock();
00688 
00689     return result;
00690 }
00691 
00692 bool AUD_OpenALDevice::AUD_OpenALHandle::setConeAngleOuter(float angle)
00693 {
00694     if(!m_status)
00695         return false;
00696 
00697     m_device->lock();
00698 
00699     alSourcef(m_source, AL_CONE_OUTER_ANGLE, angle);
00700 
00701     m_device->unlock();
00702 
00703     return true;
00704 }
00705 
00706 float AUD_OpenALDevice::AUD_OpenALHandle::getConeAngleInner()
00707 {
00708     float result = std::numeric_limits<float>::quiet_NaN();
00709 
00710     if(!m_status)
00711         return result;
00712 
00713     m_device->lock();
00714 
00715     alGetSourcef(m_source, AL_CONE_INNER_ANGLE, &result);
00716 
00717     m_device->unlock();
00718 
00719     return result;
00720 }
00721 
00722 bool AUD_OpenALDevice::AUD_OpenALHandle::setConeAngleInner(float angle)
00723 {
00724     if(!m_status)
00725         return false;
00726 
00727     m_device->lock();
00728 
00729     alSourcef(m_source, AL_CONE_INNER_ANGLE, angle);
00730 
00731     m_device->unlock();
00732 
00733     return true;
00734 }
00735 
00736 float AUD_OpenALDevice::AUD_OpenALHandle::getConeVolumeOuter()
00737 {
00738     float result = std::numeric_limits<float>::quiet_NaN();
00739 
00740     if(!m_status)
00741         return result;
00742 
00743     m_device->lock();
00744 
00745     alGetSourcef(m_source, AL_CONE_OUTER_GAIN, &result);
00746 
00747     m_device->unlock();
00748 
00749     return result;
00750 }
00751 
00752 bool AUD_OpenALDevice::AUD_OpenALHandle::setConeVolumeOuter(float volume)
00753 {
00754     if(!m_status)
00755         return false;
00756 
00757     m_device->lock();
00758 
00759     alSourcef(m_source, AL_CONE_OUTER_GAIN, volume);
00760 
00761     m_device->unlock();
00762 
00763     return true;
00764 }
00765 
00766 /******************************************************************************/
00767 /**************************** Threading Code **********************************/
00768 /******************************************************************************/
00769 
00770 void* AUD_openalRunThread(void* device)
00771 {
00772     AUD_OpenALDevice* dev = (AUD_OpenALDevice*)device;
00773     dev->updateStreams();
00774     return NULL;
00775 }
00776 
00777 void AUD_OpenALDevice::start(bool join)
00778 {
00779     lock();
00780 
00781     if(!m_playing)
00782     {
00783         if(join)
00784             pthread_join(m_thread, NULL);
00785 
00786         pthread_attr_t attr;
00787         pthread_attr_init(&attr);
00788         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
00789 
00790         pthread_create(&m_thread, &attr, AUD_openalRunThread, this);
00791 
00792         pthread_attr_destroy(&attr);
00793 
00794         m_playing = true;
00795     }
00796 
00797     unlock();
00798 }
00799 
00800 void AUD_OpenALDevice::updateStreams()
00801 {
00802     AUD_Reference<AUD_OpenALHandle> sound;
00803 
00804     int length;
00805 
00806     ALint info;
00807     AUD_DeviceSpecs specs = m_specs;
00808     ALCenum cerr;
00809     std::list<AUD_Reference<AUD_OpenALHandle> > stopSounds;
00810     std::list<AUD_Reference<AUD_OpenALHandle> > pauseSounds;
00811     AUD_HandleIterator it;
00812 
00813     while(1)
00814     {
00815         lock();
00816 
00817         alcSuspendContext(m_context);
00818         cerr = alcGetError(m_device);
00819         if(cerr == ALC_NO_ERROR)
00820         {
00821             // for all sounds
00822             for(it = m_playingSounds.begin(); it != m_playingSounds.end(); it++)
00823             {
00824                 sound = *it;
00825 
00826                 // is it a streamed sound?
00827                 if(!sound->m_isBuffered)
00828                 {
00829                     // check for buffer refilling
00830                     alGetSourcei(sound->m_source, AL_BUFFERS_PROCESSED, &info);
00831 
00832                     if(info)
00833                     {
00834                         specs.specs = sound->m_reader->getSpecs();
00835                         m_buffer.assureSize(m_buffersize * AUD_DEVICE_SAMPLE_SIZE(specs));
00836 
00837                         // for all empty buffers
00838                         while(info--)
00839                         {
00840                             // if there's still data to play back
00841                             if(!sound->m_eos)
00842                             {
00843                                 // read data
00844                                 length = m_buffersize;
00845                                 sound->m_reader->read(length, sound->m_eos, m_buffer.getBuffer());
00846 
00847                                 // looping necessary?
00848                                 if(length == 0 && sound->m_loopcount)
00849                                 {
00850                                     if(sound->m_loopcount > 0)
00851                                         sound->m_loopcount--;
00852 
00853                                     sound->m_reader->seek(0);
00854 
00855                                     length = m_buffersize;
00856                                     sound->m_reader->read(length, sound->m_eos, m_buffer.getBuffer());
00857                                 }
00858 
00859                                 if(sound->m_loopcount != 0)
00860                                     sound->m_eos = false;
00861 
00862                                 // read nothing?
00863                                 if(length == 0)
00864                                 {
00865                                     break;
00866                                 }
00867 
00868                                 // unqueue buffer
00869                                 alSourceUnqueueBuffers(sound->m_source, 1,
00870                                                 &sound->m_buffers[sound->m_current]);
00871                                 ALenum err;
00872                                 if((err = alGetError()) != AL_NO_ERROR)
00873                                 {
00874                                     sound->m_eos = true;
00875                                     break;
00876                                 }
00877 
00878                                 // fill with new data
00879                                 alBufferData(sound->m_buffers[sound->m_current],
00880                                              sound->m_format,
00881                                              m_buffer.getBuffer(), length *
00882                                              AUD_DEVICE_SAMPLE_SIZE(specs),
00883                                              specs.rate);
00884 
00885                                 if((err = alGetError()) != AL_NO_ERROR)
00886                                 {
00887                                     sound->m_eos = true;
00888                                     break;
00889                                 }
00890 
00891                                 // and queue again
00892                                 alSourceQueueBuffers(sound->m_source, 1,
00893                                                 &sound->m_buffers[sound->m_current]);
00894                                 if(alGetError() != AL_NO_ERROR)
00895                                 {
00896                                     sound->m_eos = true;
00897                                     break;
00898                                 }
00899 
00900                                 sound->m_current = (sound->m_current+1) %
00901                                                  AUD_OpenALHandle::CYCLE_BUFFERS;
00902                             }
00903                             else
00904                                 break;
00905                         }
00906                     }
00907                 }
00908 
00909                 // check if the sound has been stopped
00910                 alGetSourcei(sound->m_source, AL_SOURCE_STATE, &info);
00911 
00912                 if(info != AL_PLAYING)
00913                 {
00914                     // if it really stopped
00915                     if(sound->m_eos)
00916                     {
00917                         if(sound->m_stop)
00918                             sound->m_stop(sound->m_stop_data);
00919 
00920                         // pause or
00921                         if(sound->m_keep)
00922                             pauseSounds.push_back(sound);
00923                         // stop
00924                         else
00925                             stopSounds.push_back(sound);
00926                     }
00927                     // continue playing
00928                     else
00929                         alSourcePlay(sound->m_source);
00930                 }
00931             }
00932 
00933             for(it = pauseSounds.begin(); it != pauseSounds.end(); it++)
00934                 (*it)->pause();
00935 
00936             for(it = stopSounds.begin(); it != stopSounds.end(); it++)
00937                 (*it)->stop();
00938 
00939             pauseSounds.clear();
00940             stopSounds.clear();
00941 
00942             alcProcessContext(m_context);
00943         }
00944 
00945         // stop thread
00946         if(m_playingSounds.empty() || (cerr != ALC_NO_ERROR))
00947         {
00948             m_playing = false;
00949             unlock();
00950             pthread_exit(NULL);
00951         }
00952 
00953         unlock();
00954 
00955 #ifdef WIN32
00956         Sleep(20);
00957 #else
00958         usleep(20000);
00959 #endif
00960     }
00961 }
00962 
00963 /******************************************************************************/
00964 /**************************** IDevice Code ************************************/
00965 /******************************************************************************/
00966 
00967 static const char* open_error = "AUD_OpenALDevice: Device couldn't be opened.";
00968 
00969 AUD_OpenALDevice::AUD_OpenALDevice(AUD_DeviceSpecs specs, int buffersize)
00970 {
00971     // cannot determine how many channels or which format OpenAL uses, but
00972     // it at least is able to play 16 bit stereo audio
00973     specs.channels = AUD_CHANNELS_STEREO;
00974     specs.format = AUD_FORMAT_S16;
00975 
00976 #if 0
00977     if(alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_TRUE)
00978     {
00979         ALCchar* devices = const_cast<ALCchar*>(alcGetString(NULL, ALC_DEVICE_SPECIFIER));
00980         printf("OpenAL devices (standard is: %s):\n", alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER));
00981 
00982         while(*devices)
00983         {
00984             printf("%s\n", devices);
00985             devices += strlen(devices) + 1;
00986         }
00987     }
00988 #endif
00989 
00990     m_device = alcOpenDevice(NULL);
00991 
00992     if(!m_device)
00993         AUD_THROW(AUD_ERROR_OPENAL, open_error);
00994 
00995     // at least try to set the frequency
00996     ALCint attribs[] = { ALC_FREQUENCY, specs.rate, 0 };
00997     ALCint* attributes = attribs;
00998     if(specs.rate == AUD_RATE_INVALID)
00999         attributes = NULL;
01000 
01001     m_context = alcCreateContext(m_device, attributes);
01002     alcMakeContextCurrent(m_context);
01003 
01004     alcGetIntegerv(m_device, ALC_FREQUENCY, 1, (ALCint*)&specs.rate);
01005 
01006     // check for specific formats and channel counts to be played back
01007     if(alIsExtensionPresent("AL_EXT_FLOAT32") == AL_TRUE)
01008         specs.format = AUD_FORMAT_FLOAT32;
01009 
01010     m_useMC = alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE;
01011 
01012     alGetError();
01013     alcGetError(m_device);
01014 
01015     m_specs = specs;
01016     m_buffersize = buffersize;
01017     m_playing = false;
01018 
01019 //  m_bufferedFactories = new std::list<AUD_OpenALBufferedFactory*>();
01020 
01021     pthread_mutexattr_t attr;
01022     pthread_mutexattr_init(&attr);
01023     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
01024 
01025     pthread_mutex_init(&m_mutex, &attr);
01026 
01027     pthread_mutexattr_destroy(&attr);
01028 
01029     start(false);
01030 }
01031 
01032 AUD_OpenALDevice::~AUD_OpenALDevice()
01033 {
01034     lock();
01035     alcSuspendContext(m_context);
01036 
01037     while(!m_playingSounds.empty())
01038         m_playingSounds.front()->stop();
01039 
01040     while(!m_pausedSounds.empty())
01041         m_pausedSounds.front()->stop();
01042 
01043 
01044     // delete all buffered factories
01045     /*while(!m_bufferedFactories->empty())
01046     {
01047         alDeleteBuffers(1, &(*(m_bufferedFactories->begin()))->buffer);
01048         delete *m_bufferedFactories->begin();
01049         m_bufferedFactories->erase(m_bufferedFactories->begin());
01050     }*/
01051 
01052     alcProcessContext(m_context);
01053 
01054     // wait for the thread to stop
01055     unlock();
01056     pthread_join(m_thread, NULL);
01057 
01058     //delete m_bufferedFactories;
01059 
01060     // quit OpenAL
01061     alcMakeContextCurrent(NULL);
01062     alcDestroyContext(m_context);
01063     alcCloseDevice(m_device);
01064 
01065     pthread_mutex_destroy(&m_mutex);
01066 }
01067 
01068 AUD_DeviceSpecs AUD_OpenALDevice::getSpecs() const
01069 {
01070     return m_specs;
01071 }
01072 
01073 bool AUD_OpenALDevice::getFormat(ALenum &format, AUD_Specs specs)
01074 {
01075     bool valid = true;
01076     format = 0;
01077 
01078     switch(m_specs.format)
01079     {
01080     case AUD_FORMAT_S16:
01081         switch(specs.channels)
01082         {
01083         case AUD_CHANNELS_MONO:
01084             format = AL_FORMAT_MONO16;
01085             break;
01086         case AUD_CHANNELS_STEREO:
01087             format = AL_FORMAT_STEREO16;
01088             break;
01089         case AUD_CHANNELS_SURROUND4:
01090             if(m_useMC)
01091             {
01092                 format = alGetEnumValue("AL_FORMAT_QUAD16");
01093                 break;
01094             }
01095         case AUD_CHANNELS_SURROUND51:
01096             if(m_useMC)
01097             {
01098                 format = alGetEnumValue("AL_FORMAT_51CHN16");
01099                 break;
01100             }
01101         case AUD_CHANNELS_SURROUND61:
01102             if(m_useMC)
01103             {
01104                 format = alGetEnumValue("AL_FORMAT_61CHN16");
01105                 break;
01106             }
01107         case AUD_CHANNELS_SURROUND71:
01108             if(m_useMC)
01109             {
01110                 format = alGetEnumValue("AL_FORMAT_71CHN16");
01111                 break;
01112             }
01113         default:
01114             valid = false;
01115         }
01116         break;
01117     case AUD_FORMAT_FLOAT32:
01118         switch(specs.channels)
01119         {
01120         case AUD_CHANNELS_MONO:
01121             format = alGetEnumValue("AL_FORMAT_MONO_FLOAT32");
01122             break;
01123         case AUD_CHANNELS_STEREO:
01124             format = alGetEnumValue("AL_FORMAT_STEREO_FLOAT32");
01125             break;
01126         case AUD_CHANNELS_SURROUND4:
01127             if(m_useMC)
01128             {
01129                 format = alGetEnumValue("AL_FORMAT_QUAD32");
01130                 break;
01131             }
01132         case AUD_CHANNELS_SURROUND51:
01133             if(m_useMC)
01134             {
01135                 format = alGetEnumValue("AL_FORMAT_51CHN32");
01136                 break;
01137             }
01138         case AUD_CHANNELS_SURROUND61:
01139             if(m_useMC)
01140             {
01141                 format = alGetEnumValue("AL_FORMAT_61CHN32");
01142                 break;
01143             }
01144         case AUD_CHANNELS_SURROUND71:
01145             if(m_useMC)
01146             {
01147                 format = alGetEnumValue("AL_FORMAT_71CHN32");
01148                 break;
01149             }
01150         default:
01151             valid = false;
01152         }
01153         break;
01154     default:
01155         valid = false;
01156     }
01157 
01158     if(!format)
01159         valid = false;
01160 
01161     return valid;
01162 }
01163 
01164 AUD_Reference<AUD_IHandle> AUD_OpenALDevice::play(AUD_Reference<AUD_IReader> reader, bool keep)
01165 {
01166     AUD_Specs specs = reader->getSpecs();
01167 
01168     // check format
01169     if(specs.channels == AUD_CHANNELS_INVALID)
01170         return AUD_Reference<AUD_IHandle>();
01171 
01172     if(m_specs.format != AUD_FORMAT_FLOAT32)
01173         reader = new AUD_ConverterReader(reader, m_specs);
01174 
01175     ALenum format;
01176 
01177     if(!getFormat(format, specs))
01178         return AUD_Reference<AUD_IHandle>();
01179 
01180     lock();
01181     alcSuspendContext(m_context);
01182 
01183     AUD_Reference<AUD_OpenALDevice::AUD_OpenALHandle> sound;
01184 
01185     try
01186     {
01187         // create the handle
01188         sound = new AUD_OpenALDevice::AUD_OpenALHandle(this, format, reader, keep);
01189     }
01190     catch(AUD_Exception&)
01191     {
01192         alcProcessContext(m_context);
01193         unlock();
01194         throw;
01195     }
01196 
01197     alcProcessContext(m_context);
01198 
01199     // play sound
01200     m_playingSounds.push_back(sound);
01201 
01202     start();
01203 
01204     unlock();
01205 
01206     return AUD_Reference<AUD_IHandle>(sound);
01207 }
01208 
01209 AUD_Reference<AUD_IHandle> AUD_OpenALDevice::play(AUD_Reference<AUD_IFactory> factory, bool keep)
01210 {
01211     /* AUD_XXX disabled
01212     AUD_OpenALHandle* sound = NULL;
01213 
01214     lock();
01215 
01216     try
01217     {
01218         // check if it is a buffered factory
01219         for(AUD_BFIterator i = m_bufferedFactories->begin();
01220             i != m_bufferedFactories->end(); i++)
01221         {
01222             if((*i)->factory == factory)
01223             {
01224                 // create the handle
01225                 sound = new AUD_OpenALHandle;
01226                 sound->keep = keep;
01227                 sound->current = -1;
01228                 sound->isBuffered = true;
01229                 sound->eos = true;
01230                 sound->loopcount = 0;
01231                 sound->stop = NULL;
01232                 sound->stop_data = NULL;
01233 
01234                 alcSuspendContext(m_context);
01235 
01236                 // OpenAL playback code
01237                 try
01238                 {
01239                     alGenSources(1, &sound->source);
01240                     if(alGetError() != AL_NO_ERROR)
01241                         AUD_THROW(AUD_ERROR_OPENAL, gensource_error);
01242 
01243                     try
01244                     {
01245                         alSourcei(sound->source, AL_BUFFER, (*i)->buffer);
01246                         if(alGetError() != AL_NO_ERROR)
01247                             AUD_THROW(AUD_ERROR_OPENAL, queue_error);
01248                     }
01249                     catch(AUD_Exception&)
01250                     {
01251                         alDeleteSources(1, &sound->source);
01252                         throw;
01253                     }
01254                 }
01255                 catch(AUD_Exception&)
01256                 {
01257                     delete sound;
01258                     alcProcessContext(m_context);
01259                     throw;
01260                 }
01261 
01262                 // play sound
01263                 m_playingSounds->push_back(sound);
01264 
01265                 alSourcei(sound->source, AL_SOURCE_RELATIVE, 1);
01266                 start();
01267 
01268                 alcProcessContext(m_context);
01269             }
01270         }
01271     }
01272     catch(AUD_Exception&)
01273     {
01274         unlock();
01275         throw;
01276     }
01277 
01278     unlock();
01279 
01280     if(sound)
01281         return sound;*/
01282 
01283     return play(factory->createReader(), keep);
01284 }
01285 
01286 void AUD_OpenALDevice::stopAll()
01287 {
01288     lock();
01289     alcSuspendContext(m_context);
01290 
01291     while(!m_playingSounds.empty())
01292         m_playingSounds.front()->stop();
01293 
01294     while(!m_pausedSounds.empty())
01295         m_pausedSounds.front()->stop();
01296 
01297     alcProcessContext(m_context);
01298     unlock();
01299 }
01300 
01301 void AUD_OpenALDevice::lock()
01302 {
01303     pthread_mutex_lock(&m_mutex);
01304 }
01305 
01306 void AUD_OpenALDevice::unlock()
01307 {
01308     pthread_mutex_unlock(&m_mutex);
01309 }
01310 
01311 float AUD_OpenALDevice::getVolume() const
01312 {
01313     float result;
01314     alGetListenerf(AL_GAIN, &result);
01315     return result;
01316 }
01317 
01318 void AUD_OpenALDevice::setVolume(float volume)
01319 {
01320     alListenerf(AL_GAIN, volume);
01321 }
01322 
01323 /* AUD_XXX Temorary disabled
01324 
01325 bool AUD_OpenALDevice::bufferFactory(void *value)
01326 {
01327     bool result = false;
01328     AUD_IFactory* factory = (AUD_IFactory*) value;
01329 
01330     // load the factory into an OpenAL buffer
01331     if(factory)
01332     {
01333         // check if the factory is already buffered
01334         lock();
01335         for(AUD_BFIterator i = m_bufferedFactories->begin();
01336             i != m_bufferedFactories->end(); i++)
01337         {
01338             if((*i)->factory == factory)
01339             {
01340                 result = true;
01341                 break;
01342             }
01343         }
01344         unlock();
01345         if(result)
01346             return result;
01347 
01348         AUD_IReader* reader = factory->createReader();
01349 
01350         if(reader == NULL)
01351             return false;
01352 
01353         AUD_DeviceSpecs specs = m_specs;
01354         specs.specs = reader->getSpecs();
01355 
01356         if(m_specs.format != AUD_FORMAT_FLOAT32)
01357             reader = new AUD_ConverterReader(reader, m_specs);
01358 
01359         ALenum format;
01360 
01361         if(!getFormat(format, specs.specs))
01362         {
01363             return false;
01364         }
01365 
01366         // load into a buffer
01367         lock();
01368         alcSuspendContext(m_context);
01369 
01370         AUD_OpenALBufferedFactory* bf = new AUD_OpenALBufferedFactory;
01371         bf->factory = factory;
01372 
01373         try
01374         {
01375             alGenBuffers(1, &bf->buffer);
01376             if(alGetError() != AL_NO_ERROR)
01377                 AUD_THROW(AUD_ERROR_OPENAL);
01378 
01379             try
01380             {
01381                 sample_t* buf;
01382                 int length = reader->getLength();
01383 
01384                 reader->read(length, buf);
01385                 alBufferData(bf->buffer, format, buf,
01386                              length * AUD_DEVICE_SAMPLE_SIZE(specs),
01387                              specs.rate);
01388                 if(alGetError() != AL_NO_ERROR)
01389                     AUD_THROW(AUD_ERROR_OPENAL);
01390             }
01391             catch(AUD_Exception&)
01392             {
01393                 alDeleteBuffers(1, &bf->buffer);
01394                 throw;
01395             }
01396         }
01397         catch(AUD_Exception&)
01398         {
01399             delete bf;
01400             alcProcessContext(m_context);
01401             unlock();
01402             return false;
01403         }
01404 
01405         m_bufferedFactories->push_back(bf);
01406 
01407         alcProcessContext(m_context);
01408         unlock();
01409     }
01410     else
01411     {
01412         // stop all playing and paused buffered sources
01413         lock();
01414         alcSuspendContext(m_context);
01415 
01416         AUD_OpenALHandle* sound;
01417         AUD_HandleIterator it = m_playingSounds->begin();
01418         while(it != m_playingSounds->end())
01419         {
01420             sound = *it;
01421             ++it;
01422 
01423             if(sound->isBuffered)
01424                 stop(sound);
01425         }
01426         alcProcessContext(m_context);
01427 
01428         while(!m_bufferedFactories->empty())
01429         {
01430             alDeleteBuffers(1,
01431                             &(*(m_bufferedFactories->begin()))->buffer);
01432             delete *m_bufferedFactories->begin();
01433             m_bufferedFactories->erase(m_bufferedFactories->begin());
01434         }
01435         unlock();
01436     }
01437 
01438     return true;
01439 }*/
01440 
01441 /******************************************************************************/
01442 /**************************** 3D Device Code **********************************/
01443 /******************************************************************************/
01444 
01445 AUD_Vector3 AUD_OpenALDevice::getListenerLocation() const
01446 {
01447     ALfloat p[3];
01448     alGetListenerfv(AL_POSITION, p);
01449     return AUD_Vector3(p[0], p[1], p[2]);
01450 }
01451 
01452 void AUD_OpenALDevice::setListenerLocation(const AUD_Vector3& location)
01453 {
01454     alListenerfv(AL_POSITION, (ALfloat*)location.get());
01455 }
01456 
01457 AUD_Vector3 AUD_OpenALDevice::getListenerVelocity() const
01458 {
01459     ALfloat v[3];
01460     alGetListenerfv(AL_VELOCITY, v);
01461     return AUD_Vector3(v[0], v[1], v[2]);
01462 }
01463 
01464 void AUD_OpenALDevice::setListenerVelocity(const AUD_Vector3& velocity)
01465 {
01466     alListenerfv(AL_VELOCITY, (ALfloat*)velocity.get());
01467 }
01468 
01469 AUD_Quaternion AUD_OpenALDevice::getListenerOrientation() const
01470 {
01471     return m_orientation;
01472 }
01473 
01474 void AUD_OpenALDevice::setListenerOrientation(const AUD_Quaternion& orientation)
01475 {
01476     ALfloat direction[6];
01477     direction[0] = -2 * (orientation.w() * orientation.y() +
01478                          orientation.x() * orientation.z());
01479     direction[1] = 2 * (orientation.x() * orientation.w() -
01480                         orientation.z() * orientation.y());
01481     direction[2] = 2 * (orientation.x() * orientation.x() +
01482                         orientation.y() * orientation.y()) - 1;
01483     direction[3] = 2 * (orientation.x() * orientation.y() -
01484                         orientation.w() * orientation.z());
01485     direction[4] = 1 - 2 * (orientation.x() * orientation.x() +
01486                             orientation.z() * orientation.z());
01487     direction[5] = 2 * (orientation.w() * orientation.x() +
01488                         orientation.y() * orientation.z());
01489     alListenerfv(AL_ORIENTATION, direction);
01490     m_orientation = orientation;
01491 }
01492 
01493 float AUD_OpenALDevice::getSpeedOfSound() const
01494 {
01495     return alGetFloat(AL_SPEED_OF_SOUND);
01496 }
01497 
01498 void AUD_OpenALDevice::setSpeedOfSound(float speed)
01499 {
01500     alSpeedOfSound(speed);
01501 }
01502 
01503 float AUD_OpenALDevice::getDopplerFactor() const
01504 {
01505     return alGetFloat(AL_DOPPLER_FACTOR);
01506 }
01507 
01508 void AUD_OpenALDevice::setDopplerFactor(float factor)
01509 {
01510     alDopplerFactor(factor);
01511 }
01512 
01513 AUD_DistanceModel AUD_OpenALDevice::getDistanceModel() const
01514 {
01515     switch(alGetInteger(AL_DISTANCE_MODEL))
01516     {
01517     case AL_INVERSE_DISTANCE:
01518         return AUD_DISTANCE_MODEL_INVERSE;
01519     case AL_INVERSE_DISTANCE_CLAMPED:
01520         return AUD_DISTANCE_MODEL_INVERSE_CLAMPED;
01521     case AL_LINEAR_DISTANCE:
01522         return AUD_DISTANCE_MODEL_LINEAR;
01523     case AL_LINEAR_DISTANCE_CLAMPED:
01524         return AUD_DISTANCE_MODEL_LINEAR_CLAMPED;
01525     case AL_EXPONENT_DISTANCE:
01526         return AUD_DISTANCE_MODEL_EXPONENT;
01527     case AL_EXPONENT_DISTANCE_CLAMPED:
01528         return AUD_DISTANCE_MODEL_EXPONENT_CLAMPED;
01529     default:
01530         return AUD_DISTANCE_MODEL_INVALID;
01531     }
01532 }
01533 
01534 void AUD_OpenALDevice::setDistanceModel(AUD_DistanceModel model)
01535 {
01536     switch(model)
01537     {
01538     case AUD_DISTANCE_MODEL_INVERSE:
01539         alDistanceModel(AL_INVERSE_DISTANCE);
01540         break;
01541     case AUD_DISTANCE_MODEL_INVERSE_CLAMPED:
01542         alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
01543         break;
01544     case AUD_DISTANCE_MODEL_LINEAR:
01545         alDistanceModel(AL_LINEAR_DISTANCE);
01546         break;
01547     case AUD_DISTANCE_MODEL_LINEAR_CLAMPED:
01548         alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
01549         break;
01550     case AUD_DISTANCE_MODEL_EXPONENT:
01551         alDistanceModel(AL_EXPONENT_DISTANCE);
01552         break;
01553     case AUD_DISTANCE_MODEL_EXPONENT_CLAMPED:
01554         alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
01555         break;
01556     default:
01557         alDistanceModel(AL_NONE);
01558     }
01559 }