aboutsummaryrefslogtreecommitdiffstats
path: root/src/screens
diff options
context:
space:
mode:
authorbasisbit <basisbit@b956fd51-792f-4845-bead-9b4dfca2ff2c>2015-08-28 01:45:23 +0000
committerbasisbit <basisbit@b956fd51-792f-4845-bead-9b4dfca2ff2c>2015-08-28 01:45:23 +0000
commitebac563f0f8f4fba120cee79e8e6a7973e394677 (patch)
tree66c330cf4c5dbe0d3b618d2eb1ae25f0dff338c7 /src/screens
parent5eadb894728d5a285e0272c007bdeeb0d5bdf59d (diff)
downloadusdx-ebac563f0f8f4fba120cee79e8e6a7973e394677.tar.gz
usdx-ebac563f0f8f4fba120cee79e8e6a7973e394677.tar.xz
usdx-ebac563f0f8f4fba120cee79e8e6a7973e394677.zip
* first usable implementation of the JukeBox mode, work in progress - you can start it by pressing "j" in the main menu
git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@3128 b956fd51-792f-4845-bead-9b4dfca2ff2c
Diffstat (limited to 'src/screens')
-rw-r--r--src/screens/UScreenJukebox.pas1809
-rw-r--r--src/screens/UScreenMain.pas23
2 files changed, 1831 insertions, 1 deletions
diff --git a/src/screens/UScreenJukebox.pas b/src/screens/UScreenJukebox.pas
new file mode 100644
index 00000000..de35bc2a
--- /dev/null
+++ b/src/screens/UScreenJukebox.pas
@@ -0,0 +1,1809 @@
+{* UltraStar Deluxe - Karaoke Game
+ *
+ * UltraStar Deluxe is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $URL: $
+ * $Id: $
+ *}
+
+unit UScreenJukebox;
+
+interface
+
+{$IFDEF FPC}
+ {$MODE Delphi}
+{$ENDIF}
+
+{$I switches.inc}
+
+uses
+ SysUtils,
+ SDL,
+ TextGL,
+ gl,
+ UCommon,
+ UFiles,
+ UGraphicClasses,
+ UIni,
+ ULog,
+ ULyrics,
+ UMenu,
+ UMusic,
+ UPlaylist,
+ USingScores,
+ USongs,
+ UTexture,
+ UThemes,
+ UPath,
+ UTime,
+ UHookableEvent,
+ UVideo;
+
+type
+ TSongJukebox = class
+ public
+ Id: integer;
+
+ // sorting methods
+ Genre: UTF8String;
+ Edition: UTF8String;
+ Language: UTF8String;
+ Year: Integer;
+
+ Title: UTF8String;
+ Artist: UTF8String;
+
+ end;
+
+ THandler = record
+ changed: boolean;
+ change_time: real;
+ end;
+
+ TLyricsSyncSource = class(TSyncSource)
+ function GetClock(): real; override;
+ end;
+
+ TMusicSyncSource = class(TSyncSource)
+ function GetClock(): real; override;
+ end;
+
+ TTimebarMode = (
+ tbmCurrent, // current song position
+ tbmRemaining, // remaining time
+ tbmTotal // total time
+ );
+
+type
+ TScreenJukebox = class(TMenu)
+ private
+ // items
+ JukeboxStaticTimeProgress: integer;
+ JukeboxStaticTimeBackground: integer;
+ JukeboxStaticSongBackground: integer;
+ JukeboxStaticSongListBackground: integer;
+ SongDescription: array[0..9] of integer;
+
+ SelectColR: real;
+ SelectColG: real;
+ SelectColB: real;
+
+ // options desc
+ JukeboxStaticOptions: integer;
+ JukeboxTextOptionsSongPosition: integer;
+ JukeboxTextOptionsLyric: integer;
+ JukeboxTextOptionsRandom: integer;
+ JukeboxTextOptionsRepeat: integer;
+ JukeboxTextOptionsFind: integer;
+ JukeboxTextOptionsSort: integer;
+
+ JukeboxTextTimeText: integer;
+ JukeboxTextTimeDesc: integer;
+ //JukeboxTextSongText: integer;
+
+ SongFinish: boolean;
+
+ tmpLyricsUpperY: real;
+ tmpLyricsLowerY: real;
+ //tmp_mouse: integer;
+
+ LyricsStart: boolean;
+
+ JukeboxFindSong: integer;
+ JukeboxRepeatSongList: integer;
+ JukeboxSongListOrder: integer;
+ JukeboxRandomSongList: integer;
+ JukeboxListText: integer;
+ JukeboxCountText: integer;
+ JukeboxLyric: integer;
+
+ Filter: UTF8String;
+
+ FindSongList: boolean;
+ RepeatSongList: boolean;
+ RandomMode: boolean;
+ OrderMode: boolean;
+ OrderType: integer;
+
+ fShowVisualization: boolean;
+ fCurrentVideo: IVideo;
+ fVideoClip: IVideo;
+ fLyricsSync: TLyricsSyncSource;
+ fMusicSync: TMusicSyncSource;
+ fTimebarMode: TTimebarMode;
+
+ protected
+ eSongLoaded: THookableEvent; //< event is called after lyrics of a song are loaded on OnShow
+ Paused: boolean; //pause Mod
+ NumEmptySentences: integer;
+ public
+ ShowLyrics: boolean;
+ CurrentSongList: integer;
+ LastTick: cardinal;
+ SongListVisible: boolean;
+
+ ChangePosition: integer;
+
+ JukeboxSongsList: array of integer;
+ JukeboxVisibleSongs: array of integer;
+
+ ActualInteraction: integer;
+ ListMin: integer;
+ CurrentSongID: integer;
+
+ //VideoAspect
+ VideoAspectText: integer;
+ VideoAspectStatic: integer;
+ AspectHandler: THandler;
+ AspectCorrection: TAspectCorrection;
+
+ StaticPausePopup: integer;
+
+ Tex_Background: TTexture;
+ FadeOut: boolean;
+ Lyrics: TLyricEngine;
+
+ StaticCover: integer;
+
+ constructor Create; override;
+ procedure OnShow; override;
+ procedure OnShowFinish; override;
+ procedure OnHide; override;
+
+ function ParseInput(PressedKey: cardinal; CharCode: UCS4Char;
+ PressedDown: boolean): boolean; override;
+ function Draw: boolean; override;
+ procedure DrawBlackBars();
+ procedure DrawItems();
+
+ procedure PlayMusic(ID: integer);
+ procedure Play;
+ procedure Finish;
+ procedure Pause; // toggle pause
+
+ procedure OnSentenceEnd(SentenceIndex: cardinal); // for linebonus + singbar
+ procedure OnSentenceChange(SentenceIndex: cardinal); // for golden notes
+
+ //procedure DeleteSong(Id: integer);
+ procedure FilterSongList(Filter: UTF8String);
+ procedure SongListSort(Order: integer);
+ procedure Sort(Order: integer);
+ procedure Reset;
+
+ procedure AddSongToJukeboxList(ID: integer);
+ function FinishedMusic: boolean;
+
+ procedure RefreshCover;
+ procedure DrawPlaylist;
+ end;
+
+implementation
+
+uses
+ Classes,
+ Math,
+ UDraw,
+ UGraphic,
+ ULanguage,
+ UNote,
+ URecord,
+ USong,
+ UDisplay,
+ UParty,
+ UScreenSong,
+ UUnicodeUtils;
+
+procedure TScreenJukebox.DrawBlackBars();
+var
+ X, X1, Y, Y1, Z, H, W: double;
+begin
+ fCurrentVideo.GetScreenPosition(X, Y, Z);
+
+ // Upper
+ X1 := 0;
+ Y1 := 0;
+ H := Y + 1;
+ W := 800;
+
+ glColor4f(0, 0, 0, 1);
+ glbegin(gl_quads);
+ glVertex2f(X1, Y1);
+ glVertex2f(X1, Y1 + H);
+ glVertex2f(X1 + W, Y1 + H);
+ glVertex2f(X1 + W, Y1);
+ glEnd;
+
+ // Bottom
+ X1 := 0;
+ Y1 := 600;
+ H := Y + 1;
+ W := 800;
+
+ glColor4f(0, 0, 0, 1);
+ glbegin(gl_quads);
+ glVertex2f(X1, Y1);
+ glVertex2f(X1, Y1 - H);
+ glVertex2f(X1 + W, Y1 - H);
+ glVertex2f(X1 + W, Y1);
+ glEnd;
+
+ // Left
+ X1 := 0;
+ Y1 := 0;
+ H := 600;
+ W := X + 1;
+
+ glColor4f(0, 0, 0, 1);
+ glbegin(gl_quads);
+ glVertex2f(X1, Y1);
+ glVertex2f(X1, Y1 + H);
+ glVertex2f(X1 + W, Y1 + H);
+ glVertex2f(X1 + W, Y1);
+ glEnd;
+
+ // Right
+ X1 := 800;
+ Y1 := 0;
+ H := 600;
+ W := X + 1;
+
+ glColor4f(0, 0, 0, 1);
+ glbegin(gl_quads);
+ glVertex2f(X1, Y1);
+ glVertex2f(X1, Y1 + H);
+ glVertex2f(X1 - W, Y1 + H);
+ glVertex2f(X1 - W, Y1);
+ glEnd;
+
+end;
+
+procedure TScreenJukebox.SongListSort(Order: integer);
+begin
+
+ case Order of
+ 1 : begin
+ Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_ARTIST');
+ Sort(2);
+ Sort(1);
+ end;
+ 2 : begin
+ Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_TITLE');
+ Sort(1);
+ Sort(2);
+ end;
+ 3 : begin
+ Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_EDITION');
+ Sort(2);
+ Sort(1);
+ Sort(3);
+ end;
+ 4 : begin
+ Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_GENRE');
+ Sort(2);
+ Sort(1);
+ Sort(4);
+ end;
+ 5 : begin
+ Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_LANGUAGE');
+ Sort(2);
+ Sort(1);
+ Sort(5);
+ end;
+ end;
+
+end;
+
+procedure TScreenJukebox.Sort(Order: integer);
+var
+ I, J, X, Tmp, Comp: integer;
+ Text: UTF8String;
+ NotEnd: boolean;
+begin
+
+ for I:= 0 to High(JukeboxVisibleSongs) do
+ begin
+ J := I;
+ X := JukeboxVisibleSongs[I];
+ NotEnd := true;
+ while (J > 0) and (NotEnd) do
+ begin
+
+ case Order of
+ 1 : Comp := UTF8CompareText(CatSongs.Song[X].Artist, CatSongs.Song[JukeboxVisibleSongs[J - 1]].Artist);
+ 2 : Comp := UTF8CompareText(CatSongs.Song[X].Title, CatSongs.Song[JukeboxVisibleSongs[J - 1]].Title);
+ 3 : Comp := UTF8CompareText(CatSongs.Song[X].Edition, CatSongs.Song[JukeboxVisibleSongs[J - 1]].Edition);
+ 4 : Comp := UTF8CompareText(CatSongs.Song[X].Genre, CatSongs.Song[JukeboxVisibleSongs[J - 1]].Genre);
+ 5 : Comp := UTF8CompareText(CatSongs.Song[X].Language, CatSongs.Song[JukeboxVisibleSongs[J - 1]].Language);
+ end;
+
+ if (Comp < 0) then
+ begin
+ JukeboxVisibleSongs[J] := JukeboxVisibleSongs[J - 1];
+ J := J - 1;
+ end
+ else
+ NotEnd := false;
+ end;
+
+ JukeboxVisibleSongs[J] := X;
+ end;
+end;
+
+procedure TScreenJukebox.FilterSongList(Filter: UTF8String);
+var
+ I: integer;
+ SongD: UTF8String;
+begin
+
+ if (Filter <> '') then
+ begin
+ SetLength(JukeboxVisibleSongs, 0);
+ for I := 0 to High(JukeboxSongsList) do
+ begin
+ SongD := CatSongs.Song[JukeboxSongsList[I]].Artist + ' - ' + CatSongs.Song[JukeboxSongsList[I]].Title;
+
+ if (UTF8ContainsStr(UTF8UpperCase(SongD), UTF8UpperCase(Filter))) then
+ begin
+ SetLength(JukeboxVisibleSongs, Length(JukeboxVisibleSongs) + 1);
+ JukeboxVisibleSongs[High(JukeboxVisibleSongs)] := JukeboxSongsList[I];
+ end;
+ end;
+ end
+ else
+ begin
+ SetLength(JukeboxVisibleSongs, 0);
+
+ for I := 0 to High(JukeboxSongsList) do
+ begin
+ SetLength(JukeboxVisibleSongs, Length(JukeboxVisibleSongs) + 1);
+ JukeboxVisibleSongs[High(JukeboxVisibleSongs)] := JukeboxSongsList[I];
+ end;
+ end;
+
+ ActualInteraction := 0;
+ Interaction := 0;
+ ListMin := 0;
+end;
+
+{
+procedure TScreenJukebox.DeleteSong(Id: integer);
+var
+ I: integer;
+ JukeboxSongsListTmp: array of integer;
+ JukeboxVisibleSongsTmp: array of integer;
+begin
+
+ SetLength(JukeboxSongsListTmp, 0);
+
+ for I := 0 to High(JukeboxSongsList) do
+ begin
+ if (I <> Id) then
+ begin
+ SetLength(JukeboxSongsListTmp, Length(JukeboxSongsListTmp) + 1);
+ JukeboxSongsListTmp[High(JukeboxSongsListTmp)] := JukeboxSongsList[I];
+ end;
+ end;
+
+ SetLength(JukeboxSongsList, Length(JukeboxSongsListTmp));
+ for I := 0 to High(JukeboxSongsListTmp) do
+ JukeboxSongsList[I] := JukeboxSongsListTmp[I];
+
+ SetLength(JukeboxVisibleSongsTmp, 0);
+ for I := 0 to High(JukeboxVisibleSongs) do
+ begin
+ if (I <> Id) then
+ begin
+ SetLength(JukeboxVisibleSongsTmp, Length(JukeboxVisibleSongsTmp) + 1);
+ JukeboxVisibleSongsTmp[High(JukeboxVisibleSongsTmp)] := JukeboxVisibleSongs[I];
+ end;
+ end;
+
+ SetLength(JukeboxVisibleSongs, Length(JukeboxVisibleSongsTmp));
+ for I := 0 to High(JukeboxVisibleSongsTmp) do
+ JukeboxVisibleSongs[I] := JukeboxVisibleSongsTmp[I];
+
+
+// ActualInteraction := 0;
+// Interaction := 0;
+// ListMin := 0;
+end;
+}
+
+procedure TScreenJukebox.Reset;
+begin
+ CurrentSongList := 0;
+
+ Interaction := 0;
+ ActualInteraction := 0;
+ ListMin := 0;
+ //RepeatSongList := false;
+ RandomMode := false;
+ OrderMode := true;
+ FindSongList := false;
+ Filter := '';
+ ShowLyrics := true;
+
+ Button[JukeboxSongListOrder].SetSelect(true);
+
+ case (Ini.Sorting) of
+ 5: begin
+ OrderType := 1;
+ Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_ARTIST');
+ end;
+ 6: begin
+ OrderType := 2;
+ Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_TITLE');
+ end;
+ 0: begin
+ OrderType := 3;
+ Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_EDITION');
+ end;
+ 1: begin
+ OrderType := 4;
+ Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_GENRE');
+ end;
+ 2: begin
+ OrderType := 5;
+ Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_LANGUAGE');
+ end;
+ else
+ begin
+ OrderType := 1;
+ OrderMode := false;
+ Button[JukeboxSongListOrder].SetSelect(false);
+ try
+ //Button[JukeboxSongListOrder].Text[0].Text := Language.Translate('OPTION_VALUE_ARTIST'); /hackyhack
+ finally
+ end;
+
+ end;
+ end;
+
+ //Button[JukeboxFindSong].Text[0].Text := ''; /hackyhack
+
+ Button[JukeboxLyric].SetSelect(true);
+ Button[JukeboxRandomSongList].SetSelect(false);
+ Button[JukeboxRepeatSongList].SetSelect(false);
+ Button[JukeboxFindSong].SetSelect(false);
+end;
+
+procedure OnEscapeJukebox(Value: boolean; Data: Pointer);
+var
+ tmp: integer;
+begin
+ Display.CheckOK := Value;
+ if (Value) then
+ begin
+ Display.CheckOK := false;
+
+ ScreenJukebox.RepeatSongList := false;
+
+ ScreenJukebox.CurrentSongList := High(ScreenJukebox.JukeboxVisibleSongs);
+
+ ScreenJukebox.Finish;
+ ScreenJukebox.FadeOut := true;
+
+ AudioPlayback.PlaySound(SoundLib.Back);
+
+ end;
+end;
+
+// method for input parsing. if false is returned, getnextwindow
+// should be checked to know the next window to load;
+
+function TScreenJukebox.ParseInput(PressedKey: Cardinal; CharCode: UCS4Char;
+ PressedDown: boolean): boolean;
+var
+ SDL_ModState: word;
+ I, RValueI, RValueE: integer;
+ tmp: integer;
+ X, Y, Z: double;
+begin
+ Result := true;
+
+ SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT +
+ KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT);
+
+ if (PressedDown) then
+ begin // key down
+ // check normal keys
+
+ if (FindSongList) and (SongListVisible) then
+ begin
+ if (IsPrintableChar(CharCode)) then
+ begin
+ LastTick := SDL_GetTicks();
+
+ Button[JukeboxFindSong].Text[0].Text := Button[JukeboxFindSong].Text[0].Text +
+ UCS4ToUTF8String(CharCode);
+
+ Filter := Button[JukeboxFindSong].Text[0].Text;
+ FilterSongList(Filter);
+ Exit;
+ end;
+ end
+ else
+ begin
+ case UCS4UpperCase(CharCode) of
+ Ord('Q'):
+ begin
+ // when not ask before exit then finish now
+ if (Ini.AskbeforeDel <> 1) then
+ Finish
+ // else just pause and let the popup make the work
+ else if not Paused then
+ Pause;
+
+ Result := false;
+ Exit;
+ end;
+
+ // show visualization
+ Ord('V'):
+ begin
+ fShowVisualization := not fShowVisualization;
+
+ if fShowVisualization then
+ begin
+ fCurrentVideo := Visualization.Open(PATH_NONE);
+ fCurrentVideo.play;
+ end
+ else
+ begin
+ fCurrentVideo := fVideoClip;
+ end;
+ Exit;
+ end;
+
+ // pause
+ Ord('P'):
+ begin
+ Pause;
+ Exit;
+ end;
+
+ // toggle time display
+ Ord('T'):
+ begin
+ LastTick := SDL_GetTicks();
+
+ if (fTimebarMode = High(TTimebarMode)) then
+ fTimebarMode := Low(TTimebarMode)
+ else
+ Inc(fTimebarMode);
+ Exit;
+ end;
+ end;
+ end;
+
+ // check special keys
+ case PressedKey of
+ SDLK_A:
+ begin
+ // change aspect ratio
+ if (SDL_ModState = KMOD_LSHIFT) then
+ begin
+ if (AspectCorrection = acoCrop) then
+ AspectCorrection := acoStretch
+ else
+ begin
+ if (AspectCorrection = acoStretch) then
+ AspectCorrection := acoLetterBox
+ else
+ begin
+ if (AspectCorrection = acoLetterBox) then
+ AspectCorrection := acoCrop;
+ end;
+ end;
+
+ //fCurrentVideo.ToggleAspectCorrection();
+ //AspectHandler.changed := true;
+ //AspectHandler.change_time := Czas.Teraz;
+ //Static[VideoAspectStatic].Visible := true;
+ //case UVideo.fAspectCorrection of
+ // acoStretch: Text[VideoAspectText].Text := Language.Translate('VIDEO_ASPECT_STRETCH');
+ // acoCrop: Text[VideoAspectText].Text := Language.Translate('VIDEO_ASPECT_CROP');
+ // acoLetterBox: Text[VideoAspectText].Text := Language.Translate('VIDEO_ASPECT_LETTER_BOX');
+ //end;
+ //DataBase.SetAspect(AktSong.Artist, AktSong.Title, integer(UVideo.fAspectCorrection));
+ //Text[VideoAspectText].Visible := true;
+
+ //fCurrentVideo.Draw;
+ end;
+ end;
+
+ SDLK_L:
+ begin
+ if (SDL_ModState = KMOD_LCTRL) then
+ begin
+ LastTick := SDL_GetTicks();
+
+ ShowLyrics := not ShowLyrics;
+ Button[JukeboxLyric].SetSelect(ShowLyrics);
+ Exit;
+ end;
+ end;
+
+ SDLK_S:
+ begin
+
+ if (SongListVisible) and (SDL_ModState = KMOD_LCTRL) then
+ begin
+ LastTick := SDL_GetTicks();
+
+ Button[JukeboxRandomSongList].SetSelect(false);
+ Button[JukeboxSongListOrder].SetSelect(true);
+
+ if (OrderMode) then
+ begin
+ if (OrderType < 5) then
+ begin
+ OrderType := OrderType + 1;
+ end
+ else
+ OrderType := 1;
+ end;
+
+ RandomMode := false;
+ OrderMode := true;
+
+ SongListSort(OrderType);
+
+ Exit;
+ end;
+
+ end;
+
+ // repeat songlist
+ SDLK_X:
+ begin
+ if (SDL_ModState = KMOD_LCTRL) then
+ begin
+ LastTick := SDL_GetTicks();
+
+ RepeatSongList := not RepeatSongList;
+ Button[JukeboxRepeatSongList].SetSelect(RepeatSongList);
+ Exit;
+ end;
+ end;
+
+ SDLK_F:
+ begin
+
+ if (SongListVisible) and (SDL_ModState = KMOD_LCTRL) then
+ begin
+ LastTick := SDL_GetTicks();
+
+ FindSongList := not FindSongList;
+
+ if (Filter = '') then
+ begin
+ if (FindSongList) then
+ Button[JukeboxFindSong].Text[0].Text := ''
+ end;
+
+ Button[JukeboxFindSong].SetSelect(FindSongList);
+
+ if not (FindSongList) then
+ FilterSongList('')
+ else
+ FilterSongList(Filter);
+
+ Exit;
+ end;
+ end;
+
+ SDLK_R:
+ begin
+
+ if (SongListVisible) and (SDL_ModState = KMOD_LCTRL) then
+ begin
+ LastTick := SDL_GetTicks();
+
+ Button[JukeboxRandomSongList].SetSelect(true);
+ Button[JukeboxSongListOrder].SetSelect(false);
+
+ RandomMode := true;
+ OrderMode := false;
+
+ for I := 0 to High(JukeboxVisibleSongs) * 2 do
+ begin
+ RValueI := RandomRange(0, High(JukeboxVisibleSongs) + 1);
+ RValueE := RandomRange(0, High(JukeboxVisibleSongs) + 1);
+
+ tmp := JukeboxVisibleSongs[RValueI];
+ JukeboxVisibleSongs[RValueI] := JukeboxVisibleSongs[RValueE];
+ JukeboxVisibleSongs[RValueE] := tmp;
+
+ if (RValueI = CurrentSongList) then
+ CurrentSongList := RValueE
+ else
+ begin
+ if (RValueE = CurrentSongList) then
+ CurrentSongList := RValueI;
+ end;
+ end;
+ end;
+ end;
+
+ SDLK_ESCAPE:
+ begin
+ if (SongListVisible) then
+ SongListVisible := false
+ else
+ ScreenPopupCheck.ShowPopup('MSG_END_JUKEBOX', OnEscapeJukebox, nil, false)
+ end;
+
+ SDLK_BACKSPACE:
+ begin
+
+ if (FindSongList) and (SongListVisible) then
+ begin
+ LastTick := SDL_GetTicks();
+ Button[JukeboxFindSong].Text[0].DeleteLastLetter();
+ Filter := Button[JukeboxFindSong].Text[0].Text;
+ FilterSongList(Filter);
+ end
+ else
+ begin
+ ScreenPopupCheck.ShowPopup('MSG_END_JUKEBOX', OnEscapeJukebox, nil, false)
+ end;
+ end;
+
+ SDLK_SPACE:
+ begin
+ Pause;
+ end;
+
+ SDLK_TAB: // change visualization preset
+ begin
+ if fShowVisualization then
+ fCurrentVideo.Position := now; // move to a random position
+ end;
+
+ SDLK_RETURN:
+ begin
+ if (SongListVisible) then
+ begin
+ LastTick := SDL_GetTicks();
+ CurrentSongList := ActualInteraction - 1;
+ Finish;
+ PlayMusic(CurrentSongList);
+ end;
+ end;
+
+ SDLK_LEFT:
+ begin
+ {if not (SongListVisible) and (CurrentSongList > 0) then
+ begin
+ CurrentSongList := CurrentSongList - 2;
+ PlayMusic(CurrentSongList);
+ end;
+ }
+ if (SDL_ModState = KMOD_LSHIFT) then
+ begin
+ fCurrentVideo.GetScreenPosition(X, Y, Z);
+ if (X < 200) then
+ begin
+ fCurrentVideo.SetScreenPosition(X + 2, Y, Z);
+ fCurrentVideo.SetWidth(fCurrentVideo.GetWidth - 4);
+ end;
+ end;
+
+ end;
+
+ SDLK_RIGHT:
+ begin
+ {
+ if not (SongListVisible) and (CurrentSongList < High(JukeboxVisibleSongs)) then
+ begin
+ CurrentSongList := CurrentSongList + 1;
+ PlayMusic(CurrentSongList);
+ end;
+ }
+
+ if (SDL_ModState = KMOD_LSHIFT) then
+ begin
+ fCurrentVideo.GetScreenPosition(X, Y, Z);
+ fCurrentVideo.SetScreenPosition(X - 2, Y, Z);
+ fCurrentVideo.SetWidth(fCurrentVideo.GetWidth + 4);
+ end;
+
+ end;
+
+ SDLK_DELETE:
+ begin
+ if (SongListVisible) then
+ begin
+ // DeleteSong(ActualInteraction);
+ end;
+ end;
+
+ SDLK_PAGEDOWN:
+ begin
+ {if (SongListVisible) and ((ActualInteraction + 10) < High(JukeboxVisibleSongs)) then
+ begin
+
+ LastTick := SDL_GetTicks();
+
+ // TODO: BUG AT END
+ if (ListMin + 10 < High(JukeboxVisibleSongs) - 9 + Interaction) then
+ begin
+ ListMin := ListMin + 10;
+ ActualInteraction := ActualInteraction + 10;
+ end
+ else
+ begin
+ ListMin := High(JukeboxVisibleSongs) - 9 + Interaction;
+ ActualInteraction := High(JukeboxVisibleSongs) - 9 + Interaction;
+ end;
+
+ end;}
+ end;
+
+ SDLK_PAGEUP:
+ begin
+ {
+ if (SongListVisible) and (ActualInteraction - 9 > 0) then
+ begin
+ if (ListMin > 10) then
+ ListMin := ListMin - 10
+ else
+ ListMin := 0;
+
+ ActualInteraction := ActualInteraction - 10;
+
+ if (ActualInteraction < 10) then
+ Interaction := ActualInteraction;
+
+ LastTick := SDL_GetTicks();
+ end;}
+ end;
+
+ // up and down could be done at the same time,
+ // but i don't want to declare variables inside
+ // functions like this one, called so many times
+
+ SDLK_DOWN:
+ begin
+ if (SongListVisible) then
+ begin
+ LastTick := SDL_GetTicks();
+
+ if (SDL_ModState = KMOD_LCTRL) and (ActualInteraction < High(JukeboxVisibleSongs)) then
+ begin
+ Button[JukeboxSongListOrder].SetSelect(false);
+ OrderMode := false;
+
+ tmp := JukeboxVisibleSongs[ActualInteraction];
+ JukeboxVisibleSongs[ActualInteraction] := JukeboxVisibleSongs[ActualInteraction + 1];
+ JukeboxVisibleSongs[ActualInteraction + 1] := tmp;
+
+ if (ActualInteraction + 1 = CurrentSongList) then
+ CurrentSongList := CurrentSongList - 1
+ else
+ begin
+ if (ActualInteraction = CurrentSongList) then
+ CurrentSongList := ActualInteraction + 1;
+ end;
+ end;
+
+ if not(SDL_ModState = KMOD_LSHIFT) and not(SDL_ModState = KMOD_LALT) and (ActualInteraction < High(JukeboxVisibleSongs)) then
+ begin
+ ActualInteraction := ActualInteraction + 1;
+
+ if (Interaction = 9) then
+ ListMin := ListMin + 1
+ else
+ InteractInc;
+
+ end;
+ end;
+
+ if not(SDL_ModState = KMOD_LALT) and not(SDL_ModState = KMOD_LSHIFT) and (not SongListVisible) then
+ begin
+ SongListVisible := true;
+ LastTick := SDL_GetTicks();
+ end;
+
+ if (SDL_ModState = KMOD_LALT) then
+ begin
+ Lyrics.UpperLineY := Lyrics.UpperLineY + 2;
+ Lyrics.LowerLineY := Lyrics.LowerLineY + 2;
+ ChangePosition := ChangePosition + 2;
+ end;
+
+ if (SDL_ModState = KMOD_LSHIFT) then
+ begin
+ fCurrentVideo.GetScreenPosition(X, Y, Z);
+ if (Y < 200) then
+ begin
+ fCurrentVideo.SetScreenPosition(X, Y + 2, Z);
+ fCurrentVideo.SetHeight(fCurrentVideo.GetHeight - 4);
+ end;
+ end;
+
+ end;
+ SDLK_UP:
+ begin
+ if (SongListVisible) and (ActualInteraction > 0) then
+ begin
+ LastTick := SDL_GetTicks();
+
+ if (SDL_ModState = KMOD_LCTRL) and (ActualInteraction > 0) then
+ begin
+ Button[JukeboxSongListOrder].SetSelect(false);
+ OrderMode := false;
+
+ tmp := JukeboxVisibleSongs[ActualInteraction];
+ JukeboxVisibleSongs[ActualInteraction] := JukeboxVisibleSongs[ActualInteraction - 1];
+ JukeboxVisibleSongs[ActualInteraction - 1] := tmp;
+
+ if (ActualInteraction - 1 = CurrentSongList) then
+ CurrentSongList := CurrentSongList + 1
+ else
+ begin
+ if (ActualInteraction = CurrentSongList) then
+ CurrentSongList := ActualInteraction - 1;
+ end;
+ end;
+
+ if not(SDL_ModState = KMOD_LSHIFT) and not(SDL_ModState = KMOD_LALT) then
+ begin
+ ActualInteraction := ActualInteraction - 1;
+
+ if (Interaction = 0) then
+ ListMin := ListMin - 1
+ else
+ InteractDec;
+ end;
+ end;
+
+ if not(SDL_ModState = KMOD_LALT) and not(SDL_ModState = KMOD_LSHIFT) and (not SongListVisible) then
+ begin
+ SongListVisible := true;
+ LastTick := SDL_GetTicks();
+ end;
+
+ if not(SDL_ModState = KMOD_LSHIFT) and (SDL_ModState = KMOD_LALT) then
+ begin
+ Lyrics.UpperLineY := Lyrics.UpperLineY - 2;
+ Lyrics.LowerLineY := Lyrics.LowerLineY - 2;
+ ChangePosition := ChangePosition - 2;
+ end;
+
+ if (SDL_ModState = KMOD_LSHIFT) then
+ begin
+ fCurrentVideo.GetScreenPosition(X, Y, Z);
+ fCurrentVideo.SetScreenPosition(X, Y - 2, Z);
+ fCurrentVideo.SetHeight(fCurrentVideo.GetHeight + 4);
+ end;
+
+ end;
+
+ end;
+ end;
+end;
+
+// pause mod
+procedure TScreenJukebox.Pause;
+begin
+ if (not Paused) then // enable pause
+ begin
+ // pause time
+ Paused := true;
+
+ LyricsState.Pause();
+
+ // pause music
+ AudioPlayback.Pause;
+
+ // pause video
+ if (fCurrentVideo <> nil) then
+ fCurrentVideo.Pause;
+
+ end
+ else // disable pause
+ begin
+ LyricsState.Start();
+
+ // play music
+ AudioPlayback.Play;
+
+ // video
+ if (fCurrentVideo <> nil) then
+ fCurrentVideo.Pause;
+
+ Paused := false;
+ end;
+end;
+// pause mod end
+
+constructor TScreenJukebox.Create;
+var
+ I, PosY: integer;
+begin
+ inherited Create;
+
+ SongListVisible := false;
+ ListMin := 0;
+ ShowLyrics := false;
+
+ //too dangerous, a mouse button is quickly pressed by accident
+ RightMbESC := false;
+
+ fShowVisualization := false;
+
+ fCurrentVideo := nil;
+
+ LoadFromTheme(Theme.Jukebox);
+
+ StaticPausePopup := AddStatic(Theme.Sing.PausePopUp);
+
+ // <note> pausepopup is not visibile at the beginning </note>
+ Statics[StaticPausePopup].Visible := false;
+
+ Lyrics := TLyricEngine.Create(
+ Theme.LyricBar.UpperX, Theme.LyricBar.UpperY, Theme.LyricBar.UpperW, Theme.LyricBar.UpperH,
+ Theme.LyricBar.LowerX, Theme.LyricBar.LowerY, Theme.LyricBar.LowerW, Theme.LyricBar.LowerH);
+
+ fLyricsSync := TLyricsSyncSource.Create();
+ fMusicSync := TMusicSyncSource.Create();
+
+ //eSongLoaded := THookableEvent.Create('ScreenSing.SongLoaded');
+
+ //Jukebox Items
+ JukeboxStaticTimeProgress := AddStatic(Theme.Jukebox.StaticTimeProgress);
+ JukeboxStaticTimeBackground := AddStatic(Theme.Jukebox.StaticTimeBackground);
+ JukeboxStaticSongBackground := AddStatic(Theme.Jukebox.StaticSongBackground);
+ JukeboxStaticSongListBackground := AddStatic(Theme.Jukebox.StaticSongListBackground);
+
+ JukeboxTextTimeText := AddText(Theme.Jukebox.TextTimeText);
+ JukeboxTextTimeDesc := AddText(Theme.Jukebox.TextTimeDesc);
+// JukeboxTextSongText := AddText(Theme.Jukebox.TextSongText);
+
+ PosY := Theme.Jukebox.SongDescription.Y;
+ for I := 0 to 9 do
+ begin
+ Theme.Jukebox.SongDescription.Y := PosY + Theme.Jukebox.SongDescription.H * I;
+ SongDescription[I] := AddButton(Theme.Jukebox.SongDescription);
+ end;
+
+ SelectColR := Theme.Jukebox.SongDescription.ColR;
+ SelectColG := Theme.Jukebox.SongDescription.ColG;
+ SelectColB := Theme.Jukebox.SongDescription.ColB;
+
+ JukeboxFindSong := AddButton(Theme.Jukebox.FindSong);
+ JukeboxRepeatSongList := AddButton(Theme.Jukebox.RepeatSongList);
+ JukeboxSongListOrder := AddButton(Theme.Jukebox.SongListOrder);
+ JukeboxRandomSongList := AddButton(Theme.Jukebox.RandomSongList);
+ JukeboxLyric := AddButton(Theme.Jukebox.Lyric);
+
+ Button[JukeboxFindSong].Selectable := false;
+ Button[JukeboxRepeatSongList].Selectable := false;
+ Button[JukeboxSongListOrder].Selectable := false;
+ Button[JukeboxRandomSongList].Selectable := false;
+ Button[JukeboxLyric].Selectable := false;
+
+ JukeboxListText := AddText(Theme.Jukebox.TextListText);
+ JukeboxCountText := AddText(Theme.Jukebox.TextCountText);
+
+ StaticCover := AddStatic(Theme.Jukebox.SongCover);
+
+ JukeboxStaticOptions := AddStatic(Theme.Jukebox.StaticOptions);
+ JukeboxTextOptionsSongPosition := AddText(Theme.Jukebox.TextOptionsSongPosition);
+ JukeboxTextOptionsLyric := AddText(Theme.Jukebox.TextOptionsLyric);
+ JukeboxTextOptionsRandom := AddText(Theme.Jukebox.TextOptionsRandom);
+ JukeboxTextOptionsRepeat := AddText(Theme.Jukebox.TextOptionsRepeat);
+ JukeboxTextOptionsFind := AddText(Theme.Jukebox.TextOptionsFind);
+ JukeboxTextOptionsSort := AddText(Theme.Jukebox.TextOptionsSort);
+end;
+
+procedure TScreenJukebox.OnShow;
+var
+ V1: boolean;
+ V1TwoP: boolean; // position of score box in two player mode
+ V1ThreeP: boolean; // position of score box in three player mode
+ V2R: boolean;
+ V2M: boolean;
+ V3R: boolean;
+ Color: TRGB;
+begin
+ inherited;
+
+ Log.LogStatus('Begin', 'OnShow');
+
+ {**
+ * Pause background music
+ *}
+ SoundLib.PauseBgMusic;
+
+ FadeOut := false;
+
+ AspectCorrection := acoLetterBox;
+
+ ChangePosition := 0;
+
+ Lyrics.UpperLineX := Theme.LyricBarJukebox.UpperX;
+ Lyrics.UpperLineY := Theme.LyricBarJukebox.UpperY;
+ Lyrics.UpperLineW := Theme.LyricBarJukebox.UpperW;
+ Lyrics.UpperLineH := Theme.LyricBarJukebox.UpperH;
+
+ Lyrics.LowerLineX := Theme.LyricBarJukebox.LowerX;
+ Lyrics.LowerLineY := Theme.LyricBarJukebox.LowerY;
+ Lyrics.LowerLineW := Theme.LyricBarJukebox.LowerW;
+ Lyrics.LowerLineH := Theme.LyricBarJukebox.LowerH;
+
+ tmpLyricsUpperY := Lyrics.UpperLineY;
+ tmpLyricsLowerY := Lyrics.LowerLineY;
+
+ Lyrics.FontStyle := ftOutline1;
+ Lyrics.LineColor_en.R := 1;
+ Lyrics.LineColor_en.G := 1;
+ Lyrics.LineColor_en.B := 1;
+ Lyrics.LineColor_en.A := 1;
+
+ Lyrics.LineColor_dis.R := 1;
+ Lyrics.LineColor_dis.G := 1;
+ Lyrics.LineColor_dis.B := 1;
+ Lyrics.LineColor_dis.A := 1;
+
+ Lyrics.LineColor_act.R := 1;
+ Lyrics.LineColor_act.G := 0.75;
+ Lyrics.LineColor_act.B := 0;
+ Lyrics.LineColor_act.A := 1;
+
+ Log.LogStatus('End', 'OnShow');
+end;
+
+procedure TScreenJukebox.OnShowFinish();
+begin
+ // hide cursor on singscreen show
+ Display.SetCursor;
+
+ Reset;
+
+ PlayMusic(0);
+end;
+
+procedure TScreenJukebox.Play();
+var
+ I: integer;
+begin
+ AudioPlayback.Open(CurrentSong.Path.Append(CurrentSong.Mp3));
+ AudioPlayback.SetVolume(1.0);
+
+ //AudioPlayback.Position := CurrentSong.Start;
+ AudioPlayback.Position := LyricsState.GetCurrentTime();
+
+ // set time
+ if (CurrentSong.Finish > 0) then
+ LyricsState.TotalTime := CurrentSong.Finish / 1000
+ else
+ begin
+ LyricsState.TotalTime := AudioPlayback.Length;
+ end;
+
+ LyricsState.UpdateBeats();
+
+ // synchronize music
+ if (Ini.SyncTo = Ord(stLyrics)) then
+ AudioPlayback.SetSyncSource(fLyricsSync)
+ else
+ AudioPlayback.SetSyncSource(nil);
+
+ // synchronize lyrics (do not set this before AudioPlayback is initialized)
+ if (Ini.SyncTo = Ord(stMusic)) then
+ LyricsState.SetSyncSource(fMusicSync)
+ else
+ LyricsState.SetSyncSource(nil);
+
+ // start lyrics
+ LyricsState.Start(true);
+
+ // start music
+ AudioPlayback.Play();
+
+ // start timer
+ CountSkipTimeSet;
+
+ LastTick := SDL_GetTicks();
+
+end;
+
+procedure TScreenJukebox.OnHide;
+begin
+ // background texture
+ if (Tex_Background.TexNum > 0) then
+ begin
+ glDeleteTextures(1, PGLuint(@Tex_Background.TexNum));
+ Tex_Background.TexNum := 0;
+ end;
+
+ Background.OnFinish;
+ Display.SetCursor;
+end;
+
+function TScreenJukebox.FinishedMusic: boolean;
+begin
+ Result := AudioPlayback.Finished;
+end;
+
+function TScreenJukebox.Draw: boolean;
+var
+ DisplayTime: real;
+ DisplayPrefix: string;
+ DisplayMin: integer;
+ DisplaySec: integer;
+ CurLyricsTime: real;
+ VideoFrameTime: Extended;
+ Line: TLyricLine;
+ LastWord: TLyricWord;
+ CurrentTick: cardinal;
+ Diff: real;
+begin
+ Background.Draw;
+
+ // draw background picture (if any, and if no visualizations)
+ // when we don't check for visualizations the visualizations would
+ // be overdrawn by the picture when {UNDEFINED UseTexture} in UVisualizer
+ if (not fShowVisualization) then
+ SingDrawJukeboxBackground;
+
+ // retrieve current lyrics time, we have to store the value to avoid
+ // that min- and sec-values do not match
+ CurLyricsTime := LyricsState.GetCurrentTime();
+
+ // retrieve time for timebar text
+ case (fTimebarMode) of
+ tbmRemaining: begin
+ DisplayTime := LyricsState.TotalTime - CurLyricsTime;
+ DisplayPrefix := '-';
+ end;
+ tbmTotal: begin
+ DisplayTime := LyricsState.TotalTime;
+ DisplayPrefix := '#';
+ end;
+ else begin
+ DisplayTime := CurLyricsTime;
+ DisplayPrefix := '';
+ end;
+ end;
+
+ DisplayMin := Round(DisplayTime) div 60;
+ DisplaySec := Round(DisplayTime) mod 60;
+ Text[JukeboxTextTimeText].Text := Format('%s%.2d:%.2d', [DisplayPrefix, DisplayMin, DisplaySec]);
+
+ // update and draw movie
+ if Assigned(fCurrentVideo) then
+ begin
+ // Just call this once
+ // when Screens = 2
+ if (ScreenAct = 1) then
+ begin
+ if (ShowFinish) then
+ begin
+ // everything is setup, determine the current position
+ VideoFrameTime := CurrentSong.VideoGAP + LyricsState.GetCurrentTime();
+ end
+ else
+ begin
+ // Important: do not yet start the triggered timer by a call to
+ // LyricsState.GetCurrentTime()
+ VideoFrameTime := CurrentSong.VideoGAP;
+ end;
+ fCurrentVideo.GetFrame(VideoFrameTime);
+ end;
+
+ fCurrentVideo.AspectCorrection := AspectCorrection;
+ fCurrentVideo.SetScreen(ScreenAct);
+ fCurrentVideo.Draw;
+ DrawBlackBars();
+ end;
+
+ // check for music finish
+ //Log.LogError('Check for music finish: ' + BoolToStr(Music.Finished) + ' ' + FloatToStr(LyricsState.CurrentTime*1000) + ' ' + IntToStr(CurrentSong.Finish));
+ if ShowFinish then
+ begin
+ if (not FinishedMusic) and
+ ((CurrentSong.Finish = 0) or
+ (LyricsState.GetCurrentTime() * 1000 <= CurrentSong.Finish)) then
+ begin
+ // analyze song if not paused
+ if (not Paused) then
+ begin
+ SingJukebox(Self);
+ end;
+ end
+ else
+ begin
+ if (not FadeOut) and (Screens=1) or (ScreenAct=2) then
+ begin
+ Finish;
+ end;
+ end;
+ end;
+
+ if (ScreenAct = 1) and (SongListVisible) then
+ DrawPlaylist;
+
+ //if (ShowLyrics) then
+ //begin
+ // if (not(LyricsStart)) then
+ // begin
+ // if (CurLyricsTime >= GetTimeFromBeat(Line.Words[0].Start) - 2) then
+ // begin
+ SingDrawJukebox;
+ // LyricsStart := true;
+ // end;
+ // end
+ // else
+ // SingDrawJukebox;
+ //end;
+
+ // draw pausepopup
+ // FIXME: this is a workaround that the static is drawn over the lyrics, lines, scores and effects
+ // maybe someone could find a better solution
+ if Paused then
+ begin
+ Statics[StaticPausePopup].Visible := true;
+ Statics[StaticPausePopup].Draw;
+ Statics[StaticPausePopup].Visible := false;
+ end;
+
+ Result := true;
+end;
+
+procedure TScreenJukebox.Finish;
+begin
+ AudioInput.CaptureStop;
+ AudioPlayback.Stop;
+ AudioPlayback.SetSyncSource(nil);
+
+ Lyrics.UpperLineY := tmpLyricsUpperY;
+ Lyrics.LowerLineY := tmpLyricsLowerY;
+
+ LyricsState.Stop();
+ LyricsState.SetSyncSource(nil);
+
+ // close video files
+ fVideoClip := nil;
+ fCurrentVideo := nil;
+
+ SetFontItalic(false);
+
+ if (CurrentSongList = High(JukeboxVisibleSongs)) then
+ begin
+ if (RepeatSongList) then
+ begin
+ // resyart playlist
+ CurrentSongList := 0;
+ CatSongs.Selected := JukeboxVisibleSongs[CurrentSongList];
+ PlayMusic(CurrentSongList);
+ end
+ else
+ begin
+ FadeTo(@ScreenMain);
+ end;
+ end
+ else
+ begin
+ CurrentSongList := CurrentSongList + 1;
+
+ CatSongs.Selected := JukeboxVisibleSongs[CurrentSongList];
+
+ PlayMusic(CurrentSongList);
+ end;
+end;
+
+procedure TScreenJukebox.OnSentenceEnd(SentenceIndex: cardinal);
+var
+ PlayerIndex: byte;
+ CurrentPlayer: PPLayer;
+ CurrentScore: real;
+ Line: PLine;
+ LinePerfection: real; // perfection of singing performance on the current line
+ Rating: integer;
+ LineScore: real;
+ LineBonus: real;
+ MaxSongScore: integer; // max. points for the song (without line bonus)
+ MaxLineScore: real; // max. points for the current line
+const
+ // TODO: move this to a better place
+ MAX_LINE_RATING = 8; // max. rating for singing performance
+begin
+ Line := @Lines[0].Line[SentenceIndex];
+
+ // check for empty sentence
+ if (Line.TotalNotes <= 0) then
+ Exit;
+
+ // set max song score
+ if (Ini.LineBonus = 0) then
+ MaxSongScore := MAX_SONG_SCORE
+ else
+ MaxSongScore := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS;
+
+ // Note: ScoreValue is the sum of all note values of the song
+ MaxLineScore := MaxSongScore * (Line.TotalNotes / Lines[0].ScoreValue);
+end;
+
+ // Called on sentence change
+ // SentenceIndex: index of the new active sentence
+procedure TScreenJukebox.OnSentenceChange(SentenceIndex: cardinal);
+begin
+ // fill lyrics queue and set upper line to the current sentence
+ while (Lyrics.GetUpperLineIndex() < SentenceIndex) or
+ (not Lyrics.IsQueueFull) do
+ begin
+ // add the next line to the queue or a dummy if no more lines are available
+ if (Lyrics.LineCounter <= High(Lines[0].Line)) then
+ Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter])
+ else
+ Lyrics.AddLine(nil);
+ end;
+end;
+
+function TLyricsSyncSource.GetClock(): real;
+begin
+ Result := LyricsState.GetCurrentTime();
+end;
+
+function TMusicSyncSource.GetClock(): real;
+begin
+ Result := AudioPlayback.Position;
+end;
+
+procedure TScreenJukebox.AddSongToJukeboxList(ID: integer);
+var
+ I: integer;
+ SongExist: boolean;
+begin
+ if (not CatSongs.Song[ID].Main) then
+ begin
+ SongExist := false;
+ for I := 0 to High(JukeboxSongsList) do
+ begin
+ if (JukeboxSongsList[I] = ID) then
+ SongExist := true;
+ end;
+
+ if (not SongExist) then
+ begin
+ SetLength(JukeboxSongsList, Length(JukeboxSongsList) + 1);
+ JukeboxSongsList[High(JukeboxSongsList)] := ID;
+
+ SetLength(JukeboxVisibleSongs, Length(JukeboxVisibleSongs) + 1);
+ JukeboxVisibleSongs[High(JukeboxVisibleSongs)] := ID;
+ end;
+ end;
+end;
+
+procedure TScreenJukebox.DrawItems();
+begin
+
+ if (SDL_GetTicks() - LastTick <= 3000) then
+ begin
+ Statics[JukeboxStaticTimeBackground].Draw;
+ Statics[JukeboxStaticTimeProgress].Draw;
+
+ // Statics[JukeboxStaticSongBackground].Draw;
+
+ Statics[JukeboxStaticSongListBackground].Draw;
+ Statics[StaticCover].Draw;
+
+ Text[JukeboxTextTimeText].Draw;
+ Text[JukeboxTextTimeDesc].Draw;
+ // Text[JukeboxTextSongText].Draw;
+
+ // options desc
+ Text[JukeboxTextOptionsSongPosition].Draw;
+ Text[JukeboxTextOptionsLyric].Draw;
+ Text[JukeboxTextOptionsRandom].Draw;
+ Text[JukeboxTextOptionsRepeat].Draw;
+ Text[JukeboxTextOptionsFind].Draw;
+ Text[JukeboxTextOptionsSort].Draw;
+ Statics[JukeboxStaticOptions].Draw;
+
+ end
+ else
+ SongListVisible := false;
+
+end;
+
+procedure TScreenJukebox.PlayMusic(ID: integer);
+var
+ Index: integer;
+ VideoFile, BgFile: IPath;
+ success: boolean;
+ Max: integer;
+ CoverPath: IPath;
+begin
+
+ // background texture
+ if (Tex_Background.TexNum > 0) then
+ begin
+ glDeleteTextures(1, PGLuint(@Tex_Background.TexNum));
+ Tex_Background.TexNum := 0;
+ end;
+
+ CurrentSong := CatSongs.Song[JukeboxVisibleSongs[ID]];
+
+ // Cover
+ RefreshCover;
+
+ // reset video playback engine
+ fCurrentVideo := nil;
+ AspectCorrection := acoCrop;
+
+ fTimebarMode := tbmCurrent;
+
+ // FIXME: bad style, put the try-except into loadsong() and not here
+ try
+ // check if file is xml
+ if CurrentSong.FileName.GetExtension.ToUTF8 = '.xml' then
+ success := CurrentSong.AnalyseXML and CurrentSong.LoadXMLSong()
+ else
+ success := CurrentSong.Analyse and CurrentSong.LoadSong();
+ except
+ success := false;
+ end;
+
+ if (not success) then
+ begin
+ // error loading song -> go back to previous screen and show some error message
+ Display.AbortScreenChange;
+ // select new song in party mode
+ if (Length(CurrentSong.LastError) > 0) then
+ ScreenPopupError.ShowPopup(Format(Language.Translate(CurrentSong.LastError), [CurrentSong.ErrorLineNo]))
+ else
+ ScreenPopupError.ShowPopup(Language.Translate('ERROR_CORRUPT_SONG'));
+ // FIXME: do we need this?
+ CurrentSong.Path := CatSongs.Song[CatSongs.Selected].Path;
+ Exit;
+ end;
+
+ {*
+ * == Background ==
+ * We have four types of backgrounds:
+ * + Blank : Nothing has been set, this is our fallback
+ * + Picture : Picture has been set, and exists - otherwise we fallback
+ * + Video : Video has been set, and exists - otherwise we fallback
+ * + Visualization: + Off : No visualization
+ * + WhenNoVideo: Overwrites blank and picture
+ * + On : Overwrites blank, picture and video
+ *}
+
+ {*
+ * set background to: video
+ *}
+ fShowVisualization := false;
+ VideoFile := CurrentSong.Path.Append(CurrentSong.Video);
+ if (Ini.VideoEnabled = 1) and CurrentSong.Video.IsSet() and VideoFile.IsFile then
+ begin
+ fVideoClip := VideoPlayback.Open(VideoFile);
+ fCurrentVideo := fVideoClip;
+ if (fVideoClip <> nil) then
+ begin
+ fShowVisualization := false;
+ fCurrentVideo.Position := CurrentSong.VideoGAP + CurrentSong.Start;
+ fCurrentVideo.Play;
+ end;
+ end;
+
+ {*
+ * set background to: picture
+ *}
+ if (CurrentSong.Background.IsSet) and (fVideoClip = nil)
+ and (TVisualizerOption(Ini.VisualizerOption) = voOff) then
+ begin
+ BgFile := CurrentSong.Path.Append(CurrentSong.Background);
+ try
+ Tex_Background := Texture.LoadTexture(BgFile);
+ except
+ Log.LogError('Background could not be loaded: ' + BgFile.ToNative);
+ Tex_Background.TexNum := 0;
+ end
+ end
+ else
+ begin
+ Tex_Background.TexNum := 0;
+ end;
+
+ {*
+ * set background to: visualization (Overwrites all)
+ *}
+ if (TVisualizerOption(Ini.VisualizerOption) in [voOn]) then
+ begin
+ fShowVisualization := true;
+ fCurrentVideo := Visualization.Open(PATH_NONE);
+ if (fCurrentVideo <> nil) then
+ fCurrentVideo.Play;
+ end;
+
+ {*
+ * set background to: visualization (Videos are still shown)
+ *}
+ if ((TVisualizerOption(Ini.VisualizerOption) in [voWhenNoVideo]) and
+ (fVideoClip = nil)) then
+ begin
+ fShowVisualization := true;
+ fCurrentVideo := Visualization.Open(PATH_NONE);
+ if (fCurrentVideo <> nil) then
+ fCurrentVideo.Play;
+ end;
+
+ // prepare lyrics timer
+ LyricsState.Reset();
+
+ LyricsState.SetCurrentTime(CurrentSong.Start);
+ LyricsState.StartTime := CurrentSong.Gap;
+ if (CurrentSong.Finish > 0) then
+ LyricsState.TotalTime := CurrentSong.Finish / 1000
+ else
+ begin
+ LyricsState.TotalTime := AudioPlayback.Length;
+ end;
+
+ LyricsState.UpdateBeats();
+
+ // main text
+ Lyrics.Clear(CurrentSong.BPM[0].BPM, CurrentSong.Resolution);
+
+ {*
+ * set background to: picture
+ *}
+ if (CurrentSong.Background.IsSet) and (fVideoClip = nil)
+ and (TVisualizerOption(Ini.VisualizerOption) = voOff) then
+ begin
+ BgFile := CurrentSong.Path.Append(CurrentSong.Background);
+ try
+ Tex_Background := Texture.LoadTexture(BgFile);
+ except
+ Log.LogError('Background could not be loaded: ' + BgFile.ToNative);
+ Tex_Background.TexNum := 0;
+ end
+ end
+ else
+ begin
+ Tex_Background.TexNum := 0;
+ end;
+
+ // initialize lyrics by filling its queue
+ while (not Lyrics.IsQueueFull) and
+ (Lyrics.LineCounter <= High(Lines[0].Line)) do
+ begin
+ Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter]);
+ end;
+
+ //Text[JukeboxTextSongText].Visible := true;
+ //Text[JukeboxTextSongText].Text := CurrentSong.Artist + ' - ' + CurrentSong.Title;
+
+ Max := 9;
+
+ if (High(JukeboxVisibleSongs) < 9) then
+ Max := High(JukeboxVisibleSongs);
+
+ for Index := 0 to 9 do
+ Button[SongDescription[Index]].Selectable := false;
+
+ for Index := 0 to Max do
+ begin
+ Button[SongDescription[Index]].Visible := true;
+ Button[SongDescription[Index]].Selectable := true;
+ end;
+
+ Button[JukeboxFindSong].Visible := true;
+ Button[JukeboxRepeatSongList].Visible := true;
+ Button[JukeboxSongListOrder].Visible := true;
+ Button[JukeboxRandomSongList].Visible := true;
+ Button[JukeboxLyric].Visible := true;
+
+ CurrentSongID := JukeboxVisibleSongs[CurrentSongList];
+
+ SongListVisible := true;
+
+ Play();
+end;
+
+procedure TScreenJukebox.RefreshCover();
+var
+ CoverPath: IPath;
+begin
+ CoverPath := CurrentSong.Path.Append(CurrentSong.Cover);
+ Statics[StaticCover].Texture := Texture.GetTexture(CoverPath, TEXTURE_TYPE_PLAIN, false);
+ Statics[StaticCover].Texture.X := Theme.Jukebox.SongCover.X;
+ Statics[StaticCover].Texture.Y := Theme.Jukebox.SongCover.Y;
+ Statics[StaticCover].Texture.W := Theme.Jukebox.SongCover.W;
+ Statics[StaticCover].Texture.H := Theme.Jukebox.SongCover.H;
+ Statics[StaticCover].Texture.Alpha := 0.7;
+end;
+
+procedure TScreenJukebox.DrawPlaylist;
+var
+ I, Max: integer;
+ SongDesc: UTF8String;
+begin
+ DrawItems;
+
+ Max := 9;
+ if (High(JukeboxVisibleSongs) < 9) then
+ Max := High(JukeboxVisibleSongs);
+
+ Text[JukeboxCountText].Text := IntToStr(ActualInteraction + 1) + '/' + IntToStr(length(JukeboxVisibleSongs));
+ Text[JukeboxListText].Draw;
+ Text[JukeboxCountText].Draw;
+
+ Button[JukeboxFindSong].Draw;
+ Button[JukeboxSongListOrder].Draw;
+
+ Button[JukeboxRepeatSongList].Draw;
+ Button[JukeboxRandomSongList].Draw;
+ Button[JukeboxLyric].Draw;
+
+ for I := 0 to Max do
+ begin
+ Button[SongDescription[I]].Visible := true;
+ Button[SongDescription[I]].Selectable := true;
+
+ SongDesc := CatSongs.Song[JukeboxVisibleSongs[I + ListMin]].Artist + ' - ' + CatSongs.Song[JukeboxVisibleSongs[I + ListMin]].Title;
+
+ if (JukeboxVisibleSongs[I + ListMin] = CurrentSongID) and (I + ListMin <> ActualInteraction) then
+ begin
+ Button[SongDescription[I]].Text[0].ColR := SelectColR;
+ Button[SongDescription[I]].Text[0].ColG := SelectColG;
+ Button[SongDescription[I]].Text[0].ColB := SelectColB;
+ end
+ else
+ begin
+ Button[SongDescription[I]].Text[0].ColR := 1;
+ Button[SongDescription[I]].Text[0].ColG := 1;
+ Button[SongDescription[I]].Text[0].ColB := 1;
+ end;
+
+ Button[SongDescription[I]].Text[0].Text := SongDesc;
+ Button[SongDescription[I]].Draw;
+ end;
+
+end;
+
+end.
+
+
diff --git a/src/screens/UScreenMain.pas b/src/screens/UScreenMain.pas
index aa313cf6..b5e3a8bb 100644
--- a/src/screens/UScreenMain.pas
+++ b/src/screens/UScreenMain.pas
@@ -85,9 +85,9 @@ function TScreenMain.ParseInput(PressedKey: Cardinal; CharCode: UCS4Char;
PressedDown: boolean): boolean;
var
SDL_ModState: word;
+ I: integer;
begin
Result := true;
-
{ reset user interaction timer }
UserInteractionTicks := SDL_GetTicks;
@@ -126,6 +126,27 @@ begin
FadeTo(@ScreenEdit, SoundLib.Start);
Exit;
end;
+
+ Ord('J'): begin
+ //ScreenSong.Mode := smPartyJukebox;
+ AudioPlayback.PlaySound(SoundLib.Start);
+
+ SetLength(ScreenJukebox.JukeboxSongsList, 0);
+ SetLength(ScreenJukebox.JukeboxVisibleSongs, 0);
+
+ for I := 0 to High(CatSongs.Song) do
+ begin
+ if not (CatSongs.Song[I].Main) then
+ ScreenJukebox.AddSongToJukeboxList(I);
+ end;
+ ScreenJukebox.ActualInteraction := 0;
+ ScreenJukebox.CurrentSongList := 0;
+ ScreenJukebox.ListMin := 0;
+ ScreenJukebox.Interaction := 0;
+ ScreenJukebox.CurrentSongID := ScreenJukebox.JukeboxVisibleSongs[ScreenJukebox.CurrentSongList];
+
+ FadeTo(@ScreenJukebox);
+ end;
end;
// check special keys