00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "aa_config.h"
00031
00032
00033 #include "rSDL.h"
00034 #include "rScreen.h"
00035 #include "defs.h"
00036
00037 #include "tString.h"
00038 #include "tLinkedList.h"
00039 #include "tDirectories.h"
00040 #include "tConfiguration.h"
00041 #include "tConsole.h"
00042 #include "tError.h"
00043 #include "eGameObject.h"
00044 #include "eCoord.h"
00045
00046 #include "eSoundMixer.h"
00047 #include "sdl_mixer/eMusicTrackSDLMixer.h"
00048 #include "sdl_mixer/eChannelSDLMixer.h"
00049
00050
00051 #include <math.h>
00052
00053
00054 #define SOUND_OFF 0
00055 #define SOUND_LOW 1
00056 #define SOUND_MED 2
00057 #define SOUND_HIGH 3
00058
00059
00060 #define PLAYLIST_INTERNAL 0
00061 #define PLAYLIST_CUSTOM 1
00062
00063 #ifdef WIN32
00064
00065 #else
00066
00067 #endif
00068
00069
00070
00071
00072 char const * MusicModeString[] = {
00073 "Title track",
00074 "GUI track",
00075 "In-game track"
00076 };
00077
00078
00079
00080
00081 char const * SoundEffectString[] = {
00082 "Cycle turn",
00083 "Cycle explosion",
00084 "Announcer says 1",
00085 "Announcer says 2",
00086 "Announcer says 3",
00087 "Announcer says GO",
00088 "New Match effect",
00089 "New Round effect",
00090 "Round Winner effect",
00091 "Match Winner effect",
00092 "Zone Spawn effect",
00093 "Cycle motor effect",
00094 "Cycle grinding a wall effect"
00095 };
00096
00097 bool eSoundMixer::m_musicIsPlaying = false;
00098
00099 int sound_quality=SOUND_MED;
00100 static tConfItem<int> sq("SOUND_QUALITY",sound_quality);
00101
00102 int musicVolume=64;
00103 static tConfItem<int> sw("MUSIC_VOLUME",musicVolume);
00104
00105 int numSoundcardChannels=2;
00106 static tConfItem<int> scc("SOUND_CHANNELS",numSoundcardChannels);
00107
00108 int musicActive = 1;
00109 static tConfItem<int> se("MUSIC_ACTIVE", musicActive);
00110
00111 float buffersize = 4.0;
00112 static tConfItem<float> sbs("SOUND_BUFFER_SIZE", buffersize);
00113
00114 tString titleTrack("music/titletrack.ogg");
00115 static tConfItemLine stt("TITLE_TRACK", titleTrack);
00116
00117 tString guiTrack("music/when.ogg");
00118 static tConfItemLine ste("GUI_TRACK", guiTrack);
00119
00120 tString playListFile("music/default.m3u");
00121 static tConfItemLine stp("MUSIC_PLAYLIST", playListFile);
00122
00123 static tString customPlaylist("");
00124 static tConfItemLine cpl("CUSTOM_MUSIC_PLAYLIST", customPlaylist);
00125
00126 static int usePlaylist = 0;
00127 static tConfItem<int> upl("USE_CUSTOM_PLAYLIST", usePlaylist);
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 int eSoundMixer::m_Mode = 0;
00142 bool eSoundMixer::m_isDirty = true;
00143 eMusicTrack* eSoundMixer::m_TitleTrack = 0;
00144 eMusicTrack* eSoundMixer::m_GuiTrack = 0;
00145 eMusicTrack* eSoundMixer::m_GameTrack = 0;
00146
00147 eSoundMixer::eSoundMixer()
00148 {
00149 #ifdef HAVE_LIBSDL_MIXER
00150 m_Owner = NULL;
00151 m_Playlist = NULL;
00152
00153 if(musicActive == 1) {
00154 m_PlayMusic = true;
00155 } else {
00156 m_PlayMusic = false;
00157 }
00158 #endif // DEDICATED
00159 }
00160
00161 void eSoundMixer::SetMicrophoneOwner(eGameObject* newOwner) {
00162 #ifdef HAVE_LIBSDL_MIXER
00163
00164 m_Owner = newOwner;
00165 #endif // DEDICATED
00166 }
00167
00168 void eSoundMixer::__channelFinished(int channel) {
00169 #ifdef HAVE_LIBSDL_MIXER
00170 m_Channels[channel].UnplaySound();
00171 #endif // DEDICATED
00172 }
00173
00174 void eSoundMixer::ChannelFinished(int channel) {
00175 #ifdef HAVE_LIBSDL_MIXER
00176 _instance->__channelFinished(channel);
00177 #endif // DEDICATED
00178 }
00179
00180 int eSoundMixer::FirstAvailableChannel() {
00181 #ifdef HAVE_LIBSDL_MIXER
00182 Uint32 oldesttime=0;
00183 int oldestchannel=-1;
00184
00185 for( int i=0; i < m_numChannels; i++) {
00186 if( !m_Channels[i].isBusy() ) return i;
00187 else {
00188 if( m_Channels[i].StartTime() < oldesttime && !m_Channels[i].IsContinuous() ) {
00189 oldesttime = m_Channels[i].StartTime();
00190 oldestchannel = i;
00191 }
00192 }
00193 }
00194
00195
00196 return oldestchannel;
00197
00198 tASSERT( 0 );
00199 #endif // DEDICATED
00200 return -1;
00201 }
00202
00203
00204 #ifdef HAVE_LIBSDL_MIXER
00205 static int se_Wrap_SDL_InitSubSystem()
00206 {
00207 #ifndef DEDICATED
00208 #ifdef DEFAULT_SDL_AUDIODRIVER
00209
00210
00211 #define XSTRING(s) #s
00212 #define STRING(s) XSTRING(s)
00213
00214
00215 if ( ! getenv("SDL_AUDIODRIVER") ) {
00216 char * arg = "SDL_AUDIODRIVER=" STRING(DEFAULT_SDL_AUDIODRIVER);
00217 putenv(arg);
00218
00219 int ret = SDL_InitSubSystem(SDL_INIT_AUDIO);
00220 if ( ret >= 0 )
00221 return ret;
00222
00223 putenv("SDL_AUDIODRIVER=");
00224 }
00225 #endif
00226 #endif
00227
00228
00229 return SDL_InitSubSystem(SDL_INIT_AUDIO);
00230 }
00231 #endif
00232
00233 void eSoundMixer::Init() {
00234 #ifdef HAVE_LIBSDL_MIXER
00235 bool initbase = false;
00236
00237 m_active = false;
00238
00239 const tPath& vpath = tDirectories::Data();
00240
00241
00242 m_musicIsPlaying = false;
00243
00244 tString musFile;
00245
00246 musFile = vpath.GetReadPath( titleTrack );
00247 std::cout << titleTrack << "\n";
00248 m_TitleTrack = new eMusicTrack(musFile, true);
00249 musFile = vpath.GetReadPath( guiTrack );
00250 std::cout << guiTrack << "\n";
00251 m_GuiTrack = new eMusicTrack(musFile, true);
00252
00253
00254
00255
00256
00257 m_GameTrack = new eMusicTrack();
00258
00259 LoadPlaylist();
00260
00261 int frequency;
00262
00263 switch (sound_quality)
00264 {
00265 case SOUND_LOW:
00266 frequency=11025; break;
00267 case SOUND_MED:
00268 frequency=22050; break;
00269 case SOUND_HIGH:
00270 frequency=44100; break;
00271 case SOUND_OFF:
00272 return; break;
00273 default:
00274 frequency=22050;
00275 }
00276
00277 if(!SDL_WasInit( SDL_INIT_AUDIO )) {
00278 int rc;
00279 rc = se_Wrap_SDL_InitSubSystem();
00280 if ( rc < 0 ) {
00281
00282 initbase = false;
00283
00284 } else {
00285 initbase = true;
00286 }
00287 } else {
00288 initbase = true;
00289 }
00290
00291 if( !initbase ) {
00292 return;
00293 }
00294
00295 int rc;
00296
00297
00298 int samples = static_cast< int >( buffersize * 512 );
00299
00300 rc = Mix_OpenAudio( frequency, AUDIO_S16LSB,
00301 numSoundcardChannels, samples );
00302
00303 if(rc==0) {
00304
00305 int a,c;
00306 Uint16 b;
00307 Mix_QuerySpec(&a,&b,&c);
00308
00309 } else {
00310
00311 return;
00312 }
00313
00314
00315 Mix_VolumeMusic( musicVolume );
00316 Mix_HookMusicFinished( &eSoundMixer::SDLMusicFinished );
00317
00318
00319
00320
00321
00322 m_SoundEffects.resize(15);
00323 m_SoundEffects[CYCLE_TURN].LoadWavFile(vpath.GetReadPath("sound/cycle_turn.ogg") );
00324 m_SoundEffects[CYCLE_TURN].SetVolume(60);
00325 m_SoundEffects[CYCLE_EXPLOSION].LoadWavFile(vpath.GetReadPath( "sound/expl.ogg" ));
00326 m_SoundEffects[ANNOUNCER_1].LoadWavFile(vpath.GetReadPath("sound/1voicemale.ogg") );
00327 m_SoundEffects[ANNOUNCER_2].LoadWavFile(vpath.GetReadPath("sound/2voicemale.ogg") );
00328 m_SoundEffects[ANNOUNCER_3].LoadWavFile(vpath.GetReadPath("sound/3voicemale.ogg") );
00329 m_SoundEffects[ANNOUNCER_GO].LoadWavFile(vpath.GetReadPath("sound/announcerGO.ogg"));
00330
00331
00332
00333
00334 m_SoundEffects[ZONE_SPAWN].LoadWavFile(vpath.GetReadPath("sound/zone_spawn.ogg") );
00335 m_SoundEffects[CYCLE_MOTOR].LoadWavFile(vpath.GetReadPath("sound/cyclrun.ogg") );
00336 m_SoundEffects[CYCLE_GRIND_WALL].LoadWavFile(vpath.GetReadPath("sound/grind.ogg") );
00337
00338 Mix_Volume(-1, 50);
00339 Mix_VolumeMusic(100);
00340
00341 m_numChannels = Mix_AllocateChannels(40);
00342 m_Channels.resize( m_numChannels );
00343 for(int i=0; i < m_numChannels; i++) {
00344 m_Channels[i].SetId(i);
00345 }
00346 Mix_ChannelFinished( &eSoundMixer::ChannelFinished );
00347
00348
00349 m_active = true;
00350 #endif
00351 }
00352
00353 eSoundMixer::~eSoundMixer() {
00354
00355 }
00356
00357 void eSoundMixer::LoadPlaylist() {
00358 #ifdef HAVE_LIBSDL_MIXER
00359 if(!m_GameTrack) return;
00360
00361 if(usePlaylist == 1) {
00362 m_GameTrack->SetPlaylist(usePlaylist);
00363 m_GameTrack->LoadPlaylist(customPlaylist);
00364 } else {
00365 const tPath& vpath = tDirectories::Data();
00366 m_GameTrack->SetPlaylist(usePlaylist);
00367 m_GameTrack->LoadPlaylist(vpath.GetReadPath(playListFile) );
00368 }
00369 #endif
00370 }
00371
00372
00373
00374 void eSoundMixer::SetMode(MusicMode newMode) {
00375 #ifdef HAVE_LIBSDL_MIXER
00376 m_Mode = newMode;
00377 m_isDirty = true;
00378 #endif // DEDICATED
00379 }
00380
00381 void eSoundMixer::SongFinished() {
00382 #ifdef HAVE_LIBSDL_MIXER
00383
00384 m_musicIsPlaying = false;
00385
00386 switch(m_Mode) {
00387 case TITLE_TRACK:
00388
00389 SetMode(GUI_TRACK);
00390 break;
00391 case GUI_TRACK:
00392 m_isDirty = true;
00393 break;
00394 case GRID_TRACK:
00395 m_isDirty = true;
00396 break;
00397 default:
00398 break;
00399 }
00400 #endif // DEDICATED
00401
00402 }
00403
00404 void eSoundMixer::SDLMusicFinished() {
00405 #ifdef HAVE_LIBSDL_MIXER
00406
00407 m_TitleTrack->currentMusic->MusicFinished();
00408 #endif
00409 }
00410
00411 void eSoundMixer::PushButton( int soundEffect ) {
00412 #ifdef HAVE_LIBSDL_MIXER
00413 if (!m_active) return;
00414
00415 int theChannel = FirstAvailableChannel();
00416 if( theChannel < 0) return;
00417 m_Channels[ theChannel ].PlaySound(m_SoundEffects[soundEffect]);
00418 #endif // DEDICATED
00419 }
00420
00421 void eSoundMixer::PushButton( int soundEffect, eCoord location ) {
00422 #ifdef HAVE_LIBSDL_MIXER
00423 if (!m_active) return;
00424
00425
00426 if(!m_Owner) return;
00427
00428 int theChannel = FirstAvailableChannel();
00429
00430 if( theChannel < 0) return;
00431 m_Channels[theChannel].Set3d(m_Owner->Position(), location, m_Owner->Direction());
00432 m_Channels[theChannel].PlaySound(m_SoundEffects[soundEffect]);
00433 #endif // DEDICATED
00434 }
00435
00436 void eSoundMixer::PlayContinuous(int soundEffect, eGameObject* owner) {
00437 #ifdef HAVE_LIBSDL_MIXER
00438 std::cout << "Playcontinuous: " << SoundEffectString[soundEffect] << "\n";
00439 if (!m_active) return;
00440 return;
00441
00442 int theChannel = FirstAvailableChannel();
00443 if( theChannel < 0 || m_Channels[theChannel].isBusy()) {
00444 std::cout << "Can't loop, sorry.\n";
00445 return;
00446 }
00447
00448 m_Channels[theChannel].SetOwner(owner);
00449
00450 if(!m_Owner) m_Channels[theChannel].DelayStarting();
00451 m_Channels[theChannel].SetHome(m_Owner);
00452 m_Channels[theChannel].LoopSound(m_SoundEffects[soundEffect]);
00453 #endif
00454 }
00455
00456 void eSoundMixer::RemoveContinuous(int soundEffect, eGameObject* owner) {
00457 #ifdef HAVE_LIBSDL_MIXER
00458 for(std::deque<eChannel>::iterator i = m_Channels.begin(); i != m_Channels.end(); ++i) {
00459 if ((*i).GetOwner() == owner) {
00460 (*i).StopSound();
00461 std::cout << "removed continuous sound\n";
00462 }
00463 }
00464 #endif
00465 }
00466
00467 void eSoundMixer::Update() {
00468 #ifdef HAVE_LIBSDL_MIXER
00469 if (!m_active) return;
00470
00471
00472
00473 for(int i=0; i<eChannel::numChannels; i++) {
00474 if( m_Channels[i].IsDelayed() ) {
00475 if( m_Owner ) {
00476 m_Channels[i].SetHome(m_Owner);
00477 m_Channels[i].Undelay();
00478 }
00479 }
00480 m_Channels[i].Update();
00481 }
00482
00483
00484 if (m_isDirty) {
00485
00486 if(!m_musicIsPlaying) {
00487
00488 switch(m_Mode) {
00489 case TITLE_TRACK:
00490 m_TitleTrack->Play();
00491 m_Mode = TITLE_TRACK;
00492 m_isDirty = false;
00493 break;
00494 case GUI_TRACK:
00495 m_GuiTrack->Play();
00496 m_isDirty = false;
00497 break;
00498 case GRID_TRACK:
00499 if(m_GuiTrack->IsPlaying()) {
00500 m_GuiTrack->FadeOut();
00501 m_GameTrack->SetDirty();
00502 m_GameTrack->Update();
00503 } else if(m_TitleTrack->IsPlaying()) {
00504 m_TitleTrack->FadeOut();
00505 m_GameTrack->SetDirty();
00506 m_GameTrack->Update();
00507 } else {
00508 m_GameTrack->Next();
00509 m_GameTrack->Play();
00510 }
00511 m_isDirty = false;
00512 break;
00513 default:
00514 break;
00515 }
00516 }
00517 }
00518
00519 if ( m_GuiTrack && m_GuiTrack->currentMusic )
00520 m_GuiTrack->currentMusic->Update();
00521 #endif // DEDICATED
00522 }
00523
00524 tString eSoundMixer::GetCurrentSong() {
00525 if(m_GameTrack != NULL)
00526 if(m_GameTrack->currentMusic != NULL) {
00527 tString const &str = m_GameTrack->currentMusic->GetFileName();
00528 #ifndef WIN32
00529 size_t pos = str.find_last_of('/');
00530 #else
00531 size_t pos = str.find_last_of('\\');
00532 #endif
00533 if(pos == tString::npos) return str;
00534 if(pos == str.size()) return tString();
00535 return str.SubStr(pos + 1);
00536 }
00537 return tString(" ");
00538 }
00539
00540 eSoundMixer* eSoundMixer::_instance = 0;
00541
00542 void eSoundMixer::ShutDown() {
00543 #ifdef HAVE_LIBSDL_MIXER
00544 if ( _instance )
00545 _instance->SetMicrophoneOwner( NULL );
00546
00547 if ( _instance && _instance->m_active )
00548 {
00549 Mix_CloseAudio();
00550 SDL_QuitSubSystem( SDL_INIT_AUDIO );
00551 }
00552
00553 delete _instance;
00554 delete m_TitleTrack;
00555 delete m_GuiTrack;
00556 if(m_GameTrack) delete m_GameTrack;
00557
00558
00559 #endif // DEDICATED
00560 }
00561
00562 eSoundMixer* eSoundMixer::GetMixer() {
00563 #ifdef HAVE_LIBSDL_MIXER
00564 if(_instance == 0) {
00565 _instance = new eSoundMixer();
00566 _instance->Init();
00567 }
00568
00569 #endif // DEDICATED
00570 return _instance;
00571 }
00572
00573 #ifdef HAVE_LIBSDL_MIXER
00574
00575 static void updateMixer() {
00576 eSoundMixer* mixer = eSoundMixer::GetMixer();
00577 mixer->Update();
00578 }
00579
00580 static rPerFrameTask mixupdate(&updateMixer);
00581
00582
00583
00584
00585 #include "uMenu.h"
00586
00587 uMenu Sound_menu("$sound_menu_text");
00588
00589 static uMenuItemInt sources_men
00590 (&Sound_menu,"$sound_channels",
00591 "$sound_channels_help",
00592 numSoundcardChannels,2,6,2);
00593
00594 static uMenuItemSelection<int> sq_men
00595 (&Sound_menu,"$sound_menu_quality_text",
00596 "$sound_menu_quality_help",
00597 sound_quality);
00598
00599 static uSelectEntry<int> a(sq_men,
00600 "$sound_menu_quality_off_text",
00601 "$sound_menu_quality_off_help",
00602 SOUND_OFF);
00603
00604 static uSelectEntry<int> b(sq_men,
00605 "$sound_menu_quality_low_text",
00606 "$sound_menu_quality_low_help",
00607 SOUND_LOW);
00608
00609 static uSelectEntry<int> c(sq_men,
00610 "$sound_menu_quality_medium_text",
00611 "$sound_menu_quality_medium_help",
00612 SOUND_MED);
00613 static uSelectEntry<int> d(sq_men,
00614 "$sound_menu_quality_high_text",
00615 "$sound_menu_quality_high_help",
00616 SOUND_HIGH);
00617
00618 static uMenuItemSelection<int> bm_men
00619 (&Sound_menu,
00620 "$sound_playlist_text",
00621 "$sound_playlist_help",
00622 usePlaylist);
00623
00624 static uSelectEntry<int> ba(bm_men,
00625 "$sound_playlistinternal_text",
00626 "$sound_playlistinternal_help",
00627 0);
00628
00629 static uSelectEntry<int> bb(bm_men,
00630 "$sound_playlistcustom_text",
00631 "$sound_playlistcustom_help",
00632 1);
00633
00634 static uMenuItemString bc(&Sound_menu, "$sound_customplaylist_text",
00635 "$sound_customplaylist_help",
00636 customPlaylist, 255);
00637
00638 void se_SoundMenu(){
00639 int oldUsePlaylist = usePlaylist;
00640 tString oldCustomPlaylist = customPlaylist;
00641 eSoundMixer* mixer = eSoundMixer::GetMixer();
00642
00643 Sound_menu.Enter();
00644 if( oldUsePlaylist != usePlaylist || oldCustomPlaylist != customPlaylist) mixer->LoadPlaylist();
00645 }
00646
00647
00648 #include "uInput.h"
00649
00650 static uActionGlobal mediaPlay("MUSIC_PLAY");
00651 static uActionGlobal mediaNext("MUSIC_NEXT");
00652 static uActionGlobal mediaPrev("MUSIC_PREVIOUS");
00653 static uActionGlobal mediaStop("MUSIC_STOP");
00654 static uActionGlobal mediaPause("MUSIC_PAUSE");
00655 static uActionGlobal mediaVolumeUp("MUSIC_VOLUME_UP");
00656 static uActionGlobal mediaVolumeDown("MUSIC_VOLUME_DOWN");
00657
00658 bool eSoundMixer::Music_play(REAL x=1){
00659 if (x>0){
00660 switch(m_Mode) {
00661 case GRID_TRACK:
00662 m_GameTrack->Play();
00663 break;
00664 default:
00665 break;
00666 }
00667 }
00668
00669 return true;
00670 }
00671
00672 bool eSoundMixer::Music_stop(REAL x=1){
00673 if (x>0){
00674 switch(m_Mode) {
00675 case GRID_TRACK:
00676 m_GameTrack->Stop();
00677 break;
00678 default:
00679 break;
00680 }
00681 }
00682
00683 return true;
00684 }
00685
00686 bool eSoundMixer::Music_pause(REAL x=1){
00687 if (x>0){
00688 switch(m_Mode) {
00689 case GUI_TRACK:
00690 m_GuiTrack->Pause();
00691 break;
00692 case GRID_TRACK:
00693 m_GameTrack->Pause();
00694 break;
00695 default:
00696 break;
00697 }
00698 }
00699
00700 return true;
00701 }
00702
00703 bool eSoundMixer::Music_volume_up(REAL x=1){
00704 if (x>0){
00705 switch(m_Mode) {
00706 case TITLE_TRACK:
00707 m_TitleTrack->VolumeUp();
00708 break;
00709 case GUI_TRACK:
00710 m_GuiTrack->VolumeUp();
00711 break;
00712 case GRID_TRACK:
00713 m_GameTrack->VolumeUp();
00714 break;
00715 default:
00716 break;
00717 }
00718 }
00719
00720 return true;
00721 }
00722
00723 bool eSoundMixer::Music_volume_down(REAL x=1){
00724 if (x>0){
00725 switch(m_Mode) {
00726 case TITLE_TRACK:
00727 m_TitleTrack->VolumeDown();
00728 break;
00729 case GUI_TRACK:
00730 m_GuiTrack->VolumeDown();
00731 break;
00732 case GRID_TRACK:
00733 m_GameTrack->VolumeDown();
00734 break;
00735 default:
00736 break;
00737 }
00738 }
00739
00740 return true;
00741 }
00742
00743 bool eSoundMixer::Music_next_song(REAL x=1) {
00744 if (x>0){
00745 switch(m_Mode) {
00746 case GRID_TRACK:
00747 m_GameTrack->Next();
00748 break;
00749 default:
00750 break;
00751 }
00752 }
00753
00754 return true;
00755 }
00756
00757 bool eSoundMixer::Music_previous_song(REAL x=1) {
00758 if (x>0){
00759 switch(m_Mode) {
00760 case GRID_TRACK:
00761 m_GameTrack->Previous();
00762 break;
00763 default:
00764 break;
00765 }
00766 }
00767
00768 return true;
00769 }
00770
00771 static uActionGlobalFunc mediapl(&mediaPlay,&eSoundMixer::Music_play, true );
00772 static uActionGlobalFunc medianext(&mediaNext,&eSoundMixer::Music_next_song, true );
00773 static uActionGlobalFunc mediaprev(&mediaPrev,&eSoundMixer::Music_previous_song, true );
00774 static uActionGlobalFunc mediast(&mediaStop,&eSoundMixer::Music_stop, true );
00775 static uActionGlobalFunc mediapa(&mediaPause,&eSoundMixer::Music_pause, true );
00776 static uActionGlobalFunc mediavu(&mediaVolumeUp,&eSoundMixer::Music_volume_up, true );
00777 static uActionGlobalFunc mediavd(&mediaVolumeDown,&eSoundMixer::Music_volume_down, true );
00778 #else
00779
00780 void se_SoundMenu(){
00781
00782 }
00783
00784
00785 #endif // DEDICATED
00786
00787