Back to index

supertuxkart  0.5+dfsg1
music_ogg.cpp
Go to the documentation of this file.
00001 //  $Id$
00002 //
00003 //  SuperTuxKart - a fun racing game with go-kart
00004 //  Copyright (C) 2007 Damien Morel <divdams@free.fr>
00005 //
00006 //  This program is free software; you can redistribute it and/or
00007 //  modify it under the terms of the GNU General Public License
00008 //  as published by the Free Software Foundation; either version 2
00009 //  of the License, or (at your option) any later version.
00010 //
00011 //  This program 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
00014 //  GNU General Public License for more details.
00015 //
00016 //  You should have received a copy of the GNU General Public License
00017 //  along with this program; if not, write to the Free Software
00018 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019 
00020 #if HAVE_OPENAL && HAVE_OGGVORBIS
00021 
00022 #include <stdexcept>
00023 #ifdef __APPLE__
00024 #  include <OpenAL/al.h>
00025 #else
00026 #  include <AL/al.h>
00027 #endif
00028 #include <AL/alut.h>
00029 
00030 #include "music_ogg.hpp"
00031 #include "file_manager.hpp"
00032 #include "user_config.hpp"
00033 
00034 #define BUFFER_SIZE (4096 * 8)
00035 
00036 
00037 MusicOggStream::MusicOggStream()
00038 {
00039     //m_oggStream= NULL;
00040     m_soundBuffers[0]= m_soundBuffers[1]= 0;
00041     m_soundSource= 0;
00042     m_pausedMusic= true;
00043 }
00044 
00045 //-----------------------------------------------------------------------------
00046 MusicOggStream::~MusicOggStream()
00047 {
00048     if(stopMusic() == false)
00049        fprintf(stderr, "WARNING: problems while stopping music.\n");
00050 }
00051 
00052 //-----------------------------------------------------------------------------
00053 bool MusicOggStream::load(const std::string& filename)
00054 {
00055     m_error = true;
00056     if(!release())
00057     {
00058         user_config->setMusic(UserConfig::UC_TEMPORARY_DISABLE);
00059         fprintf(stderr,"Problems oggStream:release. Disabling music.\n");
00060         return false;
00061     }
00062 
00063     m_fileName = filename;
00064     if(m_fileName=="") return false;
00065     
00066     m_oggFile = fopen(m_fileName.c_str(), "rb");
00067 
00068     if(!m_oggFile)
00069     {
00070         printf("Loading Music: %s failed\n", m_fileName.c_str());
00071         return false;
00072     }
00073 
00074 #if defined( WIN32 ) || defined( WIN64 )
00075     if( ov_open_callbacks((void *)m_oggFile, &m_oggStream, NULL, 0, OV_CALLBACKS_DEFAULT) < 0)
00076 #else
00077     if (ov_open(m_oggFile, &m_oggStream, NULL, 0) < 0)
00078 #endif
00079     {
00080         fclose(m_oggFile);
00081         printf("Loading Music: %s failed\n", m_fileName.c_str());
00082         return false;
00083     }
00084     
00085     m_vorbisInfo = ov_info(&m_oggStream, -1);
00086 
00087     if(m_vorbisInfo->channels == 1)
00088         nb_channels = AL_FORMAT_MONO16;
00089     else
00090         nb_channels = AL_FORMAT_STEREO16;
00091 
00092 
00093     alGenBuffers(2, m_soundBuffers);
00094     if(check() == false)
00095         return false;
00096 
00097     alGenSources(1, &m_soundSource);
00098     if(check() == false)
00099         return false;
00100 
00101     alSource3f(m_soundSource, AL_POSITION,        0.0, 0.0, 0.0);
00102     alSource3f(m_soundSource, AL_VELOCITY,        0.0, 0.0, 0.0);
00103     alSource3f(m_soundSource, AL_DIRECTION,       0.0, 0.0, 0.0);
00104     alSourcef (m_soundSource, AL_ROLLOFF_FACTOR,  0.0          );
00105     alSourcei (m_soundSource, AL_SOURCE_RELATIVE, AL_TRUE      );
00106 
00107     m_error=false;
00108     return true;
00109 }
00110 
00111 //-----------------------------------------------------------------------------
00112 bool MusicOggStream::empty()
00113 {
00114     int queued= 0;
00115     alGetSourcei(m_soundSource, AL_BUFFERS_QUEUED, &queued);
00116 
00117     while(queued--)
00118     {
00119         ALuint buffer = 0;
00120         alSourceUnqueueBuffers(m_soundSource, 1, &buffer);
00121 
00122         if(check() == false)
00123             return false;
00124     }
00125 
00126     return true;
00127 }
00128 
00129 //-----------------------------------------------------------------------------
00130 bool MusicOggStream::release()
00131 {
00132     if (m_fileName == "")
00133     {
00134         // nothing is loaded
00135         return true;
00136     }
00137 
00138     pauseMusic();
00139     m_fileName= "";
00140 
00141     empty();
00142     alDeleteSources(1, &m_soundSource);
00143     check();
00144     alDeleteBuffers(2, m_soundBuffers);
00145     check();
00146 
00147     // Handle error correctly
00148     if(!m_error) ov_clear(&m_oggStream);
00149 
00150     return true;
00151 }
00152 
00153 //-----------------------------------------------------------------------------
00154 bool MusicOggStream::playMusic()
00155 {
00156     if(isPlaying())
00157         return true;
00158 
00159     if(!streamIntoBuffer(m_soundBuffers[0]))
00160         return false;
00161 
00162     if(!streamIntoBuffer(m_soundBuffers[1]))
00163         return false;
00164 
00165     alSourceQueueBuffers(m_soundSource, 2, m_soundBuffers);
00166 
00167     alSourcePlay(m_soundSource);
00168     m_pausedMusic= false;
00169 
00170     return true;
00171 }
00172 
00173 //-----------------------------------------------------------------------------
00174 bool MusicOggStream::isPlaying()
00175 {
00176     ALenum state;
00177     alGetSourcei(m_soundSource, AL_SOURCE_STATE, &state);
00178 
00179     return (state == AL_PLAYING);
00180 }
00181 
00182 //-----------------------------------------------------------------------------
00183 bool MusicOggStream::stopMusic()
00184 {
00185     return (release());
00186 }
00187 
00188 //-----------------------------------------------------------------------------
00189 bool MusicOggStream::pauseMusic()
00190 {
00191     if (m_fileName == "")
00192     {
00193         // nothing is loaded
00194         return true;
00195     }
00196 
00197     alSourceStop(m_soundSource);
00198     m_pausedMusic= true;
00199     return true;
00200 }
00201 
00202 //-----------------------------------------------------------------------------
00203 bool MusicOggStream::resumeMusic()
00204 {
00205     if (m_fileName == "")
00206     {
00207         // nothing is loaded
00208         return true;
00209     }
00210 
00211     alSourcePlay(m_soundSource);
00212     m_pausedMusic= false;
00213     return true;
00214 }
00215 
00216 //-----------------------------------------------------------------------------
00217 void MusicOggStream::updateFading(float percent)
00218 {
00219     alSourcef(m_soundSource,AL_GAIN,percent);
00220     update();
00221 }   // updateFading
00222 
00223 //-----------------------------------------------------------------------------
00224 void MusicOggStream::updateFaster(float percent, float max_pitch)
00225 {
00226     alSourcef(m_soundSource,AL_PITCH,1+max_pitch*percent);
00227     update();
00228 }   // updateFaster
00229 
00230 //-----------------------------------------------------------------------------
00231 void MusicOggStream::update()
00232 {
00233 
00234     if (m_pausedMusic)
00235     {
00236         // nothing todo
00237         return;
00238     }
00239 
00240     int processed= 0;
00241     bool active= true;
00242 
00243     alGetSourcei(m_soundSource, AL_BUFFERS_PROCESSED, &processed);
00244 
00245     while(processed--)
00246     {
00247         ALuint buffer;
00248 
00249         alSourceUnqueueBuffers(m_soundSource, 1, &buffer);
00250         if(check() == false)
00251             return;
00252 
00253         active = streamIntoBuffer(buffer);
00254         alSourceQueueBuffers(m_soundSource, 1, &buffer);
00255 
00256         if(check() == false)
00257             return;
00258     }
00259 
00260     // check for underrun
00261     if (active)
00262     {
00263         // we have data, so we should be playing...
00264         ALenum state;
00265         alGetSourcei(m_soundSource, AL_SOURCE_STATE, &state);
00266         if (state != AL_PLAYING)
00267         {
00268                fprintf(stderr,"WARNING: Alsa source state: %d\n", state);
00269             alGetSourcei(m_soundSource, AL_BUFFERS_PROCESSED, &processed);
00270             alSourcePlay(m_soundSource);
00271         }
00272     }
00273     else
00274     {
00275         // no more data. Seek to beginning -> loop
00276            ov_time_seek(&m_oggStream, 0);
00277     }
00278 }
00279 
00280 //-----------------------------------------------------------------------------
00281 bool MusicOggStream::streamIntoBuffer(ALuint buffer)
00282 {
00283     char pcm[BUFFER_SIZE];
00284 #ifdef WORDS_BIGENDIAN
00285     int  isBigEndian = 1;
00286 #else
00287     int  isBigEndian = 0;
00288 #endif
00289     int  size = 0;
00290     int  portion;
00291     int  result;
00292 
00293     while(size < BUFFER_SIZE)
00294     {
00295         result = ov_read(&m_oggStream, pcm + size, BUFFER_SIZE - size, isBigEndian, 2, 1, &portion);
00296 
00297         if(result > 0)
00298             size += result;
00299         else
00300             if(result < 0)
00301                 throw errorString(result);
00302             else
00303                 break;
00304     }
00305 
00306     if(size == 0)
00307         return false;
00308 
00309 
00310     alBufferData(buffer, nb_channels, pcm, size, m_vorbisInfo->rate);
00311     check();
00312 
00313     return true;
00314 }
00315 
00316 //-----------------------------------------------------------------------------
00317 bool MusicOggStream::check()
00318 {
00319     int error = alGetError();
00320 
00321     if(error != AL_NO_ERROR)
00322     {
00323        fprintf(stderr, "OpenAL error: %d\n", error);
00324         return false;
00325     }
00326 
00327     return true;
00328 }
00329 
00330 //-----------------------------------------------------------------------------
00331 string MusicOggStream::errorString(int code)
00332 {
00333     switch(code)
00334     {
00335         case OV_EREAD:
00336             return string("Read error from media.");
00337         case OV_ENOTVORBIS:
00338             return string("It is not Vorbis data.");
00339         case OV_EVERSION:
00340             return string("Vorbis version mismatch.");
00341         case OV_EBADHEADER:
00342             return string("Invalid Vorbis bitstream header.");
00343         case OV_EFAULT:
00344             return string("Internal logic fault (bug or heap/stack corruption).");
00345         default:
00346             return string("Unknown Vorbis error.");
00347     }
00348 }
00349 
00350 #endif // HAVE_OPENAL && HAVE_OGGVORBIS