{* 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 UScreenSong;
interface
{$IFDEF FPC}
{$MODE Delphi}
{$ENDIF}
{$I switches.inc}
uses
SysUtils,
SDL,
UCommon,
UDisplay,
UFiles,
UIni,
ULanguage,
ULog,
UMenu,
UMenuEqualizer,
UMusic,
UPath,
USong,
USongs,
UTexture,
UThemes,
UTime;
type
TVisArr = array of integer;
TScreenSong = class(TMenu)
private
Equalizer: Tms_Equalizer;
PreviewOpened: Integer; // interaction of the Song that is loaded for preview music
// -1 if nothing is opened
isScrolling: boolean; // true if song flow is about to move
fCurrentVideo: IVideo;
procedure StartMusicPreview();
procedure StopMusicPreview();
procedure StartVideoPreview();
procedure StopVideoPreview();
public
TextArtist: integer;
TextTitle: integer;
TextNumber: integer;
//Video Icon Mod
VideoIcon: cardinal;
//Medley Icons
MedleyIcon: cardinal;
CalcMedleyIcon: cardinal;
TextCat: integer;
StaticCat: integer;
SongCurrent: real;
SongTarget: real;
HighSpeed: boolean;
CoverFull: boolean;
CoverTime: real;
CoverX: integer;
CoverY: integer;
CoverW: integer;
is_jump: boolean; // Jump to Song Mod
is_jump_title:boolean; //Jump to SOng MOd-YTrue if search for Title
//Party Mod
Mode: TSingMode;
//party Statics (Joker)
StaticTeam1Joker1: cardinal;
StaticTeam1Joker2: cardinal;
StaticTeam1Joker3: cardinal;
StaticTeam1Joker4: cardinal;
StaticTeam1Joker5: cardinal;
StaticTeam2Joker1: cardinal;
StaticTeam2Joker2: cardinal;
StaticTeam2Joker3: cardinal;
StaticTeam2Joker4: cardinal;
StaticTeam2Joker5: cardinal;
StaticTeam3Joker1: cardinal;
StaticTeam3Joker2: cardinal;
StaticTeam3Joker3: cardinal;
StaticTeam3Joker4: cardinal;
StaticTeam3Joker5: cardinal;
StaticParty: array of cardinal;
TextParty: array of cardinal;
StaticNonParty: array of cardinal;
TextNonParty: array of cardinal;
constructor Create; override;
procedure SetScroll;
//procedure SetScroll1;
//procedure SetScroll2;
procedure SetScroll3;
procedure SetScroll4;
procedure SetScroll5;
procedure SetScroll6;
function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
function ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: integer): boolean; override;
function Draw: boolean; override;
procedure GenerateThumbnails();
procedure OnShow; override;
procedure OnShowFinish; override;
procedure OnHide; override;
procedure SelectNext;
procedure SelectPrev;
procedure SkipTo(Target: cardinal);
procedure FixSelected; //Show Wrong Song when Tabs on Fix
procedure FixSelected2; //Show Wrong Song when Tabs on Fix
procedure ShowCatTL(Cat: integer);// Show Cat in Top left
procedure ShowCatTLCustom(Caption: UTF8String);// Show Custom Text in Top left
procedure HideCatTL;// Show Cat in Tob left
procedure Refresh; //Refresh Song Sorting
procedure ChangeMusic;
//Party Mode
procedure SelectRandomSong;
procedure SetJoker;
procedure SetStatics;
//procedures for Menu
procedure StartSong;
procedure OpenEditor;
procedure DoJoker(Team: integer);
procedure SelectPlayers;
procedure OnSongSelect; // called when song flows movement stops at a song
procedure OnSongDeSelect; // called before current song is deselected
procedure UnloadDetailedCover;
//Extensions
procedure DrawExtensions;
//Medley
procedure StartMedley(NumSongs: integer; MinSource: TMedleySource);
function getVisibleMedleyArr(MinSource: TMedleySource): TVisArr;
end;
var
ThumbnailsGenerated: boolean; //true if Thumbnails were already genearated during application run
implementation
uses
Math,
gl,
UCovers,
UGraphic,
UMain,
UMenuButton,
UNote,
UParty,
UPlaylist,
UScreenSongMenu,
USkins,
UUnicodeUtils;
// ***** Public methods ****** //
//Show Wrong Song when Tabs on Fix
procedure TScreenSong.FixSelected;
var
I, I2: integer;
begin
if CatSongs.VisibleSongs > 0 then
begin
I2 := 0;
for I := Low(CatSongs.Song) to High(Catsongs.Song) do
begin
if CatSongs.Song[I].Visible then
inc(I2);
if I = Interaction - 1 then
break;
end;
SongCurrent := I2;
SongTarget := I2;
end;
end;
procedure TScreenSong.FixSelected2;
var
I, I2: integer;
begin
if CatSongs.VisibleSongs > 0 then
begin
I2 := 0;
for I := Low(CatSongs.Song) to High(Catsongs.Song) do
begin
if CatSongs.Song[I].Visible then
inc(I2);
if I = Interaction - 1 then
break;
end;
SongTarget := I2;
end;
end;
//Show Wrong Song when Tabs on Fix End
procedure TScreenSong.ShowCatTLCustom(Caption: UTF8String);// Show Custom Text in Top left
begin
Text[TextCat].Text := Caption;
Text[TextCat].Visible := true;
Statics[StaticCat].Visible := false;
end;
//Show Cat in Top Left Mod
procedure TScreenSong.ShowCatTL(Cat: integer);
begin
//Change
Text[TextCat].Text := CatSongs.Song[Cat].Artist;
//Statics[StaticCat].Texture := Texture.GetTexture(Button[Cat].Texture.Name, TEXTURE_TYPE_PLAIN, true);
//Show
Text[TextCat].Visible := true;
Statics[StaticCat].Visible := true;
end;
procedure TScreenSong.HideCatTL;
begin
//Hide
//Text[TextCat].Visible := false;
Statics[StaticCat].Visible := false;
//New -> Show Text specified in Theme
Text[TextCat].Visible := true;
Text[TextCat].Text := Theme.Song.TextCat.Text;
end;
//Show Cat in Top Left Mod End
// Method for input parsing. If false is returned, GetNextWindow
// should be checked to know the next window to load;
function TScreenSong.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean;
var
I: integer;
I2: integer;
SDL_ModState: word;
UpperLetter: UCS4Char;
TempStr: UTF8String;
begin
Result := true;
//Song Screen Extensions (Jumpto + Menu)
if (ScreenSongMenu.Visible) then
begin
Result := ScreenSongMenu.ParseInput(PressedKey, CharCode, PressedDown);
Exit;
end
else if (ScreenSongJumpto.Visible) then
begin
Result := ScreenSongJumpto.ParseInput(PressedKey, CharCode, PressedDown);
Exit;
end;
if (PressedDown) then
begin // Key Down
SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT
+ KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT + KMOD_RALT);
//Jump to Artist/Titel
if ((SDL_ModState and KMOD_LALT <> 0) and (Mode = smNormal)) then
begin
UpperLetter := UCS4UpperCase(CharCode);
if (UpperLetter in ([Ord('A')..Ord('Z'), Ord('0') .. Ord('9')]) ) then
begin
I2 := Length(CatSongs.Song);
//Jump To Titel
if (SDL_ModState = (KMOD_LALT or KMOD_LSHIFT)) then
begin
for I := 1 to High(CatSongs.Song) do
begin
if (CatSongs.Song[(I + Interaction) mod I2].Visible) then
begin
TempStr := CatSongs.Song[(I + Interaction) mod I2].Title;
if (Length(TempStr) > 0) and
(UCS4UpperCase(UTF8ToUCS4String(TempStr)[0]) = UpperLetter) then
begin
SkipTo(CatSongs.VisibleIndex((I + Interaction) mod I2));
AudioPlayback.PlaySound(SoundLib.Change);
SetScroll4;
//Break and Exit
Exit;
end;
end;
end;
end
//Jump to Artist
else if (SDL_ModState = KMOD_LALT) then
begin
for I := 1 to High(CatSongs.Song) do
begin
if (CatSongs.Song[(I + Interaction) mod I2].Visible) then
begin
TempStr := CatSongs.Song[(I + Interaction) mod I2].Artist;
if (Length(TempStr) > 0) and
(UCS4UpperCase(UTF8ToUCS4String(TempStr)[0]) = UpperLetter) then
begin
SkipTo(CatSongs.VisibleIndex((I + Interaction) mod I2));
AudioPlayback.PlaySound(SoundLib.Change);
SetScroll4;
//Break and Exit
Exit;
end;
end;
end;
end;
end;
Exit;
end;
// **********************
// * workaround for LCTRL+R: it should be changed when we have a solution for the
// * CTRL+'A'..'Z' problem
if (SDL_ModState = KMOD_LCTRL) and (PressedKey = SDLK_R) then
CharCode := UCS4Char('R');
// **********************
// check normal keys
case UCS4UpperCase(CharCode) of
Ord('Q'):
begin
Result := false;
Exit;
end;
Ord('M'): //Show SongMenu
begin
if (Songs.SongList.Count > 0) then
begin
if (Mode = smNormal) then
begin
if (not CatSongs.Song[Interaction].Main) then // clicked on Song
begin
if CatSongs.CatNumShow = -3 then
begin
ScreenSongMenu.OnShow;
ScreenSongMenu.MenuShow(SM_Playlist);
end
else
begin
ScreenSongMenu.OnShow;
ScreenSongMenu.MenuShow(SM_Main);
end;
end
else
begin
ScreenSongMenu.OnShow;
ScreenSongMenu.MenuShow(SM_Playlist_Load);
end;
end //Party Mode -> Show Party Menu
else
begin
ScreenSongMenu.OnShow;
ScreenSongMenu.MenuShow(SM_Party_Main);
end;
end;
Exit;
end;
Ord('P'): //Show Playlist Menu
begin
if (Songs.SongList.Count > 0) and (Mode = smNormal) then
begin
ScreenSongMenu.OnShow;
ScreenSongMenu.MenuShow(SM_Playlist_Load);
end;
Exit;
end;
Ord('J'): //Show Jumpto Menu
begin
if (Songs.SongList.Count > 0) and (Mode = smNormal) then
begin
ScreenSongJumpto.Visible := true;
end;
Exit;
end;
Ord('E'):
begin
OpenEditor;
Exit;
end;
Ord('S'):
begin
if //(SDL_ModState = KMOD_LSHIFT) and
(CatSongs.Song[Interaction].Medley.Source >= msCalculated) and (Mode = smNormal) then
StartMedley(0, msCalculated)
else if (CatSongs.Song[Interaction].Medley.Source >= msTag) and (Mode = smNormal) then
StartMedley(0, msTag);
end;
Ord('D'):
begin
if (Mode = smNormal) and //(SDL_ModState = KMOD_LSHIFT) and
(length(getVisibleMedleyArr(msCalculated)) > 0) then
StartMedley(5, msCalculated)
else if (Mode = smNormal) and (Length(getVisibleMedleyArr(msTag)) > 0) then
StartMedley(5, msTag);
end;
Ord('R'):
begin
if (Songs.SongList.Count > 0) and
(Mode = smNormal) then
begin
if (SDL_ModState = KMOD_LSHIFT) and (Ini.TabsAtStartup = 1) then // random category
begin
I2 := 0; // count cats
for I := 0 to High(CatSongs.Song) do
begin
if CatSongs.Song[I].Main then
Inc(I2);
end;
I2 := Random(I2 + 1); // random and include I2
// find cat:
for I := 0 to High(CatSongs.Song) do
begin
if CatSongs.Song[I].Main then
Dec(I2);
if (I2 <= 0) then
begin
// show cat in top left mod
ShowCatTL (I);
Interaction := I;
CatSongs.ShowCategoryList;
CatSongs.ClickCategoryButton(I);
SelectNext;
FixSelected;
break;
end;
end;
end
else if (SDL_ModState = KMOD_LCTRL) and (Ini.TabsAtStartup = 1) then // random in all categories
begin
repeat
I2 := Random(High(CatSongs.Song) + 1);
until (not CatSongs.Song[I2].Main);
// search cat
for I := I2 downto 0 do
begin
if CatSongs.Song[I].Main then
break;
end;
// in I is now the categorie in I2 the song
// choose cat
CatSongs.ShowCategoryList;
// show cat in top left mod
ShowCatTL (I);
CatSongs.ClickCategoryButton(I);
SelectNext;
// Fix: not existing song selected:
//if (I + 1 = I2) then
Inc(I2);
// choose song
SkipTo(I2 - I);
end
else // random in one category
begin
SkipTo(Random(CatSongs.VisibleSongs));
end;
AudioPlayback.PlaySound(SoundLib.Change);
SetScroll4;
end;
Exit;
end;
end; // normal keys
// check special keys
case PressedKey of
SDLK_ESCAPE,
SDLK_BACKSPACE :
begin
if (Mode = smNormal) then
begin
//On Escape goto Cat-List Hack
if (Ini.TabsAtStartup = 1) and (CatSongs.CatNumShow <> -1) then
begin
//Find Category
I := Interaction;
while (not CatSongs.Song[I].Main) do
begin
Dec(I);
if (I < 0) then
break;
end;
if (I <= 1) then
Interaction := High(CatSongs.Song)
else
Interaction := I - 1;
//Stop Music
StopMusicPreview();
CatSongs.ShowCategoryList;
//Show Cat in Top Left Mod
HideCatTL;
//Show Wrong Song when Tabs on Fix
SelectNext;
FixSelected;
//SelectPrev(true);
//CatSongs.Song[0].Visible := false;
end
else
begin
//On Escape goto Cat-List Hack End
//Tabs off and in Search or Playlist -> Go back to Song view
if (CatSongs.CatNumShow < -1) then
begin
//Atm: Set Empty Filter
CatSongs.SetFilter('', fltAll);
//Show Cat in Top Left Mod
HideCatTL;
Interaction := 0;
//Show Wrong Song when Tabs on Fix
SelectNext;
FixSelected;
end
else
begin
StopMusicPreview();
AudioPlayback.PlaySound(SoundLib.Back);
FadeTo(@ScreenMain);
end;
end;
end
//When in party Mode then Ask before Close
else if (Mode = smPartyClassic) then
begin
AudioPlayback.PlaySound(SoundLib.Back);
CheckFadeTo(@ScreenMain,'MSG_END_PARTY');
end;
end;
SDLK_RETURN:
begin
if (Songs.SongList.Count > 0) then
begin
if CatSongs.Song[Interaction].Main then
begin // clicked on Category Button
//Show Cat in Top Left Mod
ShowCatTL (Interaction);
//I := CatSongs.VisibleIndex(Interaction);
CatSongs.ClickCategoryButton(Interaction);
{I2 := CatSongs.VisibleIndex(Interaction);
SongCurrent := SongCurrent - I + I2;
SongTarget := SongTarget - I + I2; }
// SetScroll4;
//Show Wrong Song when Tabs on Fix
SelectNext;
FixSelected;
end
else
begin // clicked on song
if (Mode = smNormal) then //Normal Mode -> Start Song
begin
//Do the Action that is specified in Ini
case Ini.OnSongClick of
0: StartSong;
1: SelectPlayers;
2:begin
if (CatSongs.CatNumShow = -3) then
ScreenSongMenu.MenuShow(SM_Playlist)
else
ScreenSongMenu.MenuShow(SM_Main);
end;
end;
end
else if (Mode = smPartyClassic) then //PartyMode -> Show Menu
begin
if (Ini.PartyPopup = 1) then
ScreenSongMenu.MenuShow(SM_Party_Main)
else
Party.CallAfterSongSelect;
end;
end;
end;
end;
SDLK_DOWN:
begin
if (Mode = smNormal) then
begin
//Only Change Cat when not in Playlist or Search Mode
if (CatSongs.CatNumShow > -2) then
begin
//Cat Change Hack
if Ini.TabsAtStartup = 1 then
begin
I := Interaction;
if I <= 0 then
I := 1;
while not catsongs.Song[I].Main do
begin
Inc (I);
if (I > High(catsongs.Song)) then
I := Low(catsongs.Song);
end;
Interaction := I;
//Show Cat in Top Left Mod
ShowCatTL (Interaction);
CatSongs.ClickCategoryButton(Interaction);
SelectNext;
FixSelected;
//Play Music:
AudioPlayback.PlaySound(SoundLib.Change);
end;
//
//Cat Change Hack End}
end;
end;
end;
SDLK_UP:
begin
if (Mode = smNormal) then
begin
//Only Change Cat when not in Playlist or Search Mode
if (CatSongs.CatNumShow > -2) then
begin
//Cat Change Hack
if Ini.TabsAtStartup = 1 then
begin
I := Interaction;
I2 := 0;
if I <= 0 then
I := 1;
while not catsongs.Song[I].Main or (I2 = 0) do
begin
if catsongs.Song[I].Main then
Inc(I2);
Dec (I);
if (I < Low(catsongs.Song)) then
I := High(catsongs.Song);
end;
Interaction := I;
//Show Cat in Top Left Mod
ShowCatTL (I);
CatSongs.ClickCategoryButton(I);
SelectNext;
FixSelected;
//Play Music:
AudioPlayback.PlaySound(SoundLib.Change);
end;
end;
//Cat Change Hack End}
end;
end;
SDLK_RIGHT:
begin
if (Songs.SongList.Count > 0) and (Mode = smNormal) then
begin
AudioPlayback.PlaySound(SoundLib.Change);
SelectNext;
SetScroll4;
end;
end;
SDLK_LEFT:
begin
if (Songs.SongList.Count > 0)and (Mode = smNormal) then
begin
AudioPlayback.PlaySound(SoundLib.Change);
SelectPrev;
SetScroll4;
end;
end;
SDLK_1:
begin //Joker
DoJoker(0);
end;
SDLK_2:
begin //Joker
DoJoker(1);
end;
SDLK_3:
begin //Joker
DoJoker(2);
end;
end;
end; // if (PressedDown)
end;
function TScreenSong.ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: integer): boolean;
var
I, J: Integer;
Btn: Integer;
begin
Result := true;
if (ScreenSongMenu.Visible) then
begin
Result := ScreenSongMenu.ParseMouse(MouseButton, BtnDown, X, Y);
exit;
end
else if (ScreenSongJumpTo.Visible) then
begin
Result := ScreenSongJumpTo.ParseMouse(MouseButton, BtnDown, X, Y);
exit;
end
else // no extension visible
begin
if (BtnDown) then
begin
//if RightMbESC is set, send ESC keypress
if RightMbESC and (MouseButton = SDL_BUTTON_RIGHT) then
Result:=ParseInput(SDLK_ESCAPE, 0, true)
//song scrolling with mousewheel
else if (MouseButton = SDL_BUTTON_WHEELDOWN) then
ParseInput(SDLK_RIGHT, 0, true)
else if (MouseButton = SDL_BUTTON_WHEELUP) then
ParseInput(SDLK_LEFT, 0, true)
//LMB anywhere starts
else if (MouseButton = SDL_BUTTON_LEFT) then
begin
if (CatSongs.VisibleSongs > 4) then
begin
// select the second visible button left from selected
I := 0;
Btn := Interaction;
while (I < 2) do
begin
Dec(Btn);
if (Btn < 0) then
Btn := High(CatSongs.Song);
if (CatSongs.Song[Btn].Visible) then
Inc(I);
end;
// transfer mousecords to the 800x600 raster we use to draw
X := Round((X / (ScreenW / Screens)) * RenderW);
if (X > RenderW) then
X := X - RenderW;
Y := Round((Y / ScreenH) * RenderH);
// test the 5 front buttons for click
for I := 0 to 4 do
begin
if InRegion(X, Y, Button[Btn].GetMouseOverArea) then
begin
// song cover clicked
if (I = 2) then
begin // Selected Song clicked -> start singing
ParseInput(SDLK_RETURN, 0, true);
end
else
begin // one of the other 4 covers in the front clicked -> select it
J := I - 2;
while (J < 0) do
begin
ParseInput(SDLK_LEFT, 0, true);
Inc(J);
end;
while (J > 0) do
begin
ParseInput(SDLK_RIGHT, 0, true);
Dec(J);
end;
end;
Break;
end;
Btn := CatSongs.FindNextVisible(Btn);
if (Btn = -1) then
Break;
end;
end
else
ParseInput(SDLK_RETURN, 0, true);
end;
end;
end;
end;
constructor TScreenSong.Create;
var
i: integer;
begin
inherited Create;
LoadFromTheme(Theme.Song);
TextArtist := AddText(Theme.Song.TextArtist);
TextTitle := AddText(Theme.Song.TextTitle);
TextNumber := AddText(Theme.Song.TextNumber);
//Show Cat in Top Left mod
TextCat := AddText(Theme.Song.TextCat);
StaticCat := AddStatic(Theme.Song.StaticCat);
//Show Video Icon Mod
VideoIcon := AddStatic(Theme.Song.VideoIcon);
//Medley Icons
MedleyIcon := AddStatic(Theme.Song.MedleyIcon);
CalcMedleyIcon := AddStatic(Theme.Song.CalculatedMedleyIcon);
//Party Mode
StaticTeam1Joker1 := AddStatic(Theme.Song.StaticTeam1Joker1);
StaticTeam1Joker2 := AddStatic(Theme.Song.StaticTeam1Joker2);
StaticTeam1Joker3 := AddStatic(Theme.Song.StaticTeam1Joker3);
StaticTeam1Joker4 := AddStatic(Theme.Song.StaticTeam1Joker4);
StaticTeam1Joker5 := AddStatic(Theme.Song.StaticTeam1Joker5);
StaticTeam2Joker1 := AddStatic(Theme.Song.StaticTeam2Joker1);
StaticTeam2Joker2 := AddStatic(Theme.Song.StaticTeam2Joker2);
StaticTeam2Joker3 := AddStatic(Theme.Song.StaticTeam2Joker3);
StaticTeam2Joker4 := AddStatic(Theme.Song.StaticTeam2Joker4);
StaticTeam2Joker5 := AddStatic(Theme.Song.StaticTeam2Joker5);
StaticTeam3Joker1 := AddStatic(Theme.Song.StaticTeam3Joker1);
StaticTeam3Joker2 := AddStatic(Theme.Song.StaticTeam3Joker2);
StaticTeam3Joker3 := AddStatic(Theme.Song.StaticTeam3Joker3);
StaticTeam3Joker4 := AddStatic(Theme.Song.StaticTeam3Joker4);
StaticTeam3Joker5 := AddStatic(Theme.Song.StaticTeam3Joker5);
//Load Party or NonParty specific Statics and Texts
SetLength(StaticParty, Length(Theme.Song.StaticParty));
for i := 0 to High(Theme.Song.StaticParty) do
StaticParty[i] := AddStatic(Theme.Song.StaticParty[i]);
SetLength(TextParty, Length(Theme.Song.TextParty));
for i := 0 to High(Theme.Song.TextParty) do
TextParty[i] := AddText(Theme.Song.TextParty[i]);
SetLength(StaticNonParty, Length(Theme.Song.StaticNonParty));
for i := 0 to High(Theme.Song.StaticNonParty) do
StaticNonParty[i] := AddStatic(Theme.Song.StaticNonParty[i]);
SetLength(TextNonParty, Length(Theme.Song.TextNonParty));
for i := 0 to High(Theme.Song.TextNonParty) do
TextNonParty[i] := AddText(Theme.Song.TextNonParty[i]);
// Song List
//Songs.LoadSongList; // moved to the UltraStar unit
CatSongs.Refresh;
GenerateThumbnails();
// Randomize Patch
Randomize;
Equalizer := Tms_Equalizer.Create(AudioPlayback, Theme.Song.Equalizer);
PreviewOpened := -1;
isScrolling := false;
fCurrentVideo := nil;
end;
procedure TScreenSong.GenerateThumbnails();
var
I: integer;
CoverButtonIndex: integer;
CoverButton: TButton;
Cover: TCover;
CoverFile: IPath;
Song: TSong;
begin
if (Length(CatSongs.Song) <= 0) then
Exit;
// set length of button array once instead for every song
SetButtonLength(Length(CatSongs.Song));
// create all buttons
for I := 0 to High(CatSongs.Song) do
begin
CoverButton := nil;
// create a clickable cover
CoverButtonIndex := AddButton(300 + I*250, 140, 200, 200, PATH_NONE, TEXTURE_TYPE_PLAIN, Theme.Song.Cover.Reflections);
if (CoverButtonIndex > -1) then
CoverButton := Button[CoverButtonIndex];
if (CoverButton = nil) then
Continue;
Song := CatSongs.Song[I];
CoverFile := Song.Path.Append(Song.Cover);
if (not CoverFile.IsFile()) then
Song.Cover := PATH_NONE;
if (Song.Cover.IsUnset) then
CoverFile := Skin.GetTextureFileName('SongCover');
// load cover and cache its texture
Cover := Covers.FindCover(CoverFile);
if (Cover = nil) then
Cover := Covers.AddCover(CoverFile);
// use the cached texture
// TODO: this is a workaround until the new song-loading works.
// The TCover object should be added to the song-object. The thumbnails
// should be loaded each time the song-screen is shown (it is real fast).
// This way, we will not waste that much memory and have a link between
// song and cover.
if (Cover <> nil) then
begin
CoverButton.Texture := Cover.GetPreviewTexture();
if (ThumbnailsGenerated = false) then
Texture.AddTexture(CoverButton.Texture, TEXTURE_TYPE_PLAIN, true);
// set selected to false -> the right texture will be displayed
CoverButton.Selected := False;
end;
Cover.Free;
end;
// reset selection
if (Length(CatSongs.Song) > 0) then
Interaction := 0;
ThumbnailsGenerated := true;
end;
{ called when song flows movement stops at a song }
procedure TScreenSong.OnSongSelect;
begin
if (Ini.PreviewVolume <> 0) then
begin
StartMusicPreview;
StartVideoPreview;
end;
// fade in detailed cover
CoverTime := 0;
end;
{ called before current song is deselected }
procedure TScreenSong.OnSongDeSelect;
begin
CoverTime := 10;
UnLoadDetailedCover;
StopMusicPreview();
StopVideoPreview();
PreviewOpened := -1;
end;
procedure TScreenSong.SetScroll;
var
VS, B: integer;
begin
VS := CatSongs.VisibleSongs;
if VS > 0 then
begin
// Set Positions
case Theme.Song.Cover.Style of
3: SetScroll3;
5: SetScroll5;
6: SetScroll6;
else SetScroll4;
end;
// Set visibility of video icon
Statics[VideoIcon].Visible := CatSongs.Song[Interaction].Video.IsSet;
// Set visibility of medley icons
Statics[MedleyIcon].Visible := (CatSongs.Song[Interaction].Medley.Source = msTag);
Statics[CalcMedleyIcon].Visible := (CatSongs.Song[Interaction].Medley.Source = msCalculated);
// Set texts
Text[TextArtist].Text := CatSongs.Song[Interaction].Artist;
Text[TextTitle].Text := CatSongs.Song[Interaction].Title;
if (Ini.TabsAtStartup = 1) and (CatSongs.CatNumShow = -1) then
begin
Text[TextNumber].Text := IntToStr(CatSongs.Song[Interaction].OrderNum) + '/' + IntToStr(CatSongs.CatCount);
Text[TextTitle].Text := '(' + IntToStr(CatSongs.Song[Interaction].CatNumber) + ' ' + Language.Translate('SING_SONGS_IN_CAT') + ')';
end
else if (CatSongs.CatNumShow = -2) then
Text[TextNumber].Text := IntToStr(CatSongs.VisibleIndex(Interaction)+1) + '/' + IntToStr(VS)
else if (CatSongs.CatNumShow = -3) then
Text[TextNumber].Text := IntToStr(CatSongs.VisibleIndex(Interaction)+1) + '/' + IntToStr(VS)
else if (Ini.TabsAtStartup = 1) then
Text[TextNumber].Text := IntToStr(CatSongs.Song[Interaction].CatNumber) + '/' + IntToStr(CatSongs.Song[Interaction - CatSongs.Song[Interaction].CatNumber].CatNumber)
else
Text[TextNumber].Text := IntToStr(Interaction+1) + '/' + IntToStr(Length(CatSongs.Song));
end
else
begin
Text[TextNumber].Text := '0/0';
Text[TextArtist].Text := '';
Text[TextTitle].Text := '';
for B := 0 to High(Button) do
Button[B].Visible := false;
end;
end;
(*
procedure TScreenSong.SetScroll1;
var
B: integer; // button
Src: integer;
//Dst: integer;
Count: integer; // Dst is not used. Count is used.
Ready: boolean;
VisCount: integer; // count of visible (or selectable) buttons
VisInt: integer; // visible position of interacted button
Typ: integer; // 0 when all songs fits the screen
Placed: integer; // number of placed visible buttons
begin
//Src := 0;
//Dst := -1;
Count := 1;
Typ := 0;
Ready := false;
Placed := 0;
VisCount := 0;
for B := 0 to High(Button) do
if CatSongs.Song[B].Visible then
Inc(VisCount);
VisInt := 0;
for B := 0 to Interaction-1 do
if CatSongs.Song[B].Visible then
Inc(VisInt);
if VisCount <= 6 then
begin
Typ := 0;
end
else
begin
if VisInt <= 3 then
begin
Typ := 1;
Count := 7;
Ready := true;
end;
if (VisCount - VisInt) <= 3 then
begin
Typ := 2;
Count := 7;
Ready := true;
end;
if not Ready then
begin
Typ := 3;
Src := Interaction;
end;
end;
// hide all buttons
for B := 0 to High(Button) do
begin
Button[B].Visible := false;
Button[B].Selectable := CatSongs.Song[B].Visible;
end;
{
for B := Src to Dst do
begin
//Button[B].Visible := true;
Button[B].Visible := CatSongs.Song[B].Visible;
Button[B].Selectable := Button[B].Visible;
Button[B].Y := 140 + (B-Src) * 60;
end;
}
if Typ = 0 then
begin
for B := 0 to High(Button) do
begin
if CatSongs.Song[B].Visible then
begin
Button[B].Visible := true;
Button[B].Y := 140 + (Placed) * 60;
Inc(Placed);
end;
end;
end;
if Typ = 1 then
begin
B := 0;
while (Count > 0) do
begin
if CatSongs.Song[B].Visible then
begin
Button[B].Visible := true;
Button[B].Y := 140 + (Placed) * 60;
Inc(Placed);
Dec(Count);
end;
Inc(B);
end;
end;
if Typ = 2 then
begin
B := High(Button);
while (Count > 0) do
begin
if CatSongs.Song[B].Visible then
begin
Button[B].Visible := true;
Button[B].Y := 140 + (6-Placed) * 60;
Inc(Placed);
Dec(Count);
end;
Dec(B);
end;
end;
if Typ = 3 then
begin
B := Src;
Count := 4;
while (Count > 0) do
begin
if CatSongs.Song[B].Visible then
begin
Button[B].Visible := true;
Button[B].Y := 140 + (3+Placed) * 60;
Inc(Placed);
Dec(Count);
end;
Inc(B);
end;
B := Src-1;
Placed := 0;
Count := 3;
while (Count > 0) do
begin
if CatSongs.Song[B].Visible then
begin
Button[B].Visible := true;
Button[B].Y := 140 + (2-Placed) * 60;
Inc(Placed);
Dec(Count);
end;
Dec(B);
end;
end;
if Length(Button) > 0 then
Statics[1].Texture.Y := Button[Interaction].Y - 5; // selection texture
end;
procedure TScreenSong.SetScroll2;
var
B: integer;
//Factor: integer; // factor of position relative to center of screen
//Factor2: real;
begin
// line
for B := 0 to High(Button) do
Button[B].X := 300 + (B - Interaction) * 260;
if Length(Button) >= 3 then
begin
if Interaction = 0 then
Button[High(Button)].X := 300 - 260;
if Interaction = High(Button) then
Button[0].X := 300 + 260;
end;
// circle
{
for B := 0 to High(Button) do
begin
Factor := (B - Interaction); // 0 to center, -1: to left, +1 to right
Factor2 := Factor / Length(Button);
Button[B].X := 300 + 10000 * sin(2*pi*Factor2);
//Button[B].Y := 140 + 50 * ;
end;
}
end;
*)
procedure TScreenSong.SetScroll3; // with slide
var
B: integer;
//Factor: integer; // factor of position relative to center of screen
//Factor2: real;
begin
SongTarget := Interaction;
// line
for B := 0 to High(Button) do
begin
Button[B].X := 300 + (B - SongCurrent) * 260;
if (Button[B].X < -Button[B].W) or (Button[B].X > 800) then
Button[B].Visible := false
else
Button[B].Visible := true;
end;
{
if Length(Button) >= 3 then
begin
if Interaction = 0 then
Button[High(Button)].X := 300 - 260;
if Interaction = High(Button) then
Button[0].X := 300 + 260;
end;
}
// circle
{
for B := 0 to High(Button) do
begin
Factor := (B - Interaction); // 0 to center, -1: to left, +1 to right
Factor2 := Factor / Length(Button);
Button[B].X := 300 + 10000 * sin(2*pi*Factor2);
//Button[B].Y := 140 + 50 * ;
end;
}
end;
(**
* Rotation
*)
procedure TScreenSong.SetScroll4;
var
B: integer;
Angle: real;
Z, Z2: real;
VS: integer;
begin
VS := CatSongs.VisibleSongs();
for B := 0 to High(Button) do
begin
Button[B].Visible := CatSongs.Song[B].Visible;
if Button[B].Visible then
begin
// angle between the cover and selected song-cover in radians
Angle := 2*Pi * (CatSongs.VisibleIndex(B) - SongCurrent) / VS;
// calc z-position from angle
Z := (1 + cos(Angle)) / 2; // scaled to range [0..1]
Z2 := (1 + 2*Z) / 3; // scaled to range [1/3..1]
// adjust cover's width and height according its z-position
// Note: Theme.Song.Cover.W is not used as width and height are equal
// and Theme.Song.Cover.W is used as circle radius in Scroll5.
Button[B].W := Theme.Song.Cover.H * Z2;
Button[B].H := Button[B].W;
// set cover position
Button[B].X := Theme.Song.Cover.X +
(0.185 * Theme.Song.Cover.H * VS * sin(Angle)) * Z2 -
((Button[B].H - Theme.Song.Cover.H)/2);
Button[B].Y := Theme.Song.Cover.Y +
(Theme.Song.Cover.H - Abs(Button[B].H)) * 0.7;
Button[B].Z := Z / 2 + 0.3;
end;
end;
end;
(**
* rotate
*)
procedure TScreenSong.SetScroll5;
var
B: integer;
Angle: real;
Pos: real;
VS: integer;
Padding: real;
X: real;
{
Theme.Song.CoverW: circle radius
Theme.Song.CoverX: x-pos. of the left edge of the selected cover
Theme.Song.CoverY: y-pos. of the upper edge of the selected cover
Theme.Song.CoverH: cover height
}
begin
VS := CatSongs.VisibleSongs();
// Update positions of all buttons
for B := 0 to High(Button) do
begin
Button[B].Visible := CatSongs.Song[B].Visible; // adjust visibility
if Button[B].Visible then // Only change pos for visible buttons
begin
// Pos is the distance to the centered cover in the range [-VS/2..+VS/2]
Pos := (CatSongs.VisibleIndex(B) - SongCurrent);
if (Pos < -VS/2) then
Pos := Pos + VS
else if (Pos > VS/2) then
Pos := Pos - VS;
// Avoid overlapping of the front covers.
// Use an alternate position for the five front covers.
if (Abs(Pos) < 2.5) then
begin
Angle := Pi * (Pos / Min(VS, 5)); // Range: (-1/4*Pi .. +1/4*Pi)
Button[B].H := Abs(Theme.Song.Cover.H * cos(Angle*0.8));
Button[B].W := Button[B].H;
//Button[B].Reflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H;
Button[B].DeSelectReflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H;
Padding := (Button[B].H - Theme.Song.Cover.H)/2;
X := Sin(Angle*1.3) * 0.9;
Button[B].X := Theme.Song.Cover.X + Theme.Song.Cover.W * X - Padding;
Button[B].Y := (Theme.Song.Cover.Y + (Theme.Song.Cover.H - Abs(Theme.Song.Cover.H * cos(Angle))) * 0.5);
Button[B].Z := 0.95 - Abs(Pos) * 0.01;
if VS < 5 then
Button[B].Texture.Alpha := 1 - Abs(Pos) / VS * 2
else
Button[B].Texture.Alpha := 1;
end
{ only draw 3 visible covers in the background
(the 3 that are on the opposite of the front covers}
else if (VS > 7) and (Abs(Pos) > floor(VS/2) - 1.5) then
begin
// Transform Pos to range [-1..-3/4, +3/4..+1]
{ the 3 covers at the back will show up in the gap between the
front cover and its neighbors
one cover will be hiddenbehind the front cover,
but this will not be a lack of performance ;) }
if Pos < 0 then
Pos := (Pos - 2 + ceil(VS/2))/8 - 0.75
else
Pos := (Pos + 2 - floor(VS/2))/8 + 0.75;
// angle in radians [-2Pi..-Pi, +Pi..+2Pi]
Angle := 2*Pi * Pos;
Button[B].H := 0.6*(Theme.Song.Cover.H-Abs(Theme.Song.Cover.H * cos(Angle/2)*0.8));
Button[B].W := Button[B].H;
Padding := (Button[B].H - Theme.Song.Cover.H)/2;
Button[B].X := Theme.Song.Cover.X+Theme.Song.Cover.H/2-Button[b].H/2+Theme.Song.Cover.W/320*((Theme.Song.Cover.H)*sin(Angle/2)*1.52);
Button[B].Y := Theme.Song.Cover.Y - (Button[B].H - Theme.Song.Cover.H)*0.75;
Button[B].Z := (0.4 - Abs(Pos/4)) -0.00001; //z < 0.49999 is behind the cover 1 is in front of the covers
Button[B].Texture.Alpha := 1;
//Button[B].Reflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H;
Button[B].DeSelectReflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H;
end
{ all other covers are not visible }
else
Button[B].Visible := false;
end;
end;
end;
procedure TScreenSong.SetScroll6; // rotate (slotmachine style)
var
B: integer;
Angle: real;
Pos: real;
VS: integer;
diff: real;
X: real;
Factor: real;
Z, Z2: real;
begin
VS := CatSongs.VisibleSongs;
if VS <= 5 then
begin
// circle
for B := 0 to High(Button) do
begin
Button[B].Visible := CatSongs.Song[B].Visible;
if Button[B].Visible then // optimization for 1000 songs - updates only visible songs, hiding in tabs becomes useful for maintaing good speed
begin
Factor := 2 * pi * (CatSongs.VisibleIndex(B) - SongCurrent) / VS {CatSongs.VisibleSongs};// 0.5.0 (II): takes another 16ms
Z := (1 + cos(Factor)) / 2;
Z2 := (1 + 2*Z) / 3;
Button[B].Y := Theme.Song.Cover.Y + (0.185 * Theme.Song.Cover.H * VS * sin(Factor)) * Z2 - ((Button[B].H - Theme.Song.Cover.H)/2); // 0.5.0 (I): 2 times faster by not calling CatSongs.VisibleSongs
Button[B].Z := Z / 2 + 0.3;
Button[B].W := Theme.Song.Cover.H * Z2;
//Button[B].Y := {50 +} 140 + 50 - 50 * Z2;
Button[B].X := Theme.Song.Cover.X + (Theme.Song.Cover.H - Abs(Button[B].H)) * 0.7 ;
Button[B].H := Button[B].W;
end;
end;
end
else
begin
//Change Pos of all Buttons
for B := Low(Button) to High(Button) do
begin
Button[B].Visible := CatSongs.Song[B].Visible; //Adjust Visibility
if Button[B].Visible then //Only Change Pos for Visible Buttons
begin
Pos := (CatSongs.VisibleIndex(B) - SongCurrent);
if (Pos < -VS/2) then
Pos := Pos + VS
else if (Pos > VS/2) then
Pos := Pos - VS;
if (Abs(Pos) < 2.5) then {fixed Positions}
begin
Angle := Pi * (Pos / 5);
//Button[B].Visible := false;
Button[B].H := Abs(Theme.Song.Cover.H * cos(Angle*0.8));//Power(Z2, 3);
Button[B].DeSelectReflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H;
Button[B].Z := 0.95 - Abs(Pos) * 0.01;
Button[B].X := (Theme.Song.Cover.X + (Theme.Song.Cover.H - Abs(Theme.Song.Cover.H * cos(Angle))) * 0.5);
Button[B].W := Button[B].H;
Diff := (Button[B].H - Theme.Song.Cover.H)/2;
X := Sin(Angle*1.3)*0.9;
Button[B].Y := Theme.Song.Cover.Y + Theme.Song.Cover.W * X - Diff;
end
else
begin {Behind the Front Covers}
// limit-bg-covers hack
if (abs(VS/2-abs(Pos))>10) then
Button[B].Visible := false;
if VS > 25 then
VS:=25;
// end of limit-bg-covers hack
if Pos < 0 then
Pos := (Pos - VS/2)/VS
else
Pos := (Pos + VS/2)/VS;
Angle := Pi * Pos*2;
Button[B].Z := (0.4 - Abs(Pos/4)) -0.00001; //z < 0.49999 is behind the cover 1 is in front of the covers
Button[B].H :=0.6*(Theme.Song.Cover.H-Abs(Theme.Song.Cover.H * cos(Angle/2)*0.8));//Power(Z2, 3);
Button[B].W := Button[B].H;
Button[B].X := Theme.Song.Cover.X - (Button[B].H - Theme.Song.Cover.H)*0.5;
Button[B].DeSelectReflectionspacing := 15 * Button[B].H/Theme.Song.Cover.H;
Button[B].Y := Theme.Song.Cover.Y+Theme.Song.Cover.H/2-Button[b].H/2+Theme.Song.Cover.W/320*(Theme.Song.Cover.H*sin(Angle/2)*1.52);
end;
end;
end;
end;
end;
procedure TScreenSong.OnShow;
begin
inherited;
{**
* Pause background music, so we can play it again on scorescreen
*}
SoundLib.PauseBgMusic;
AudioPlayback.Stop;
PreviewOpened := -1;
// reset video playback engine
fCurrentVideo := nil;
// reset Medley-Playlist
SetLength(PlaylistMedley.Song, 0);
if Mode = smMedley then
Mode := smNormal;
if Ini.Players <= 3 then
PlayersPlay := Ini.Players + 1;
if Ini.Players = 4 then
PlayersPlay := 6;
//Cat Mod etc
if (Ini.TabsAtStartup = 1) and (CatSongs.CatNumShow = -1) then
begin
CatSongs.ShowCategoryList;
FixSelected;
//Show Cat in Top Left Mod
HideCatTL;
end;
if Length(CatSongs.Song) > 0 then
begin
SetScroll;
end;
//Playlist Mode
if Mode = smNormal then
begin
//If Playlist Shown -> Select Next automatically
if CatSongs.CatNumShow = -3 then
begin
SelectNext;
end;
end
//Party Mode
else if Mode = smPartyClassic then
begin
SelectRandomSong;
//Show Menu directly in PartyMode
//But only if selected in Options
if Ini.PartyPopup = 1 then
begin
ScreenSongMenu.MenuShow(SM_Party_Main);
end;
end;
isScrolling := false;
SetJoker;
SetStatics;
end;
procedure TScreenSong.OnShowFinish;
begin
isScrolling := true;
CoverTime := 10;
end;
procedure TScreenSong.OnHide;
begin
// turn music volume to 100%
AudioPlayback.SetVolume(1.0);
// stop preview
StopMusicPreview();
StopVideoPreview();
end;
procedure TScreenSong.DrawExtensions;
begin
//Draw Song Menu
if (ScreenSongMenu.Visible) then
begin
ScreenSongMenu.Draw;
end
else if (ScreenSongJumpto.Visible) then
begin
ScreenSongJumpto.Draw;
end
end;
function TScreenSong.Draw: boolean;
var
dx: real;
dt: real;
I: integer;
VideoAlpha: real;
begin
if isScrolling then
begin
dx := SongTarget-SongCurrent;
dt := TimeSkip * 7;
if dt > 1 then
dt := 1;
SongCurrent := SongCurrent + dx*dt;
if SameValue(SongCurrent, SongTarget, 0.002) and (CatSongs.VisibleSongs > 0) then
begin
isScrolling := false;
SongCurrent := SongTarget;
OnSongSelect;
end;
end;
{
if SongCurrent > Catsongs.VisibleSongs then
begin
SongCurrent := SongCurrent - Catsongs.VisibleSongs;
SongTarget := SongTarget - Catsongs.VisibleSongs;
end;
}
//Log.BenchmarkStart(5);
SetScroll;
//Log.BenchmarkEnd(5);
//Log.LogBenchmark('SetScroll4', 5);
//Fading Functions, Only if Covertime is under 5 Seconds
if (CoverTime < 9) then
begin
// cover fade
if (CoverTime < 1) and (CoverTime + TimeSkip >= 1) then
begin
// load new texture
Texture.GetTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, false);
Button[Interaction].Texture.Alpha := 1;
Button[Interaction].Texture2 := Texture.GetTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, false);
Button[Interaction].Texture2.Alpha := 1;
end;
//Update Fading Time
CoverTime := CoverTime + TimeSkip;
//Update Fading Texture
Button[Interaction].Texture2.Alpha := (CoverTime - 1) * 1.5;
if Button[Interaction].Texture2.Alpha > 1 then
Button[Interaction].Texture2.Alpha := 1;
end;
//inherited Draw;
//heres a little Hack, that causes the Statics
//are Drawn after the Buttons because of some Blending Problems.
//This should cause no Problems because all Buttons on this screen
//Has Z Position.
//Draw BG
DrawBG;
VideoAlpha := Button[interaction].Texture.Alpha*(CoverTime-1);
//Instead of Draw FG Procedure:
//We draw Buttons for our own
for I := 0 to Length(Button) - 1 do
begin
if (I<>Interaction) or not Assigned(fCurrentVideo) or (VideoAlpha<1) or AudioPlayback.Finished then
Button[I].Draw;
end;
if AudioPlayback.Finished then
StopVideoPreview;
if Assigned(fCurrentVideo) then
begin
// Just call this once
// when Screens = 2
if (ScreenAct = 1) then
fCurrentVideo.GetFrame(CatSongs.Song[Interaction].VideoGAP + AudioPlayback.Position);
fCurrentVideo.SetScreen(ScreenAct);
fCurrentVideo.Alpha := VideoAlpha;
//set up window
with Button[interaction] do
begin
fCurrentVideo.SetScreenPosition(X, Y, Z);
fCurrentVideo.Width := W;
fCurrentVideo.Height := H;
fCurrentVideo.ReflectionSpacing := Reflectionspacing;
end;
fCurrentVideo.AspectCorrection := acoCrop;
fCurrentVideo.Draw;
if Button[interaction].Reflection then
fCurrentVideo.DrawReflection;
end;
// Statics
for I := 0 to Length(Statics) - 1 do
Statics[I].Draw;
// and texts
for I := 0 to Length(Text) - 1 do
Text[I].Draw;
Equalizer.Draw;
DrawExtensions;
Result := true;
end;
procedure TScreenSong.SelectNext;
var
Skip: integer;
VS: integer;
begin
VS := CatSongs.VisibleSongs;
if VS > 0 then
begin
if (not isScrolling) and (VS > 0) then
begin
isScrolling := true;
OnSongDeselect;
end;
Skip := 1;
// this 1 could be changed by CatSongs.FindNextVisible
while (not CatSongs.Song[(Interaction + Skip) mod Length(Interactions)].Visible) do
Inc(Skip);
SongTarget := SongTarget + 1;//Skip;
Interaction := (Interaction + Skip) mod Length(Interactions);
// try to keep all at the beginning
if SongTarget > VS-1 then
begin
SongTarget := SongTarget - VS;
SongCurrent := SongCurrent - VS;
end;
end;
// Interaction -> Button, load cover
// show uncached texture
//Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, false);
end;
procedure TScreenSong.SelectPrev;
var
Skip: integer;
VS: integer;
begin
VS := CatSongs.VisibleSongs;
if VS > 0 then
begin
if (not isScrolling) and (VS > 0) then
begin
isScrolling := true;
OnSongDeselect;
end;
Skip := 1;
while (not CatSongs.Song[(Interaction - Skip + Length(Interactions)) mod Length(Interactions)].Visible) do
Inc(Skip);
SongTarget := SongTarget - 1;//Skip;
Interaction := (Interaction - Skip + Length(Interactions)) mod Length(Interactions);
// try to keep all at the beginning
if SongTarget < 0 then
begin
SongTarget := SongTarget + CatSongs.VisibleSongs;
SongCurrent := SongCurrent + CatSongs.VisibleSongs;
end;
// show uncached texture
//Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, false);
end;
end;
procedure TScreenSong.StartMusicPreview();
var
Song: TSong;
PreviewPos: real;
begin
AudioPlayback.Close();
if CatSongs.VisibleSongs = 0 then
Exit;
Song := CatSongs.Song[Interaction];
if not assigned(Song) then
Exit;
//fix: if main cat than there is nothing to play
if Song.main then
Exit;
if AudioPlayback.Open(Song.Path.Append(Song.Mp3)) then
begin
PreviewOpened := Interaction;
if Song.PreviewStart > 0 then
PreviewPos := Song.PreviewStart
else
PreviewPos := AudioPlayback.Length / 4;
// fix for invalid music file lengths
if (PreviewPos > 60.0) and (Song.PreviewStart = 0) then
PreviewPos := 60.0;
AudioPlayback.Position := PreviewPos;
// set preview volume
if Ini.PreviewFading = 0 then
begin
// music fade disabled: start with full volume
AudioPlayback.SetVolume(IPreviewVolumeVals[Ini.PreviewVolume]);
AudioPlayback.Play()
end
else
begin
// music fade enabled: start muted and fade-in
AudioPlayback.SetVolume(0);
AudioPlayback.FadeIn(Ini.PreviewFading, IPreviewVolumeVals[Ini.PreviewVolume]);
end;
end;
end;
procedure TScreenSong.StopMusicPreview();
begin
// Stop preview of previous song
AudioPlayback.Stop;
end;
procedure TScreenSong.StartVideoPreview();
var
VideoFile: IPath;
Song: TSong;
begin
if (Ini.VideoPreview=0) then
Exit;
if Assigned(fCurrentVideo) then
begin
fCurrentVideo.Stop();
fCurrentVideo := nil;
end;
//if no audio open => exit
if (PreviewOpened = -1) then
Exit;
if CatSongs.VisibleSongs = 0 then
Exit;
Song := CatSongs.Song[Interaction];
if not assigned(Song) then
Exit;
//fix: if main cat than there is nothing to play
if Song.main then
Exit;
VideoFile := Song.Path.Append(Song.Video);
if (Song.Video.IsSet) and VideoFile.IsFile then
begin
fCurrentVideo := VideoPlayback.Open(VideoFile);
if (fCurrentVideo <> nil) then
begin
fCurrentVideo.Position := Song.VideoGAP + AudioPlayback.Position;
fCurrentVideo.Play;
end;
end;
end;
procedure TScreenSong.StopVideoPreview();
begin
// Stop video preview of previous song
if Assigned(fCurrentVideo) then
begin
fCurrentVideo.Stop();
fCurrentVideo := nil;
end;
end;
// Changes previewed song
procedure TScreenSong.ChangeMusic;
begin
StopMusicPreview();
StopVideoPreview();
PreviewOpened := -1;
StartMusicPreview();
StartVideoPreview();
end;
procedure TScreenSong.SkipTo(Target: cardinal);
var
i: integer;
begin
Interaction := High(CatSongs.Song);
SongTarget := 0;
for i := 1 to Target+1 do
SelectNext;
FixSelected2;
end;
procedure TScreenSong.SelectRandomSong;
var
I, I2: integer;
begin
case PlaylistMan.Mode of
smNormal: // all songs just select random song
begin
// when tabs are activated then use tab method
if (Ini.TabsAtStartup = 1) then
begin
repeat
I2 := Low(CatSongs.Song) + Random(High(CatSongs.Song) + 1 - Low(CatSongs.Song));
until CatSongs.Song[I2].Main = false;
// search cat
for I := I2 downto Low(CatSongs.Song) do
begin
if CatSongs.Song[I].Main then
break;
end;
// I is the cat number, I2 is the no of the song within this cat
// choose cat
CatSongs.ShowCategoryList;
// show cat in top left mod
ShowCatTL(I);
CatSongs.ClickCategoryButton(I);
SelectNext;
// choose song
SkipTo(I2 - I);
end
// when tabs are deactivated use easy method
else
SkipTo(Random(CatSongs.VisibleSongs));
end;
smPartyClassic: // one category select category and select random song
begin
CatSongs.ShowCategoryList;
CatSongs.ClickCategoryButton(PlaylistMan.CurPlayList);
ShowCatTL(PlaylistMan.CurPlayList);
SelectNext;
FixSelected2;
SkipTo(Random(CatSongs.VisibleSongs));
end;
smPlaylistRandom: // playlist: select playlist and select random song
begin
PlaylistMan.SetPlayList(PlaylistMan.CurPlayList);
SkipTo(Random(CatSongs.VisibleSongs));
FixSelected2;
end;
end;
AudioPlayback.PlaySound(SoundLib.Change);
SetScroll;
end;
procedure TScreenSong.SetJoker;
begin
// If Party Mode
if Mode = smPartyClassic then //Show Joker that are available
begin
if (Length(Party.Teams) >= 1) then
begin
Statics[StaticTeam1Joker1].Visible := (Party.Teams[0].JokersLeft >= 1);
Statics[StaticTeam1Joker2].Visible := (Party.Teams[0].JokersLeft >= 2);
Statics[StaticTeam1Joker3].Visible := (Party.Teams[0].JokersLeft >= 3);
Statics[StaticTeam1Joker4].Visible := (Party.Teams[0].JokersLeft >= 4);
Statics[StaticTeam1Joker5].Visible := (Party.Teams[0].JokersLeft >= 5);
end
else
begin
Statics[StaticTeam1Joker1].Visible := false;
Statics[StaticTeam1Joker2].Visible := false;
Statics[StaticTeam1Joker3].Visible := false;
Statics[StaticTeam1Joker4].Visible := false;
Statics[StaticTeam1Joker5].Visible := false;
end;
if (Length(Party.Teams) >= 2) then
begin
Statics[StaticTeam2Joker1].Visible := (Party.Teams[1].JokersLeft >= 1);
Statics[StaticTeam2Joker2].Visible := (Party.Teams[1].JokersLeft >= 2);
Statics[StaticTeam2Joker3].Visible := (Party.Teams[1].JokersLeft >= 3);
Statics[StaticTeam2Joker4].Visible := (Party.Teams[1].JokersLeft >= 4);
Statics[StaticTeam2Joker5].Visible := (Party.Teams[1].JokersLeft >= 5);
end
else
begin
Statics[StaticTeam2Joker1].Visible := false;
Statics[StaticTeam2Joker2].Visible := false;
Statics[StaticTeam2Joker3].Visible := false;
Statics[StaticTeam2Joker4].Visible := false;
Statics[StaticTeam2Joker5].Visible := false;
end;
if (Length(Party.Teams) >= 3) then
begin
Statics[StaticTeam3Joker1].Visible := (Party.Teams[2].JokersLeft >= 1);
Statics[StaticTeam3Joker2].Visible := (Party.Teams[2].JokersLeft >= 2);
Statics[StaticTeam3Joker3].Visible := (Party.Teams[2].JokersLeft >= 3);
Statics[StaticTeam3Joker4].Visible := (Party.Teams[2].JokersLeft >= 4);
Statics[StaticTeam3Joker5].Visible := (Party.Teams[2].JokersLeft >= 5);
end
else
begin
Statics[StaticTeam3Joker1].Visible := false;
Statics[StaticTeam3Joker2].Visible := false;
Statics[StaticTeam3Joker3].Visible := false;
Statics[StaticTeam3Joker4].Visible := false;
Statics[StaticTeam3Joker5].Visible := false;
end;
end
else
begin //Hide all
Statics[StaticTeam1Joker1].Visible := false;
Statics[StaticTeam1Joker2].Visible := false;
Statics[StaticTeam1Joker3].Visible := false;
Statics[StaticTeam1Joker4].Visible := false;
Statics[StaticTeam1Joker5].Visible := false;
Statics[StaticTeam2Joker1].Visible := false;
Statics[StaticTeam2Joker2].Visible := false;
Statics[StaticTeam2Joker3].Visible := false;
Statics[StaticTeam2Joker4].Visible := false;
Statics[StaticTeam2Joker5].Visible := false;
Statics[StaticTeam3Joker1].Visible := false;
Statics[StaticTeam3Joker2].Visible := false;
Statics[StaticTeam3Joker3].Visible := false;
Statics[StaticTeam3Joker4].Visible := false;
Statics[StaticTeam3Joker5].Visible := false;
end;
end;
procedure TScreenSong.SetStatics;
var
I: integer;
Visible: boolean;
begin
//Set Visibility of Party Statics and Text
Visible := (Mode = smPartyClassic);
for I := 0 to High(StaticParty) do
Statics[StaticParty[I]].Visible := Visible;
for I := 0 to High(TextParty) do
Text[TextParty[I]].Visible := Visible;
//Set Visibility of Non Party Statics and Text
Visible := not Visible;
for I := 0 to High(StaticNonParty) do
Statics[StaticNonParty[I]].Visible := Visible;
for I := 0 to High(TextNonParty) do
Text[TextNonParty[I]].Visible := Visible;
end;
//Procedures for Menu
procedure TScreenSong.StartSong;
begin
CatSongs.Selected := Interaction;
if (Mode = smPartyFree) then
Party.SaveSungPartySong(Interaction);
StopMusicPreview();
//Party Mode
if (Mode = smPartyClassic) then
begin
FadeTo(@ScreenSing);
end
else
begin
FadeTo(@ScreenSing);
end;
end;
procedure TScreenSong.SelectPlayers;
begin
CatSongs.Selected := Interaction;
StopMusicPreview();
ScreenName.Goto_SingScreen := true;
FadeTo(@ScreenName);
end;
procedure TScreenSong.OpenEditor;
begin
if (Songs.SongList.Count > 0) and
(not CatSongs.Song[Interaction].Main) and
(Mode = smNormal) then
begin
StopMusicPreview();
AudioPlayback.PlaySound(SoundLib.Start);
CurrentSong := CatSongs.Song[Interaction];
FadeTo(@ScreenEditSub);
end;
end;
//Team No of Team (0-5)
procedure TScreenSong.DoJoker (Team: integer);
begin
if (Mode = smPartyClassic) and
(High(Party.Teams) >= Team) and
(Party.Teams[Team].JokersLeft > 0) then
begin
//Use Joker
Dec(Party.Teams[Team].JokersLeft);
SelectRandomSong;
SetJoker;
end;
end;
//Detailed Cover Unloading. Unloads the Detailed, uncached Cover of the cur. Song
procedure TScreenSong.UnloadDetailedCover;
begin
// show cached texture
Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, true);
Button[Interaction].Texture2.Alpha := 0;
if Button[Interaction].Texture.Name <> Skin.GetTextureFileName('SongCover') then
Texture.UnloadTexture(Button[Interaction].Texture.Name, TEXTURE_TYPE_PLAIN, false);
end;
procedure TScreenSong.Refresh;
begin
{
CatSongs.Refresh;
CatSongs.ShowCategoryList;
Interaction := 0;
SelectNext(true);
FixSelected;
}
end;
procedure TScreenSong.StartMedley(NumSongs: integer; MinSource: TMedleySource);
procedure AddSong(SongNr: integer);
begin
SetLength(PlaylistMedley.Song, Length(PlaylistMedley.Song) + 1);
PlaylistMedley.Song[Length(PlaylistMedley.Song) - 1] := SongNr;
end;
function SongAdded(SongNr: integer): boolean;
var
i: integer;
skipped: boolean;
begin
skipped := false;
for i := 0 to Length(PlaylistMedley.Song) - 1 do
begin
if SongNr = PlaylistMedley.Song[i] then
begin
skipped := true;
break;
end;
end;
Result := skipped;
end;
function NumSongsAdded(): Integer;
begin
Result := Length(PlaylistMedley.Song);
end;
function GetNextSongNr(MinS: TMedleySource): integer;
var
I, num: integer;
unused_arr: array of integer;
visible_arr: TVisArr;
begin
SetLength(unused_arr, 0);
visible_arr := getVisibleMedleyArr(MinS);
for I := 0 to Length(visible_arr) - 1 do
begin
if (not SongAdded(visible_arr[I])) then
begin
SetLength(unused_arr, Length(unused_arr)+1);
unused_arr[Length(unused_arr) - 1] := visible_arr[I];
end;
end;
num := Random(Length(unused_arr));
Result := unused_arr[num];
end;
var
I: integer;
VS: integer;
begin
if NumSongs > 0 then
begin
VS := Length(getVisibleMedleyArr(MinSource));
if VS < NumSongs then
PlaylistMedley.NumMedleySongs := VS
else
PlaylistMedley.NumMedleySongs := NumSongs;
//set up Playlist Medley
SetLength(PlaylistMedley.Song, 0);
for I := 0 to PlaylistMedley.NumMedleySongs - 1 do
begin
AddSong(GetNextSongNr(MinSource));
end;
end
else //start this song
begin
SetLength(PlaylistMedley.Song, 1);
PlaylistMedley.Song[0] := Interaction;
PlaylistMedley.NumMedleySongs := 1;
end;
if Mode = smNormal then
begin
Mode := smMedley;
StopMusicPreview();
//TODO: how about case 2? menu for medley mode?
case Ini.OnSongClick of
0: FadeTo(@ScreenSing);
1: SelectPlayers;
2: FadeTo(@ScreenSing);
{2: begin
if CatSongs.CatNumShow = -3 then
ScreenSongMenu.MenuShow(SM_Playlist)
else
ScreenSongMenu.MenuShow(SM_Main);
end;}
end;
end;
end;
function TScreenSong.getVisibleMedleyArr(MinSource: TMedleySource): TVisArr;
var
I: integer;
begin
SetLength(Result, 0);
if CatSongs.Song[Interaction].Main then
begin
for I := 0 to Length(CatSongs.Song) - 1 do
begin
if not CatSongs.Song[I].Main and (CatSongs.Song[I].Medley.Source >= MinSource) then
begin
SetLength(Result, Length(Result) + 1);
Result[Length(Result) - 1] := I;
end;
end;
end
else
begin
for I := 0 to Length(CatSongs.Song) - 1 do
begin
if CatSongs.Song[I].Visible and (CatSongs.Song[I].Medley.Source >= MinSource) then
begin
SetLength(Result, Length(Result) + 1);
Result[Length(Result)-1] := I;
end;
end;
end;
end;
end.