Blender  V2.59
AUD_SoftwareDevice.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: AUD_SoftwareDevice.cpp 35141 2011-02-25 10:21:56Z jesterking $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * Copyright 2009-2011 Jörg Hermann Müller
00007  *
00008  * This file is part of AudaSpace.
00009  *
00010  * Audaspace is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * AudaSpace is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with Audaspace; if not, write to the Free Software Foundation,
00022  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00032 #include "AUD_SoftwareDevice.h"
00033 #include "AUD_IReader.h"
00034 #include "AUD_DefaultMixer.h"
00035 #include "AUD_IFactory.h"
00036 
00037 #include <cstring>
00038 #include <limits>
00039 
00041 struct AUD_SoftwareHandle : AUD_Handle
00042 {
00044         AUD_IReader* reader;
00045 
00047         bool keep;
00048 
00050         float volume;
00051 
00053         int loopcount;
00054 
00056         stopCallback stop;
00057 
00059         void* stop_data;
00060 };
00061 
00062 typedef std::list<AUD_SoftwareHandle*>::iterator AUD_HandleIterator;
00063 
00064 void AUD_SoftwareDevice::create()
00065 {
00066         m_playback = false;
00067         m_volume = 1.0f;
00068         m_mixer = new AUD_DefaultMixer(m_specs);
00069 
00070         pthread_mutexattr_t attr;
00071         pthread_mutexattr_init(&attr);
00072         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
00073 
00074         pthread_mutex_init(&m_mutex, &attr);
00075 
00076         pthread_mutexattr_destroy(&attr);
00077 }
00078 
00079 void AUD_SoftwareDevice::destroy()
00080 {
00081         if(m_playback)
00082                 playing(m_playback = false);
00083 
00084         delete m_mixer;
00085 
00086         AUD_SoftwareHandle* handle;
00087 
00088         // delete all playing sounds
00089         while(!m_playingSounds.empty())
00090         {
00091                 handle = m_playingSounds.front();
00092                 m_playingSounds.pop_front();
00093                 delete handle->reader;
00094                 delete handle;
00095         }
00096 
00097         // delete all paused sounds
00098         while(!m_pausedSounds.empty())
00099         {
00100                 handle = m_pausedSounds.front();
00101                 m_pausedSounds.pop_front();
00102                 delete handle->reader;
00103                 delete handle;
00104         }
00105 
00106         pthread_mutex_destroy(&m_mutex);
00107 }
00108 
00109 void AUD_SoftwareDevice::mix(data_t* buffer, int length)
00110 {
00111         lock();
00112 
00113         {
00114                 AUD_SoftwareHandle* sound;
00115                 int len;
00116                 int pos;
00117                 sample_t* buf;
00118                 std::list<AUD_SoftwareHandle*> stopSounds;
00119                 std::list<AUD_Buffer*> tempBufs;
00120                 AUD_Buffer* tempbuf;
00121                 int samplesize = AUD_SAMPLE_SIZE(m_specs);
00122 
00123                 // for all sounds
00124                 AUD_HandleIterator it = m_playingSounds.begin();
00125                 while(it != m_playingSounds.end())
00126                 {
00127                         sound = *it;
00128                         // increment the iterator to make sure it's valid,
00129                         // in case the sound gets deleted after stopping
00130                         ++it;
00131 
00132                         // get the buffer from the source
00133                         pos = 0;
00134                         len = length;
00135                         sound->reader->read(len, buf);
00136 
00137                         // in case of looping
00138                         while(pos + len < length && sound->loopcount)
00139                         {
00140                                 tempbuf = new AUD_Buffer(len * samplesize);
00141                                 memcpy(tempbuf->getBuffer(), buf, len * samplesize);
00142                                 tempBufs.push_back(tempbuf);
00143                                 m_mixer->add(tempbuf->getBuffer(), pos, len, sound->volume);
00144 
00145                                 pos += len;
00146 
00147                                 if(sound->loopcount > 0)
00148                                         sound->loopcount--;
00149 
00150                                 sound->reader->seek(0);
00151 
00152                                 len = length - pos;
00153                                 sound->reader->read(len, buf);
00154 
00155                                 // prevent endless loop
00156                                 if(!len)
00157                                         break;
00158                         }
00159 
00160                         m_mixer->add(buf, pos, len, sound->volume);
00161                         pos += len;
00162 
00163                         // in case the end of the sound is reached
00164                         if(pos < length)
00165                         {
00166                                 if(sound->stop)
00167                                         sound->stop(sound->stop_data);
00168 
00169                                 if(sound->keep)
00170                                         pause(sound);
00171                                 else
00172                                         stopSounds.push_back(sound);
00173                         }
00174                 }
00175 
00176                 // superpose
00177                 m_mixer->superpose(buffer, length, m_volume);
00178 
00179                 // cleanup
00180                 while(!stopSounds.empty())
00181                 {
00182                         sound = stopSounds.front();
00183                         stopSounds.pop_front();
00184                         stop(sound);
00185                 }
00186 
00187                 while(!tempBufs.empty())
00188                 {
00189                         tempbuf = tempBufs.front();
00190                         tempBufs.pop_front();
00191                         delete tempbuf;
00192                 }
00193         }
00194 
00195         unlock();
00196 }
00197 
00198 bool AUD_SoftwareDevice::isValid(AUD_Handle* handle)
00199 {
00200         for(AUD_HandleIterator i = m_playingSounds.begin();
00201                 i != m_playingSounds.end(); i++)
00202                 if(*i == handle)
00203                         return true;
00204         for(AUD_HandleIterator i = m_pausedSounds.begin();
00205                 i != m_pausedSounds.end(); i++)
00206                 if(*i == handle)
00207                         return true;
00208         return false;
00209 }
00210 
00211 AUD_DeviceSpecs AUD_SoftwareDevice::getSpecs() const
00212 {
00213         return m_specs;
00214 }
00215 
00216 AUD_Handle* AUD_SoftwareDevice::play(AUD_IReader* reader, bool keep)
00217 {
00218         // prepare the reader
00219         reader = m_mixer->prepare(reader);
00220         if(reader == NULL)
00221                 return NULL;
00222 
00223         // play sound
00224         AUD_SoftwareHandle* sound = new AUD_SoftwareHandle;
00225         sound->keep = keep;
00226         sound->reader = reader;
00227         sound->volume = 1.0f;
00228         sound->loopcount = 0;
00229         sound->stop = NULL;
00230         sound->stop_data = NULL;
00231 
00232         lock();
00233         m_playingSounds.push_back(sound);
00234 
00235         if(!m_playback)
00236                 playing(m_playback = true);
00237         unlock();
00238 
00239         return sound;
00240 }
00241 
00242 AUD_Handle* AUD_SoftwareDevice::play(AUD_IFactory* factory, bool keep)
00243 {
00244         return play(factory->createReader(), keep);
00245 }
00246 
00247 bool AUD_SoftwareDevice::pause(AUD_Handle* handle)
00248 {
00249         bool result = false;
00250 
00251         lock();
00252 
00253         // only songs that are played can be paused
00254         for(AUD_HandleIterator i = m_playingSounds.begin();
00255                 i != m_playingSounds.end(); i++)
00256         {
00257                 if(*i == handle)
00258                 {
00259                         m_pausedSounds.push_back(*i);
00260                         m_playingSounds.erase(i);
00261                         if(m_playingSounds.empty())
00262                                 playing(m_playback = false);
00263                         result = true;
00264                         break;
00265                 }
00266         }
00267 
00268         unlock();
00269 
00270         return result;
00271 }
00272 
00273 bool AUD_SoftwareDevice::resume(AUD_Handle* handle)
00274 {
00275         bool result = false;
00276 
00277         lock();
00278 
00279         // only songs that are paused can be resumed
00280         for(AUD_HandleIterator i = m_pausedSounds.begin();
00281                 i != m_pausedSounds.end(); i++)
00282         {
00283                 if(*i == handle)
00284                 {
00285                         m_playingSounds.push_back(*i);
00286                         m_pausedSounds.erase(i);
00287                         if(!m_playback)
00288                                 playing(m_playback = true);
00289                         result = true;
00290                         break;
00291                 }
00292         }
00293 
00294         unlock();
00295 
00296         return result;
00297 }
00298 
00299 bool AUD_SoftwareDevice::stop(AUD_Handle* handle)
00300 {
00301         bool result = false;
00302 
00303         lock();
00304 
00305         for(AUD_HandleIterator i = m_playingSounds.begin();
00306                 i != m_playingSounds.end(); i++)
00307         {
00308                 if(*i == handle)
00309                 {
00310                         delete (*i)->reader;
00311                         delete *i;
00312                         m_playingSounds.erase(i);
00313                         if(m_playingSounds.empty())
00314                                 playing(m_playback = false);
00315                         result = true;
00316                         break;
00317                 }
00318         }
00319         if(!result)
00320         {
00321                 for(AUD_HandleIterator i = m_pausedSounds.begin();
00322                         i != m_pausedSounds.end(); i++)
00323                 {
00324                         if(*i == handle)
00325                         {
00326                                 delete (*i)->reader;
00327                                 delete *i;
00328                                 m_pausedSounds.erase(i);
00329                                 result = true;
00330                                 break;
00331                         }
00332                 }
00333         }
00334 
00335         unlock();
00336 
00337         return result;
00338 }
00339 
00340 bool AUD_SoftwareDevice::getKeep(AUD_Handle* handle)
00341 {
00342         bool result = false;
00343 
00344         lock();
00345 
00346         if(isValid(handle))
00347                 result = ((AUD_SoftwareHandle*)handle)->keep;
00348 
00349         unlock();
00350 
00351         return result;
00352 }
00353 
00354 bool AUD_SoftwareDevice::setKeep(AUD_Handle* handle, bool keep)
00355 {
00356         bool result = false;
00357 
00358         lock();
00359 
00360         if(isValid(handle))
00361         {
00362                 ((AUD_SoftwareHandle*)handle)->keep = keep;
00363                 result = true;
00364         }
00365 
00366         unlock();
00367 
00368         return result;
00369 }
00370 
00371 bool AUD_SoftwareDevice::seek(AUD_Handle* handle, float position)
00372 {
00373         lock();
00374 
00375         bool result = false;
00376 
00377         if(isValid(handle))
00378         {
00379                 AUD_IReader* reader = ((AUD_SoftwareHandle*)handle)->reader;
00380                 reader->seek((int)(position * reader->getSpecs().rate));
00381                 result = true;
00382         }
00383 
00384         unlock();
00385 
00386         return result;
00387 }
00388 
00389 float AUD_SoftwareDevice::getPosition(AUD_Handle* handle)
00390 {
00391         lock();
00392 
00393         float position = 0.0f;
00394 
00395         if(isValid(handle))
00396         {
00397                 AUD_SoftwareHandle* h = (AUD_SoftwareHandle*)handle;
00398                 position = h->reader->getPosition() / (float)m_specs.rate;
00399         }
00400 
00401         unlock();
00402 
00403         return position;
00404 }
00405 
00406 AUD_Status AUD_SoftwareDevice::getStatus(AUD_Handle* handle)
00407 {
00408         AUD_Status status = AUD_STATUS_INVALID;
00409 
00410         lock();
00411 
00412         for(AUD_HandleIterator i = m_playingSounds.begin();
00413                 i != m_playingSounds.end(); i++)
00414         {
00415                 if(*i == handle)
00416                 {
00417                         status = AUD_STATUS_PLAYING;
00418                         break;
00419                 }
00420         }
00421         if(status == AUD_STATUS_INVALID)
00422         {
00423                 for(AUD_HandleIterator i = m_pausedSounds.begin();
00424                         i != m_pausedSounds.end(); i++)
00425                 {
00426                         if(*i == handle)
00427                         {
00428                                 status = AUD_STATUS_PAUSED;
00429                                 break;
00430                         }
00431                 }
00432         }
00433 
00434         unlock();
00435 
00436         return status;
00437 }
00438 
00439 void AUD_SoftwareDevice::lock()
00440 {
00441         pthread_mutex_lock(&m_mutex);
00442 }
00443 
00444 void AUD_SoftwareDevice::unlock()
00445 {
00446         pthread_mutex_unlock(&m_mutex);
00447 }
00448 
00449 float AUD_SoftwareDevice::getVolume() const
00450 {
00451         return m_volume;
00452 }
00453 
00454 void AUD_SoftwareDevice::setVolume(float volume)
00455 {
00456         m_volume = volume;
00457 }
00458 
00459 float AUD_SoftwareDevice::getVolume(AUD_Handle* handle)
00460 {
00461         lock();
00462         float result = std::numeric_limits<float>::quiet_NaN();
00463         if(isValid(handle))
00464                 result = ((AUD_SoftwareHandle*)handle)->volume;
00465         unlock();
00466         return result;
00467 }
00468 
00469 bool AUD_SoftwareDevice::setVolume(AUD_Handle* handle, float volume)
00470 {
00471         lock();
00472         bool result = isValid(handle);
00473         if(result)
00474                 ((AUD_SoftwareHandle*)handle)->volume = volume;
00475         unlock();
00476         return result;
00477 }
00478 
00479 float AUD_SoftwareDevice::getPitch(AUD_Handle* handle)
00480 {
00481         return std::numeric_limits<float>::quiet_NaN();
00482 }
00483 
00484 bool AUD_SoftwareDevice::setPitch(AUD_Handle* handle, float pitch)
00485 {
00486         return false;
00487 }
00488 
00489 int AUD_SoftwareDevice::getLoopCount(AUD_Handle* handle)
00490 {
00491         lock();
00492         int result = 0;
00493         if(isValid(handle))
00494                 result = ((AUD_SoftwareHandle*)handle)->loopcount;
00495         unlock();
00496         return result;
00497 }
00498 
00499 bool AUD_SoftwareDevice::setLoopCount(AUD_Handle* handle, int count)
00500 {
00501         lock();
00502         bool result = isValid(handle);
00503         if(result)
00504                 ((AUD_SoftwareHandle*)handle)->loopcount = count;
00505         unlock();
00506         return result;
00507 }
00508 
00509 bool AUD_SoftwareDevice::setStopCallback(AUD_Handle* handle, stopCallback callback, void* data)
00510 {
00511         lock();
00512         bool result = isValid(handle);
00513         if(result)
00514         {
00515                 AUD_SoftwareHandle* h = (AUD_SoftwareHandle*)handle;
00516                 h->stop = callback;
00517                 h->stop_data = data;
00518         }
00519         unlock();
00520         return result;
00521 }