aboutsummaryrefslogtreecommitdiffstats
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
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
-rw-r--r--src/base/UDraw.pas175
-rw-r--r--src/base/UGraphic.pas10
-rw-r--r--src/base/UNote.pas30
-rw-r--r--src/base/UThemes.pas80
-rw-r--r--src/menu/UDisplay.pas7
-rw-r--r--src/screens/UScreenJukebox.pas1809
-rw-r--r--src/screens/UScreenMain.pas23
-rw-r--r--src/ultrastardx.dpr1
8 files changed, 2132 insertions, 3 deletions
diff --git a/src/base/UDraw.pas b/src/base/UDraw.pas
index 72e95f4b..6fe19ea8 100644
--- a/src/base/UDraw.pas
+++ b/src/base/UDraw.pas
@@ -53,6 +53,11 @@ procedure SingDrawTimeBar();
//Draw Editor NoteLines
procedure EditDrawLine(Left, Top, Right: real; NrLines: integer; Space: integer);
+// Draw Jukebox
+procedure SingDrawJukebox;
+procedure SingDrawJukeboxBackground;
+procedure SingDrawJukeboxTimeBar();
+
type
TRecR = record
Top: real;
@@ -93,6 +98,7 @@ uses
UMusic,
URecord,
UScreenSing,
+ UScreenJukebox,
USong,
UTexture;
@@ -171,6 +177,92 @@ begin
end;
end;
+procedure SingDrawJukeboxBackground;
+var
+ Rec: TRecR;
+ TexRec: TRecR;
+begin
+ if (ScreenJukebox.Tex_Background.TexNum > 0) then
+ begin
+ if (Ini.MovieSize <= 1) then //HalfSize BG
+ begin
+ (* half screen + gradient *)
+ Rec.Top := 110; // 80
+ Rec.Bottom := Rec.Top + 20;
+ Rec.Left := 0;
+ Rec.Right := 800;
+
+ TexRec.Top := (Rec.Top / 600) * ScreenJukebox.Tex_Background.TexH;
+ TexRec.Bottom := (Rec.Bottom / 600) * ScreenJukebox.Tex_Background.TexH;
+ TexRec.Left := 0;
+ TexRec.Right := ScreenJukebox.Tex_Background.TexW;
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, ScreenJukebox.Tex_Background.TexNum);
+ glEnable(GL_BLEND);
+ glBegin(GL_QUADS);
+ (* gradient draw *)
+ (* top *)
+ glColor4f(1, 1, 1, 0);
+ glTexCoord2f(TexRec.Right, TexRec.Top); glVertex2f(Rec.Right, Rec.Top);
+ glTexCoord2f(TexRec.Left, TexRec.Top); glVertex2f(Rec.Left, Rec.Top);
+ glColor4f(1, 1, 1, 1);
+ glTexCoord2f(TexRec.Left, TexRec.Bottom); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(TexRec.Right, TexRec.Bottom); glVertex2f(Rec.Right, Rec.Bottom);
+ (* mid *)
+ Rec.Top := Rec.Bottom;
+ Rec.Bottom := 490 - 20; // 490 - 20
+ TexRec.Top := TexRec.Bottom;
+ TexRec.Bottom := (Rec.Bottom / 600) * ScreenJukebox.Tex_Background.TexH;
+ glTexCoord2f(TexRec.Left, TexRec.Top); glVertex2f(Rec.Left, Rec.Top);
+ glTexCoord2f(TexRec.Left, TexRec.Bottom); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(TexRec.Right, TexRec.Bottom); glVertex2f(Rec.Right, Rec.Bottom);
+ glTexCoord2f(TexRec.Right, TexRec.Top); glVertex2f(Rec.Right, Rec.Top);
+ (* bottom *)
+ Rec.Top := Rec.Bottom;
+ Rec.Bottom := 490; // 490
+ TexRec.Top := TexRec.Bottom;
+ TexRec.Bottom := (Rec.Bottom / 600) * ScreenJukebox.Tex_Background.TexH;
+ glTexCoord2f(TexRec.Right, TexRec.Top); glVertex2f(Rec.Right, Rec.Top);
+ glTexCoord2f(TexRec.Left, TexRec.Top); glVertex2f(Rec.Left, Rec.Top);
+ glColor4f(1, 1, 1, 0);
+ glTexCoord2f(TexRec.Left, TexRec.Bottom); glVertex2f(Rec.Left, Rec.Bottom);
+ glTexCoord2f(TexRec.Right, TexRec.Bottom); glVertex2f(Rec.Right, Rec.Bottom);
+
+ glEnd;
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ end
+ else //Full Size BG
+ begin
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, ScreenJukebox.Tex_Background.TexNum);
+ //glEnable(GL_BLEND);
+ glBegin(GL_QUADS);
+
+ glTexCoord2f(0, 0); glVertex2f(0, 0);
+ glTexCoord2f(0, ScreenJukebox.Tex_Background.TexH); glVertex2f(0, 600);
+ glTexCoord2f( ScreenJukebox.Tex_Background.TexW, ScreenJukebox.Tex_Background.TexH); glVertex2f(800, 600);
+ glTexCoord2f( ScreenJukebox.Tex_Background.TexW, 0); glVertex2f(800, 0);
+
+ glEnd;
+ glDisable(GL_TEXTURE_2D);
+ //glDisable(GL_BLEND);
+ end;
+ end
+ else
+ begin
+ // black screen
+ glColor4f(0, 0, 0, 1);
+ glbegin(gl_quads);
+ glVertex2f(0, 0);
+ glVertex2f(0, 600);
+ glVertex2f(800, 600);
+ glVertex2f(800, 0);
+ glEnd;
+ end;
+end;
+
procedure SingDrawOscilloscope(X, Y, W, H: real; NrSound: integer);
var
SampleIndex: integer;
@@ -901,6 +993,39 @@ begin
glDisable(GL_TEXTURE_2D);
end;
+procedure SingDrawJukebox;
+var
+ NR: TRecR; // lyrics area bounds (NR = NoteRec?)
+ LyricEngine: TLyricEngine;
+begin
+ // positions
+ if Ini.SingWindow = 0 then
+ NR.Left := 120
+ else
+ NR.Left := 20;
+
+ NR.Right := 780;
+
+ NR.Width := NR.Right - NR.Left;
+ NR.WMid := NR.Width / 2;
+ NR.Mid := NR.Left + NR.WMid;
+
+ // FIXME: accessing ScreenJukebox is not that generic
+ LyricEngine := ScreenJukebox.Lyrics;
+
+ // draw time-bar
+ if (ScreenAct = 1) and (ScreenJukebox.SongListVisible) then
+ SingDrawJukeboxTimeBar();
+
+ // draw Lyrics
+ if (ScreenJukebox.ShowLyrics) then
+ LyricEngine.Draw(LyricsState.MidBeat);
+ //SingDrawLyricHelper(NR.Left, NR.WMid);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+end;
+
{//SingBar Mod
procedure SingDrawSingbar(X, Y, W, H: real; Percent: integer);
var
@@ -1171,5 +1296,55 @@ begin
glcolor4f(1, 1, 1, 1);
end;
+procedure SingDrawJukeboxTimeBar();
+var
+ x, y: real;
+ width, height: real;
+ LyricsProgress: real;
+ CurLyricsTime: real;
+begin
+ x := Theme.Jukebox.StaticTimeProgress.x;
+ y := Theme.Jukebox.StaticTimeProgress.y;
+
+ width := Theme.Jukebox.StaticTimeProgress.w;
+ height := Theme.Jukebox.StaticTimeProgress.h;
+
+ glColor4f(Theme.Jukebox.StaticTimeProgress.ColR,
+ Theme.Jukebox.StaticTimeProgress.ColG,
+ Theme.Jukebox.StaticTimeProgress.ColB, 1); //Set Color
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_BLEND);
+ glBindTexture(GL_TEXTURE_2D, Tex_JukeboxTimeProgress.TexNum);
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0);
+ glVertex2f(x, y);
+
+ CurLyricsTime := LyricsState.GetCurrentTime();
+ if (CurLyricsTime > 0) and
+ (LyricsState.TotalTime > 0) then
+ begin
+ LyricsProgress := CurLyricsTime / LyricsState.TotalTime;
+ // avoid that the bar "overflows" for inaccurate song lengths
+ if (LyricsProgress > 1.0) then
+ LyricsProgress := 1.0;
+ glTexCoord2f((width * LyricsProgress) / 8, 0);
+ glVertex2f(x + width * LyricsProgress, y);
+
+ glTexCoord2f((width * LyricsProgress) / 8, 1);
+ glVertex2f(x + width * LyricsProgress, y + height);
+ end;
+
+ glTexCoord2f(0, 1);
+ glVertex2f(x, y + height);
+ glEnd;
+
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ glcolor4f(1, 1, 1, 1);
+
+end;
+
end.
diff --git a/src/base/UGraphic.pas b/src/base/UGraphic.pas
index 4f0c8c77..2c80b542 100644
--- a/src/base/UGraphic.pas
+++ b/src/base/UGraphic.pas
@@ -59,6 +59,7 @@ uses
UScreenSong,
UScreenSing,
UScreenScore,
+ UScreenJukeBox,
UScreenTop5,
UScreenEditSub,
UScreenEdit,
@@ -111,6 +112,7 @@ var
ScreenLevel: TScreenLevel;
ScreenSong: TScreenSong;
ScreenSing: TScreenSing;
+ ScreenJukebox: TScreenJukebox;
ScreenScore: TScreenScore;
ScreenTop5: TScreenTop5;
ScreenOptions: TScreenOptions;
@@ -173,6 +175,7 @@ var
FullScreen: boolean;
Tex_TimeProgress: TTexture;
+ Tex_JukeboxTimeProgress: TTexture;
//Sing Bar Mod
Tex_SingBar_Back: TTexture;
@@ -372,6 +375,10 @@ begin
//TimeBar mod
Tex_TimeProgress := Texture.LoadTexture(Skin.GetTextureFileName('TimeBar'));
//eoa TimeBar mod
+
+ //JukeBox mod
+ Tex_JukeboxTimeProgress := Texture.LoadTexture(Skin.GetTextureFileName('JukeboxTimeBar'));
+ //end Jukebox Mod
//SingBar Mod
Tex_SingBar_Back := Texture.LoadTexture(Skin.GetTextureFileName('SingBarBack'), TEXTURE_TYPE_PLAIN, 0);
@@ -741,6 +748,8 @@ begin
Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Song', 3); Log.BenchmarkStart(3);
ScreenSongMenu := TScreenSongMenu.Create;
Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Song Menu', 3); Log.BenchmarkStart(3);
+ ScreenJukebox := TScreenJukebox.Create;
+ Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Jukebox', 3); Log.BenchmarkStart(3);
ScreenSing := TScreenSing.Create;
Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Sing', 3); Log.BenchmarkStart(3);
ScreenScore := TScreenScore.Create;
@@ -819,6 +828,7 @@ begin
ScreenLevel.Free;
ScreenSong.Free;
ScreenSing.Free;
+ ScreenJukebox.Free;
ScreenScore.Free;
ScreenTop5.Free;
ScreenOptions.Free;
diff --git a/src/base/UNote.pas b/src/base/UNote.pas
index c82cc2e3..dc2c6922 100644
--- a/src/base/UNote.pas
+++ b/src/base/UNote.pas
@@ -44,6 +44,7 @@ uses
ULyrics,
URecord,
UScreenSing,
+ UScreenJukebox,
USong,
UTime;
@@ -135,6 +136,8 @@ procedure NewNote(Screen: TScreenSing); // detect note
function GetMidBeat(Time: real): real;
function GetTimeFromBeat(Beat: integer; SelfSong: TSong = nil): real;
+procedure SingJukebox(Screen: TScreenJukebox);
+
implementation
uses
@@ -325,6 +328,33 @@ begin
NewBeatDetect(Screen);
end;
+procedure SingJukebox(Screen: TScreenJukebox);
+var
+ Count: integer;
+ CountGr: integer;
+ CP: integer;
+begin
+ LyricsState.UpdateBeats();
+
+ // sentences routines
+ for CountGr := 0 to 0 do //High(Lines)
+ begin;
+ CP := CountGr;
+ // old parts
+ LyricsState.OldLine := Lines[CP].Current;
+
+ // choose current parts
+ for Count := 0 to Lines[CP].High do
+ begin
+ if LyricsState.CurrentBeat >= Lines[CP].Line[Count].Start then
+ Lines[CP].Current := Count;
+ end;
+ end; // for CountGr
+
+ // on sentence change...
+ Screen.onSentenceChange(Lines[0].Current);
+end;
+
procedure NewSentence(Screen: TScreenSing);
var
i: integer;
diff --git a/src/base/UThemes.pas b/src/base/UThemes.pas
index c90c7982..7bf4a4e5 100644
--- a/src/base/UThemes.pas
+++ b/src/base/UThemes.pas
@@ -107,9 +107,13 @@ type
W: integer;
Z: real;
Color: string;
+ DColor: string;
ColR: real;
ColG: real;
ColB: real;
+ DColR: real;
+ DColG: real;
+ DColB: real;
Font: integer;
Size: integer;
Align: integer;
@@ -370,11 +374,44 @@ type
PausePopUp: TThemeStatic;
end;
+ TThemeJukebox = class(TThemeBasic)
+ StaticTimeProgress: TThemeStatic;
+ StaticTimeBackground: TThemeStatic;
+ StaticSongBackground: TThemeStatic;
+ StaticSongListBackground: TThemeStatic;
+ TextTimeText: TThemeText;
+ TextTimeDesc: TThemeText;
+ TextSongText: TThemeText;
+ SongDescription: TThemeButton;
+ FindSong: TThemeButton;
+ RepeatSongList: TThemeButton;
+ SongListOrder: TThemeButton;
+ RandomSongList: TThemeButton;
+ Lyric: TThemeButton;
+ TextListText: TThemeText;
+ TextCountText: TThemeText;
+ SongCover: TThemeStatic;
+
+ //options desc
+ StaticOptions: TThemeStatic;
+ TextOptionsSongPosition: TThemeText;
+ TextOptionsLyric: TThemeText;
+ TextOptionsSort: TThemeText;
+ TextOptionsRandom: TThemeText;
+ TextOptionsRepeat: TThemeText;
+ TextOptionsFind: TThemeText;
+ end;
+
TThemeLyricBar = record
IndicatorYOffset, UpperX, UpperW, UpperY, UpperH,
LowerX, LowerW, LowerY, LowerH : integer;
end;
+ TThemeLyricBarJukebox = record
+ IndicatorYOffset, UpperX, UpperW, UpperY, UpperH,
+ LowerX, LowerW, LowerY, LowerH : integer;
+ end;
+
TThemeScore = class(TThemeBasic)
TextArtist: TThemeText;
TextTitle: TThemeText;
@@ -758,6 +795,8 @@ type
Song: TThemeSong;
Sing: TThemeSing;
LyricBar: TThemeLyricBar;
+ LyricBarJukebox: TThemeLyricBarJukebox;
+ Jukebox: TThemeJukebox;
Score: TThemeScore;
Top5: TThemeTop5;
Options: TThemeOptions;
@@ -1154,6 +1193,44 @@ begin
LyricBar.LowerY := ThemeIni.ReadInteger('SingLyricsLowerBar', 'Y', 0);
LyricBar.LowerH := ThemeIni.ReadInteger('SingLyricsLowerBar', 'H', 0);
+ // Lyric Jukebox
+ LyricBarJukebox.UpperX := ThemeIni.ReadInteger('JukeboxLyricsUpperBar', 'X', 0);
+ LyricBarJukebox.UpperW := ThemeIni.ReadInteger('JukeboxLyricsUpperBar', 'W', 0);
+ LyricBarJukebox.UpperY := ThemeIni.ReadInteger('JukeboxLyricsUpperBar', 'Y', 0);
+ LyricBarJukebox.UpperH := ThemeIni.ReadInteger('JukeboxLyricsUpperBar', 'H', 0);
+ LyricBarJukebox.LowerX := ThemeIni.ReadInteger('JukeboxLyricsLowerBar', 'X', 0);
+ LyricBarJukebox.LowerW := ThemeIni.ReadInteger('JukeboxLyricsLowerBar', 'W', 0);
+ LyricBarJukebox.LowerY := ThemeIni.ReadInteger('JukeboxLyricsLowerBar', 'Y', 0);
+ LyricBarJukebox.LowerH := ThemeIni.ReadInteger('JukeboxLyricsLowerBar', 'H', 0);
+ LyricBarJukebox.IndicatorYOffset := ThemeIni.ReadInteger('JukeboxLyricsUpperBar', 'IndicatorYOffset', 0);
+
+ // Jukebox
+ ThemeLoadStatic(Jukebox.StaticTimeProgress, 'JukeboxTimeProgress');
+ ThemeLoadStatic(Jukebox.StaticTimeBackground, 'JukeboxTimeBackground');
+ ThemeLoadStatic(Jukebox.StaticSongBackground, 'JukeboxSongBackground');
+ ThemeLoadStatic(Jukebox.StaticSongListBackground, 'JukeboxSongListBackground');
+ ThemeLoadText(Jukebox.TextTimeText, 'JukeboxTimeText');
+ ThemeLoadText(Jukebox.TextTimeDesc, 'JukeboxTimeDesc');
+ ThemeLoadText(Jukebox.TextSongText, 'JukeboxTextSong');
+ ThemeLoadButton(Jukebox.SongDescription, 'JukeboxSongDescription'); //TODO: BasisBit fish theme loading and fix theme for JukeBox
+ ThemeLoadButton(Jukebox.FindSong, 'JukeboxFind');
+ ThemeLoadButton(Jukebox.RepeatSongList, 'JukeboxRepeat');
+ ThemeLoadButton(Jukebox.SongListOrder, 'JukeboxSort');
+ ThemeLoadButton(Jukebox.RandomSongList, 'JukeboxRandom');
+ ThemeLoadButton(Jukebox.Lyric, 'JukeboxLyric');
+ ThemeLoadText(Jukebox.TextListText, 'JukeboxListText');
+ ThemeLoadText(Jukebox.TextCountText, 'JukeboxCountText');
+ ThemeLoadStatic(Jukebox.SongCover, 'JukeboxSongCover');
+
+ // options desc
+ ThemeLoadStatic(Jukebox.StaticOptions, 'JukeboxStaticOptions');
+ ThemeLoadText(Jukebox.TextOptionsSongPosition, 'JukeboxOptionsSongPositionDesc');
+ ThemeLoadText(Jukebox.TextOptionsLyric, 'JukeboxOptionsLyricDesc');
+ ThemeLoadText(Jukebox.TextOptionsRandom, 'JukeboxOptionsRandomDesc');
+ ThemeLoadText(Jukebox.TextOptionsRepeat, 'JukeboxOptionsRepeatDesc');
+ ThemeLoadText(Jukebox.TextOptionsFind, 'JukeboxOptionsFindDesc');
+ ThemeLoadText(Jukebox.TextOptionsSort, 'JukeboxOptionsSortDesc');
+
// Sing
ThemeLoadBasic(Sing, 'Sing');
//TimeBar mod
@@ -2447,6 +2524,9 @@ begin
freeandnil(Sing);
Sing := TThemeSing.Create;
+
+ freeandnil(Jukebox);
+ Jukebox := TThemeJukebox.Create;
freeandnil(Score);
Score := TThemeScore.Create;
diff --git a/src/menu/UDisplay.pas b/src/menu/UDisplay.pas
index 9a196a74..3dba08fe 100644
--- a/src/menu/UDisplay.pas
+++ b/src/menu/UDisplay.pas
@@ -702,10 +702,10 @@ begin
glDisable(GL_TEXTURE_2D);
glColor4f(1, 1, 1, 0.5);
glBegin(GL_QUADS);
- glVertex2f(690, 44);
+ glVertex2f(690, 60);
glVertex2f(690, 0);
glVertex2f(800, 0);
- glVertex2f(800, 44);
+ glVertex2f(800, 60);
glEnd;
glDisable(GL_BLEND);
@@ -740,6 +740,9 @@ begin
SetFontPos(695, 26);
glColor4f(1, 0, 0, 1);
glPrint (OSD_LastError);
+ SetFontPos(695, 39);
+ glColor4f(0.5, 0.5, 0, 1);
+ glPrint ('Pre-alpha');
glColor4f(1, 1, 1, 1);
end;
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
diff --git a/src/ultrastardx.dpr b/src/ultrastardx.dpr
index 39303e79..d798d632 100644
--- a/src/ultrastardx.dpr
+++ b/src/ultrastardx.dpr
@@ -319,6 +319,7 @@ uses
UScreenSong in 'screens\UScreenSong.pas',
UScreenSing in 'screens\UScreenSing.pas',
UScreenScore in 'screens\UScreenScore.pas',
+ UScreenJukebox in 'screens\UScreenJukebox.pas',
UScreenOptions in 'screens\UScreenOptions.pas',
UScreenOptionsGame in 'screens\UScreenOptionsGame.pas',
UScreenOptionsGraphics in 'screens\UScreenOptionsGraphics.pas',