00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <boost/regex.hpp>
00012
00013 #include <cstring>
00014 #include <stdlib.h>
00015
00016
00017 #include <SDL.h>
00018 #include <SDL_mixer.h>
00019 #include <SDL_sound.h>
00020
00021
00022 #include "../global.h"
00023
00024 #include "sound.h"
00025
00026 #include "../basestrm.h"
00027 #include "../music.h"
00028 #include "../sgstream.h"
00029
00032 const int WAIT_SLEEP_MSEC = 50;
00033
00034
00035
00036 class SoundSystem_InternalData {
00037 public:
00038 Mix_Music *musicBuf;
00039 MusicPlayList* currentPlaylist;
00040
00041 Sound* channel[MIX_CHANNELS];
00042
00043 ASCString lastMusicMessage;
00044
00045 SoundSystem_InternalData() : musicBuf(NULL), currentPlaylist(NULL) {
00046 for ( int i = 0; i < MIX_CHANNELS; ++i )
00047 channel[i] = NULL;
00048
00049 };
00050 };
00051
00052 SoundSystem* SoundSystem::instance = NULL;
00053
00054 SoundSystem :: SoundSystem ( bool muteEffects, bool muteMusic, bool _off )
00055 : sdl_initialized(false), mix_initialized( false )
00056 {
00057 internalData = new SoundSystem_InternalData;
00058
00059 musicState = uninitialized;
00060
00061 this->effectsMuted = muteEffects;
00062 this->off = _off;
00063
00064 if ( instance )
00065 fatalError ( "Only one instance of SoundSystem possible !");
00066
00067 instance = this;
00068
00069 if( off )
00070 return;
00071
00072 displayLogMessage(0,"Initializing sound device. If this hangs, run ASC without sound (asc -q)\n");
00073 displayLogMessage(0,"Step 1/3 (SDL_Init)...");
00074
00075 if ( SDL_Init ( SDL_INIT_AUDIO ) < 0 ) {
00076 displayLogMessage(0,"failed, disabling sound\n");
00077 warning("Couldn't initialize SDL audio interface !");
00078 off = true;
00079 sdl_initialized = false;
00080 return;
00081 }
00082
00083 displayLogMessage(0,"ok\nStep 2/3 (SDL_Sound Sound_Init)...");
00084 if (!Sound_Init()) {
00085 displayLogMessage(0,"failed, disabling sound\n");
00086 warning("Couldn't initialize SDL_sound !");
00087 off = true;
00088 sdl_initialized = false;
00089 return;
00090 }
00091
00092 sdl_initialized = true;
00093
00094 int audio_rate = MIX_DEFAULT_FREQUENCY;
00095 Uint16 audio_format = MIX_DEFAULT_FORMAT;
00096 int audio_channels = 2;
00097
00098 displayLogMessage(0,"ok\nStep 3/3 (SDL_Mixer Mix_OpenAudio)...");
00099 if ( Mix_OpenAudio ( audio_rate, audio_format, audio_channels, 2048 ) < 0 ) {
00100 displayLogMessage(0,"failed, disabling sound\n");
00101 mix_initialized = false;
00102 warning("Couldn't initialize SDL_mixer !");
00103 off = true;
00104 return;
00105 } else {
00106 mix_initialized = true;
00107 if ( muteMusic )
00108 musicState = init_paused;
00109 else
00110 musicState = init_ready;
00111
00112 Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
00113 displayLogMessage ( 5, "Opened audio at %d Hz %d bit %s\n", audio_rate, (audio_format&0xFF), (audio_channels > 1) ? "stereo" : "mono");
00114 Mix_HookMusicFinished ( trackFinished );
00115
00116 Mix_ChannelFinished( channelFinishedCallback );
00117
00118 displayLogMessage(0,"ok\nSound system successfully initialized!\n");
00119 }
00120 }
00121
00122
00123 void SoundSystem::setEffectsMute ( bool mute )
00124 {
00125 if ( off )
00126 return;
00127
00128 if ( mute != this->effectsMuted ) {
00129 if ( mute ) {
00130 for ( int i = 0; i < MIX_CHANNELS; i++ )
00131 if ( Mix_Playing(i) )
00132 Mix_HaltChannel( i );
00133
00134 }
00135 this->effectsMuted = mute;
00136 }
00137 }
00138
00139
00140 void SoundSystem :: trackFinished( void )
00141 {
00142 getInstance()->nextTrack();
00143 }
00144
00145 ASCString SoundSystem :: getDiagnosticText()
00146 {
00147
00148 static ASCString boolean[2] = {"false", "true"};
00149
00150 ASCString text = "Sound System Status: ";
00151
00152 if( off )
00153 text += "off\n";
00154 else
00155 text += "on\n";
00156
00157 text += "Effects Muted: " + boolean[effectsMuted] + "\n";
00158 text += "SDL Initialized: " + boolean[sdl_initialized] + "\n";
00159 text += "Mixer Initialized: " + boolean[mix_initialized] + "\n";
00160 text += "Music Volume: " + ASCString::toString( musicVolume ) + "\n";
00161 text += "Effects Volume: " + ASCString::toString( effectVolume ) + "\n";
00162
00163 text += "\n";
00164 text += "Last message from mixer was:\n";
00165 text += internalData->lastMusicMessage + "\n\n";
00166
00167 if ( internalData->currentPlaylist )
00168 text += internalData->currentPlaylist->getDiagnosticText();
00169 else
00170 text += "No play list active!";
00171
00172 return text;
00173 }
00174
00175
00176 void SoundSystem :: nextTrack( void )
00177 {
00178 if ( off || musicState==paused || musicState==init_paused)
00179 return;
00180
00181 if ( internalData->musicBuf ) {
00182 Mix_FreeMusic( internalData->musicBuf );
00183 internalData->musicBuf = NULL;
00184 }
00185
00186 if ( internalData->currentPlaylist ) {
00187 ASCString filename = internalData->currentPlaylist->getNextTrack();
00188
00189 if ( !filename.empty() ) {
00190 musicState = playing;
00191 internalData->musicBuf = Mix_LoadMUS( filename.c_str() );
00192
00193 if ( !internalData->musicBuf ) {
00194 internalData->lastMusicMessage = "Could not load music file " + filename + " ; SDL reports error " + SDL_GetError();
00195 displayLogMessage ( 1, internalData->lastMusicMessage + "\n" );
00196 SDL_ClearError();
00197 } else {
00198 int chan = Mix_PlayMusic ( internalData->musicBuf, 1 );
00199 Mix_VolumeMusic ( musicVolume );
00200 displayLogMessage ( 4, "Playing music on channel %d \n", chan );
00201 }
00202 }
00203 } else
00204 displayLogMessage ( 1, "No play list available \n" );
00205 }
00206
00207 void SoundSystem :: playMusic ( MusicPlayList* playlist )
00208 {
00209 internalData->currentPlaylist = playlist;
00210 nextTrack();
00211 }
00212
00213
00214 void SoundSystem :: pauseMusic()
00215 {
00216 if ( off )
00217 return;
00218
00219 if ( musicState == playing ) {
00220 Mix_PauseMusic ();
00221 musicState = paused;
00222 }
00223 }
00224
00225 void SoundSystem :: resumeMusic()
00226 {
00227 if ( off )
00228 return;
00229
00230 if ( musicState == init_ready || musicState == init_paused ) {
00231 if (musicState == init_paused)
00232 musicState = init_ready;
00233 nextTrack();
00234 return;
00235 }
00236
00237 if ( musicState == paused ) {
00238 Mix_ResumeMusic ();
00239 musicState = playing;
00240 }
00241 }
00242
00243 void SoundSystem :: resumePauseMusic()
00244 {
00245 if ( musicState == playing )
00246 pauseMusic();
00247 else
00248 resumeMusic();
00249 }
00250
00251 void SoundSystem :: setMusicVolume( int volume )
00252 {
00253 musicVolume = volume * 128 / 100;
00254
00255 if ( off )
00256 return;
00257
00258 Mix_VolumeMusic ( musicVolume );
00259 }
00260
00261 void SoundSystem :: setEffectVolume( int volume )
00262 {
00263 effectVolume = volume * 128 / 100;
00264
00265 if ( off )
00266 return;
00267
00268 Mix_Volume ( -1, effectVolume );
00269 }
00270
00271
00272 SoundSystem::~SoundSystem()
00273 {
00274 if ( !off ) {
00275 Mix_HaltMusic();
00276
00277 if ( internalData->musicBuf ) {
00278 Mix_FreeMusic( internalData->musicBuf );
00279 internalData-> musicBuf = NULL;
00280 }
00281 }
00282
00283 if( mix_initialized )
00284 Mix_CloseAudio();
00285
00286 if( sdl_initialized )
00287 SDL_CloseAudio();
00288
00289 delete internalData;
00290
00291 instance = NULL;
00292 }
00293
00294
00295
00296 void SoundSystem::channelFinishedCallback( int channelnum )
00297 {
00298 if ( getInstance()->internalData->channel[channelnum] )
00299 getInstance()->internalData->channel[channelnum]->finishedSignal( channelnum );
00300 }
00301
00302
00303
00304 pair<Sound_Sample*, Mix_Chunk*> loadWave ( const ASCString& name )
00305 {
00306 Mix_Chunk* chunk = NULL;
00307 Sound_Sample* sample = NULL;
00308
00309 if ( !exist ( name )) {
00310 errorMessage ( " can't open sound file: " + name );
00311 return make_pair(sample,chunk);
00312 }
00313
00314 tnfilestream stream ( name, tnstream::reading );
00315
00316 ASCString ext;
00317 boost::smatch what;
00318 static boost::regex extension( ".*\\.([^\\.]+)");
00319 if( boost::regex_match( name, what, extension))
00320 ext.assign( what[1].first, what[1].second );
00321
00322
00323 int frequency;
00324 Uint16 format;
00325 int channels;
00326 Mix_QuerySpec(&frequency, &format, &channels);
00327 Sound_AudioInfo ai;
00328 ai.format = format;
00329 ai.channels = channels;
00330 ai.rate = frequency;
00331
00332 try {
00333 sample = Sound_NewSample ( SDL_RWFromStream ( &stream ), ext.c_str(), &ai, 1<<16);
00334 if ( sample )
00335 displayLogMessage ( 10, " SoundSystem::loadWave - sound " + name + " loaded successfully\n");
00336 else {
00337 displayLogMessage (0, ASCString(" SoundSystem::loadWave" ) + name + " failed. Message: " + Sound_GetError() + "\n");
00338 return make_pair(sample,chunk);
00339 }
00340 }
00341 catch ( tfileerror err ) {
00342 warning(" Error loading sound file " + name );
00343 sample = NULL;
00344 return make_pair(sample,chunk);
00345 }
00346
00347 Uint32 size = Sound_DecodeAll ( sample );
00348 if ( sample->buffer_size <= 0 )
00349 warning( "decoding of file " + name + " failed");
00350
00351 chunk = new Mix_Chunk;
00352 chunk->allocated = size;
00353 chunk->abuf = (Uint8*) sample->buffer;
00354 chunk->alen = size;
00355 chunk->volume = MIX_MAX_VOLUME;
00356
00357 return make_pair(sample,chunk);
00358 }
00359
00360
00361 class Sound_InternalData {
00362 public:
00364 Mix_Chunk *mainwave;
00365 Mix_Chunk *startwave;
00366 Sound_Sample *mainsample;
00367 Sound_Sample *startsample;
00368 Sound_InternalData() : mainwave(NULL), startwave(NULL), mainsample(NULL), startsample(NULL) {};
00369 };
00370
00371 Sound::Sound( const ASCString& filename, int _fadeIn ) : name ( filename ), fadeIn ( _fadeIn ), waitingForMainWave(false)
00372 {
00373 internalData = new Sound_InternalData;
00374
00375 if ( !SoundSystem::instance )
00376 fatalError ( "Sound::Sound failed, because there is no SoundSystem initialized");
00377
00378 pair<Sound_Sample*, Mix_Chunk*> res = loadWave( filename );
00379 internalData->mainsample = res.first;
00380 internalData->mainwave = res.second;
00381 }
00382
00383 Sound::Sound( const ASCString& startSoundFilename, const ASCString& continuousSoundFilename, int _fadeIn ) : name ( startSoundFilename ), fadeIn ( _fadeIn ), waitingForMainWave(false)
00384 {
00385 internalData = new Sound_InternalData;
00386
00387 if ( !SoundSystem::instance )
00388 fatalError ( "Sound::Sound failed, because there is no SoundSystem initialized");
00389
00390 pair<Sound_Sample*, Mix_Chunk*> res = loadWave( startSoundFilename );
00391 internalData->startsample = res.first;
00392 internalData->startwave = res.second;
00393
00394 res = loadWave( continuousSoundFilename );
00395 internalData->mainsample = res.first;
00396 internalData->mainwave = res.second;
00397 }
00398
00399
00400
00401
00402 int Sound::startPlaying( bool loop )
00403 {
00404 int channel;
00405
00406 int loopcontrol;
00407 if ( loop )
00408 loopcontrol = -1;
00409 else
00410 loopcontrol = 0;
00411
00412 Mix_Chunk* wave = internalData->startwave;
00413 if ( !wave )
00414 wave = internalData->mainwave;
00415 else
00416 loopcontrol = 0;
00417
00418 if ( fadeIn )
00419 channel = Mix_FadeInChannel ( -1, wave, loopcontrol, fadeIn );
00420 else {
00421 channel = Mix_PlayChannel ( -1, wave, loopcontrol );
00422 Mix_Volume ( channel, SoundSystem::instance->getEffectVolume() );
00423 }
00424 if ( internalData->startwave ) {
00425 waitingForMainWave = true;
00426 }
00427
00428 return channel;
00429 }
00430
00431 void Sound::finishedSignal( int channelnum )
00432 {
00433 if ( waitingForMainWave ) {
00434 Mix_PlayChannel ( channelnum, internalData->mainwave, -1 );
00435 Mix_Volume ( channelnum, SoundSystem::instance->getEffectVolume() );
00436 waitingForMainWave = false;
00437 }
00438 }
00439
00440 void Sound::play(void)
00441 {
00442 if( SoundSystem::instance->areEffectsMuted() || !internalData->mainwave)
00443 return;
00444
00445 int channel = startPlaying( false );
00446 SoundSystem::instance->internalData->channel[ channel ] = this;
00447 }
00448
00449 void Sound::playLoop()
00450 {
00451 if( SoundSystem::instance->areEffectsMuted() || !internalData->mainwave)
00452 return;
00453
00454 int channel = startPlaying( true );
00455 SoundSystem::instance->internalData->channel[ channel ] = this;
00456 }
00457
00458 void Sound::stop()
00459 {
00460 for ( int i = 0; i < MIX_CHANNELS; i++ )
00461 if ( SoundSystem::instance->internalData->channel[ i ] == this && Mix_Playing(i) )
00462 Mix_HaltChannel( i );
00463 }
00464
00465
00466 void Sound::playWait(void)
00467 {
00468 if( SoundSystem::instance->areEffectsMuted() || !internalData->mainwave)
00469 return;
00470
00471 if ( internalData->startwave ) {
00472 int channel = Mix_PlayChannel ( -1, internalData->startwave, 0 );
00473 SoundSystem::instance->internalData->channel[ channel ] = this;
00474 do {
00475 SDL_Delay(WAIT_SLEEP_MSEC);
00476 } while( SoundSystem::instance->internalData->channel[ channel ] == this && Mix_Playing(channel) );
00477 }
00478
00479 int channel = Mix_PlayChannel ( -1, internalData->mainwave, 0 );
00480 SoundSystem::instance->internalData->channel[ channel ] = this;
00481
00482 do {
00483 SDL_Delay(WAIT_SLEEP_MSEC);
00484 } while( SoundSystem::instance->internalData->channel[ channel ] == this && Mix_Playing(channel) );
00485 }
00486
00487 void Sound :: fadeOut ( int ms )
00488 {
00489 for ( int i = 0; i < MIX_CHANNELS; i++ )
00490 if ( SoundSystem::instance->internalData->channel[ i ] == this && Mix_Playing(i) )
00491 Mix_FadeOutChannel( i, ms );
00492 }
00493
00494
00495
00496 Sound::~Sound(void)
00497 {
00498 stop();
00499
00500 if ( internalData->mainwave )
00501 delete internalData->mainwave ;
00502
00503 if ( internalData->startwave )
00504 delete internalData->startwave;
00505
00506 if ( internalData->mainsample )
00507 Sound_FreeSample ( internalData->mainsample );
00508
00509 if ( internalData->startsample )
00510 Sound_FreeSample ( internalData->startsample );
00511
00512 delete internalData;
00513 }
00514
00515