src/sound/jukebox.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  *  Wormux is a convivial mass murder game.
00003  *  Copyright (C) 2001-2004 Lawrence Azzoug.
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00018  ******************************************************************************
00019  * Sound engine
00020  *****************************************************************************/
00021 
00022 #include "jukebox.h"
00023 #include <iostream>
00024 
00025 #include "../game/config.h"
00026 #include "../tool/debug.h"
00027 #include "../tool/i18n.h"
00028 #include "../tool/random.h"
00029 #include "../tool/file_tools.h"
00030 
00031 JukeBox jukebox;
00032 
00033 JukeBox::JukeBox()
00034 {
00035   m_init = false;
00036   
00037   m_config.music = true;
00038   m_config.effects = true;
00039   m_config.frequency = 44100; //MIX_DEFAULT_FREQUENCY;
00040   m_config.channels = 2; // stereo
00041 }
00042 
00043 void JukeBox::Pause() 
00044 {
00045   Mix_Pause(-1);
00046   Mix_PauseMusic();
00047 }
00048 
00049 void JukeBox::Resume() 
00050 {    
00051   Mix_Resume(-1);
00052   Mix_ResumeMusic();
00053 }
00054 
00055 void JukeBox::Init() 
00056 {
00057   if (!m_config.music && !m_config.effects) {
00058     End();
00059     return;
00060   }
00061 
00062   if (m_init) return;
00063 
00064   Uint16 audio_format = MIX_DEFAULT_FORMAT;
00065 
00066   /* Initialize the SDL library */
00067   if ( SDL_Init(SDL_INIT_AUDIO) < 0 ) {
00068     std::cerr << "* Couldn't initialize SDL: "<< SDL_GetError() << std::endl;
00069     return;
00070   } 
00071   
00072   int audio_buffer = 1024;
00073 
00074   /* Open the audio device */
00075   if (Mix_OpenAudio(m_config.frequency, audio_format, m_config.channels, audio_buffer) < 0) {
00076     std::cerr << "* Couldn't open audio: " <<  SDL_GetError() << std::endl;
00077     return;
00078   } else {
00079     Mix_QuerySpec(&m_config.frequency, &audio_format, &m_config.channels);
00080     std::cout << "o Opened audio at " << m_config.frequency <<" Hz "<< (audio_format&0xFF) 
00081               <<" bit " << std::endl;
00082   }
00083   Mix_ChannelFinished(JukeBox::EndChunk);
00084   
00085   m_init = true;  
00086   
00087   LoadXML("share");
00088 }
00089 
00090 void JukeBox::End() 
00091 {
00092   if (!m_init) return;
00093   m_init = false;
00094 
00095   StopAll();
00096 
00097   m_soundsamples.clear();
00098   m_profiles_loaded.clear();
00099 
00100   Mix_CloseAudio();
00101 }
00102 
00103 void JukeBox::SetFrequency (int frequency)
00104 {
00105   if ((frequency != 11025) 
00106       && (frequency != 22050) 
00107       && (frequency != 44100)) frequency = 44100;
00108 
00109   if (m_config.frequency == frequency) return;
00110 
00111   m_config.frequency = frequency;
00112 
00113   // Close and reopen audio device
00114   End();
00115   Init();
00116 }
00117 
00118 // Code not used
00119 #if 0
00120 void JukeBox::SetNumbersOfChannel(int channels)
00121 {
00122   if (m_config.channels == channels) return;
00123 
00124   m_config.channels = channels;
00125 
00126   // Close and reopen audio device
00127   End();
00128   Init();
00129 }
00130 #endif
00131 
00132 void JukeBox::LoadXML(const std::string& profile)
00133 {
00134 
00135   if (!UseEffects()) return;
00136 
00137   // is xml_file already loaded ?
00138   std::set<std::string>::iterator it_profile = m_profiles_loaded.find(profile) ;
00139   if (it_profile !=  m_profiles_loaded.end()) {
00140           MSG_DEBUG("jukebox", "Profile %s is already loaded !", profile.c_str());
00141       return;
00142   } 
00143   std::cout << "o Loading sound profile " << profile << std::endl;
00144 
00145   XmlReader doc;
00146 
00147   // Load the XML
00148   std::string folder = Config::GetInstance()->GetDataDir() + PATH_SEPARATOR + "sound"+ PATH_SEPARATOR + profile + PATH_SEPARATOR;
00149   std::string xml_filename = folder + "profile.xml";
00150   if( !IsFileExist(xml_filename) ){
00151     std::cerr << "[Sound] Error : file " << xml_filename << " not found" << std::endl;
00152     return;
00153   }
00154   if(!doc.Load(xml_filename))
00155     return;
00156 
00157   xmlpp::Node::NodeList nodes = doc.GetRoot()->get_children("sound");
00158   xmlpp::Node::NodeList::iterator 
00159     it=nodes.begin(),
00160     fin=nodes.end();
00161 
00162   for (; it != fin; ++it)
00163     {
00164       // lit le XML
00165       xmlpp::Element *elem = dynamic_cast<xmlpp::Element*> (*it);
00166       std::string sample="no_sample";
00167       std::string file="no_file";
00168       XmlReader::ReadStringAttr(elem, "sample", sample);
00169       XmlReader::ReadStringAttr(elem, "file", file);
00170 
00171           MSG_DEBUG("jukebox", "Load sound sample %s/%s: %s", profile.c_str(), sample.c_str(), file.c_str());
00172 
00173       // Charge le son
00174       std::string sample_filename = folder + file;
00175       if( !IsFileExist(sample_filename) ){
00176         std::cerr << "Sound error: File " << sample_filename.c_str() 
00177                   << " does not exist !" << std::endl; 
00178         continue;
00179       }
00180         
00181       // Inserting sound sample in list
00182       m_soundsamples.insert(sound_sample(profile+"/"+sample, sample_filename));  
00183     }
00184 
00185   // The profile is loaded
00186   m_profiles_loaded.insert(profile);
00187 }
00188 
00189 int JukeBox::Play (const std::string& category, const std::string& sample, 
00190                    const int loop)
00191 {
00192   if (!UseEffects()) return -1;
00193 
00194   uint nb_sons= m_soundsamples.count(category+"/"+sample);
00195   if (nb_sons) 
00196   {
00197     std::pair<sample_iterator, sample_iterator> p = m_soundsamples.equal_range(category+"/"+sample);
00198     sample_iterator it = p.first;
00199 
00200     // Choose a random sound sample
00201     if (nb_sons > 1)
00202     {
00203       uint selection = uint(randomObj.GetLong(0, nb_sons));
00204       if (selection == nb_sons) --selection ;
00205 
00206       it = p.first ;
00207       
00208       for ( uint i=0 ; i<selection && it!=p.second ; ++i ) it++ ;
00209     }
00210 
00211     // Play the sound
00212     Mix_Chunk * sampleChunk = Mix_LoadWAV(it->second.c_str());
00213     MSG_DEBUG("jukebox.play", "Playing sample %s/%s", category.c_str(), sample.c_str());
00214     return PlaySample(sampleChunk, loop);
00215   }
00216   else if (category != "default") { // try with default profile
00217     return Play("default", sample, loop) ; // try with default profile
00218   } 
00219 
00220   MSG_DEBUG("jukebox", "Error: No sound found for sample %s/%s", category.c_str(), sample.c_str());
00221   return -1;
00222 }
00223 
00224 int JukeBox::Stop (int channel)
00225 {
00226   if(!m_config.music && !m_config.effects) return 0;
00227   if (channel == -1) return 0;
00228   return Mix_HaltChannel(channel);
00229 }
00230 
00231 int JukeBox::StopAll()
00232 {
00233   if (!m_config.music && !m_config.effects) return 0;
00234 
00235   // halt playback on all channels
00236   return Mix_HaltChannel(-1);
00237 }
00238 
00239 int JukeBox::PlaySample (Mix_Chunk * sample, int loop)
00240 {
00241   if (loop != -1) loop--;
00242 
00243   int channel = Mix_PlayChannel(-1, sample, loop);
00244 
00245   if (channel == -1) {
00246         MSG_DEBUG("jukebox", "Error: Jukebox::PlaySample: %s", Mix_GetError());
00247         Mix_FreeChunk(sample);
00248   }
00249   else
00250     chunks[channel] = sample;
00251   return channel;
00252 }
00253 
00254 void JukeBox::EndChunk(int channel)
00255 {
00256   Mix_Chunk* chk = jukebox.chunks[channel];
00257   
00258   if(!chk) return;
00259   
00260   Mix_FreeChunk(chk);
00261   jukebox.chunks[channel] = 0;
00262 }

Generated on Mon Jan 1 13:10:59 2007 for Wormux by  doxygen 1.4.7