soundclip.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2011 by the FIFE team                              *
00003  *   http://www.fifengine.net                                              *
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 #include <sstream>
00026 
00027 // 3rd party library includes
00028 
00029 // FIFE includes
00030 // These includes are split up in two parts, separated by one empty line
00031 // First block: files included from the FIFE root src directory
00032 // Second block: files included from the same folder
00033 #include "util/base/exception.h"
00034 #include "util/log/logger.h"
00035 #include "loaders/native/audio/ogg_loader.h"
00036 
00037 #include "soundclip.h"
00038 
00039 namespace FIFE {
00040     static Logger _log(LM_AUDIO);
00041 
00042     SoundClip::SoundClip(IResourceLoader* loader) :
00043         IResource(createUniqueClipName(), loader),
00044         m_isstream(false),
00045         m_decoder(NULL),
00046         m_deletedecoder(false) {
00047 
00048     }
00049 
00050     SoundClip::SoundClip(const std::string& name, IResourceLoader* loader) :
00051         IResource(name, loader),
00052         m_isstream(false),
00053         m_decoder(NULL),
00054         m_deletedecoder(false) {
00055 
00056     }
00057 
00058     void SoundClip::load(){
00059         if (m_loader){
00060             m_loader->load(this);
00061         }
00062         else {  //no loader specified so find one to use
00063             if(m_name.find(".ogg", m_name.size() - 4) != std::string::npos) {
00064                 OggLoader loader;
00065                 loader.load(this);
00066             } else {
00067                 FL_WARN(_log, LMsg() << "No audio-decoder available for file \"" << m_name << "\"!");
00068                 throw InvalidFormat("Error: Ogg loader can't load files without ogg extension");
00069             }
00070         }
00071 
00072         assert(m_decoder);  //should be set by now
00073 
00074         m_isstream = m_decoder->needsStreaming();
00075 
00076         if (!m_isstream) {
00077 
00078             // only for non-streaming buffers
00079             SoundBufferEntry* ptr = new SoundBufferEntry();
00080 
00081             // iterate the bufs and fill them with data
00082             for (int32_t i = 0; i < BUFFER_NUM; i++) {
00083 
00084                 if (m_decoder->decode(BUFFER_LEN)) {
00085                     // EOF or error
00086                     break;
00087                 }
00088 
00089                 // generate buffer and fill it with data
00090                 alGenBuffers(1, &ptr->buffers[i]);
00091 
00092                 alBufferData(ptr->buffers[i], m_decoder->getALFormat(), m_decoder->getBuffer(),
00093                     m_decoder->getBufferSize(), m_decoder->getSampleRate());
00094 
00095                 CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error copying data to buffers")
00096 
00097                 ptr->usedbufs++;
00098             }
00099 
00100             m_decoder->releaseBuffer();
00101 
00102             // push the buffer information to the vector
00103             m_buffervec.push_back(ptr);
00104 
00105         }
00106 
00107         m_state = IResource::RES_LOADED;
00108     }
00109 
00110     void SoundClip::free(){
00111         if (m_state == IResource::RES_LOADED) {
00112             if (m_isstream) {
00113                 // erase all elements from the list
00114                 std::vector<SoundBufferEntry*>::iterator it;
00115 
00116                 for (it = m_buffervec.begin(); it != m_buffervec.end(); ++it) {
00117                     if ((*it)->buffers[0] != 0) {
00118                         alDeleteBuffers(BUFFER_NUM, (*it)->buffers);
00119                     }
00120                     delete (*it);
00121                 }
00122                 m_buffervec.clear();
00123             }
00124             else {
00125                 // for non-streaming soundclips
00126                 SoundBufferEntry* ptr = m_buffervec.at(0);
00127 
00128                 for(uint32_t i = 0; i < ptr->usedbufs; i++) {
00129                     alDeleteBuffers(1, &ptr->buffers[i]);
00130                 }
00131             }
00132         }
00133         m_state = IResource::RES_NOT_LOADED;
00134     }
00135 
00136     uint32_t SoundClip::beginStreaming() {
00137         // create new sound buffer entry
00138         SoundBufferEntry* ptr = new SoundBufferEntry();
00139         ptr->usedbufs=0;
00140         alGenBuffers(BUFFER_NUM, ptr->buffers);
00141 
00142         CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error creating streaming-buffers")
00143 
00144         m_buffervec.push_back(ptr);
00145 
00146         return m_buffervec.size()-1;
00147     }
00148 
00149     bool SoundClip::setStreamPos(uint32_t streamid, SoundPositionType type, float value) {
00150         uint64_t pos = 0;
00151 
00152         // convert position to bytes
00153         switch (type) {
00154             case SD_BYTE_POS:
00155                 pos = static_cast<uint64_t>(value);
00156                 break;
00157             case SD_TIME_POS:
00158                 value *= m_decoder->getSampleRate();
00159             case SD_SAMPLE_POS:
00160                 pos = static_cast<uint64_t>((m_decoder->getBitResolution() / 8) * (m_decoder->isStereo() ? 2 : 1) * value);
00161                 break;
00162         }
00163 
00164         if (pos > m_decoder->getDecodedLength()) {
00165             // EOF!
00166             return true;
00167         }
00168 
00169         // set cursor position
00170         m_buffervec.at(streamid)->deccursor = pos;
00171         return false;
00172     }
00173 
00174     float SoundClip::getStreamPos(uint32_t streamid, SoundPositionType type) const{
00175         uint64_t pos = m_buffervec.at(streamid)->deccursor;
00176         switch(type) {
00177             case SD_BYTE_POS:
00178                 return pos;
00179             case SD_SAMPLE_POS:
00180                 return pos / (m_decoder->getBitResolution() / 8 * (m_decoder->isStereo() ? 2 : 1));
00181             case SD_TIME_POS:
00182                 return pos / (m_decoder->getBitResolution() / 8 * (m_decoder->isStereo() ? 2 : 1) * m_decoder->getSampleRate());
00183         }
00184         return 0.0f;
00185     }
00186 
00187     void SoundClip::acquireStream(uint32_t streamid) {
00188 
00189         SoundBufferEntry* ptr = m_buffervec.at(streamid);
00190 
00191         for (int32_t i = 0; i < BUFFER_NUM; i++) {
00192             getStream(streamid, ptr->buffers[i]);
00193         }
00194     }
00195 
00196     bool SoundClip::getStream(uint32_t streamid, ALuint buffer) {
00197 
00198         SoundBufferEntry* ptr = m_buffervec.at(streamid);
00199 
00200         if (ptr->deccursor >= m_decoder->getDecodedLength()) {
00201             // EOF!
00202             return true;
00203         }
00204 
00205         // set cursor of decoder
00206         m_decoder->setCursor(ptr->deccursor);
00207 
00208         // Error while decoding file?
00209         if (m_decoder->decode(BUFFER_LEN)) {
00210             throw Exception("error while reading from audio file");
00211         }
00212 
00213         // fill the buffer with data
00214         alBufferData(buffer, m_decoder->getALFormat(),
00215             m_decoder->getBuffer(), m_decoder->getBufferSize(), m_decoder->getSampleRate());
00216 
00217         m_decoder->releaseBuffer();
00218 
00219         // update cursor
00220         ptr->deccursor += BUFFER_LEN;
00221 
00222         CHECK_OPENAL_LOG(_log, LogManager::LEVEL_ERROR, "error catching stream")
00223 
00224         return false;
00225     }
00226 
00227     void SoundClip::quitStreaming(uint32_t streamid) {
00228         // release the buffers
00229         SoundBufferEntry* ptr = m_buffervec.at(streamid);
00230         alDeleteBuffers(BUFFER_NUM, ptr->buffers);
00231         ptr->buffers[0] = 0;
00232     }
00233 
00234     SoundClip::~SoundClip() {
00235         free();
00236 
00237         // delete decoder
00238         if (m_deletedecoder && m_decoder != NULL) {
00239             delete m_decoder;
00240         }
00241     }
00242 
00243     std::string SoundClip::createUniqueClipName() {
00244             // automated counting for name generation, in case the user doesn't provide a name
00245             static uint32_t uniqueNumber = 0;
00246             static std::string baseName = "soundclip";
00247 
00248             std::ostringstream oss;
00249             oss << uniqueNumber << "_" << baseName;
00250 
00251             const std::string name = oss.str();
00252             ++uniqueNumber;
00253 
00254             return name;
00255     }
00256 }