@ -10,6 +10,7 @@
/** @file music_gui.cpp GUI for the music playback. */
# include "stdafx.h"
# include <vector>
# include "openttd.h"
# include "base_media_base.h"
# include "music/music_driver.hpp"
@ -35,278 +36,393 @@
# include "safeguards.h"
/**
* Get the name of the song .
* @ param index of the song .
* @ return the name of the song .
*/
static const char * GetSongName ( int index )
struct MusicSystem {
struct PlaylistEntry : MusicSongInfo {
const MusicSet * set ; ///< music set the song comes from
uint set_index ; ///< index of song in set
PlaylistEntry ( const MusicSet * set , uint set_index ) : MusicSongInfo ( set - > songinfo [ set_index ] ) , set ( set ) , set_index ( set_index ) { }
bool IsValid ( ) const { return ! StrEmpty ( this - > songname ) ; }
} ;
typedef std : : vector < PlaylistEntry > Playlist ;
enum PlaylistChoices {
PLCH_ALLMUSIC ,
PLCH_OLDSTYLE ,
PLCH_NEWSTYLE ,
PLCH_EZYSTREET ,
PLCH_CUSTOM1 ,
PLCH_CUSTOM2 ,
PLCH_THEMEONLY ,
PLCH_MAX ,
} ;
Playlist active_playlist ; ///< current play order of songs, including any shuffle
Playlist displayed_playlist ; ///< current playlist as displayed in GUI, never in shuffled order
Playlist music_set ; ///< all songs in current music set, in set order
PlaylistChoices selected_playlist ;
void BuildPlaylists ( ) ;
void ChangePlaylist ( PlaylistChoices pl ) ;
void ChangeMusicSet ( const char * set_name ) ;
void Shuffle ( ) ;
void Unshuffle ( ) ;
void Play ( ) ;
void Stop ( ) ;
void Next ( ) ;
void Prev ( ) ;
void CheckStatus ( ) ;
bool IsPlaying ( ) const ;
bool IsShuffle ( ) const ;
PlaylistEntry GetCurrentSong ( ) const ;
bool IsCustomPlaylist ( ) const ;
void PlaylistAdd ( size_t song_index ) ;
void PlaylistRemove ( size_t song_index ) ;
void PlaylistClear ( ) ;
private :
void ChangePlaylistPosition ( int ofs ) ;
int playlist_position ;
void SaveCustomPlaylist ( PlaylistChoices pl ) ;
Playlist standard_playlists [ PLCH_MAX ] ;
} ;
MusicSystem _music ;
/** Rebuild all playlists for the current music set */
void MusicSystem : : BuildPlaylists ( )
{
return BaseMusic : : GetUsedSet ( ) - > songinfo [ index ] . songname ;
const MusicSet * set = BaseMusic : : GetUsedSet ( ) ;
/* Clear current playlists */
for ( size_t i = 0 ; i < lengthof ( this - > standard_playlists ) ; + + i ) this - > standard_playlists [ i ] . clear ( ) ;
this - > music_set . clear ( ) ;
/* Build standard playlists, and a list of available music */
for ( uint i = 0 ; i < NUM_SONGS_AVAILABLE ; i + + ) {
PlaylistEntry entry ( set , i ) ;
if ( ! entry . IsValid ( ) ) continue ;
this - > music_set . push_back ( entry ) ;
/* Add theme song to theme-only playlist */
if ( i = = 0 ) this - > standard_playlists [ PLCH_THEMEONLY ] . push_back ( entry ) ;
/* Don't add the theme song to standard playlists */
if ( i > 0 ) {
this - > standard_playlists [ PLCH_ALLMUSIC ] . push_back ( entry ) ;
uint theme = ( i - 1 ) / NUM_SONGS_CLASS ;
this - > standard_playlists [ PLCH_OLDSTYLE + theme ] . push_back ( entry ) ;
}
}
/* Load custom playlists
* Song index offsets are 1 - based , zero indicates invalid / end - of - list value */
for ( uint i = 0 ; i < NUM_SONGS_PLAYLIST ; i + + ) {
if ( _settings_client . music . custom_1 [ i ] > 0 ) {
PlaylistEntry entry ( set , _settings_client . music . custom_1 [ i ] - 1 ) ;
if ( entry . IsValid ( ) ) this - > standard_playlists [ PLCH_CUSTOM1 ] . push_back ( entry ) ;
}
if ( _settings_client . music . custom_2 [ i ] > 0 ) {
PlaylistEntry entry ( set , _settings_client . music . custom_2 [ i ] - 1 ) ;
if ( entry . IsValid ( ) ) this - > standard_playlists [ PLCH_CUSTOM2 ] . push_back ( entry ) ;
}
}
}
/**
* Get the track number of the song .
* @ param index of the song .
* @ return the track number of the song .
* Switch to another playlist , or reload the current one .
* @ param pl Playlist to select
*/
static int GetTrackNumber ( int index )
void MusicSystem : : ChangePlaylist ( PlaylistChoices pl )
{
return BaseMusic : : GetUsedSet ( ) - > songinfo [ index ] . tracknr ;
}
assert ( pl < PLCH_MAX & & pl > = PLCH_ALLMUSIC ) ;
/** The currently played song */
static byte _music_wnd_cursong = 1 ;
/** Whether a song is currently played */
static bool _song_is_active = false ;
/** Indices of the songs in the current playlist */
static byte _cur_playlist [ NUM_SONGS_PLAYLIST + 1 ] ;
/** Indices of all songs */
static byte _playlist_all [ NUM_SONGS_AVAILABLE + 1 ] ;
/** Indices of all old style songs */
static byte _playlist_old_style [ NUM_SONGS_CLASS + 1 ] ;
/** Indices of all new style songs */
static byte _playlist_new_style [ NUM_SONGS_CLASS + 1 ] ;
/** Indices of all ezy street songs */
static byte _playlist_ezy_street [ NUM_SONGS_CLASS + 1 ] ;
assert_compile ( lengthof ( _settings_client . music . custom_1 ) = = NUM_SONGS_PLAYLIST + 1 ) ;
assert_compile ( lengthof ( _settings_client . music . custom_2 ) = = NUM_SONGS_PLAYLIST + 1 ) ;
/** The different playlists that can be played. */
static byte * const _playlists [ ] = {
_playlist_all ,
_playlist_old_style ,
_playlist_new_style ,
_playlist_ezy_street ,
_settings_client . music . custom_1 ,
_settings_client . music . custom_2 ,
} ;
this - > displayed_playlist = this - > standard_playlists [ pl ] ;
this - > active_playlist = this - > displayed_playlist ;
this - > selected_playlist = pl ;
this - > playlist_position = 0 ;
if ( this - > selected_playlist ! = PLCH_THEMEONLY ) _settings_client . music . playlist = this - > selected_playlist ;
if ( _settings_client . music . shuffle ) {
this - > Shuffle ( ) ;
/* Shuffle() will also Play() if necessary, only start once */
} else if ( _settings_client . music . playing ) {
this - > Play ( ) ;
}
InvalidateWindowData ( WC_MUSIC_TRACK_SELECTION , 0 ) ;
InvalidateWindowData ( WC_MUSIC_WINDOW , 0 ) ;
}
/**
* Validate a playlist .
* @ param playlist The playlist to validate .
* @ param last The last location in the list .
* Change to named music set , and reset playback .
* @ param set_name Name of music set to select
*/
void ValidatePlaylist ( byte * playlist , byte * last )
void MusicSystem : : ChangeMusicSet ( const char * set_name )
{
while ( * playlist ! = 0 & & playlist < = last ) {
/* Song indices are saved off-by-one so 0 is "nothing". */
if ( * playlist < = NUM_SONGS_AVAILABLE & & ! StrEmpty ( GetSongName ( * playlist - 1 ) ) ) {
playlist + + ;
continue ;
}
for ( byte * p = playlist ; * p ! = 0 & & p < = last ; p + + ) {
p [ 0 ] = p [ 1 ] ;
}
}
BaseMusic : : SetSet ( set_name ) ;
/* Make sure the list is null terminated. */
* last = 0 ;
this - > BuildPlaylists ( ) ;
this - > ChangePlaylist ( this - > selected_playlist ) ;
InvalidateWindowData ( WC_GAME_OPTIONS , WN_GAME_OPTIONS_GAME_OPTIONS , 0 , true ) ;
}
/** Prepare the playlists */
void Initialize Music( )
/** Enable shuffle mode and restart playback */
void MusicSystem : : Shuffle ( )
{
uint j = 0 ;
for ( uint i = 0 ; i < NUM_SONGS_AVAILABLE ; i + + ) {
if ( StrEmpty ( GetSongName ( i ) ) ) continue ;
_playlist_all [ j + + ] = i + 1 ;
}
/* Terminate the list */
_playlist_all [ j ] = 0 ;
/* Now make the 'styled' playlists */
for ( uint k = 0 ; k < NUM_SONG_CLASSES ; k + + ) {
j = 0 ;
for ( uint i = 0 ; i < NUM_SONGS_CLASS ; i + + ) {
int id = k * NUM_SONGS_CLASS + i + 1 ;
if ( StrEmpty ( GetSongName ( id ) ) ) continue ;
_playlists [ k + 1 ] [ j + + ] = id + 1 ;
}
/* Terminate the list */
_playlists [ k + 1 ] [ j ] = 0 ;
_settings_client . music . shuffle = true ;
this - > active_playlist = this - > displayed_playlist ;
for ( size_t i = 0 ; i < this - > active_playlist . size ( ) ; i + + ) {
size_t shuffle_index = InteractiveRandom ( ) % ( this - > active_playlist . size ( ) - i ) ;
std : : swap ( this - > active_playlist [ i ] , this - > active_playlist [ i + shuffle_index ] ) ;
}
ValidatePlaylist ( _settings_client . music . custom_1 , lastof ( _settings_client . music . custom_1 ) ) ;
ValidatePlaylist ( _settings_client . music . custom_2 , lastof ( _settings_client . music . custom_2 ) ) ;
if ( _settings_client . music . playing ) this - > Play ( ) ;
if ( BaseMusic : : GetUsedSet ( ) - > num_available < _music_wnd_cursong ) {
/* If there are less songs than the currently played song,
* just pause and reset to no song . */
_music_wnd_cursong = 0 ;
_song_is_active = false ;
}
InvalidateWindowData ( WC_MUSIC_WINDOW , 0 ) ;
}
static void SkipToPrevSong ( )
/** Disable shuffle and restart playback */
void MusicSystem : : Unshuffle ( )
{
byte * b = _cur_playlist ;
byte * p = b ;
byte t ;
_settings_client . music . shuffle = false ;
this - > active_playlist = this - > displayed_playlist ;
if ( b[ 0 ] = = 0 ) return ; // empty playlist
if ( _settings_client. music . playing ) this - > Play ( ) ;
do p + + ; while ( p [ 0 ] ! = 0 ) ; // find the end
InvalidateWindowData ( WC_MUSIC_WINDOW , 0 ) ;
}
t = * - - p ; // and copy the bytes
while ( p ! = b ) {
p - - ;
p [ 1 ] = p [ 0 ] ;
}
* b = t ;
/** Start/restart playback at current song */
void MusicSystem : : Play ( )
{
/* Always set the playing flag, even if there is no music */
_settings_client . music . playing = true ;
MusicDriver : : GetInstance ( ) - > StopSong ( ) ;
/* Make sure playlist_position is a valid index, if playlist has changed etc. */
this - > ChangePlaylistPosition ( 0 ) ;
/* If there is no music, don't try to play it */
if ( this - > active_playlist . empty ( ) ) return ;
_song_is_active = false ;
MusicSongInfo song = this - > active_playlist [ this - > playlist_position ] ;
if ( _game_mode = = GM_MENU & & this - > selected_playlist = = PLCH_THEMEONLY ) song . loop = true ;
MusicDriver : : GetInstance ( ) - > PlaySong ( song ) ;
InvalidateWindowData ( WC_MUSIC_WINDOW , 0 ) ;
}
static void SkipToNextSong ( )
/** Stop playback and set flag that we don't intend to play music */
void MusicSystem : : Stop ( )
{
byte * b = _cur_playlist ;
byte t ;
t = b [ 0 ] ;
if ( t ! = 0 ) {
while ( b [ 1 ] ! = 0 ) {
b [ 0 ] = b [ 1 ] ;
b + + ;
}
b [ 0 ] = t ;
}
MusicDriver : : GetInstance ( ) - > StopSong ( ) ;
_settings_client . music . playing = false ;
_song_is_active = false ;
InvalidateWindowData ( WC_MUSIC_WINDOW , 0 ) ;
}
static void MusicVolumeChanged ( byte new_vol )
/** Skip to next track */
void MusicSystem : : Next ( )
{
MusicDriver : : GetInstance ( ) - > SetVolume ( new_vol ) ;
this - > ChangePlaylistPosition ( + 1 ) ;
if ( _settings_client . music . playing ) this - > Play ( ) ;
InvalidateWindowData ( WC_MUSIC_WINDOW , 0 ) ;
}
static void DoPlaySong ( )
/** Skip to previous track */
void MusicSystem : : Prev ( )
{
char filename [ MAX_PATH ] ;
MusicSongInfo songinfo = BaseMusic : : GetUsedSet ( ) - > songinfo [ _music_wnd_cursong - 1 ] ; // copy
if ( FioFindFullPath ( filename , lastof ( filename ) , BASESET_DIR , songinfo . filename ) = = NULL ) {
FioFindFullPath ( filename , lastof ( filename ) , OLD_GM_DIR , songinfo . filename ) ;
this - > ChangePlaylistPosition ( - 1 ) ;
if ( _settings_client . music . playing ) this - > Play ( ) ;
InvalidateWindowData ( WC_MUSIC_WINDOW , 0 ) ;
}
/** Check that music is playing if it should, and that appropriate playlist is active for game/main menu */
void MusicSystem : : CheckStatus ( )
{
if ( ( _game_mode = = GM_MENU ) ! = ( this - > selected_playlist = = PLCH_THEMEONLY ) ) {
/* Make sure the theme-only playlist is active when on the title screen, and not during gameplay */
this - > ChangePlaylist ( ( _game_mode = = GM_MENU ) ? PLCH_THEMEONLY : ( PlaylistChoices ) _settings_client . music . playlist ) ;
}
songinfo . filename = filename ; // non-owned pointer
songinfo . loop = ( _game_mode = = GM_MENU ) & & ( _music_wnd_cursong = = 1 ) ;
MusicDriver : : GetInstance ( ) - > PlaySong ( songinfo ) ;
SetWindowDirty ( WC_MUSIC_WINDOW , 0 ) ;
if ( this - > active_playlist . empty ( ) ) return ;
/* If we were supposed to be playing, but music has stopped, move to next song */
if ( this - > IsPlaying ( ) & & ! MusicDriver : : GetInstance ( ) - > IsSongPlaying ( ) ) this - > Next ( ) ;
}
static void DoStopMusic ( )
/** Is the player getting music right now? */
bool MusicSystem : : IsPlaying ( ) const
{
MusicDriver : : GetInstance ( ) - > StopSong ( ) ;
SetWindowDirty ( WC_MUSIC_WINDOW , 0 ) ;
return _settings_client . music . playing & & ! this - > active_playlist . empty ( ) ;
}
/** Reload the active playlist data from playlist selection and shuffle setting */
static void ResetPlaylist ( )
/** Is shuffle mode enabled? */
bool MusicSystem : : IsShuffle ( ) const
{
uint i = 0 ;
uint j = 0 ;
memset ( _cur_playlist , 0 , sizeof ( _cur_playlist ) ) ;
do {
/* File is the index into the file table of the music set. The play list uses 0 as 'no entry',
* so we need to subtract 1. In case of ' no entry ' ( file = - 1 ) , just skip adding it outright . */
int file = _playlists [ _settings_client . music . playlist ] [ i ] - 1 ;
if ( file > = 0 ) {
const char * filename = BaseMusic : : GetUsedSet ( ) - > files [ file ] . filename ;
/* We are now checking for the existence of that file prior
* to add it to the list of available songs */
if ( ! StrEmpty ( filename ) & & FioCheckFileExists ( filename , BASESET_DIR ) ) {
_cur_playlist [ j ] = _playlists [ _settings_client . music . playlist ] [ i ] ;
j + + ;
}
}
} while ( _playlists [ _settings_client . music . playlist ] [ + + i ] ! = 0 & & j < lengthof ( _cur_playlist ) - 1 ) ;
/* Do not shuffle when on the intro-start window, as the song to play has to be the original TTD Theme*/
if ( _settings_client . music . shuffle & & _game_mode ! = GM_MENU ) {
i = 500 ;
do {
uint32 r = InteractiveRandom ( ) ;
byte * a = & _cur_playlist [ GB ( r , 0 , 5 ) ] ;
byte * b = & _cur_playlist [ GB ( r , 8 , 5 ) ] ;
if ( * a ! = 0 & & * b ! = 0 ) {
byte t = * a ;
* a = * b ;
* b = t ;
}
} while ( - - i ) ;
}
return _settings_client . music . shuffle ;
}
static void StopMusic ( )
/** Return the current song, or a dummy if none */
MusicSystem : : PlaylistEntry MusicSystem : : GetCurrentSong ( ) const
{
_music_wnd_cursong = 0 ;
DoStopMusic ( ) ;
_song_is_active = false ;
SetWindowWidgetDirty ( WC_MUSIC_WINDOW , 0 , 9 ) ;
if ( ! this - > IsPlaying ( ) ) return PlaylistEntry ( BaseMusic : : GetUsedSet ( ) , 0 ) ;
return this - > active_playlist [ this - > playlist_position ] ;
}
/** Is one of the custom playlists selected? */
bool MusicSystem : : IsCustomPlaylist ( ) const
{
return ( this - > selected_playlist = = PLCH_CUSTOM1 ) | | ( this - > selected_playlist = = PLCH_CUSTOM2 ) ;
}
/**
* Append a song to a custom playlist .
* Always adds to the currently active playlist .
* @ param song_index Index of song in the current music set to add
*/
void MusicSystem : : PlaylistAdd ( size_t song_index )
{
if ( ! this - > IsCustomPlaylist ( ) ) return ;
/* Pick out song from the music set */
if ( song_index > = this - > music_set . size ( ) ) return ;
PlaylistEntry entry = this - > music_set [ song_index ] ;
/* Check for maximum length */
if ( this - > standard_playlists [ this - > selected_playlist ] . size ( ) > = NUM_SONGS_PLAYLIST ) return ;
/* Add it to the appropriate playlist, and the display */
this - > standard_playlists [ this - > selected_playlist ] . push_back ( entry ) ;
this - > displayed_playlist . push_back ( entry ) ;
/* Add it to the active playlist, if playback is shuffled select a random position to add at */
if ( this - > active_playlist . empty ( ) ) {
this - > active_playlist . push_back ( entry ) ;
if ( this - > IsPlaying ( ) ) this - > Play ( ) ;
} else if ( this - > IsShuffle ( ) ) {
/* Generate a random position between 0 and n (inclusive, new length) to insert at */
size_t maxpos = this - > displayed_playlist . size ( ) ;
size_t newpos = InteractiveRandom ( ) % maxpos ;
this - > active_playlist . insert ( this - > active_playlist . begin ( ) + newpos , entry ) ;
/* Make sure to shift up the current playback position if the song was inserted before it */
if ( ( int ) newpos < = this - > playlist_position ) this - > playlist_position + + ;
} else {
this - > active_playlist . push_back ( entry ) ;
}
this - > SaveCustomPlaylist ( this - > selected_playlist ) ;
InvalidateWindowData ( WC_MUSIC_TRACK_SELECTION , 0 ) ;
}
/** Begin playing the next song on the playlist */
static void PlayPlaylistSong ( )
/**
* Remove a song from a custom playlist .
* @ param song_index Index in the custom playlist to remove .
*/
void MusicSystem : : PlaylistRemove ( size_t song_index )
{
if ( _cur_playlist [ 0 ] = = 0 ) {
ResetPlaylist ( ) ;
/* if there is not songs in the playlist, it may indicate
* no file on the gm folder , or even no gm folder .
* Stop the playback , then */
if ( _cur_playlist [ 0 ] = = 0 ) {
_song_is_active = false ;
_music_wnd_cursong = 0 ;
_settings_client . music . playing = false ;
return ;
if ( ! this - > IsCustomPlaylist ( ) ) return ;
Playlist & pl = this - > standard_playlists [ this - > selected_playlist ] ;
if ( song_index > = pl . size ( ) ) return ;
/* Remove from "simple" playlists */
PlaylistEntry song = pl [ song_index ] ;
pl . erase ( pl . begin ( ) + song_index ) ;
this - > displayed_playlist . erase ( this - > displayed_playlist . begin ( ) + song_index ) ;
/* Find in actual active playlist (may be shuffled) and remove,
* if it ' s the current song restart playback */
for ( size_t i = 0 ; i < this - > active_playlist . size ( ) ; i + + ) {
Playlist : : iterator s2 = this - > active_playlist . begin ( ) + i ;
if ( s2 - > filename = = song . filename & & s2 - > cat_index = = song . cat_index ) {
this - > active_playlist . erase ( s2 ) ;
if ( ( int ) i = = this - > playlist_position & & this - > IsPlaying ( ) ) this - > Play ( ) ;
break ;
}
}
_music_wnd_cursong = _cur_playlist [ 0 ] ;
DoPlaySong ( ) ;
_song_is_active = true ;
SetWindowWidgetDirty ( WC_MUSIC_WINDOW , 0 , 9 ) ;
this - > SaveCustomPlaylist ( this - > selected_playlist ) ;
InvalidateWindowData ( WC_MUSIC_TRACK_SELECTION , 0 ) ;
}
void ResetMusic ( )
/**
* Remove all songs from the current custom playlist .
* Effectively stops playback too .
*/
void MusicSystem : : PlaylistClear ( )
{
_music_wnd_cursong = 1 ;
DoPlaySong ( ) ;
if ( ! this - > IsCustomPlaylist ( ) ) return ;
this - > standard_playlists [ this - > selected_playlist ] . clear ( ) ;
this - > ChangePlaylist ( this - > selected_playlist ) ;
this - > SaveCustomPlaylist ( this - > selected_playlist ) ;
}
/**
* Check music playback status and start / stop / song - finished .
* Called from main loop .
* Change playlist position pointer by the given offset , making sure to keep it within valid range .
* If the playlist is empty , position is always set to 0.
* @ param ofs Amount to move playlist position by .
*/
void MusicLoop ( )
void Music System: : ChangePlaylistPosition ( int ofs )
{
if ( ! _settings_client . music . playing & & _song_is_active ) {
StopMusic ( ) ;
} else if ( _settings_client . music . playing & & ! _song_is_active ) {
PlayPlaylistSong ( ) ;
if ( this - > active_playlist . empty ( ) ) {
this - > playlist_position = 0 ;
} else {
this - > playlist_position + = ofs ;
while ( this - > playlist_position > = ( int ) this - > active_playlist . size ( ) ) this - > playlist_position - = ( int ) this - > active_playlist . size ( ) ;
while ( this - > playlist_position < 0 ) this - > playlist_position + = ( int ) this - > active_playlist . size ( ) ;
}
}
if ( ! _song_is_active ) return ;
/**
* Save a custom playlist to settings after modification .
* @ param pl Playlist to store back
*/
void MusicSystem : : SaveCustomPlaylist ( PlaylistChoices pl )
{
byte * settings_pl ;
if ( pl = = PLCH_CUSTOM1 ) {
settings_pl = _settings_client . music . custom_1 ;
} else if ( pl = = PLCH_CUSTOM2 ) {
settings_pl = _settings_client . music . custom_2 ;
} else {
return ;
}
if ( ! MusicDriver : : GetInstance ( ) - > IsSongPlaying ( ) ) {
if ( _game_mode ! = GM_MENU ) {
StopMusic ( ) ;
SkipToNextSong ( ) ;
PlayPlaylistSong ( ) ;
} else {
ResetMusic ( ) ;
}
size_t num = 0 ;
MemSetT ( settings_pl , 0 , NUM_SONGS_PLAYLIST ) ;
for ( Playlist : : const_iterator song = this - > standard_playlists [ pl ] . begin ( ) ; song ! = this - > standard_playlists [ pl ] . end ( ) ; + + song ) {
/* Music set indices in the settings playlist are 1-based, 0 means unused slot */
settings_pl [ num + + ] = ( byte ) song - > set_index + 1 ;
}
}
static void SelectPlaylist ( byte list )
/**
* Check music playback status and start / stop / song - finished .
* Called from main loop .
*/
void MusicLoop ( )
{
_settings_client . music . playlist = list ;
InvalidateWindowData ( WC_MUSIC_TRACK_SELECTION , 0 ) ;
InvalidateWindowData ( WC_MUSIC_WINDOW , 0 ) ;
_music . CheckStatus ( ) ;
}
/**
@ -316,29 +432,20 @@ static void SelectPlaylist(byte list)
void ChangeMusicSet ( int index )
{
if ( BaseMusic : : GetIndexOfUsedSet ( ) = = index ) return ;
/* Resume playback after switching?
* Always if music is already playing , and also if the user is switching
* away from an empty music set .
* If the user switches away from an empty set , assume it ' s because they
* want to hear music now . */
bool shouldplay = _song_is_active | | ( BaseMusic : : GetUsedSet ( ) - > num_available = = 0 ) ;
StopMusic ( ) ;
const char * name = BaseMusic : : GetSet ( index ) - > name ;
BaseMusic : : SetSet ( name ) ;
free ( BaseMusic : : ini_set ) ;
BaseMusic : : ini_set = stredup ( name ) ;
InitializeMusic ( ) ;
ResetPlaylist ( ) ;
_settings_client . music . playing = shouldplay ;
_music . ChangeMusicSet ( name ) ;
}
InvalidateWindowData ( WC_MUSIC_TRACK_SELECTION , 0 ) ;
InvalidateWindowData ( WC_MUSIC_WINDOW , 0 ) ;
InvalidateWindowData ( WC_GAME_OPTIONS , WN_GAME_OPTIONS_GAME_OPTIONS , 0 , true ) ;
/**
* Prepare the music system for use .
* Called from \ c InitializeGame
*/
void InitializeMusic ( )
{
_music . BuildPlaylists ( ) ;
}
struct MusicTrackSelectionWindow : public Window {
MusicTrackSelectionWindow ( WindowDesc * desc , WindowNumber number ) : Window ( desc )
{
@ -395,13 +502,10 @@ struct MusicTrackSelectionWindow : public Window {
case WID_MTS_LIST_LEFT : case WID_MTS_LIST_RIGHT : {
Dimension d = { 0 , 0 } ;
for ( uint i = 0 ; i < NUM_SONGS_AVAILABLE ; i + + ) {
const char * song_name = GetSongName ( i ) ;
if ( StrEmpty ( song_name ) ) continue ;
SetDParam ( 0 , GetTrackNumber ( i ) ) ;
for ( MusicSystem : : Playlist : : const_iterator song = _music . music_set . begin ( ) ; song ! = _music . music_set . end ( ) ; + + song ) {
SetDParam ( 0 , song - > tracknr ) ;
SetDParam ( 1 , 2 ) ;
SetDParamStr ( 2 , GetSongName( i ) ) ;
SetDParamStr ( 2 , song - > songname ) ;
Dimension d2 = GetStringBoundingBox ( STR_PLAYLIST_TRACK_NAME ) ;
d . width = max ( d . width , d2 . width ) ;
d . height + = d2 . height ;
@ -421,13 +525,10 @@ struct MusicTrackSelectionWindow : public Window {
GfxFillRect ( r . left + 1 , r . top + 1 , r . right - 1 , r . bottom - 1 , PC_BLACK ) ;
int y = r . top + WD_FRAMERECT_TOP ;
for ( uint i = 0 ; i < NUM_SONGS_AVAILABLE ; i + + ) {
const char * song_name = GetSongName ( i ) ;
if ( StrEmpty ( song_name ) ) continue ;
SetDParam ( 0 , GetTrackNumber ( i ) ) ;
for ( MusicSystem : : Playlist : : const_iterator song = _music . music_set . begin ( ) ; song ! = _music . music_set . end ( ) ; + + song ) {
SetDParam ( 0 , song - > tracknr ) ;
SetDParam ( 1 , 2 ) ;
SetDParamStr ( 2 , song _ name) ;
SetDParamStr ( 2 , song - > songname ) ;
DrawString ( r . left + WD_FRAMERECT_LEFT , r . right - WD_FRAMERECT_RIGHT , y , STR_PLAYLIST_TRACK_NAME ) ;
y + = FONT_HEIGHT_SMALL ;
}
@ -438,11 +539,10 @@ struct MusicTrackSelectionWindow : public Window {
GfxFillRect ( r . left + 1 , r . top + 1 , r . right - 1 , r . bottom - 1 , PC_BLACK ) ;
int y = r . top + WD_FRAMERECT_TOP ;
for ( const byte * p = _playlists [ _settings_client . music . playlist ] ; * p ! = 0 ; p + + ) {
uint i = * p - 1 ;
SetDParam ( 0 , GetTrackNumber ( i ) ) ;
for ( MusicSystem : : Playlist : : const_iterator song = _music . music_set . begin ( ) ; song ! = _music . music_set . end ( ) ; + + song ) {
SetDParam ( 0 , song - > tracknr ) ;
SetDParam ( 1 , 2 ) ;
SetDParamStr ( 2 , GetSongName( i ) ) ;
SetDParamStr ( 2 , song- > songname ) ;
DrawString ( r . left + WD_FRAMERECT_LEFT , r . right - WD_FRAMERECT_RIGHT , y , STR_PLAYLIST_TRACK_NAME ) ;
y + = FONT_HEIGHT_SMALL ;
}
@ -456,42 +556,13 @@ struct MusicTrackSelectionWindow : public Window {
switch ( widget ) {
case WID_MTS_LIST_LEFT : { // add to playlist
int y = this - > GetRowFromWidget ( pt . y , widget , 0 , FONT_HEIGHT_SMALL ) ;
if ( _settings_client . music . playlist < 4 ) return ;
if ( ! IsInsideMM ( y , 0 , BaseMusic : : GetUsedSet ( ) - > num_available ) ) return ;
byte * p = _playlists [ _settings_client . music . playlist ] ;
for ( uint i = 0 ; i ! = NUM_SONGS_PLAYLIST - 1 ; i + + ) {
if ( p [ i ] = = 0 ) {
/* Find the actual song number */
for ( uint j = 0 ; j < NUM_SONGS_AVAILABLE ; j + + ) {
if ( GetTrackNumber ( j ) = = y + 1 ) {
p [ i ] = j + 1 ;
break ;
}
}
p [ i + 1 ] = 0 ;
this - > SetDirty ( ) ;
ResetPlaylist ( ) ;
break ;
}
}
_music . PlaylistAdd ( y ) ;
break ;
}
case WID_MTS_LIST_RIGHT : { // remove from playlist
int y = this - > GetRowFromWidget ( pt . y , widget , 0 , FONT_HEIGHT_SMALL ) ;
if ( _settings_client . music . playlist < 4 ) return ;
if ( ! IsInsideMM ( y , 0 , NUM_SONGS_PLAYLIST ) ) return ;
byte * p = _playlists [ _settings_client . music . playlist ] ;
for ( uint i = y ; i ! = NUM_SONGS_PLAYLIST - 1 ; i + + ) {
p [ i ] = p [ i + 1 ] ;
}
this - > SetDirty ( ) ;
ResetPlaylist ( ) ;
_music . PlaylistRemove ( y ) ;
break ;
}
@ -503,17 +574,12 @@ struct MusicTrackSelectionWindow : public Window {
}
case WID_MTS_CLEAR : // clear
for ( uint i = 0 ; _playlists [ _settings_client . music . playlist ] [ i ] ! = 0 ; i + + ) _playlists [ _settings_client . music . playlist ] [ i ] = 0 ;
this - > SetDirty ( ) ;
StopMusic ( ) ;
ResetPlaylist ( ) ;
_music . PlaylistClear ( ) ;
break ;
case WID_MTS_ALL : case WID_MTS_OLD : case WID_MTS_NEW :
case WID_MTS_EZY : case WID_MTS_CUSTOM1 : case WID_MTS_CUSTOM2 : // set playlist
SelectPlaylist ( widget - WID_MTS_ALL ) ;
StopMusic ( ) ;
ResetPlaylist ( ) ;
_music . ChangePlaylist ( ( MusicSystem : : PlaylistChoices ) ( widget - WID_MTS_ALL ) ) ;
break ;
}
}
@ -628,8 +694,8 @@ struct MusicWindow : public Window {
case WID_M_TRACK_NAME : {
Dimension d = GetStringBoundingBox ( STR_MUSIC_TITLE_NONE ) ;
for ( uint i = 0 ; i < NUM_SONGS_AVAILABLE ; i + + ) {
SetDParamStr ( 0 , GetSongName( i ) ) ;
for ( MusicSystem: : Playlist : : const_iterator song = _music . music_set . begin ( ) ; song ! = _music . music_set . end ( ) ; + + song ) {
SetDParamStr ( 0 , song- > songname ) ;
d = maxdim ( d , GetStringBoundingBox ( STR_MUSIC_TITLE_NAME ) ) ;
}
d . width + = WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT ;
@ -655,8 +721,8 @@ struct MusicWindow : public Window {
break ;
}
StringID str = STR_MUSIC_TRACK_NONE ;
if ( _ song_is_active ! = 0 & & _music_wnd_cursong ! = 0 ) {
SetDParam ( 0 , GetTrackNumber( _music_wnd_cursong - 1 ) ) ;
if ( _ music. IsPlaying ( ) ) {
SetDParam ( 0 , _music. GetCurrentSong ( ) . tracknr ) ;
SetDParam ( 1 , 2 ) ;
str = STR_MUSIC_TRACK_DIGIT ;
}
@ -669,9 +735,9 @@ struct MusicWindow : public Window {
StringID str = STR_MUSIC_TITLE_NONE ;
if ( BaseMusic : : GetUsedSet ( ) - > num_available = = 0 ) {
str = STR_MUSIC_TITLE_NOMUSIC ;
} else if ( _ song_is_active ! = 0 & & _music_wnd_cursong ! = 0 ) {
} else if ( _ music. IsPlaying ( ) ) {
str = STR_MUSIC_TITLE_NAME ;
SetDParamStr ( 0 , GetSongName( _music_wnd_cursong - 1 ) ) ;
SetDParamStr ( 0 , _music. GetCurrentSong ( ) . songname ) ;
}
DrawString ( r . left + WD_FRAMERECT_LEFT , r . right - WD_FRAMERECT_RIGHT , r . top + WD_FRAMERECT_TOP , str , TC_FROMSTRING , SA_HOR_CENTER ) ;
break ;
@ -711,23 +777,19 @@ struct MusicWindow : public Window {
{
switch ( widget ) {
case WID_M_PREV : // skip to prev
if ( ! _song_is_active ) return ;
SkipToPrevSong ( ) ;
this - > SetDirty ( ) ;
_music . Prev ( ) ;
break ;
case WID_M_NEXT : // skip to next
if ( ! _song_is_active ) return ;
SkipToNextSong ( ) ;
this - > SetDirty ( ) ;
_music . Next ( ) ;
break ;
case WID_M_STOP : // stop playing
_ settings_client. music . playing = false ;
_ music. Stop ( ) ;
break ;
case WID_M_PLAY : // start playing
_ settings_client. music . playing = true ;
_ music. Play ( ) ;
break ;
case WID_M_MUSIC_VOL : case WID_M_EFFECT_VOL : { // volume sliders
@ -742,7 +804,7 @@ struct MusicWindow : public Window {
if ( new_vol < 3 ) new_vol = 0 ;
if ( new_vol ! = * vol ) {
* vol = new_vol ;
if ( widget = = WID_M_MUSIC_VOL ) Music VolumeChanged ( new_vol ) ;
if ( widget = = WID_M_MUSIC_VOL ) Music Driver: : GetInstance ( ) - > Set Volume( new_vol ) ;
this - > SetDirty ( ) ;
}
@ -751,12 +813,13 @@ struct MusicWindow : public Window {
}
case WID_M_SHUFFLE : // toggle shuffle
_settings_client . music . shuffle ^ = 1 ;
this - > SetWidgetLoweredState ( WID_M_SHUFFLE , _settings_client . music . shuffle ) ;
if ( _music . IsShuffle ( ) ) {
_music . Unshuffle ( ) ;
} else {
_music . Shuffle ( ) ;
}
this - > SetWidgetLoweredState ( WID_M_SHUFFLE , _music . IsShuffle ( ) ) ;
this - > SetWidgetDirty ( WID_M_SHUFFLE ) ;
StopMusic ( ) ;
ResetPlaylist ( ) ;
this - > SetDirty ( ) ;
break ;
case WID_M_PROGRAMME : // show track selection
@ -765,10 +828,7 @@ struct MusicWindow : public Window {
case WID_M_ALL : case WID_M_OLD : case WID_M_NEW :
case WID_M_EZY : case WID_M_CUSTOM1 : case WID_M_CUSTOM2 : // playlist
SelectPlaylist ( widget - WID_M_ALL ) ;
StopMusic ( ) ;
ResetPlaylist ( ) ;
this - > SetDirty ( ) ;
_music . ChangePlaylist ( ( MusicSystem : : PlaylistChoices ) ( widget - WID_M_ALL ) ) ;
break ;
}
}