diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt index 8411fd121c..c46d1855ea 100644 --- a/Docs/Changelog_sm5.txt +++ b/Docs/Changelog_sm5.txt @@ -6,9 +6,11 @@ ________________________________________________________________________________ 2015/03/01 ---------- -* [SelectMusic] Select Music now plays preview.ogg for a simfile if it exists - instead of using the song file for the sample music. The sample length - from the simfile is used and the sample start is treated as 0. [kyzentun] +* [SelectMusic] Select Music now plays music file named by #PREVIEW tag if + it's not blank, instead of using the song file for the sample music. The + sample length from the simfile is used and the sample start is treated as + 0. [kyzentun] +* [Song] GetPreviewMusicPath added. [kyzentun] * [foreach] foreach_ordered lua function now works on tables that have both number and string keys. Number keys are iterated over first. [kyzentun] diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml index 9fe1ca6ca5..90403dbf74 100644 --- a/Docs/Luadoc/Lua.xml +++ b/Docs/Luadoc/Lua.xml @@ -1542,6 +1542,7 @@ + diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml index 4da6fdb346..faee212099 100644 --- a/Docs/Luadoc/LuaDocumentation.xml +++ b/Docs/Luadoc/LuaDocumentation.xml @@ -4464,6 +4464,9 @@ save yourself some time, copy this for undocumented things: Gets the Song's origin. + + Returns the path to the Song's preview music. This handles the #PREVIEW tag internally, so it works with songs that use it and songs that don't. + Returns the path to the Song's preview video, if it exists. (Returns nil otherwise.) diff --git a/Themes/_fallback/Languages/en.ini b/Themes/_fallback/Languages/en.ini index 8f23a9e5c8..6d8c5aad46 100644 --- a/Themes/_fallback/Languages/en.ini +++ b/Themes/_fallback/Languages/en.ini @@ -1142,6 +1142,7 @@ Predicted Meter=Predicted Meter Preferences=Preferences PreloadSounds=Preload Sounds Premium=Premium +Preview=Preview Preview Length=Preview Length Preview Start=Preview Start Export Packages=Export Packages @@ -1497,6 +1498,7 @@ Enter a new artist transliteration.=Enter a new artist transliteration. Enter a new artist.=Enter a new artist. Enter a new genre.=Enter a new genre. Enter a new credit.=Enter a new credit. +Enter a preview file.=Enter a preview file. Enter a new description.=Enter a new description. Enter a new chart name.=Enter the name/title of this chart. Enter a new chart style.=Enter a new chart style (e.g. "Pad", "Keyboard"). @@ -1997,6 +1999,7 @@ The name you chose conflicts with another edit. Please use a different name.=The The chart name cannot contain any of the following characters: %s=The chart name cannot contain any of the following characters: %s The edit name cannot contain any of the following characters: %s=The edit name can not contain any of the following characters: %s The step author's name cannot contain any of the following characters: %s=The step author's name cannot contain any of the following characters: %s +The preview file '%s' does not exist.=The preview file '%s' does not exist. [SongSort] FewestPlays=Fewest Plays diff --git a/src/NotesLoaderSSC.cpp b/src/NotesLoaderSSC.cpp index 5f1d084dfb..ca647b5c55 100644 --- a/src/NotesLoaderSSC.cpp +++ b/src/NotesLoaderSSC.cpp @@ -426,6 +426,11 @@ bool SSCLoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach out.m_sMusicFile = sParams[1]; } + else if(sValueName == "PREVIEW") + { + out.m_PreviewFile= sParams[1]; + } + else if( sValueName=="INSTRUMENTTRACK" ) { SMLoader::ProcessInstrumentTracks( out, sParams[1] ); diff --git a/src/NotesWriterSSC.cpp b/src/NotesWriterSSC.cpp index 1f5971f149..9e373edbe9 100644 --- a/src/NotesWriterSSC.cpp +++ b/src/NotesWriterSSC.cpp @@ -230,6 +230,10 @@ static void WriteGlobalTags( RageFile &f, const Song &out ) f.PutLine( ssprintf( "#LYRICSPATH:%s;", SmEscape(out.m_sLyricsFile).c_str() ) ); f.PutLine( ssprintf( "#CDTITLE:%s;", SmEscape(out.m_sCDTitleFile).c_str() ) ); f.PutLine( ssprintf( "#MUSIC:%s;", SmEscape(out.m_sMusicFile).c_str() ) ); + if(!out.m_PreviewFile.empty()) + { + f.PutLine(ssprintf("#PREVIEW:%s;", SmEscape(out.m_PreviewFile).c_str())); + } { vector vs = out.GetInstrumentTracksToVectorString(); diff --git a/src/ScreenEdit.cpp b/src/ScreenEdit.cpp index 3caf613f97..763f50fbd2 100644 --- a/src/ScreenEdit.cpp +++ b/src/ScreenEdit.cpp @@ -952,6 +952,9 @@ static MenuDef g_SongInformation( MenuRowDef(ScreenEdit::credit, "Credit", true, EditMode_Practice, true, true, 0, NULL ), + MenuRowDef(ScreenEdit::preview, + "Preview", + true, EditMode_Full, true, true, 0, NULL ), MenuRowDef(ScreenEdit::main_title_transliteration, "Main title transliteration", true, EditMode_Practice, true, true, 0, NULL ), @@ -1477,10 +1480,10 @@ void ScreenEdit::PlayPreviewMusic() { SOUND->StopMusic(); SOUND->PlayMusic( - m_pSong->GetMusicPath(), + m_pSong->GetPreviewMusicPath(), NULL, false, - m_pSong->m_fMusicSampleStartSeconds, + m_pSong->GetPreviewStartSeconds(), m_pSong->m_fMusicSampleLengthSeconds, FADE_IN_PREVIEW, FADE_OUT_PREVIEW ); @@ -4318,6 +4321,12 @@ static void ChangeCredit( const RString &sNew ) pSong->m_sCredit = sNew; } +static void ChangePreview(const RString& sNew) +{ + Song* pSong = GAMESTATE->m_pCurSong; + pSong->m_PreviewFile= sNew; +} + static void ChangeMainTitleTranslit( const RString &sNew ) { Song* pSong = GAMESTATE->m_pCurSong; @@ -4707,6 +4716,7 @@ void ScreenEdit::HandleMainMenuChoice( MainMenuChoice c, const vector &iAns g_SongInformation.rows[artist].SetOneUnthemedChoice( pSong->m_sArtist ); g_SongInformation.rows[genre].SetOneUnthemedChoice( pSong->m_sGenre ); g_SongInformation.rows[credit].SetOneUnthemedChoice( pSong->m_sCredit ); + g_SongInformation.rows[preview].SetOneUnthemedChoice(pSong->m_PreviewFile); g_SongInformation.rows[main_title_transliteration].SetOneUnthemedChoice( pSong->m_sMainTitleTranslit ); g_SongInformation.rows[sub_title_transliteration].SetOneUnthemedChoice( pSong->m_sSubTitleTranslit ); g_SongInformation.rows[artist_transliteration].SetOneUnthemedChoice( pSong->m_sArtistTranslit ); @@ -5419,6 +5429,7 @@ static LocalizedString ENTER_SUB_TITLE ("ScreenEdit","Enter a new sub title.") static LocalizedString ENTER_ARTIST ("ScreenEdit","Enter a new artist."); static LocalizedString ENTER_GENRE ("ScreenEdit","Enter a new genre."); static LocalizedString ENTER_CREDIT ("ScreenEdit","Enter a new credit."); +static LocalizedString ENTER_PREVIEW ("ScreenEdit", "Enter a preview file."); static LocalizedString ENTER_MAIN_TITLE_TRANSLIT ("ScreenEdit","Enter a new main title transliteration."); static LocalizedString ENTER_SUB_TITLE_TRANSLIT ("ScreenEdit","Enter a new sub title transliteration."); static LocalizedString ENTER_ARTIST_TRANSLIT ("ScreenEdit","Enter a new artist transliteration."); @@ -5447,6 +5458,9 @@ void ScreenEdit::HandleSongInformationChoice( SongInformationChoice c, const vec case credit: ScreenTextEntry::TextEntry( SM_None, ENTER_CREDIT, pSong->m_sCredit, 100, NULL, ChangeCredit, NULL ); break; + case preview: + ScreenTextEntry::TextEntry(SM_None, ENTER_PREVIEW, pSong->m_PreviewFile, 100, SongUtil::ValidateCurrentSongPreview, ChangePreview, NULL); + break; case main_title_transliteration: ScreenTextEntry::TextEntry( SM_None, ENTER_MAIN_TITLE_TRANSLIT, pSong->m_sMainTitleTranslit, 100, NULL, ChangeMainTitleTranslit, NULL ); break; diff --git a/src/ScreenEdit.h b/src/ScreenEdit.h index 73958de654..51832b79f7 100644 --- a/src/ScreenEdit.h +++ b/src/ScreenEdit.h @@ -568,6 +568,7 @@ public: artist, genre, credit, + preview, main_title_transliteration, sub_title_transliteration, artist_transliteration, diff --git a/src/ScreenManager.cpp b/src/ScreenManager.cpp index 230b6a186f..762dc7a58a 100644 --- a/src/ScreenManager.cpp +++ b/src/ScreenManager.cpp @@ -742,7 +742,12 @@ void ScreenManager::LoadDelayedScreen() // Screens may not call SetNewScreen from the ctor or Init(). (We don't do this // check inside PrepareScreen; that may be called from a thread for concurrent // loading, and the main thread may call SetNewScreen during that time.) - ASSERT_M( m_sDelayedScreen.empty(), m_sDelayedScreen ); + // Emit an error instead of asserting. -Kyz + if(!m_sDelayedScreen.empty()) + { + LuaHelpers::ReportScriptError("Setting a new screen during an InitCommand is not allowed."); + m_sDelayedScreen= ""; + } bLoaded = ActivatePreparedScreenAndBackground( sScreenName ); ASSERT( bLoaded ); diff --git a/src/ScreenNetSelectMusic.cpp b/src/ScreenNetSelectMusic.cpp index a6a7ac04ba..d153d7f387 100644 --- a/src/ScreenNetSelectMusic.cpp +++ b/src/ScreenNetSelectMusic.cpp @@ -548,10 +548,10 @@ void ScreenNetSelectMusic::MusicChanged() { SOUND->StopMusic(); SOUND->PlayMusic( - GAMESTATE->m_pCurSong->GetMusicPath(), + GAMESTATE->m_pCurSong->GetPreviewMusicPath(), NULL, true, - GAMESTATE->m_pCurSong->m_fMusicSampleStartSeconds, + GAMESTATE->m_pCurSong->GetPreviewStartSeconds(), GAMESTATE->m_pCurSong->m_fMusicSampleLengthSeconds ); } } diff --git a/src/ScreenWithMenuElements.cpp b/src/ScreenWithMenuElements.cpp index e935cd31ef..88dd8f88f6 100644 --- a/src/ScreenWithMenuElements.cpp +++ b/src/ScreenWithMenuElements.cpp @@ -79,17 +79,14 @@ void ScreenWithMenuElements::Init() // decorations { - AutoActor decorations; - decorations.LoadB( m_sName, "decorations" ); - decorations->SetName("Decorations"); - decorations->SetDrawOrder( DRAW_ORDER_DECORATIONS ); - ActorFrame *pFrame = dynamic_cast(static_cast(decorations)); + m_Decorations.LoadB( m_sName, "decorations" ); + m_Decorations->SetName("Decorations"); + m_Decorations->SetDrawOrder( DRAW_ORDER_DECORATIONS ); + ActorFrame *pFrame = dynamic_cast(static_cast(m_Decorations)); if( pFrame ) { - m_vDecorations = pFrame->GetChildren(); - FOREACH( Actor*, m_vDecorations, child ) - this->AddChild( *child ); - pFrame->RemoveAllChildren(); + this->AddChild(m_Decorations); + LOAD_ALL_COMMANDS(m_Decorations); } } @@ -167,8 +164,6 @@ ScreenWithMenuElements::~ScreenWithMenuElements() if( m_MemoryCardDisplay[p] != NULL ) SAFE_DELETE( m_MemoryCardDisplay[p] ); } - FOREACH( Actor*, m_vDecorations, actor ) - delete *actor; } void ScreenWithMenuElements::SetHelpText( RString s ) diff --git a/src/ScreenWithMenuElements.h b/src/ScreenWithMenuElements.h index 3b5497e49e..f424d35bbd 100644 --- a/src/ScreenWithMenuElements.h +++ b/src/ScreenWithMenuElements.h @@ -45,7 +45,7 @@ protected: MemoryCardDisplay *m_MemoryCardDisplay[NUM_PLAYERS]; MenuTimer *m_MenuTimer; AutoActor m_sprOverlay; - vector m_vDecorations; + AutoActor m_Decorations; Transition m_In; Transition m_Out; diff --git a/src/Song.cpp b/src/Song.cpp index 343a61009c..3d7148d13f 100644 --- a/src/Song.cpp +++ b/src/Song.cpp @@ -43,7 +43,7 @@ * @brief The internal version of the cache for StepMania. * * Increment this value to invalidate the current cache. */ -const int FILE_CACHE_VERSION = 222; +const int FILE_CACHE_VERSION = 223; /** @brief How long does a song sample last by default? */ const float DEFAULT_MUSIC_SAMPLE_LENGTH = 12.f; @@ -1479,22 +1479,20 @@ RString Song::GetPreviewVidPath() const RString Song::GetPreviewMusicPath() const { - RString preview= GetSongDir() + "preview.ogg"; - if(FILEMAN->DoesFileExist(preview)) + if(m_PreviewFile.empty()) { - return preview; + return GetMusicPath(); } - return GetMusicPath(); + return GetSongAssetPath(m_PreviewFile, m_sSongDir); } float Song::GetPreviewStartSeconds() const { - RString preview= GetSongDir() + "preview.ogg"; - if(FILEMAN->DoesFileExist(preview)) + if(m_PreviewFile.empty()) { - return 0.0f; + return m_fMusicSampleStartSeconds; } - return m_fMusicSampleStartSeconds; + return 0.0f; } RString Song::GetDisplayMainTitle() const @@ -1814,6 +1812,12 @@ public: lua_pushnil(L); return 1; } + static int GetPreviewMusicPath(T* p, lua_State* L) + { + RString s= p->GetPreviewMusicPath(); + lua_pushstring(L, s); + return 1; + } static int GetJacketPath( T* p, lua_State *L ) { RString s = p->GetJacketPath(); @@ -1886,7 +1890,7 @@ public: } static int GetSampleStart( T* p, lua_State *L ) { - lua_pushnumber(L, p->m_fMusicSampleStartSeconds); + lua_pushnumber(L, p->GetPreviewStartSeconds()); return 1; } static int GetSampleLength( T* p, lua_State *L ) @@ -2128,6 +2132,7 @@ public: ADD_METHOD( ShowInDemonstrationAndRanking ); ADD_METHOD( HasPreviewVid ); ADD_METHOD( GetPreviewVidPath ); + ADD_METHOD(GetPreviewMusicPath); } }; diff --git a/src/Song.h b/src/Song.h index 76c1bd360d..212219c2e5 100644 --- a/src/Song.h +++ b/src/Song.h @@ -224,6 +224,7 @@ public: RString m_sOrigin; // song origin (for .ssc format) RString m_sMusicFile; + RString m_PreviewFile; RString m_sInstrumentTrackFile[NUM_InstrumentTrack]; /** @brief The length of the music file. */ diff --git a/src/SongUtil.cpp b/src/SongUtil.cpp index e5017a44ec..5827f5abb9 100644 --- a/src/SongUtil.cpp +++ b/src/SongUtil.cpp @@ -899,6 +899,24 @@ bool SongUtil::ValidateCurrentStepsCredit( const RString &sAnswer, RString &sErr return true; } +static LocalizedString PREVIEW_DOES_NOT_EXIST("SongUtil", "The preview file '%s' does not exist."); +bool SongUtil::ValidateCurrentSongPreview(const RString& answer, RString& error) +{ + if(answer.empty()) + { return true; } + Song* song= GAMESTATE->m_pCurSong; + RString real_file= song->m_PreviewFile; + song->m_PreviewFile= answer; + RString path= song->GetPreviewMusicPath(); + bool valid= DoesFileExist(path); + song->m_PreviewFile= real_file; + if(!valid) + { + error= ssprintf(PREVIEW_DOES_NOT_EXIST.GetValue(), answer.c_str()); + } + return valid; +} + void SongUtil::GetAllSongGenres( vector &vsOut ) { set genres; diff --git a/src/SongUtil.h b/src/SongUtil.h index 97ea6e5616..827f86812e 100644 --- a/src/SongUtil.h +++ b/src/SongUtil.h @@ -165,6 +165,7 @@ namespace SongUtil bool ValidateCurrentStepsDescription( const RString &sAnswer, RString &sErrorOut ); bool ValidateCurrentStepsCredit( const RString &sAnswer, RString &sErrorOut ); bool ValidateCurrentStepsChartName(const RString &answer, RString &error); + bool ValidateCurrentSongPreview(const RString& answer, RString& error); void GetAllSongGenres( vector &vsOut ); /**