2011-12-14 00:23:17 +03:00
# include "StdInc.h"
2009-04-30 13:53:06 +03:00
# include <boost/bimap.hpp>
2009-04-22 21:48:56 +03:00
# include <SDL_mixer.h>
# include "CSndHandler.h"
2007-06-20 15:00:18 +03:00
# include "CMusicHandler.h"
2010-12-20 23:22:53 +02:00
# include "../lib/CCreatureHandler.h"
# include "../lib/CSpellHandler.h"
2009-05-21 03:55:30 +03:00
# include "../client/CGameInfo.h"
2011-08-20 04:15:37 +03:00
# include "../lib/JsonNode.h"
2011-12-14 00:23:17 +03:00
# include "../lib/GameConstants.h"
2007-06-20 15:00:18 +03:00
2009-04-15 17:03:31 +03:00
/*
* CMusicHandler . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2009-04-22 21:48:56 +03:00
using namespace boost : : assign ;
2009-05-01 02:25:17 +03:00
static boost : : bimap < soundBase : : soundID , std : : string > sounds ;
// Not pretty, but there's only one music handler object in the game.
2011-08-19 22:50:24 +03:00
static void soundFinishedCallbackC ( int channel )
{
CCS - > soundh - > soundFinishedCallback ( channel ) ;
}
static void musicFinishedCallbackC ( void )
{
2010-12-19 16:39:56 +02:00
CCS - > musich - > musicFinishedCallback ( ) ;
2009-05-01 02:25:17 +03:00
}
2009-04-30 13:53:06 +03:00
2009-05-22 07:14:59 +03:00
void CAudioBase : : init ( )
{
if ( initialized )
return ;
if ( Mix_OpenAudio ( 44100 , MIX_DEFAULT_FORMAT , 2 , 1024 ) = = - 1 )
{
2009-10-13 05:04:06 +03:00
tlog1 < < " Mix_OpenAudio error: " < < Mix_GetError ( ) < < std : : endl ;
2009-05-22 07:14:59 +03:00
return ;
}
initialized = true ;
}
void CAudioBase : : release ( )
{
2011-08-19 22:50:24 +03:00
if ( initialized )
{
2009-05-22 07:14:59 +03:00
Mix_CloseAudio ( ) ;
initialized = false ;
}
}
2011-12-14 00:23:17 +03:00
void CAudioBase : : setVolume ( ui32 percent )
2009-05-22 07:14:59 +03:00
{
if ( percent > 100 )
percent = 100 ;
2012-02-16 20:10:58 +03:00
2009-05-22 07:14:59 +03:00
volume = percent ;
}
2012-01-12 18:23:00 +03:00
void CSoundHandler : : onVolumeChange ( const JsonNode & volumeNode )
2009-04-30 13:53:06 +03:00
{
2012-01-12 18:23:00 +03:00
setVolume ( volumeNode . Float ( ) ) ;
}
CSoundHandler : : CSoundHandler ( ) :
listener ( settings . listen [ " general " ] [ " sound " ] )
{
listener ( boost : : bind ( & CSoundHandler : : onVolumeChange , this , _1 ) ) ;
2009-04-22 21:48:56 +03:00
// Map sound names
# define VCMI_SOUND_NAME(x) ( soundBase::x,
2009-04-30 13:53:06 +03:00
# define VCMI_SOUND_FILE(y) #y )
sounds = boost : : assign : : list_of < boost : : bimap < soundBase : : soundID , std : : string > : : relation >
2009-04-22 21:48:56 +03:00
VCMI_SOUND_LIST ;
# undef VCMI_SOUND_NAME
# undef VCMI_SOUND_FILE
2009-04-22 21:50:22 +03:00
// Vectors for helper(s)
2009-05-06 05:39:03 +03:00
pickupSounds + = soundBase : : pickup01 , soundBase : : pickup02 , soundBase : : pickup03 ,
2009-04-22 21:50:22 +03:00
soundBase : : pickup04 , soundBase : : pickup05 , soundBase : : pickup06 , soundBase : : pickup07 ;
2011-08-19 22:50:24 +03:00
2011-08-08 00:37:07 +03:00
horseSounds + = // must be the same order as terrains (see EterrainType);
2009-04-23 22:50:27 +03:00
soundBase : : horseDirt , soundBase : : horseSand , soundBase : : horseGrass ,
soundBase : : horseSnow , soundBase : : horseSwamp , soundBase : : horseRough ,
soundBase : : horseSubterranean , soundBase : : horseLava ,
soundBase : : horseWater , soundBase : : horseRock ;
2011-08-19 22:50:24 +03:00
battleIntroSounds + = soundBase : : battle00 , soundBase : : battle01 ,
soundBase : : battle02 , soundBase : : battle03 , soundBase : : battle04 ,
soundBase : : battle05 , soundBase : : battle06 , soundBase : : battle07 ;
2009-05-22 07:14:59 +03:00
} ;
2009-04-22 21:50:22 +03:00
2009-05-22 07:14:59 +03:00
void CSoundHandler : : init ( )
{
CAudioBase : : init ( ) ;
2011-08-19 22:50:24 +03:00
if ( initialized )
{
2009-05-22 07:14:59 +03:00
// Load sounds
2011-12-14 00:23:17 +03:00
sndh . add_file ( std : : string ( GameConstants : : DATA_DIR + " /Data/Heroes3.snd " ) ) ;
sndh . add_file ( std : : string ( GameConstants : : DATA_DIR + " /Data/Heroes3-cd2.snd " ) , false ) ;
sndh . add_file ( std : : string ( GameConstants : : DATA_DIR + " /Data/H3ab_ahd.snd " ) ) ;
2011-08-19 22:50:24 +03:00
Mix_ChannelFinished ( soundFinishedCallbackC ) ;
2011-08-07 22:14:46 +03:00
}
2009-05-06 05:32:36 +03:00
}
2009-05-22 07:14:59 +03:00
void CSoundHandler : : release ( )
2009-05-06 05:32:36 +03:00
{
2011-08-19 22:50:24 +03:00
if ( initialized )
{
2009-05-22 07:14:59 +03:00
Mix_HaltChannel ( - 1 ) ;
std : : map < soundBase : : soundID , Mix_Chunk * > : : iterator it ;
2011-08-19 22:50:24 +03:00
for ( it = soundChunks . begin ( ) ; it ! = soundChunks . end ( ) ; it + + )
{
2009-05-22 07:14:59 +03:00
if ( it - > second )
Mix_FreeChunk ( it - > second ) ;
}
2009-05-06 05:32:36 +03:00
}
2009-05-22 07:14:59 +03:00
CAudioBase : : release ( ) ;
2007-06-20 15:00:18 +03:00
}
2009-04-30 13:53:06 +03:00
// Allocate an SDL chunk and cache it.
2009-05-06 05:32:36 +03:00
Mix_Chunk * CSoundHandler : : GetSoundChunk ( soundBase : : soundID soundID )
2007-06-20 15:00:18 +03:00
{
2009-04-30 13:53:06 +03:00
// Find its name
boost : : bimap < soundBase : : soundID , std : : string > : : left_iterator it ;
it = sounds . left . find ( soundID ) ;
if ( it = = sounds . left . end ( ) )
return NULL ;
2008-03-20 16:23:54 +02:00
2009-04-30 13:53:06 +03:00
// Load and insert
int size ;
2011-08-07 22:14:46 +03:00
const char * data = sndh . extract ( it - > second , size ) ;
2009-04-22 21:48:56 +03:00
if ( ! data )
return NULL ;
2008-03-20 11:55:33 +02:00
2009-04-30 13:53:06 +03:00
SDL_RWops * ops = SDL_RWFromConstMem ( data , size ) ;
Mix_Chunk * chunk ;
2009-04-22 21:48:56 +03:00
chunk = Mix_LoadWAV_RW ( ops , 1 ) ; // will free ops
2011-08-19 22:50:24 +03:00
if ( ! chunk )
{
2009-04-30 13:53:06 +03:00
tlog1 < < " Unable to mix sound " < < it - > second < < " ( " < < Mix_GetError ( ) < < " ) " < < std : : endl ;
return NULL ;
}
soundChunks . insert ( std : : pair < soundBase : : soundID , Mix_Chunk * > ( soundID , chunk ) ) ;
2009-04-22 21:48:56 +03:00
return chunk ;
}
2009-04-26 02:31:39 +03:00
2009-04-30 13:53:06 +03:00
// Get a soundID given a filename
2011-08-20 04:15:37 +03:00
soundBase : : soundID CSoundHandler : : getSoundID ( const std : : string & fileName )
2009-04-26 02:31:39 +03:00
{
2009-04-30 13:53:06 +03:00
boost : : bimap < soundBase : : soundID , std : : string > : : right_iterator it ;
2009-04-26 02:31:39 +03:00
2009-04-30 13:53:06 +03:00
it = sounds . right . find ( fileName ) ;
if ( it = = sounds . right . end ( ) )
2009-04-26 02:31:39 +03:00
return soundBase : : invalid ;
else
return it - > second ;
}
2010-12-19 16:39:56 +02:00
void CSoundHandler : : initCreaturesSounds ( const std : : vector < ConstTransitivePtr < CCreature > > & creatures )
2009-04-26 02:31:39 +03:00
{
2011-08-20 04:15:37 +03:00
tlog5 < < " \t \t Reading config/cr_sounds.json " < < std : : endl ;
2011-12-14 00:23:17 +03:00
const JsonNode config ( GameConstants : : DATA_DIR + " /config/cr_sounds.json " ) ;
2009-04-26 02:31:39 +03:00
2009-10-12 08:00:28 +03:00
CBattleSounds . resize ( creatures . size ( ) ) ;
2011-08-20 04:15:37 +03:00
if ( ! config [ " creature_sounds " ] . isNull ( ) ) {
2012-02-16 20:10:58 +03:00
2011-09-01 07:01:54 +03:00
BOOST_FOREACH ( const JsonNode & node , config [ " creature_sounds " ] . Vector ( ) ) {
2011-08-20 04:15:37 +03:00
const JsonNode * value ;
int id ;
2009-04-26 02:31:39 +03:00
2011-08-20 04:15:37 +03:00
value = & node [ " name " ] ;
2009-05-30 19:00:26 +03:00
2011-08-20 04:15:37 +03:00
bmap < std : : string , int > : : const_iterator i = CGI - > creh - > nameToID . find ( value - > String ( ) ) ;
if ( i ! = CGI - > creh - > nameToID . end ( ) )
2009-05-30 19:00:26 +03:00
id = i - > second ;
else
{
2011-08-20 04:15:37 +03:00
tlog1 < < " Sound info for an unknown creature: " < < value - > String ( ) < < std : : endl ;
2009-05-30 19:00:26 +03:00
continue ;
}
2011-08-20 04:15:37 +03:00
/* This is a bit ugly. Maybe we should use an array for
* sound ids instead of separate variables and define
* attack / defend / killed / . . . as indexes . */
# define GET_SOUND_VALUE(value_name) do { value = &node[#value_name]; if (!value->isNull()) CBattleSounds[id].value_name = getSoundID(value->String()); } while(0)
GET_SOUND_VALUE ( attack ) ;
GET_SOUND_VALUE ( defend ) ;
GET_SOUND_VALUE ( killed ) ;
GET_SOUND_VALUE ( move ) ;
GET_SOUND_VALUE ( shoot ) ;
GET_SOUND_VALUE ( wince ) ;
GET_SOUND_VALUE ( ext1 ) ;
GET_SOUND_VALUE ( ext2 ) ;
GET_SOUND_VALUE ( startMoving ) ;
GET_SOUND_VALUE ( endMoving ) ;
# undef GET_SOUND_VALUE
2009-04-26 02:31:39 +03:00
}
}
2012-02-16 20:10:58 +03:00
2009-06-02 01:31:11 +03:00
//commented to avoid spurious warnings
/*
2009-04-26 02:31:39 +03:00
// Find creatures without sounds
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < creatures . size ( ) ; i + + )
2009-04-26 02:31:39 +03:00
{
// Note: this will exclude war machines, but it's better
// than nothing.
if ( vstd : : contains ( CGI - > creh - > notUsedMonsters , i ) )
continue ;
2009-05-14 06:13:54 +03:00
CCreature & c = creatures [ i ] ;
2009-04-26 02:31:39 +03:00
if ( c . sounds . killed = = soundBase : : invalid )
tlog1 < < " creature " < < c . idNumber < < " doesn't have sounds " < < std : : endl ;
2009-06-02 01:31:11 +03:00
} */
2009-04-26 02:31:39 +03:00
}
2010-12-19 16:39:56 +02:00
void CSoundHandler : : initSpellsSounds ( const std : : vector < ConstTransitivePtr < CSpell > > & spells )
2009-05-14 07:49:04 +03:00
{
2011-12-14 00:23:17 +03:00
const JsonNode config ( GameConstants : : DATA_DIR + " /config/sp_sounds.json " ) ;
2009-05-14 07:49:04 +03:00
2011-08-20 04:57:03 +03:00
if ( ! config [ " spell_sounds " ] . isNull ( ) ) {
2011-09-01 07:01:54 +03:00
BOOST_FOREACH ( const JsonNode & node , config [ " spell_sounds " ] . Vector ( ) ) {
2011-08-20 04:57:03 +03:00
int spellid = node [ " id " ] . Float ( ) ;
2010-12-19 16:39:56 +02:00
const CSpell * s = CGI - > spellh - > spells [ spellid ] ;
2009-05-14 07:49:04 +03:00
2010-12-19 16:39:56 +02:00
if ( vstd : : contains ( spellSounds , s ) )
2009-05-14 07:49:04 +03:00
tlog1 < < " Spell << " < < spellid < < " already has a sound " < < std : : endl ;
2011-08-20 04:57:03 +03:00
spellSounds [ s ] = getSoundID ( node [ " soundfile " ] . String ( ) ) ;
2009-05-14 07:49:04 +03:00
}
}
}
2009-04-22 21:48:56 +03:00
// Plays a sound, and return its channel so we can fade it out later
2009-05-06 05:32:36 +03:00
int CSoundHandler : : playSound ( soundBase : : soundID soundID , int repeats )
2009-04-22 21:48:56 +03:00
{
2009-05-22 07:14:59 +03:00
if ( ! initialized )
2009-04-22 21:48:56 +03:00
return - 1 ;
2008-08-02 18:08:03 +03:00
2009-05-22 07:14:59 +03:00
int channel ;
Mix_Chunk * chunk = GetSoundChunk ( soundID ) ;
2009-04-22 21:48:56 +03:00
2009-04-30 13:53:06 +03:00
if ( chunk )
2008-03-20 11:55:33 +02:00
{
2009-04-30 13:53:06 +03:00
channel = Mix_PlayChannel ( - 1 , chunk , repeats ) ;
if ( channel = = - 1 )
2009-10-13 05:04:06 +03:00
tlog1 < < " Unable to play sound file " < < soundID < < " , error " < < Mix_GetError ( ) < < std : : endl ;
2011-08-19 22:50:24 +03:00
else
callbacks [ channel ] ; //insert empty callback
}
else
{
2009-04-30 13:53:06 +03:00
channel = - 1 ;
2008-03-20 11:55:33 +02:00
}
2009-04-22 21:48:56 +03:00
return channel ;
2008-08-02 18:08:03 +03:00
}
2009-04-22 21:50:22 +03:00
// Helper. Randomly select a sound from an array and play it
2009-05-06 05:32:36 +03:00
int CSoundHandler : : playSoundFromSet ( std : : vector < soundBase : : soundID > & sound_vec )
2009-04-22 21:50:22 +03:00
{
return playSound ( sound_vec [ rand ( ) % sound_vec . size ( ) ] ) ;
}
2009-04-24 00:09:10 +03:00
2009-05-06 05:32:36 +03:00
void CSoundHandler : : stopSound ( int handler )
2009-04-24 00:09:10 +03:00
{
2009-05-22 07:14:59 +03:00
if ( initialized & & handler ! = - 1 )
2009-04-26 01:51:16 +03:00
Mix_HaltChannel ( handler ) ;
2009-05-01 02:25:17 +03:00
}
2009-05-06 06:13:46 +03:00
// Sets the sound volume, from 0 (mute) to 100
2011-12-14 00:23:17 +03:00
void CSoundHandler : : setVolume ( ui32 percent )
2009-05-06 06:13:46 +03:00
{
2009-05-22 07:14:59 +03:00
CAudioBase : : setVolume ( percent ) ;
2009-05-06 06:13:46 +03:00
2009-05-22 07:14:59 +03:00
if ( initialized )
Mix_Volume ( - 1 , ( MIX_MAX_VOLUME * volume ) / 100 ) ;
2009-05-06 06:13:46 +03:00
}
2011-08-19 22:50:24 +03:00
void CSoundHandler : : setCallback ( int channel , boost : : function < void ( ) > function )
{
std : : map < int , boost : : function < void ( ) > > : : iterator iter ;
iter = callbacks . find ( channel ) ;
//channel not found. It may have finished so fire callback now
if ( iter = = callbacks . end ( ) )
function ( ) ;
else
iter - > second = function ;
}
void CSoundHandler : : soundFinishedCallback ( int channel )
{
std : : map < int , boost : : function < void ( ) > > : : iterator iter ;
iter = callbacks . find ( channel ) ;
assert ( iter ! = callbacks . end ( ) ) ;
if ( iter - > second )
iter - > second ( ) ;
callbacks . erase ( iter ) ;
}
2012-01-12 18:23:00 +03:00
void CMusicHandler : : onVolumeChange ( const JsonNode & volumeNode )
{
setVolume ( volumeNode . Float ( ) ) ;
}
CMusicHandler : : CMusicHandler ( ) :
listener ( settings . listen [ " general " ] [ " music " ] )
2009-05-06 05:32:36 +03:00
{
2012-01-12 18:23:00 +03:00
listener ( boost : : bind ( & CMusicHandler : : onVolumeChange , this , _1 ) ) ;
2009-05-06 05:32:36 +03:00
// Map music IDs
2012-02-16 20:10:58 +03:00
# ifdef CPP11_USE_INITIALIZERS_LIST
# define VCMI_MUSIC_ID(x) { musicBase::x ,
# define VCMI_MUSIC_FILE(y) y },
musics = { VCMI_MUSIC_LIST } ;
# undef VCMI_MUSIC_NAME
# undef VCMI_MUSIC_FILE
# else
# define VCMI_MUSIC_ID(x) ( musicBase::x ,
# define VCMI_MUSIC_FILE(y) y )
musics = map_list_of
VCMI_MUSIC_LIST ;
# undef VCMI_MUSIC_NAME
# undef VCMI_MUSIC_FILE
# endif
2010-08-18 17:24:30 +03:00
// Vectors for helper
2011-08-20 14:27:09 +03:00
aiMusics + = musicBase : : AITheme0 , musicBase : : AITheme1 , musicBase : : AITheme2 ;
2012-02-16 20:10:58 +03:00
battleMusics + = musicBase : : combat1 , musicBase : : combat2 ,
2009-05-06 05:32:36 +03:00
musicBase : : combat3 , musicBase : : combat4 ;
2012-02-16 20:10:58 +03:00
2010-08-18 17:24:30 +03:00
townMusics + = musicBase : : castleTown , musicBase : : rampartTown ,
musicBase : : towerTown , musicBase : : infernoTown ,
musicBase : : necroTown , musicBase : : dungeonTown ,
2011-08-19 22:50:24 +03:00
musicBase : : strongHoldTown , musicBase : : fortressTown ,
2010-08-18 17:24:30 +03:00
musicBase : : elemTown ;
2011-08-17 23:44:14 +03:00
terrainMusics + = musicBase : : dirt , musicBase : : sand , musicBase : : grass ,
musicBase : : snow , musicBase : : swamp , musicBase : : rough ,
musicBase : : underground , musicBase : : lava , musicBase : : water ;
2009-05-06 05:32:36 +03:00
}
2009-05-22 07:14:59 +03:00
void CMusicHandler : : init ( )
2009-05-06 05:32:36 +03:00
{
2009-05-22 07:14:59 +03:00
CAudioBase : : init ( ) ;
2009-05-06 05:32:36 +03:00
2009-05-22 07:14:59 +03:00
if ( initialized )
Mix_HookMusicFinished ( musicFinishedCallbackC ) ;
}
2009-05-06 05:32:36 +03:00
2009-05-22 07:14:59 +03:00
void CMusicHandler : : release ( )
{
2011-08-19 22:50:24 +03:00
if ( initialized )
{
boost : : mutex : : scoped_lock guard ( musicMutex ) ;
2009-05-22 07:14:59 +03:00
2011-08-19 22:50:24 +03:00
Mix_HookMusicFinished ( NULL ) ;
2009-05-22 07:14:59 +03:00
2011-08-19 22:50:24 +03:00
current . reset ( ) ;
next . reset ( ) ;
2009-05-22 07:14:59 +03:00
}
CAudioBase : : release ( ) ;
2009-05-06 05:32:36 +03:00
}
2009-05-01 02:25:17 +03:00
// Plays a music
// loop: -1 always repeats, 0=do not play, 1+=number of loops
void CMusicHandler : : playMusic ( musicBase : : musicID musicID , int loop )
{
2011-08-19 22:50:24 +03:00
if ( current . get ( ) ! = NULL & & * current = = musicID )
2009-05-22 07:14:59 +03:00
return ;
2011-08-19 22:50:24 +03:00
queueNext ( new MusicEntry ( this , musicID , loop ) ) ;
}
2009-05-01 02:25:17 +03:00
2011-08-19 22:50:24 +03:00
// Helper. Randomly plays tracks from music_vec
void CMusicHandler : : playMusicFromSet ( std : : vector < musicBase : : musicID > & music_vec , int loop )
{
if ( current . get ( ) ! = NULL & & * current = = music_vec )
return ;
2009-05-01 02:25:17 +03:00
2011-08-19 22:50:24 +03:00
queueNext ( new MusicEntry ( this , music_vec , loop ) ) ;
}
void CMusicHandler : : queueNext ( MusicEntry * queued )
{
if ( ! initialized )
return ;
boost : : mutex : : scoped_lock guard ( musicMutex ) ;
next . reset ( queued ) ;
2009-05-01 02:25:17 +03:00
2011-08-19 22:50:24 +03:00
if ( current . get ( ) ! = NULL )
2009-05-20 12:02:50 +03:00
{
2011-08-19 22:50:24 +03:00
current - > stop ( 1000 ) ;
2009-05-20 12:02:50 +03:00
}
else
{
2011-08-19 22:50:24 +03:00
current = next ;
current - > play ( ) ;
2009-05-01 02:25:17 +03:00
}
}
// Stop and free the current music
void CMusicHandler : : stopMusic ( int fade_ms )
{
2009-05-22 07:14:59 +03:00
if ( ! initialized )
return ;
2011-08-19 22:50:24 +03:00
boost : : mutex : : scoped_lock guard ( musicMutex ) ;
2009-05-01 02:25:17 +03:00
2011-08-19 22:50:24 +03:00
if ( current . get ( ) ! = NULL )
current - > stop ( fade_ms ) ;
next . reset ( ) ;
2009-05-01 02:25:17 +03:00
}
2009-05-06 06:13:46 +03:00
// Sets the music volume, from 0 (mute) to 100
2011-12-14 00:23:17 +03:00
void CMusicHandler : : setVolume ( ui32 percent )
2009-05-06 06:13:46 +03:00
{
2009-05-22 07:14:59 +03:00
CAudioBase : : setVolume ( percent ) ;
2009-05-06 06:13:46 +03:00
2009-05-22 07:14:59 +03:00
if ( initialized )
Mix_VolumeMusic ( ( MIX_MAX_VOLUME * volume ) / 100 ) ;
2009-05-06 06:13:46 +03:00
}
2009-05-01 02:25:17 +03:00
// Called by SDL when a music finished.
void CMusicHandler : : musicFinishedCallback ( void )
{
2011-08-19 22:50:24 +03:00
boost : : mutex : : scoped_lock guard ( musicMutex ) ;
2009-05-01 02:25:17 +03:00
2011-08-19 22:50:24 +03:00
if ( current . get ( ) ! = NULL )
2009-05-20 12:02:50 +03:00
{
2011-08-19 22:50:24 +03:00
//return if current music still not finished
if ( current - > play ( ) )
return ;
else
current . reset ( ) ;
2009-05-01 02:25:17 +03:00
}
2011-08-19 22:50:24 +03:00
if ( current . get ( ) = = NULL & & next . get ( ) ! = NULL )
2009-05-20 12:02:50 +03:00
{
2011-08-19 22:50:24 +03:00
current = next ;
current - > play ( ) ;
2009-05-01 02:25:17 +03:00
}
2011-08-19 22:50:24 +03:00
}
2009-05-01 02:25:17 +03:00
2011-08-19 22:50:24 +03:00
MusicEntry : : MusicEntry ( CMusicHandler * _owner , musicBase : : musicID _musicID , int _loopCount ) :
owner ( _owner ) ,
music ( NULL ) ,
loopCount ( _loopCount )
{
load ( _musicID ) ;
2009-05-06 05:32:36 +03:00
}
2009-06-10 22:44:09 +03:00
2011-08-19 22:50:24 +03:00
MusicEntry : : MusicEntry ( CMusicHandler * _owner , std : : vector < musicBase : : musicID > & _musicVec , int _loopCount ) :
currentID ( musicBase : : music_todo ) ,
owner ( _owner ) ,
music ( NULL ) ,
loopCount ( _loopCount ) ,
musicVec ( _musicVec )
2009-06-10 22:44:09 +03:00
{
2011-08-19 22:50:24 +03:00
//In this case music will be loaded only on playing - no need to call load() here
}
MusicEntry : : ~ MusicEntry ( )
{
tlog5 < < " Del-ing music file " < < filename < < " \n " ;
if ( music )
Mix_FreeMusic ( music ) ;
}
void MusicEntry : : load ( musicBase : : musicID ID )
{
currentID = ID ;
2011-12-14 00:23:17 +03:00
filename = GameConstants : : DATA_DIR + " /Mp3/ " ;
2011-08-19 22:50:24 +03:00
filename + = owner - > musics [ ID ] ;
tlog5 < < " Loading music file " < < filename < < " \n " ;
if ( music )
Mix_FreeMusic ( music ) ;
music = Mix_LoadMUS ( filename . c_str ( ) ) ;
2011-08-17 23:44:14 +03:00
2011-09-19 23:50:25 +03:00
if ( ! music )
{
tlog3 < < " Warning: Cannot open " < < filename < < " : " < < Mix_GetError ( ) < < std : : endl ;
return ;
}
2011-08-17 23:44:14 +03:00
# ifdef _WIN32
//The assertion will fail if old MSVC libraries pack .dll is used
2011-09-23 18:58:18 +03:00
assert ( Mix_GetMusicType ( music ) ! = MUS_MP3 ) ;
2011-08-17 23:44:14 +03:00
# endif
2009-06-10 22:44:09 +03:00
}
2011-08-19 22:50:24 +03:00
bool MusicEntry : : play ( )
2009-06-10 22:44:09 +03:00
{
2011-08-19 22:50:24 +03:00
if ( loopCount = = 0 )
return false ;
if ( loopCount > 0 )
loopCount - - ;
if ( ! musicVec . empty ( ) )
load ( musicVec . at ( rand ( ) % musicVec . size ( ) ) ) ;
2011-09-23 18:58:18 +03:00
tlog5 < < " Playing music file " < < filename < < " \n " ;
2011-08-19 22:50:24 +03:00
if ( Mix_PlayMusic ( music , 1 ) = = - 1 )
{
2009-06-10 22:44:09 +03:00
tlog1 < < " Unable to play music ( " < < Mix_GetError ( ) < < " ) " < < std : : endl ;
2011-08-19 22:50:24 +03:00
return false ;
}
return true ;
}
2009-06-10 22:44:09 +03:00
2011-08-19 22:50:24 +03:00
void MusicEntry : : stop ( int fade_ms )
{
tlog5 < < " Stoping music file " < < filename < < " \n " ;
loopCount = 0 ;
Mix_FadeOutMusic ( fade_ms ) ;
2009-10-04 05:02:45 +03:00
}
2011-08-19 22:50:24 +03:00
bool MusicEntry : : operator = = ( musicBase : : musicID _musicID ) const
{
return musicVec . empty ( ) & & currentID = = _musicID ;
}
bool MusicEntry : : operator = = ( std : : vector < musicBase : : musicID > & _musicVec ) const
{
return musicVec = = _musicVec ;
2011-08-20 04:15:37 +03:00
}