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 "soundclipmanager.h"
00038 
00039 namespace FIFE {
00040     static Logger _log(LM_AUDIO);
00041 
00042     SoundEmitter::SoundEmitter(SoundManager* manager, uint32_t uid) : m_manager(manager), m_source(0), m_soundclip(), 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) {
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             //SoundClipManager::instance()->free(m_soundclipid);
00081             m_soundclip.reset();
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(SoundClipPtr soundclip) {
00099         m_soundclipid = soundclip->getHandle();
00100         m_soundclip = soundclip;
00101 
00102         attachSoundClip();
00103     }
00104 
00105     void SoundEmitter::setCallback(const type_callback& cb) {
00106         m_callback = cb;
00107     }
00108 
00109     void SoundEmitter::attachSoundClip() {
00110         if (!m_soundclip->isStream()) {
00111             // non-streaming
00112             alSourceQueueBuffers(m_source, m_soundclip->countBuffers(), m_soundclip->getBuffers());
00113             alSourcei(m_source, AL_LOOPING, m_loop ? AL_TRUE : AL_FALSE);
00114 
00115         } else {
00116             // streaming
00117             m_streamid = m_soundclip->beginStreaming();
00118             m_soundclip->acquireStream(m_streamid);
00119 
00120             // queue initial buffers
00121             alSourceQueueBuffers(m_source, BUFFER_NUM, m_soundclip->getBuffers(m_streamid));
00122             alSourcei(m_source, AL_LOOPING, AL_FALSE);
00123         }
00124 
00125         CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error attaching sound clip")
00126     }
00127 
00128     void SoundEmitter::updateEvent(uint32_t time) {
00129         ALint procs;
00130         ALint bufs;
00131         ALuint buffer;
00132 
00133         alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &procs);
00134 
00135         while (procs--) {
00136             alSourceUnqueueBuffers(m_source, 1, &buffer);
00137 
00138             if (m_soundclip->getStream(m_streamid, buffer)) {
00139                 // EOF!
00140                 if (m_loop) {
00141                     // play again from the beginning
00142                     m_soundclip->setStreamPos(m_streamid, SD_BYTE_POS, 0);
00143                     m_soundclip->getStream(m_streamid, buffer);
00144                 } else {
00145 
00146                     // check if the playback has been finished
00147                     alGetSourcei(m_source, AL_BUFFERS_QUEUED, &bufs);
00148                     if (bufs == 0) {
00149                         setPeriod(-1);
00150                         alSourceStop(m_source);
00151                         if(m_callback) {
00152                             m_callback();
00153                         }
00154                     }
00155                     continue;
00156                 }
00157             }
00158             alSourceQueueBuffers(m_source, 1, &buffer);
00159         }
00160 
00161         CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error while streaming")
00162     }
00163 
00164     void SoundEmitter::setLooping(bool loop) {
00165         if (m_soundclip) {
00166             if (!m_soundclip->isStream()) {
00167                 alSourcei(m_source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
00168             } else {
00169                 alSourcei(m_source, AL_LOOPING, AL_FALSE);
00170             }
00171         }
00172         m_loop = loop;
00173     }
00174 
00175     void SoundEmitter::play() {
00176         if (m_soundclip) {
00177             alSourcePlay(m_source);
00178             if (m_soundclip->isStream()) {
00179                 setPeriod(5000);
00180             }
00181         }
00182     }
00183 
00184     void SoundEmitter::stop() {
00185         if (m_soundclip) {
00186             alSourceStop(m_source);
00187 
00188             if (m_soundclip->isStream()) {
00189                 setPeriod(-1);
00190                 setCursor(SD_BYTE_POS, 0);
00191             } else {
00192                 alSourceRewind(m_source);
00193             }
00194         }
00195     }
00196 
00197     void SoundEmitter::setCursor(SoundPositionType type, float value) {
00198         if (!m_soundclip) {
00199             return;
00200         }
00201 
00202         ALint state = 0;
00203 
00204         if (!m_soundclip->isStream()) {
00205             switch(type) {
00206             case SD_BYTE_POS:
00207                 alSourcef(m_source, AL_BYTE_OFFSET, value);
00208                 break;
00209             case SD_SAMPLE_POS:
00210                 alSourcef(m_source, AL_SAMPLE_OFFSET, value);
00211                 break;
00212             case SD_TIME_POS:
00213                 alSourcef(m_source, AL_SEC_OFFSET, value);
00214                 break;
00215             }
00216 
00217             CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error setting cursor position")
00218         }
00219         else {
00220             alGetSourcei(m_source, AL_SOURCE_STATE, &state);
00221 
00222             if (state == AL_PLAYING || AL_PAUSED) {
00223                 setPeriod(-1);
00224                 alSourceStop(m_source);
00225             }
00226 
00227             m_soundclip->setStreamPos(m_streamid, type, value);
00228 
00229             // detach all buffers
00230             alSourcei(m_source, AL_BUFFER, 0);
00231 
00232             // queue the buffers with new data
00233             m_soundclip->acquireStream(m_streamid);
00234             alSourceQueueBuffers(m_source, BUFFER_NUM, m_soundclip->getBuffers(m_streamid));
00235 
00236             if (state == AL_PLAYING) {
00237                 setPeriod(5000);
00238                 alSourcePlay(m_source);
00239             }
00240 
00241             CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error setting stream cursor position")
00242         }
00243     }
00244 
00245     float SoundEmitter::getCursor(SoundPositionType type) {
00246         if (!m_soundclip) {
00247             return 0.0f;
00248         }
00249 
00250         ALfloat pos = 0.0f;
00251 
00252         switch(type) {
00253             case SD_BYTE_POS:
00254                 alGetSourcef(m_source, AL_BYTE_OFFSET, &pos);
00255                 break;
00256             case SD_SAMPLE_POS:
00257                 alGetSourcef(m_source, AL_SAMPLE_OFFSET, &pos);
00258                 break;
00259             case SD_TIME_POS:
00260                 alGetSourcef(m_source, AL_SEC_OFFSET, &pos);
00261                 break;
00262         }
00263 
00264         if (m_soundclip->isStream()) {
00265             pos += m_soundclip->getStreamPos(m_streamid, type);
00266         }
00267 
00268         CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error getting cursor")
00269 
00270         return pos;
00271     }
00272 }