16 #endif //tells VCC not to generate min/max macros
38 #define MAX_RECENT_HISTORY "5"
48 static char const unknown_error[16] =
"Unknown error";
49 char const *err = strerror( errorcode );
50 if (!err) err = unknown_error;
51 fprintf( stderr,
"ERROR IN PTHREAD FUNCTION %s: %s (%d)\n", str, err, errorcode );
57 #define checkerr(func) do{print_check_err(((func)),#func);}while(0)
67 , thread_initialized( false )
70 socketw = socketr = -1;
71 music_load_info = NULL;
73 music_loading =
false;
78 music_load_info =
new AUDSoundProperties;
81 #ifndef USE_SOUNDSERVER
83 musicinfo_mutex = CreateMutex( NULL,
TRUE, NULL );
85 #ifdef ERRORCHECK_MUTEX
86 pthread_mutexattr_t checkme;
87 pthread_mutexattr_init( &checkme );
88 pthread_mutexattr_settype( &checkme, PTHREAD_MUTEX_ERRORCHECK );
89 checkerr( pthread_mutex_init( &musicinfo_mutex, &checkme ) );
90 #else //ERRORCHECK_MUTEX
91 checkerr( pthread_mutex_init( &musicinfo_mutex, NULL ) );
95 checkerr( pthread_mutex_lock( &musicinfo_mutex ) );
98 if (!g_game.music_enabled)
106 const char *listvars[
MAXLIST] = {
"battleplaylist",
"peaceplaylist",
"panicplaylist",
"victoryplaylist",
"lossplaylist"};
107 const char *deflistvars[
MAXLIST] = {
"battle.m3u",
"peace.m3u",
"panic.m3u",
"victory.m3u",
"loss.m3u"};
110 #ifdef USE_SOUNDSERVER
111 #if !defined (_WIN32)
116 pid = execlp( soundserver_path.c_str(), soundserver_path.c_str(), NULL );
118 pid = execlp( soundserver_path.c_str(), soundserver_path.c_str(), NULL );
122 }
else if (pid == -1) {
127 #if defined (_WIN32) && !defined (__CYGWIN__)
130 int pid = spawnl( P_NOWAIT, ss_path.c_str(), ss_path.c_str(), NULL );
134 int pid = spawnl( P_NOWAIT, ss_path.c_str(), ss_path.c_str(), NULL );
146 socketw = socketr = -1;
150 if ( 0 == pipe( pipesw
164 sprintf( buffer1,
"%d", pipesw[0] );
165 sprintf( buffer2,
"%d", pipesr[1] );
167 #if defined (_WIN32) && !defined (__CYGWIN__)
169 int pid = spawnl( P_NOWAIT, ss_path.c_str(), ss_path.c_str(), buffer1, buffer2, NULL );
172 bool chsuccess = (chdir(
"bin" ) == 0);
173 int pid = spawnl( P_NOWAIT, ss_path.c_str(), ss_path.c_str(), buffer1, buffer2, NULL );
174 if (chsuccess) chdir(
".." );
183 FILE *fp =
fopen( tmp.c_str(),
"rb" );
186 fp =
fopen( tmp.c_str(),
"rb" );
196 pid = execlp( soundserver_path.c_str(), soundserver_path.c_str(), buffer1, buffer2, NULL );
198 pid = execlp( soundserver_path.c_str(), soundserver_path.c_str(), buffer1, buffer2, NULL );
201 close( atoi( buffer1 ) );
202 close( atoi( buffer2 ) );
204 }
else if (pid == -1) {
213 for (i = 0; (i < 10) && (socket == -1); i++)
215 socketw = socketr =
socket;
217 if (socketw == -1 || socketr == -1) {
223 fNET_Write( socketw, data.size(), data.c_str() );
225 INET_Write( socketw, data.size(), data.c_str() );
231 _SetVolume( 1,
true );
243 muzak[
i]._SetVolume( muzak[
i].soft_vol+inc,
false, 0.1 );
244 else if ( (layer >= 0) && (layer < muzak_count) )
245 muzak[layer]._SetVolume( muzak[layer].soft_vol+inc,
false, 0.1 );
249 #ifdef USE_SOUNDSERVER
250 static float tmpmin(
float a,
float b )
252 return a < b ? a :
b;
254 static float tmpmax(
float a,
float b )
256 return a < b ? b :
a;
260 void Music::_SetVolume(
float vol,
bool hardware,
float latency_override )
264 #ifdef USE_SOUNDSERVER
265 vol =
tmpmax( 0.0f, tmpmin( (hardware ? 1.0f : 2.0f), vol ) );
267 if ( ( hardware && (this->vol == vol) )
268 || ( !hardware && (this->soft_vol == vol) ) )
271 sprintf( tempbuf,
"vh%f\n", vol );
274 sprintf( tempbuf,
"vs%f\n%f\n", vol,
276 < 0) ? ( (vol > soft_vol) ? soft_vol_up_latency : soft_vol_down_latency ) : latency_override ) );
281 this->soft_vol = vol;
283 fNET_Write( socketw, strlen( tempbuf ), tempbuf );
286 INET_Write( socketw, strlen( tempbuf ), tempbuf );
288 if (vol < 0) vol = 0;
290 this->soft_vol = vol;
291 for (std::list< int >::const_iterator iter = playingSource.begin(); iter != playingSource.end(); iter++)
296 bool Music::LoadMusic(
const char *
file )
298 using namespace VSFileSystem;
307 this->playlist.push_back( PlayList() );
311 f.ReadLine( songname, 1022 );
312 int size = strlen( songname );
314 if (songname[size-1] ==
'\n')
315 songname[size-1] =
'\0';
317 if (songname[size-2] ==
'\r' || songname[size-2] ==
'\n')
318 songname[size-2] =
'\0';
319 if (songname[0] ==
'\0')
321 if (songname[0] ==
'#') {
322 if (strncmp( songname,
"#pragma ", 8 ) == 0) {
323 char *sep = strchr( songname+8,
' ' );
326 this->playlist.back().pragmas[songname+8] = sep+1;
327 }
else if (songname[8]) {
328 this->playlist.back().pragmas[songname+8] =
"1";
333 this->playlist.back().songs.push_back( std::string( songname ) );
344 int ans =
int( ( ( (
double) rand() )/( (
double) RAND_MAX ) )*max );
350 int Music::SelectTracks(
int layer )
355 static size_t maxrecent =
361 if ( !playlist[lastlist].empty() && !playlist[lastlist].haspragma(
"norepeat" ) ) {
362 int whichsong = (random ? rand() : playlist[lastlist].counter++)%playlist[lastlist].size();
364 std::list< std::string > &recent = muzak[(layer >= 0) ? layer : 0].recent_songs;
365 while ( random && (--spincount > 0)
366 && ( std::find( recent.begin(), recent.end(), playlist[lastlist][whichsong] ) != recent.end() ) )
367 whichsong = (random ? rand() : playlist[lastlist].counter++)%playlist[lastlist].size();
370 recent.push_back( playlist[lastlist][whichsong] );
371 while (recent.size() > maxrecent)
373 GotoSong( lastlist, whichsong,
true, layer );
380 static std::string loading_tune =
vs_config->
getVariable(
"audio",
"loading_sound",
"../music/loading.ogg" );
388 #ifndef USE_SOUNDSERVER
407 #ifdef USE_SOUNDSERVER
408 int socketr = me->socketr;
409 while (!me->killthread) {
410 printf(
"Reading from socket %d\n", socketr );
412 printf(
"Got data from socket %c\n", data );
418 while (!me->killthread) {
420 WaitForSingleObject( me->musicinfo_mutex, INFINITE );
422 checkerr( pthread_mutex_lock( &me->musicinfo_mutex ) );
424 if (me->killthread)
break;
425 me->music_loading =
true;
426 me->music_loaded =
false;
427 me->music_load_info->success =
false;
428 size_t len = me->music_load_info->hashname.length();
429 char *songname = (
char*) malloc( len+1 );
430 songname[len] =
'\0';
431 memcpy( songname, me->music_load_info->hashname.data(), len );
432 std::map< std::string, AUDSoundProperties >::iterator wherecache =
cachedSongs.find( songname );
434 static std::string cachable_songs =
vs_config->
getVariable(
"audio",
"cache_songs",
"../music/land.ogg" );
435 bool docacheme = cachable_songs.find( songname ) != std::string::npos;
436 if (foundcache ==
false && docacheme) {
437 me->music_load_info->wave = NULL;
442 ReleaseMutex( me->musicinfo_mutex );
444 checkerr( pthread_mutex_unlock( &me->musicinfo_mutex ) );
449 *me->music_load_info = wherecache->second;
456 if (me->freeWav && docacheme) {
458 wherecache->second = *me->music_load_info;
461 me->music_loaded =
true;
462 while (me->music_loaded)
471 void Music::_LoadLastSongAsync()
473 #ifndef USE_SOUNDSERVER
477 if (!music_load_info)
return;
481 std::string song = music_load_list.back();
483 std::map< std::string, AUDSoundProperties >::iterator where =
Muzak::cachedSongs.find( song );
485 if (where->second.wave != NULL) {
489 music_load_info->wave = NULL;
491 playingSource.push_back( source );
492 if (playingSource.size() == 1) {
500 music_load_info->hashname = song;
502 music_loading =
true;
504 ReleaseMutex( musicinfo_mutex );
506 checkerr( pthread_mutex_unlock( &musicinfo_mutex ) );
514 #ifdef USE_SOUNDSERVER
518 if (!thread_initialized) {
520 a_thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)
Muzak::readerThread, (PVOID)
this, 0, NULL );
522 int res = pthread_create( &a_thread, NULL, Muzak::readerThread, (
void*)
this );
524 thread_initialized = 1;
549 if ( !music_load_list.empty() ) {
554 if (WaitForSingleObject( musicinfo_mutex, 0 ) == WAIT_TIMEOUT) {
556 int trylock_ret = pthread_mutex_trylock( &musicinfo_mutex );
557 if (trylock_ret == EBUSY) {
559 fprintf( stderr,
"Failed to lock music loading mutex despite loaded flag being set...\n" );
564 music_loading =
false;
565 music_loaded =
false;
569 if (music_load_info->success && music_load_info->wave) {
572 free( music_load_info->wave );
573 music_load_info->wave = NULL;
575 playingSource.push_back( source );
578 if (playingSource.size() == 1) {
585 music_load_list.pop_back();
586 if ( !music_load_list.empty() )
587 _LoadLastSongAsync();
591 if ( !playingSource.empty() )
594 playingSource.pop_front();
595 if ( !playingSource.empty() ) {
602 && music_load_list.empty() && muzak[
muzak_cross_index].music_load_list.empty() ) {
621 }
else if ( (layer >= 0) && (layer <
muzak_count) ) {
622 if (mus == muzak[layer].cur_song_file)
return;
623 muzak[layer]._GotoSong( mus );
626 muzak->_GotoSong( mus );
630 std::vector< std::string >
rsplit( std::string tmpstr, std::string splitter )
632 std::string::size_type where;
633 std::vector< std::string >ret;
634 while ( ( where = tmpstr.rfind( splitter ) ) != std::string::npos ) {
635 ret.push_back( tmpstr.substr( where+1 ) );
636 tmpstr = tmpstr.substr( 0, where );
638 if ( tmpstr.length() )
639 ret.push_back( tmpstr );
643 void Music::_GotoSong( std::string mus )
646 if (mus == cur_song_file || mus.length() == 0)
return;
649 #ifndef USE_SOUNDSERVER
652 music_load_list =
rsplit( mus,
"|" );
653 if (!thread_initialized) {
655 a_thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)
Muzak::readerThread, (PVOID)
this, 0, NULL );
657 thread_initialized =
true;
659 fprintf( stderr,
"Error creating music load thread: %d\n", GetLastError() );
661 int thread_create_ret = pthread_create( &a_thread, NULL, Muzak::readerThread,
this );
662 if (thread_create_ret == 0)
663 thread_initialized =
true;
668 _LoadLastSongAsync();
670 string data = string(
"p" )+mus+string(
"\n" );
672 fNET_Write( socketw, data.size(), data.c_str() );
674 INET_Write( socketw, data.size(), data.c_str() );
682 if ( whichsong !=
NOLIST && whichlist !=
NOLIST && whichlist < (
int) playlist.size() && whichsong
683 < (
int) playlist[whichlist].
size() ) {
684 if (muzak[(layer >= 0) ? layer : 0].lastlist != whichlist) {
689 std::list< std::string > &recent = muzak[(layer >= 0) ? layer : 0].recent_songs;
694 muzak[0].lastlist = muzak[1].lastlist = whichlist;
697 lastlist = whichlist;
698 GotoSong( playlist[whichlist][whichsong], layer );
700 _SkipRandList( layer );
713 muzak->_SkipRandSong( whichlist );
714 }
else if ( (layer >= 0) && (layer <
muzak_count) ) {
715 muzak[layer]._SkipRandSong( whichlist, layer );
720 void Music::_SkipRandSong(
int whichlist,
int layer )
725 if ( whichlist !=
NOLIST && whichlist >= 0 && whichlist < (
int) playlist.size() ) {
726 lastlist = whichlist;
728 if ( playlist[whichlist].
size() )
729 GotoSong( whichlist, random ?
randInt( playlist[whichlist].
size() ) : playlist[whichlist].counter++
730 %playlist[whichlist].size(),
true, layer );
732 fprintf( stderr,
"Error no songs in playlist %d\n", whichlist );
736 _SkipRandList( layer );
749 muzak->_SkipRandList();
750 }
else if ( (layer >= 0) && (layer <
muzak_count) ) {
751 muzak[layer]._SkipRandList( layer );
756 void Music::_SkipRandList(
int layer )
760 for (
unsigned int i = 0;
i < playlist.size();
i++) {
762 if ( !playlist[i].empty() )
763 GotoSong( i, random ?
randInt( playlist[i].
size() ) : playlist[
i].counter++%playlist[
i].size(),
false, layer );
772 if (muzak) res = muzak->_Addlist( listfile );
775 muzak[
i]._Addlist( listfile );
779 int Music::_Addlist( std::string listfile )
783 bool retval = LoadMusic( listfile.c_str() );
785 return playlist.size()-1;
801 }
else if ( (layer >= 0) && (layer <
muzak_count) ) {
802 muzak[layer]._Skip( layer );
807 void Music::_Skip(
int layer )
810 SelectTracks( layer );
815 #ifdef USE_SOUNDSERVER
816 char send[2] = {
't',
'\n'};
819 if (threadalive && thread_initialized) {
822 while ( threadalive && (spindown-- > 0) )
837 if (threadalive && thread_initialized) {
840 ReleaseMutex( musicinfo_mutex );
842 checkerr( pthread_mutex_unlock( &musicinfo_mutex ) );
845 while ( threadalive && (spindown-- > 0) )
876 #ifdef USE_SOUNDSERVER
910 }
else if ( (layer >= 0) && (layer <
muzak_count) ) {
911 muzak[layer]._Stop();
915 void Music::_StopNow()
918 #ifdef USE_SOUNDSERVER
930 void Music::_StopLater()
933 #ifdef USE_SOUNDSERVER
936 for (std::list< int >::const_iterator iter = playingSource.begin(); iter != playingSource.end(); iter++) {
940 playingSource.clear();
948 #ifdef USE_SOUNDSERVER
950 char send[1] = {
's'};
956 for (std::list< int >::const_iterator iter = playingSource.begin(); iter != playingSource.end(); iter++) {
961 playingSource.clear();
971 muzak[
i]._SetVolume( vol, hardware, latency_override );
972 else if ( (layer >= 0) && (layer < muzak_count) )
973 muzak[layer]._SetVolume( vol, hardware, latency_override );
979 static vector< float >saved_vol;
989 if (muzak[
i].soft_vol != 0) {
990 saved_vol[
i] = muzak[
i].soft_vol;
991 muzak[
i]._SetVolume( 0,
false, muting_fadeout );
993 }
else if (saved_vol[
i] >= 0) {
994 muzak[
i]._SetVolume( saved_vol[
i],
false, muting_fadein );
997 }
else if ( (layer >= 0) && (layer <
muzak_count) ) {
999 if (muzak[layer].soft_vol != 0) {
1000 saved_vol[layer] = muzak[layer].soft_vol;
1001 muzak[layer]._SetVolume( 0,
false, muting_fadeout );
1003 }
else if (saved_vol[layer] >= 0) {
1004 muzak[layer]._SetVolume( saved_vol[layer],
false, muting_fadein );
1019 }
else if ( (layer >= 0) && (layer <
muzak_count) ) {