FIFE  2008.0
soundemitter.cpp
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2008 by the FIFE team                              *
00003  *   http://www.fifengine.de                                               *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 
00024 // Platform specific includes
00025 
00026 // 3rd party library includes
00027 
00028 // FIFE includes
00029 // These includes are split up in two parts, separated by one empty line
00030 // First block: files included from the FIFE root src directory
00031 // Second block: files included from the same folder
00032 #include "util/log/logger.h"
00033 #include "util/time/timemanager.h"
00034 #include "util/base/exception.h"
00035 #include "soundemitter.h"
00036 #include "soundmanager.h"
00037 #include "soundclippool.h"
00038 
00039 namespace FIFE {
00040     static Logger _log(LM_AUDIO);
00041 
00042     SoundEmitter::SoundEmitter(SoundManager* manager, SoundClipPool* pool, unsigned int uid) : m_manager(manager), m_pool(pool), m_source(0), m_soundclip(NULL), m_soundclipid(0), m_streamid(0),
00043                                                             m_emitterid(uid), m_loop(false) {
00044         if (!m_manager->isActive()) {
00045             return;
00046         }
00047 
00048         TimeManager::instance()->registerEvent(this);
00049         setPeriod(-1);
00050         alGenSources(1, &m_source);
00051         CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error creating source")
00052     }
00053 
00054     SoundEmitter::~SoundEmitter() {
00055         if (!m_manager->isActive()) {
00056             return;
00057         }
00058 
00059         setPeriod(-1);
00060         TimeManager::instance()->unregisterEvent(this);
00061         reset();
00062         alDeleteSources(1, &m_source);
00063     }
00064 
00065     void SoundEmitter::reset(bool defaultall) {
00066         if (m_soundclip != NULL) {
00067 
00068             setPeriod(-1);
00069             alSourceStop(m_source);
00070 
00071             // Release all buffers
00072             alSourcei(m_source, AL_BUFFER, AL_NONE);
00073             alGetError();
00074 
00075             if (m_soundclip->isStream()) {
00076                 m_soundclip->quitStreaming(m_streamid);
00077             }
00078 
00079             // release the soundclip
00080             m_pool->release(m_soundclipid, true);
00081             m_soundclip = NULL;
00082 
00083             // default source properties
00084             if (defaultall) {
00085                 setPosition(0.0f, 0.0f, 0.0f);
00086                 setVelocity(0.0f, 0.0f, 0.0f);
00087                 setGain(1.0f);
00088                 setPositioning(false);
00089                 alSourcei(m_source, AL_LOOPING, AL_FALSE);
00090             }
00091         }
00092     }
00093 
00094     void SoundEmitter::release() {
00095         m_manager->releaseEmitter(m_emitterid);
00096     }
00097 
00098     void SoundEmitter::setSoundClip(unsigned int sound_id) {
00099         m_soundclipid = sound_id;
00100         m_soundclip = &(m_pool->getSoundClip(m_soundclipid));
00101         m_soundclip->addRef();
00102 
00103         attachSoundClip();
00104     }
00105 
00106     void SoundEmitter::setCallback(const type_callback& cb) {
00107         m_callback = cb;
00108     }
00109 
00110     void SoundEmitter::attachSoundClip() {
00111         if (!m_soundclip->isStream()) {
00112             // non-streaming
00113             alSourceQueueBuffers(m_source, m_soundclip->countBuffers(), m_soundclip->getBuffers());
00114             alSourcei(m_source, AL_LOOPING, m_loop ? AL_TRUE : AL_FALSE);
00115 
00116         } else {
00117             // streaming
00118             m_streamid = m_soundclip->beginStreaming();
00119             m_soundclip->acquireStream(m_streamid);
00120 
00121             // queue initial buffers
00122             alSourceQueueBuffers(m_source, BUFFER_NUM, m_soundclip->getBuffers(m_streamid));
00123             alSourcei(m_source, AL_LOOPING, AL_FALSE);
00124         }
00125 
00126         CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error attaching sound clip")
00127     }
00128 
00129     void SoundEmitter::updateEvent(unsigned long time) {
00130         ALint procs;
00131         ALint bufs;
00132         ALuint buffer;
00133 
00134         alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &procs);
00135 
00136         while (procs--) {
00137             alSourceUnqueueBuffers(m_source, 1, &buffer);
00138 
00139             if (m_soundclip->getStream(m_streamid, buffer)) {
00140                 // EOF!
00141                 if (m_loop) {
00142                     // play again from the beginning
00143                     m_soundclip->setStreamPos(m_streamid, SD_BYTE_POS, 0);
00144                     m_soundclip->getStream(m_streamid, buffer);
00145                 } else {
00146 
00147                     // check if the playback has been finished
00148                     alGetSourcei(m_source, AL_BUFFERS_QUEUED, &bufs);
00149                     if (bufs == 0) {
00150                         setPeriod(-1);
00151                         alSourceStop(m_source);
00152                         if(m_callback) {
00153                             m_callback();
00154                         }
00155                     }
00156                     continue;
00157                 }
00158             }
00159             alSourceQueueBuffers(m_source, 1, &buffer);
00160         }
00161 
00162         CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error while streaming")
00163     }
00164 
00165     void SoundEmitter::setLooping(bool loop) {
00166         if (m_soundclip) {
00167             if (!m_soundclip->isStream()) {
00168                 alSourcei(m_source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
00169             } else {
00170                 alSourcei(m_source, AL_LOOPING, AL_FALSE);
00171             }
00172         }
00173         m_loop = loop;
00174     }
00175 
00176     void SoundEmitter::play() {
00177         if (m_soundclip) {
00178             alSourcePlay(m_source);
00179             if (m_soundclip->isStream()) {
00180                 setPeriod(5000);
00181             }
00182         }
00183     }
00184 
00185     void SoundEmitter::stop() {
00186         if (m_soundclip) {
00187             alSourceStop(m_source);
00188 
00189             if (m_soundclip->isStream()) {
00190                 setPeriod(-1);
00191                 setCursor(SD_BYTE_POS, 0);
00192             } else {
00193                 alSourceRewind(m_source);
00194             }
00195         }
00196     }
00197 
00198     void SoundEmitter::setCursor(SoundPositionType type, float value) {
00199         if (!m_soundclip) {
00200             return;
00201         }
00202 
00203         ALint state = 0;
00204 
00205         if (!m_soundclip->isStream()) {
00206             switch(type) {
00207             case SD_BYTE_POS:
00208                 alSourcef(m_source, AL_BYTE_OFFSET, value);
00209                 break;
00210             case SD_SAMPLE_POS:
00211                 alSourcef(m_source, AL_SAMPLE_OFFSET, value);
00212                 break;
00213             case SD_TIME_POS:
00214                 alSourcef(m_source, AL_SEC_OFFSET, value);
00215                 break;
00216             }
00217 
00218             CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error setting cursor position")
00219         }
00220         else {
00221             alGetSourcei(m_source, AL_SOURCE_STATE, &state);
00222 
00223             if (state == AL_PLAYING || AL_PAUSED) {
00224                 setPeriod(-1);
00225                 alSourceStop(m_source);
00226             }
00227 
00228             m_soundclip->setStreamPos(m_streamid, type, value);
00229 
00230             // detach all buffers
00231             alSourcei(m_source, AL_BUFFER, 0);
00232 
00233             // queue the buffers with new data
00234             m_soundclip->acquireStream(m_streamid);
00235             alSourceQueueBuffers(m_source, BUFFER_NUM, m_soundclip->getBuffers(m_streamid));
00236 
00237             if (state == AL_PLAYING) {
00238                 setPeriod(5000);
00239                 alSourcePlay(m_source);
00240             }
00241 
00242             CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error setting stream cursor position")
00243         }
00244     }
00245 
00246     float SoundEmitter::getCursor(SoundPositionType type) {
00247         if (!m_soundclip) {
00248             return 0.0f;
00249         }
00250 
00251         ALfloat pos = 0.0f;
00252 
00253         switch(type) {
00254             case SD_BYTE_POS:
00255                 alGetSourcef(m_source, AL_BYTE_OFFSET, &pos);
00256                 break;
00257             case SD_SAMPLE_POS:
00258                 alGetSourcef(m_source, AL_SAMPLE_OFFSET, &pos);
00259                 break;
00260             case SD_TIME_POS:
00261                 alGetSourcef(m_source, AL_SEC_OFFSET, &pos);
00262                 break;
00263         }
00264 
00265         if (m_soundclip->isStream()) {
00266             pos += m_soundclip->getStreamPos(m_streamid, type);
00267         }
00268 
00269         CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error getting cursor")
00270 
00271         return pos;
00272     }
00273 }