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>
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"
2012-08-02 14:03:26 +03:00
# include "../lib/Filesystem/CResourceLoader.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 )
2012-08-06 10:34:37 +03:00
{
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-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 ( ) )
2012-08-09 10:40:47 +03:00
return nullptr ;
2008-03-20 16:23:54 +02:00
2009-04-30 13:53:06 +03:00
// Load and insert
2012-08-09 10:40:47 +03:00
try
{
auto data = CResourceHandler : : get ( ) - > loadData ( ResourceID ( std : : string ( " SOUNDS/ " ) + it - > second , EResType : : SOUND ) ) ;
2009-04-22 21:48:56 +03:00
2012-08-09 10:40:47 +03:00
SDL_RWops * ops = SDL_RWFromMem ( data . first . release ( ) , data . second ) ;
Mix_Chunk * chunk ;
chunk = Mix_LoadWAV_RW ( ops , 1 ) ; // will free ops
soundChunks . insert ( std : : pair < soundBase : : soundID , Mix_Chunk * > ( soundID , chunk ) ) ;
return chunk ;
}
catch ( std : : exception & e )
2011-08-19 22:50:24 +03:00
{
2012-08-09 10:40:47 +03:00
tlog3 < < " Cannot get sound " < < soundID < < " chunk: " < < e . what ( ) < < " \n " ;
return nullptr ;
2009-04-30 13:53:06 +03:00
}
2009-04-22 21:48:56 +03:00
}
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 ;
2012-08-02 14:03:26 +03:00
const JsonNode config ( ResourceID ( " 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
{
2012-08-02 14:03:26 +03:00
const JsonNode config ( ResourceID ( " 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
2012-05-18 20:35:46 +03:00
soundBase : : soundID sound = getSoundID ( node [ " soundfile " ] . String ( ) ) ;
if ( sound = = soundBase : : invalid )
tlog0 < < " Error: invalid sound for id " < < spellid < < " \n " ;
spellSounds [ s ] = sound ;
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
2010-08-18 17:24:30 +03:00
// Vectors for helper
2012-08-06 10:34:37 +03:00
const std : : string setEnemy [ ] = { " AITheme0 " , " AITheme1 " , " AITheme2 " } ;
const std : : string setBattle [ ] = { " Combat01 " , " Combat02 " , " Combat03 " , " Combat04 " } ;
const std : : string setTerrain [ ] = { " Dirt " , " Sand " , " Grass " , " Snow " , " Swamp " , " Rough " , " Underground " , " Lava " , " Water " } ;
const std : : string setTowns [ ] = { " CstleTown " , " Rampart " , " TowerTown " , " InfernoTown " ,
" NecroTown " , " Dungeon " , " Stronghold " , " FortressTown " , " ElemTown " } ;
2012-02-16 20:10:58 +03:00
2012-08-06 10:34:37 +03:00
auto fillSet = [ = ] ( std : : string setName , const std : : string list [ ] , size_t amount )
{
for ( size_t i = 0 ; i < amount ; i + + )
addEntryToSet ( setName , i , std : : string ( " music/ " ) + list [ i ] ) ;
} ;
fillSet ( " enemy-turn " , setEnemy , ARRAY_COUNT ( setEnemy ) ) ;
fillSet ( " battle " , setBattle , ARRAY_COUNT ( setBattle ) ) ;
fillSet ( " terrain " , setTerrain , ARRAY_COUNT ( setTerrain ) ) ;
fillSet ( " town-theme " , setTowns , ARRAY_COUNT ( setTowns ) ) ;
}
2011-08-17 23:44:14 +03:00
2012-08-06 10:34:37 +03:00
void CMusicHandler : : addEntryToSet ( std : : string set , int musicID , std : : string musicURI )
{
musicsSet [ set ] [ musicID ] = musicURI ;
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
}
2012-08-06 10:34:37 +03:00
void CMusicHandler : : playMusic ( std : : string musicURI , bool loop )
2009-05-01 02:25:17 +03:00
{
2012-08-06 10:34:37 +03:00
if ( current & & current - > isTrack ( musicURI ) )
2009-05-22 07:14:59 +03:00
return ;
2012-08-06 10:34:37 +03:00
queueNext ( new MusicEntry ( this , " " , musicURI , loop ) ) ;
2011-08-19 22:50:24 +03:00
}
2009-05-01 02:25:17 +03:00
2012-08-06 10:34:37 +03:00
void CMusicHandler : : playMusicFromSet ( std : : string whichSet , bool loop )
2011-08-19 22:50:24 +03:00
{
2012-08-06 10:34:37 +03:00
auto selectedSet = musicsSet . find ( whichSet ) ;
if ( selectedSet = = musicsSet . end ( ) )
{
tlog0 < < " Error: playing music from non-existing set: " < < whichSet < < " \n " ;
2011-08-19 22:50:24 +03:00
return ;
2012-08-06 10:34:37 +03:00
}
2009-05-01 02:25:17 +03:00
2012-08-06 10:34:37 +03:00
if ( current & & current - > isSet ( whichSet ) )
return ;
queueNext ( new MusicEntry ( this , whichSet , " " , loop ) ) ;
}
void CMusicHandler : : playMusicFromSet ( std : : string whichSet , int entryID , bool loop )
{
auto selectedSet = musicsSet . find ( whichSet ) ;
if ( selectedSet = = musicsSet . end ( ) )
{
tlog0 < < " Error: playing music from non-existing set: " < < whichSet < < " \n " ;
return ;
}
auto selectedEntry = selectedSet - > second . find ( entryID ) ;
if ( selectedEntry = = selectedSet - > second . end ( ) )
{
tlog0 < < " Error: playing non-existing entry " < < entryID < < " from set: " < < whichSet < < " \n " ;
return ;
}
2012-08-10 11:49:18 +03:00
if ( current & & current - > isTrack ( selectedEntry - > second ) )
return ;
2012-08-06 10:34:37 +03:00
queueNext ( new MusicEntry ( this , " " , selectedEntry - > second , loop ) ) ;
2011-08-19 22:50:24 +03:00
}
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
2012-08-27 23:45:58 +03:00
if ( current . get ( ) = = nullptr | | ! current - > stop ( 1000 ) )
2009-05-20 12:02:50 +03:00
{
2012-02-17 23:34:34 +03:00
current . reset ( next . release ( ) ) ;
2011-08-19 22:50:24 +03:00
current - > play ( ) ;
2009-05-01 02:25:17 +03:00
}
}
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
}
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
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
{
2012-02-17 23:34:34 +03:00
current . reset ( next . release ( ) ) ;
2011-08-19 22:50:24 +03:00
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
2012-08-06 10:34:37 +03:00
MusicEntry : : MusicEntry ( CMusicHandler * owner , std : : string setName , std : : string musicURI , bool looped ) :
owner ( owner ) ,
music ( nullptr ) ,
2012-08-27 23:45:58 +03:00
loop ( looped ? - 1 : 1 ) ,
2012-08-06 10:34:37 +03:00
setName ( setName )
2009-06-10 22:44:09 +03:00
{
2012-08-06 10:34:37 +03:00
if ( ! musicURI . empty ( ) )
load ( musicURI ) ;
2011-08-19 22:50:24 +03:00
}
MusicEntry : : ~ MusicEntry ( )
{
2012-08-06 10:34:37 +03:00
tlog5 < < " Del-ing music file " < < currentName < < " \n " ;
2011-08-19 22:50:24 +03:00
if ( music )
Mix_FreeMusic ( music ) ;
}
2012-08-06 10:34:37 +03:00
void MusicEntry : : load ( std : : string musicURI )
2011-08-19 22:50:24 +03:00
{
2012-06-13 16:04:06 +03:00
if ( music )
{
2012-08-06 10:34:37 +03:00
tlog5 < < " Del-ing music file " < < currentName < < " \n " ;
2012-06-13 16:04:06 +03:00
Mix_FreeMusic ( music ) ;
}
2012-08-06 10:34:37 +03:00
currentName = musicURI ;
2011-08-19 22:50:24 +03:00
2012-08-06 10:34:37 +03:00
tlog5 < < " Loading music file " < < musicURI < < " \n " ;
2011-08-19 22:50:24 +03:00
2012-08-06 10:34:37 +03:00
music = Mix_LoadMUS ( CResourceHandler : : get ( ) - > getResourceName ( ResourceID ( musicURI , EResType : : MUSIC ) ) . c_str ( ) ) ;
2011-08-17 23:44:14 +03:00
2011-09-19 23:50:25 +03:00
if ( ! music )
{
2012-08-06 10:34:37 +03:00
tlog3 < < " Warning: Cannot open " < < currentName < < " : " < < Mix_GetError ( ) < < std : : endl ;
2011-09-19 23:50:25 +03:00
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
{
2012-08-27 23:45:58 +03:00
if ( ! ( loop - - ) & & music ) //already played once - return
2011-08-19 22:50:24 +03:00
return false ;
2012-08-06 10:34:37 +03:00
if ( ! setName . empty ( ) )
{
auto set = owner - > musicsSet [ setName ] ;
size_t entryID = rand ( ) % set . size ( ) ;
auto iterator = set . begin ( ) ;
std : : advance ( iterator , entryID ) ;
load ( iterator - > second ) ;
}
2011-08-19 22:50:24 +03:00
2012-08-06 10:34:37 +03:00
tlog5 < < " Playing music file " < < currentName < < " \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
2012-08-27 23:45:58 +03:00
bool MusicEntry : : stop ( int fade_ms )
2011-08-19 22:50:24 +03:00
{
2012-08-27 23:45:58 +03:00
if ( Mix_PlayingMusic ( ) )
{
tlog5 < < " Stoping music file " < < currentName < < " \n " ;
loop = 0 ;
Mix_FadeOutMusic ( fade_ms ) ;
return true ;
}
return false ;
2009-10-04 05:02:45 +03:00
}
2011-08-19 22:50:24 +03:00
2012-08-06 10:34:37 +03:00
bool MusicEntry : : isSet ( std : : string set )
2011-08-19 22:50:24 +03:00
{
2012-08-06 10:34:37 +03:00
return ! setName . empty ( ) & & set = = setName ;
2011-08-19 22:50:24 +03:00
}
2012-08-06 10:34:37 +03:00
bool MusicEntry : : isTrack ( std : : string track )
2011-08-19 22:50:24 +03:00
{
2012-08-06 10:34:37 +03:00
return setName . empty ( ) & & track = = currentName ;
2011-08-20 04:15:37 +03:00
}