aboutsummaryrefslogtreecommitdiffstats
path: root/src/screens
diff options
context:
space:
mode:
Diffstat (limited to 'src/screens')
-rw-r--r--src/screens/UScreenScore.pas209
-rw-r--r--src/screens/UScreenSing.pas781
-rw-r--r--src/screens/UScreenSong.pas207
3 files changed, 933 insertions, 264 deletions
diff --git a/src/screens/UScreenScore.pas b/src/screens/UScreenScore.pas
index de7675bf..4b7332b4 100644
--- a/src/screens/UScreenScore.pas
+++ b/src/screens/UScreenScore.pas
@@ -34,16 +34,16 @@ interface
{$I switches.inc}
uses
- UMenu,
- SDL,
SysUtils,
+ math,
+ SDL,
+ gl,
UDisplay,
+ UMenu,
UMusic,
USongs,
- UThemes,
- gl,
- math,
- UTexture;
+ UTexture,
+ UThemes;
const
ZBars: real = 0.8; // Z value for the bars
@@ -167,6 +167,11 @@ type
TextPhrase_ActualValue: array[1..6] of integer;
TextGolden_ActualValue: array[1..6] of integer;
+ ActualRound: integer;
+
+ procedure RefreshTexts;
+ procedure ResetScores;
+
procedure MapPlayersToPosition;
procedure FillPlayer(Item, P: integer);
@@ -196,7 +201,7 @@ type
public
constructor Create; override;
function ParseInput(PressedKey: cardinal; CharCode: UCS4Char; PressedDown: boolean): boolean; override;
- function ParseMouse(MouseButton: Integer; BtnDown: Boolean; X, Y: integer): boolean; override;
+ function ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: integer): boolean; override;
procedure OnShow; override;
procedure OnShowFinish; override;
function Draw: boolean; override;
@@ -206,14 +211,15 @@ implementation
uses
UGraphic,
- UScreenSong,
- UMenuStatic,
- UTime,
UIni,
- USkins,
ULog,
ULanguage,
+ UMenuStatic,
UNote,
+ UScreenSong,
+ USkins,
+ USong,
+ UTime,
UUnicodeUtils;
@@ -237,27 +243,96 @@ begin
SDLK_BACKSPACE,
SDLK_RETURN:
begin
- FadeTo(@ScreenTop5);
- Exit;
+ if ScreenSong.Mode = smMedley then
+ FadeTo(@ScreenSong)
+ else
+ FadeTo(@ScreenTop5);
+
+ Exit;
end;
SDLK_SYSREQ:
begin
Display.SaveScreenShot;
end;
+
+ SDLK_RIGHT:
+ begin
+ if ActualRound < Length(PlaylistMedley.Stats) - 1 then
+ begin
+ AudioPlayback.PlaySound(SoundLib.Change);
+ inc(ActualRound);
+ RefreshTexts;
+ end;
+ end;
+
+ SDLK_LEFT:
+ begin
+ if ActualRound > 0 then
+ begin
+ AudioPlayback.PlaySound(SoundLib.Change);
+ dec(ActualRound);
+ RefreshTexts;
+ end;
+ end;
end;
end;
end;
-function TScreenScore.ParseMouse(MouseButton: Integer; BtnDown: Boolean; X, Y: integer): boolean;
+function TScreenScore.ParseMouse(MouseButton: integer; BtnDown: boolean; X, Y: integer): boolean;
begin
Result := True;
- if (MouseButton = SDL_BUTTON_LEFT) and BtnDown then begin
+ if (MouseButton = SDL_BUTTON_LEFT) and BtnDown then
+ begin
//left-click anywhere sends return
ParseInput(SDLK_RETURN, 0, true);
end;
end;
+procedure TScreenScore.RefreshTexts;
+var
+ P: integer;
+
+begin
+ if ActualRound < Length(PlaylistMedley.Stats) - 1 then
+ begin
+ Text[TextArtist].Text := IntToStr(ActualRound+1) + '/' +
+ IntToStr(Length(PlaylistMedley.Stats)-1) + ': ' +
+ PlaylistMedley.Stats[ActualRound].SongArtist;
+ Text[TextTitle].Text := PlaylistMedley.Stats[ActualRound].SongTitle;
+ Text[TextTitle].Visible := true;
+ Text[TextArtistTitle].Text := IntToStr(ActualRound+1) + '/' +
+ IntToStr(Length(PlaylistMedley.Stats)-1) + ': ' +
+ PlaylistMedley.Stats[ActualRound].SongArtist +
+ ' - ' + PlaylistMedley.Stats[ActualRound].SongTitle;
+ end
+ else
+ begin
+ if ScreenSong.Mode = smMedley then
+ begin
+ Text[TextArtist].Text := Language.Translate('SING_TOTAL');
+ Text[TextTitle].Visible := false;
+ Text[TextArtistTitle].Text := Language.Translate('SING_TOTAL');
+ end
+ else
+ begin
+ Text[TextArtist].Text := PlaylistMedley.Stats[ActualRound].SongArtist;
+ Text[TextTitle].Text := PlaylistMedley.Stats[ActualRound].SongTitle;
+ Text[TextTitle].Visible := true;
+ Text[TextArtistTitle].Text := PlaylistMedley.Stats[ActualRound].SongArtist + ' - ' +
+ PlaylistMedley.Stats[ActualRound].SongTitle;
+ end;
+ end;
+
+ if ScreenSong.Mode = smMedley then
+ begin
+ for P := 0 to PlayersPlay - 1 do
+ Player[P] := PlaylistMedley.Stats[ActualRound].Player[P];
+ end;
+
+ ResetScores;
+end;
+
procedure TScreenScore.LoadSwapTextures;
var
P, I: integer;
@@ -621,23 +696,15 @@ begin
inherited;
- MapPlayersToPosition;
-
- for P := 1 to PlayersPlay do
+ ActualRound := 0;
+ if ScreenSong.Mode = smMedley then
begin
- // data
- aPlayerScoreScreenDatas[P].Bar_Y := Theme.Score.StaticBackLevel[PlayerPositionMap[P-1].Position].Y;
-
- // ratings
- aPlayerScoreScreenRatings[P].RateEaseStep := 1;
- aPlayerScoreScreenRatings[P].RateEaseValue := 20;
-
- // actual values
- TextScore_ActualValue[P] := 0;
- TextPhrase_ActualValue[P] := 0;
- TextGolden_ActualValue[P] := 0;
+ for P := 0 to PlayersPlay - 1 do
+ Player[P] := PlaylistMedley.Stats[ActualRound].Player[P];
end;
+ MapPlayersToPosition;
+
Text[TextArtist].Text := CurrentSong.Artist;
Text[TextTitle].Text := CurrentSong.Title;
Text[TextArtistTitle].Text := CurrentSong.Artist + ' - ' + CurrentSong.Title;
@@ -672,43 +739,29 @@ begin
for P := 1 to 6 do
begin
- Text[TextName[P]].Visible := V[P];
- Text[TextScore[P]].Visible := V[P];
-
- // We set alpha to 0 , so we can nicely blend them in when we need them
- Text[TextScore[P]].Alpha := 0;
- Text[TextNotesScore[P]].Alpha := 0;
- Text[TextNotes[P]].Alpha := 0;
- Text[TextLineBonus[P]].Alpha := 0;
- Text[TextLineBonusScore[P]].Alpha := 0;
- Text[TextGoldenNotes[P]].Alpha := 0;
- Text[TextGoldenNotesScore[P]].Alpha := 0;
- Text[TextTotal[P]].Alpha := 0;
- Text[TextTotalScore[P]].Alpha := 0;
- Statics[StaticBoxLightest[P]].Texture.Alpha := 0;
- Statics[StaticBoxLight[P]].Texture.Alpha := 0;
- Statics[StaticBoxDark[P]].Texture.Alpha := 0;
-
- Text[TextNotes[P]].Visible := V[P];
- Text[TextNotesScore[P]].Visible := V[P];
- Text[TextLineBonus[P]].Visible := V[P];
- Text[TextLineBonusScore[P]].Visible := V[P];
- Text[TextGoldenNotes[P]].Visible := V[P];
- Text[TextGoldenNotesScore[P]].Visible := V[P];
- Text[TextTotal[P]].Visible := V[P];
- Text[TextTotalScore[P]].Visible := V[P];
+ Text[TextName[P]].Visible := V[P];
+ Text[TextScore[P]].Visible := V[P];
+
+ Text[TextNotes[P]].Visible := V[P];
+ Text[TextNotesScore[P]].Visible := V[P];
+ Text[TextLineBonus[P]].Visible := V[P];
+ Text[TextLineBonusScore[P]].Visible := V[P];
+ Text[TextGoldenNotes[P]].Visible := V[P];
+ Text[TextGoldenNotesScore[P]].Visible := V[P];
+ Text[TextTotal[P]].Visible := V[P];
+ Text[TextTotalScore[P]].Visible := V[P];
for I := 0 to high(PlayerStatic[P]) do
Statics[PlayerStatic[P, I]].Visible := V[P];
for I := 0 to high(PlayerTexts[P]) do
- Text[PlayerTexts[P, I]].Visible := V[P];
+ Text[PlayerTexts[P, I]].Visible := V[P];
Statics[StaticBoxLightest[P]].Visible := V[P];
Statics[StaticBoxLight[P]].Visible := V[P];
Statics[StaticBoxDark[P]].Visible := V[P];
-
- Statics[StaticPlayerIdBox[P]].Visible := V[P];
+
+ Statics[StaticPlayerIdBox[P]].Visible := V[P];
// we draw that on our own
Statics[StaticBackLevel[P]].Visible := false;
@@ -717,9 +770,51 @@ begin
Statics[StaticLevelRound[P]].Visible := false;
end;
+ RefreshTexts;
+end;
+
+procedure TScreenScore.ResetScores;
+var
+ P: integer;
+
+begin
+ for P := 1 to PlayersPlay do
+ begin
+ // data
+ aPlayerScoreScreenDatas[P].Bar_Y := Theme.Score.StaticBackLevel[PlayerPositionMap[P-1].Position].Y;
+
+ // ratings
+ aPlayerScoreScreenRatings[P].RateEaseStep := 1;
+ aPlayerScoreScreenRatings[P].RateEaseValue := 20;
+
+ // actual values
+ TextScore_ActualValue[P] := 0;
+ TextPhrase_ActualValue[P] := 0;
+ TextGolden_ActualValue[P] := 0;
+ end;
+
+ for P := 1 to 6 do
+ begin
+ // We set alpha to 0 , so we can nicely blend them in when we need them
+ Text[TextScore[P]].Alpha := 0;
+ Text[TextNotesScore[P]].Alpha := 0;
+ Text[TextNotes[P]].Alpha := 0;
+ Text[TextLineBonus[P]].Alpha := 0;
+ Text[TextLineBonusScore[P]].Alpha := 0;
+ Text[TextGoldenNotes[P]].Alpha := 0;
+ Text[TextGoldenNotesScore[P]].Alpha := 0;
+ Text[TextTotal[P]].Alpha := 0;
+ Text[TextTotalScore[P]].Alpha := 0;
+ Statics[StaticBoxLightest[P]].Texture.Alpha := 0;
+ Statics[StaticBoxLight[P]].Texture.Alpha := 0;
+ Statics[StaticBoxDark[P]].Texture.Alpha := 0;
+ end;
+
BarScore_EaseOut_Step := 1;
BarPhrase_EaseOut_Step := 1;
BarGolden_EaseOut_Step := 1;
+
+ BarTime := SDL_GetTicks();
end;
procedure TScreenScore.onShowFinish;
diff --git a/src/screens/UScreenSing.pas b/src/screens/UScreenSing.pas
index 221526f8..ff4f33e6 100644
--- a/src/screens/UScreenSing.pas
+++ b/src/screens/UScreenSing.pas
@@ -36,24 +36,30 @@ interface
uses
SysUtils,
SDL,
- TextGL,
gl,
+ TextGL,
UFiles,
UGraphicClasses,
+ UHookableEvent,
UIni,
ULog,
ULyrics,
UMenu,
UMusic,
+ UPath,
USingScores,
USongs,
UTexture,
UThemes,
- UPath,
- UTime,
- UHookableEvent;
+ UTime;
type
+ TPos = record // Lines[part].Line[line].Note[note]
+ part: integer;
+ line: integer;
+ note: integer;
+ end;
+
TLyricsSyncSource = class(TSyncSource)
function GetClock(): real; override;
end;
@@ -72,11 +78,18 @@ type
TScreenSing = class(TMenu)
private
fShowVisualization: boolean;
- fCurrentVideo: IVideo;
- fVideoClip: IVideo;
- fLyricsSync: TLyricsSyncSource;
- fMusicSync: TMusicSyncSource;
- fTimebarMode: TTimebarMode;
+ fCurrentVideo: IVideo;
+ fVideoClip: IVideo;
+ fLyricsSync: TLyricsSyncSource;
+ fMusicSync: TMusicSyncSource;
+ fTimebarMode: TTimebarMode;
+
+ StartNote, EndNote: TPos;
+
+ procedure LoadNextSong();
+ procedure UpdateMedleyStats(medley_end: boolean);
+ procedure DrawMedleyCountdown();
+ procedure SongError();
protected
eSongLoaded: THookableEvent; //< event is called after lyrics of a song are loaded on OnShow
Paused: boolean; //pause Mod
@@ -97,6 +110,8 @@ type
StaticP1ThreeP: integer;
TextP1ThreeP: integer;
+ MedleyStart, MedleyEnd: real;
+
StaticP2R: integer;
TextP2R: integer;
@@ -120,12 +135,12 @@ type
// some settings to be set by plugins
Settings: record
- Finish: Boolean; //< if true, screen will finish on next draw
+ Finish: boolean; //< if true, screen will finish on next draw
- LyricsVisible: Boolean; //< shows or hides lyrics
- NotesVisible: Integer; //< if bit[playernum] is set the notes for the specified player are visible. By default all players notes are visible
+ LyricsVisible: boolean; //< shows or hides lyrics
+ NotesVisible: integer; //< if bit[playernum] is set the notes for the specified player are visible. By default all players notes are visible
- PlayerEnabled: Integer; //< defines whether a player can score atm
+ PlayerEnabled: integer; //< defines whether a player can score atm
end;
procedure ClearSettings;
procedure ApplySettings; //< applies changes of settings record
@@ -152,24 +167,24 @@ implementation
uses
Classes,
Math,
+ UDisplay,
UDraw,
UGraphic,
ULanguage,
UNote,
+ UParty,
URecord,
USong,
- UDisplay,
- UParty,
UUnicodeUtils;
// method for input parsing. if false is returned, getnextwindow
// should be checked to know the next window to load;
-function TScreenSing.ParseInput(PressedKey: Cardinal; CharCode: UCS4Char;
+function TScreenSing.ParseInput(PressedKey: cardinal; CharCode: UCS4Char;
PressedDown: boolean): boolean;
begin
Result := true;
- if (PressedDown) then
+ if PressedDown then
begin // key down
// check normal keys
case UCS4UpperCase(CharCode) of
@@ -213,7 +228,7 @@ begin
// toggle time display
Ord('T'):
begin
- if (fTimebarMode = High(TTimebarMode)) then
+ if fTimebarMode = High(TTimebarMode) then
fTimebarMode := Low(TTimebarMode)
else
Inc(fTimebarMode);
@@ -228,6 +243,8 @@ begin
begin
// record sound hack:
//Sound[0].BufferLong
+ if ScreenSong.Mode = smMedley then
+ PlaylistMedley.NumMedleySongs := PlaylistMedley.CurrentMedleySong;
Finish;
FadeOut := true;
@@ -360,17 +377,14 @@ end;
procedure TScreenSing.OnShow;
var
- Index: integer;
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;
- VideoFile, BgFile: IPath;
- success: boolean;
BadPlayer: integer;
+
begin
inherited;
@@ -382,22 +396,21 @@ begin
ClearSettings;
Party.CallBeforeSing;
- // reset video playback engine
- fCurrentVideo := nil;
-
- // setup score manager
- Scores.ClearPlayers; // clear old player values
- Color.R := 0;
- Color.G := 0;
- Color.B := 0; // dummy atm <- \(O.o)/? B like bummy?
+ // prepare players
+ SetLength(Player, PlayersPlay);
- // add new players
- for Index := 0 to PlayersPlay - 1 do
+ //Reset Player Medley stats
+ if (ScreenSong.Mode = smMedley) then
begin
- Scores.AddPlayer(Tex_ScoreBG[Index], Color);
- end;
+ PlaylistMedley.CurrentMedleySong:=1;
- Scores.Init; // get positions for players
+ PlaylistMedley.NumPlayer := PlayersPlay;
+ SetLength(PlaylistMedley.Stats, 0);
+
+ fTimebarMode := tbmRemaining;
+ end
+ else
+ fTimebarMode := tbmCurrent;
// prepare players
SetLength(Player, PlayersPlay);
@@ -472,11 +485,265 @@ begin
Statics[StaticP3R].Visible := V3R;
Text[TextP3R].Visible := V3R;
- fTimebarMode := tbmCurrent;
+ BadPlayer := AudioInputProcessor.CheckPlayersConfig(PlayersPlay);
+ if BadPlayer <> 0 then
+ begin
+ ScreenPopupError.ShowPopup(
+ Format(Language.Translate('ERROR_PLAYER_NO_DEVICE_ASSIGNMENT'),
+ [BadPlayer]));
+ end;
+
+ // set custom options
+ case Ini.LyricsFont of
+ 0: // normal fonts
+ begin
+ Lyrics.FontStyle := ftNormal;
+
+ Lyrics.LineColor_en.R := Skin_FontR;
+ Lyrics.LineColor_en.G := Skin_FontG;
+ Lyrics.LineColor_en.B := Skin_FontB;
+ Lyrics.LineColor_en.A := 1;
+
+ Lyrics.LineColor_dis.R := 0.4;
+ Lyrics.LineColor_dis.G := 0.4;
+ Lyrics.LineColor_dis.B := 0.4;
+ Lyrics.LineColor_dis.A := 1;
+
+ Lyrics.LineColor_act.R := 0.02;
+ Lyrics.LineColor_act.G := 0.6;
+ Lyrics.LineColor_act.B := 0.8;
+ Lyrics.LineColor_act.A := 1;
+ end;
+ 1, 2: // outline fonts
+ begin
+ if (Ini.LyricsFont = 1) then
+ Lyrics.FontStyle := ftOutline1
+ else
+ Lyrics.FontStyle := ftOutline2;
+
+ Lyrics.LineColor_en.R := 0.75;
+ Lyrics.LineColor_en.G := 0.75;
+ Lyrics.LineColor_en.B := 1;
+ Lyrics.LineColor_en.A := 1;
+
+ Lyrics.LineColor_dis.R := 0.8;
+ Lyrics.LineColor_dis.G := 0.8;
+ Lyrics.LineColor_dis.B := 0.8;
+ Lyrics.LineColor_dis.A := 1;
+
+ Lyrics.LineColor_act.R := 0.5;
+ Lyrics.LineColor_act.G := 0.5;
+ Lyrics.LineColor_act.B := 1;
+ Lyrics.LineColor_act.A := 1;
+ end;
+ end; // case
+
+ // deactivate pause
+ Paused := false;
+
+ LoadNextSong();
+
+ Log.LogStatus('End', 'OnShow');
+end;
+
+procedure TScreenSing.onShowFinish;
+begin
+ // hide cursor on singscreen show
+ Display.SetCursor;
+
+ // prepare music
+ // Important: AudioPlayback must not be initialized in onShow() as TScreenSong
+ // uses stops AudioPlayback in onHide() which interferes with TScreenSings onShow.
+ AudioPlayback.Open(CurrentSong.Path.Append(CurrentSong.Mp3));
+ if ScreenSong.Mode = smMedley then
+ AudioPlayback.SetVolume(0.1)
+ else
+ AudioPlayback.SetVolume(1.0);
+ AudioPlayback.Position := LyricsState.GetCurrentTime();
+
+ // 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
+ if ScreenSong.Mode = smMedley then
+ AudioPlayback.FadeIn(CurrentSong.Medley.FadeIn_time, 1.0)
+ else
+ AudioPlayback.Play();
+
+
+ // start timer
+ CountSkipTimeSet;
+end;
+
+procedure TScreenSing.SongError();
+var
+ I, len: integer;
+
+begin
+ if ScreenSong.Mode <> smMedley then
+ begin
+ // error loading song -> go back to previous screen and show some error message
+ Display.AbortScreenChange;
+ // select new song in party mode
+ if ScreenSong.Mode = smPartyMode then
+ ScreenSong.SelectRandomSong();
+ 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
+ else
+ begin
+ if PlaylistMedley.CurrentMedleySong < PlaylistMedley.NumMedleySongs then
+ begin
+ //Error Loading Song in Medley Mode -> skip actual Medley Song an go on if possible
+ len := Length(PlaylistMedley.Song);
+ for I := PlaylistMedley.CurrentMedleySong-1 to len - 1 do
+ PlaylistMedley.Song[I] := PlaylistMedley.Song[I+1];
+
+ SetLength(PlaylistMedley.Song, Len-1);
+ Dec(PlaylistMedley.NumMedleySongs);
+ LoadNextSong;
+ Exit;
+ end
+ else
+ begin
+ if PlaylistMedley.NumMedleySongs = 1 then
+ begin
+ //Error Loading Song in Medley Mode -> Go back to Song Screen and Show some Error Message
+ Display.AbortScreenChange;
+ // select new song in party mode
+ if ScreenSong.Mode = smPartyMode then
+ ScreenSong.SelectRandomSong();
+ 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
+ else
+ begin
+ //Error Loading Song in Medley Mode -> Finish actual round
+ len := Length(PlaylistMedley.Song);
+ SetLength(PlaylistMedley.Song, len-1);
+ Dec(PlaylistMedley.NumMedleySongs);
+ Finish;
+ Exit;
+ end;
+ end;
+ end;
+end;
+
+procedure TScreenSing.LoadNextSong();
+var
+ Color: TRGB;
+ Index: integer;
+ VideoFile: IPath;
+ BgFile: IPath;
+ success: boolean;
+
+ function FindNote(beat: integer): TPos;
+ var
+ line: integer;
+ note: integer;
+ found: boolean;
+ min: integer;
+ diff: integer;
+
+ begin
+ found := false;
+
+ for line := 0 to length(Lines[0].Line) - 1 do
+ begin
+ for note := 0 to length(Lines[0].Line[line].Note) - 1 do
+ begin
+ if (beat >= Lines[0].Line[line].Note[line].Start) and
+ (beat <= Lines[0].Line[line].Note[line].Start + Lines[0].Line[line].Note[note].Length) then
+ begin
+ Result.part := 0;
+ Result.line := line;
+ Result.note := note;
+ found:=true;
+ break;
+ end;
+ end;
+ end;
+
+ if found then //found exactly
+ exit;
+
+ min := high(integer);
+ //second try (approximating)
+ for line := 0 to length(Lines[0].Line) - 1 do
+ begin
+ for note := 0 to length(Lines[0].Line[line].Note) - 1 do
+ begin
+ diff := abs(Lines[0].Line[line].Note[note].Start - beat);
+ if diff < min then
+ begin
+ Result.part := 0;
+ Result.line := line;
+ Result.note := note;
+ min := diff;
+ end;
+ end;
+ end;
+ end;
+
+begin
+ // reset video playback engine
+ fCurrentVideo := nil;
+
+ // setup score manager
+ Scores.ClearPlayers; // clear old player values
+ Color.R := 0;
+ Color.G := 0;
+ Color.B := 0; // dummy atm <- \(O.o)/? B like bummy?
+
+ // add new players
+ for Index := 0 to PlayersPlay - 1 do
+ begin
+ Scores.AddPlayer(Tex_ScoreBG[Index], Color);
+ end;
+
+ Scores.Init; // get positions for players
// FIXME: sets path and filename to ''
ResetSingTemp;
+ PlaylistMedley.ApplausePlayed := false;
+
+ if ScreenSong.Mode = smMedley then
+ begin
+ if length(PlaylistMedley.Song) >= PlaylistMedley.CurrentMedleySong then
+ begin
+ CatSongs.Selected := PlaylistMedley.Song[PlaylistMedley.CurrentMedleySong-1];
+ //Music.Open(CatSongs.Song[CatSongs.Selected].Path + CatSongs.Song[CatSongs.Selected].Mp3);
+ end
+ else
+ begin
+ SongError;
+ Exit;
+ end;
+ end;
+
CurrentSong := CatSongs.Song[CatSongs.Selected];
// FIXME: bad style, put the try-except into loadsong() and not here
@@ -485,27 +752,40 @@ begin
if CurrentSong.FileName.GetExtension.ToUTF8 = '.xml' then
success := CurrentSong.AnalyseXML and CurrentSong.LoadXMLSong()
else
- success := CurrentSong.Analyse and CurrentSong.LoadSong();
+ 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 ScreenSong.Mode = smPartyMode then
- ScreenSong.SelectRandomSong();
- 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;
+ SongError();
Exit;
end;
+ // Set up Medley timings
+ if ScreenSong.Mode = smMedley then
+ begin
+ CurrentSong.SetMedleyMode();
+
+{ ** ToDo
+ Text[SongNameText].Text := IntToStr(PlaylistMedley.CurrentMedleySong) +
+ '/' + IntToStr(PlaylistMedley.NumMedleySongs) + ': ' +
+ CurrentSong.Artist + ' - ' + CurrentSong.Title;
+}
+ //medley start and end timestamps
+ StartNote := FindNote(CurrentSong.Medley.StartBeat - round(CurrentSong.BPM[0].BPM*CurrentSong.Medley.FadeIn_time / 60));
+ MedleyStart := GetTimeFromBeat(Lines[0].Line[StartNote.line].Note[0].Start);
+
+ //check Medley-Start
+ if MedleyStart+CurrentSong.Medley.FadeIn_time * 0.5 > GetTimeFromBeat(CurrentSong.Medley.StartBeat) then
+ MedleyStart := GetTimeFromBeat(CurrentSong.Medley.StartBeat) - CurrentSong.Medley.FadeIn_time;
+ if MedleyStart < 0 then
+ MedleyStart := 0;
+
+ MedleyEnd := GetTimeFromBeat(CurrentSong.Medley.EndBeat) + CurrentSong.Medley.FadeOut_time;
+ end;
+
{*
* == Background ==
* We have four types of backgrounds:
@@ -529,7 +809,10 @@ begin
if (fVideoClip <> nil) then
begin
fShowVisualization := false;
- fCurrentVideo.Position := CurrentSong.VideoGAP + CurrentSong.Start;
+ if ScreenSong.Mode = smMedley then
+ fCurrentVideo.Position := CurrentSong.VideoGAP + MedleyStart
+ else
+ fCurrentVideo.Position := CurrentSong.VideoGAP + CurrentSong.Start;
fCurrentVideo.Play;
end;
end;
@@ -572,28 +855,31 @@ begin
begin
fShowVisualization := true;
fCurrentVideo := Visualization.Open(PATH_NONE);
- if (fCurrentVideo <> nil) then
+ 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
- LyricsState.TotalTime := AudioPlayback.Length;
- LyricsState.UpdateBeats();
- BadPlayer := AudioInputProcessor.CheckPlayersConfig(PlayersPlay);
- if (BadPlayer <> 0) then
+ if ScreenSong.Mode = smMedley then
begin
- ScreenPopupError.ShowPopup(
- Format(Language.Translate('ERROR_PLAYER_NO_DEVICE_ASSIGNMENT'),
- [BadPlayer]));
+ LyricsState.SetCurrentTime(MedleyStart);
+ LyricsState.StartTime := CurrentSong.Gap;
+ LyricsState.TotalTime := MedleyEnd;
+ end
+ else
+ begin
+ LyricsState.SetCurrentTime(CurrentSong.Start);
+ LyricsState.StartTime := CurrentSong.Gap;
+ if CurrentSong.Finish > 0 then
+ LyricsState.TotalTime := CurrentSong.Finish / 1000
+ else
+ LyricsState.TotalTime := AudioPlayback.Length;
end;
+ LyricsState.UpdateBeats();
+
// prepare and start voice-capture
AudioInput.CaptureStart;
@@ -619,51 +905,6 @@ begin
// main text
Lyrics.Clear(CurrentSong.BPM[0].BPM, CurrentSong.Resolution);
- // set custom options
- case Ini.LyricsFont of
- 0: // normal fonts
- begin
- Lyrics.FontStyle := ftNormal;
-
- Lyrics.LineColor_en.R := Skin_FontR;
- Lyrics.LineColor_en.G := Skin_FontG;
- Lyrics.LineColor_en.B := Skin_FontB;
- Lyrics.LineColor_en.A := 1;
-
- Lyrics.LineColor_dis.R := 0.4;
- Lyrics.LineColor_dis.G := 0.4;
- Lyrics.LineColor_dis.B := 0.4;
- Lyrics.LineColor_dis.A := 1;
-
- Lyrics.LineColor_act.R := 0.02;
- Lyrics.LineColor_act.G := 0.6;
- Lyrics.LineColor_act.B := 0.8;
- Lyrics.LineColor_act.A := 1;
- end;
- 1, 2: // outline fonts
- begin
- if (Ini.LyricsFont = 1) then
- Lyrics.FontStyle := ftOutline1
- else
- Lyrics.FontStyle := ftOutline2;
-
- Lyrics.LineColor_en.R := 0.75;
- Lyrics.LineColor_en.G := 0.75;
- Lyrics.LineColor_en.B := 1;
- Lyrics.LineColor_en.A := 1;
-
- Lyrics.LineColor_dis.R := 0.8;
- Lyrics.LineColor_dis.G := 0.8;
- Lyrics.LineColor_dis.B := 0.8;
- Lyrics.LineColor_dis.A := 1;
-
- Lyrics.LineColor_act.R := 0.5;
- Lyrics.LineColor_act.G := 0.5;
- Lyrics.LineColor_act.B := 1;
- Lyrics.LineColor_act.A := 1;
- end;
- end; // case
-
// initialize lyrics by filling its queue
while (not Lyrics.IsQueueFull) and
(Lyrics.LineCounter <= High(Lines[0].Line)) do
@@ -671,9 +912,6 @@ begin
Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter]);
end;
- // deactivate pause
- Paused := false;
-
// kill all stars not killed yet (goldenstarstwinkle mod)
GoldenRec.SentenceChange;
@@ -684,51 +922,18 @@ begin
if Lines[0].Line[Index].TotalNotes = 0 then
Inc(NumEmptySentences);
- eSongLoaded.CallHookChain(False);
+ eSongLoaded.CallHookChain(false);
- Log.LogStatus('End', 'OnShow');
-end;
-
-procedure TScreenSing.onShowFinish;
-begin
- // hide cursor on singscreen show
- Display.SetCursor;
-
- // prepare music
- // Important: AudioPlayback must not be initialized in onShow() as TScreenSong
- // uses stops AudioPlayback in onHide() which interferes with TScreenSings onShow.
- AudioPlayback.Open(CurrentSong.Path.Append(CurrentSong.Mp3));
- AudioPlayback.SetVolume(1.0);
- AudioPlayback.Position := CurrentSong.Start;
-
- // 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;
+ if (ScreenSong.Mode = smMedley) and (PlaylistMedley.CurrentMedleySong > 1) then
+ onShowFinish;
end;
procedure TScreenSing.ClearSettings;
begin
- Settings.Finish := False;
- Settings.LyricsVisible := True;
- Settings.NotesVisible := high(Integer);
- Settings.PlayerEnabled := high(Integer);
+ Settings.Finish := false;
+ Settings.LyricsVisible := true;
+ Settings.NotesVisible := high(integer);
+ Settings.PlayerEnabled := high(integer);
end;
{ applies changes of settings record }
@@ -739,13 +944,13 @@ end;
procedure TScreenSing.EndSong;
begin
- Settings.Finish := True;
+ Settings.Finish := true;
end;
procedure TScreenSing.OnHide;
begin
// background texture
- if (Tex_Background.TexNum > 0) then
+ if Tex_Background.TexNum > 0 then
begin
glDeleteTextures(1, PGLuint(@Tex_Background.TexNum));
Tex_Background.TexNum := 0;
@@ -757,15 +962,19 @@ end;
function TScreenSing.Draw: boolean;
var
- DisplayTime: real;
- DisplayPrefix: string;
- DisplayMin: integer;
- DisplaySec: integer;
- T: integer;
- CurLyricsTime: real;
- VideoFrameTime: Extended;
- Line: TLyricLine;
- LastWord: TLyricWord;
+ DisplayTime: real;
+ DisplayPrefix: string;
+ DisplayMin: integer;
+ DisplaySec: integer;
+ T: integer;
+ CurLyricsTime: real;
+ TotalTime: real;
+ VideoFrameTime: extended;
+ Line: TLyricLine;
+ LastWord: TLyricWord;
+ medley_end: boolean;
+ medley_start_applause: boolean;
+
begin
Background.Draw;
@@ -805,19 +1014,28 @@ begin
// retrieve current lyrics time, we have to store the value to avoid
// that min- and sec-values do not match
- CurLyricsTime := LyricsState.GetCurrentTime();
+ if ScreenSong.Mode = smMedley then
+ begin
+ CurLyricsTime := LyricsState.GetCurrentTime() - ScreenSing.MedleyStart;
+ TotalTime := ScreenSing.MedleyEnd - ScreenSing.MedleyStart;
+ end
+ else
+ begin
+ CurLyricsTime := LyricsState.GetCurrentTime();
+ TotalTime := LyricsState.TotalTime;
+ end;
// retrieve time for timebar text
case (fTimebarMode) of
tbmRemaining: begin
- DisplayTime := LyricsState.TotalTime - CurLyricsTime;
+ DisplayTime := TotalTime - CurLyricsTime;
DisplayPrefix := '-';
end;
tbmTotal: begin
- DisplayTime := LyricsState.TotalTime;
+ DisplayTime := TotalTime;
DisplayPrefix := '#';
end;
- else begin
+ else begin // current time
DisplayTime := CurLyricsTime;
DisplayPrefix := '';
end;
@@ -838,6 +1056,19 @@ begin
SungToEnd := true;
end;
+ // for medley-mode:
+ CurLyricsTime := LyricsState.GetCurrentTime();
+ if (ScreenSong.Mode = smMedley) and (CurLyricsTime > MedleyEnd) then
+ medley_end := true
+ else
+ medley_end := false;
+
+ if (ScreenSong.Mode = smMedley) and (CurLyricsTime >
+ GetTimeFromBeat(CurrentSong.Medley.EndBeat)) then
+ medley_start_applause := true
+ else
+ medley_start_applause := false;
+
// update and draw movie
if Assigned(fCurrentVideo) then
begin
@@ -866,28 +1097,35 @@ begin
// draw static menu (FG)
DrawFG;
+ //Medley Countdown
+ if ScreenSong.Mode = smMedley then
+ DrawMedleyCountdown;
+
// 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 AudioPlayback.Finished) and
- ((CurrentSong.Finish = 0) or
- (LyricsState.GetCurrentTime() * 1000 <= CurrentSong.Finish)) and
- (not Settings.Finish) then
+ if (not AudioPlayback.Finished) and (not medley_end or (ScreenSong.Mode <> smMedley)) and
+ ((CurrentSong.Finish = 0) or (LyricsState.GetCurrentTime()*1000 <= CurrentSong.Finish)) and
+ (not Settings.Finish) then
begin
// analyze song if not paused
if (not Paused) then
begin
Sing(Self);
+
+ //Update Medley Stats
+ if (ScreenSong.Mode = smMedley) and not FadeOut then
+ UpdateMedleyStats(medley_start_applause);
+
Party.CallOnSing;
end;
end
else
begin
- if (not FadeOut) and (Screens=1) or (ScreenAct=2) then
+ if (not FadeOut) and (Screens = 1) or (ScreenAct = 2) then
begin
Finish;
- FadeOut := true;
end;
end;
end;
@@ -915,6 +1153,10 @@ begin
end;
procedure TScreenSing.Finish;
+var
+ I, J: integer;
+ len, num: integer;
+
begin
AudioInput.CaptureStop;
AudioPlayback.Stop;
@@ -944,34 +1186,134 @@ begin
SetFontItalic(false);
- if not FadeOut then
- Party.CallAfterSing;
+ if ScreenSong.Mode = smMedley then
+ begin
+ if not FadeOut then
+ begin
+ for I := 0 to PlayersPlay - 1 do
+ PlaylistMedley.Stats[Length(PlaylistMedley.Stats) - 1].Player[I] := Player[I];
+
+ Inc(PlaylistMedley.CurrentMedleySong);
+ if PlaylistMedley.CurrentMedleySong <= PlaylistMedley.NumMedleySongs then
+ begin
+ LoadNextSong;
+ end
+ else
+ begin
+ //build sums
+ len := Length(PlaylistMedley.Stats);
+ num := PlaylistMedley.NumPlayer;
+
+ SetLength(PlaylistMedley.Stats, len + 1);
+ SetLength(PlaylistMedley.Stats[len].Player, num);
+
+ for J := 0 to len - 1 do
+ begin
+ for I := 0 to num - 1 do
+ begin
+ PlaylistMedley.Stats[len].Player[I].Score :=
+ PlaylistMedley.Stats[len].Player[I].Score +
+ PlaylistMedley.Stats[J].Player[I].Score;
+
+ PlaylistMedley.Stats[len].Player[I].ScoreLine :=
+ PlaylistMedley.Stats[len].Player[I].ScoreLine +
+ PlaylistMedley.Stats[J].Player[I].ScoreLine;
+
+ PlaylistMedley.Stats[len].Player[I].ScoreGolden :=
+ PlaylistMedley.Stats[len].Player[I].ScoreGolden +
+ PlaylistMedley.Stats[J].Player[I].ScoreGolden;
+
+ PlaylistMedley.Stats[len].Player[I].ScoreInt :=
+ PlaylistMedley.Stats[len].Player[I].ScoreInt +
+ PlaylistMedley.Stats[J].Player[I].ScoreInt;
+
+ PlaylistMedley.Stats[len].Player[I].ScoreLineInt :=
+ PlaylistMedley.Stats[len].Player[I].ScoreLineInt +
+ PlaylistMedley.Stats[J].Player[I].ScoreLineInt;
+
+ PlaylistMedley.Stats[len].Player[I].ScoreGoldenInt :=
+ PlaylistMedley.Stats[len].Player[I].ScoreGoldenInt +
+ PlaylistMedley.Stats[J].Player[I].ScoreGoldenInt;
+
+ PlaylistMedley.Stats[len].Player[I].ScoreTotalInt :=
+ PlaylistMedley.Stats[len].Player[I].ScoreTotalInt +
+ PlaylistMedley.Stats[J].Player[I].ScoreTotalInt;
+ end; //of for I
+ end; //of for J
+
+ //build mean on sum
+ for I := 0 to num - 1 do
+ begin
+ PlaylistMedley.Stats[len].Player[I].Score := round(
+ PlaylistMedley.Stats[len].Player[I].Score / len);
+
+ PlaylistMedley.Stats[len].Player[I].ScoreLine := round(
+ PlaylistMedley.Stats[len].Player[I].ScoreLine / len);
+
+ PlaylistMedley.Stats[len].Player[I].ScoreGolden := round(
+ PlaylistMedley.Stats[len].Player[I].ScoreGolden / len);
+
+ PlaylistMedley.Stats[len].Player[I].ScoreInt := round(
+ PlaylistMedley.Stats[len].Player[I].ScoreInt / len);
+
+ PlaylistMedley.Stats[len].Player[I].ScoreLineInt := round(
+ PlaylistMedley.Stats[len].Player[I].ScoreLineInt / len);
+
+ PlaylistMedley.Stats[len].Player[I].ScoreGoldenInt := round(
+ PlaylistMedley.Stats[len].Player[I].ScoreGoldenInt / len);
+
+ PlaylistMedley.Stats[len].Player[I].ScoreTotalInt := round(
+ PlaylistMedley.Stats[len].Player[I].ScoreTotalInt / len);
+ end;
+
+ Party.CallAfterSing;
+ FadeOut:=true;
+ end;
+ end;
+ end
+ else
+ begin
+ SetLength(PlaylistMedley.Stats, 1);
+ SetLength(PlaylistMedley.Stats[0].Player, PlayersPlay);
+ for I := 0 to PlayersPlay - 1 do
+ PlaylistMedley.Stats[0].Player[I] := Player[I];
+
+ PlaylistMedley.Stats[0].SongArtist := CurrentSong.Artist;
+ PlaylistMedley.Stats[0].SongTitle := CurrentSong.Title;
+
+ if not FadeOut then
+ Party.CallAfterSing;
+
+ FadeOut := true;
+ end;
end;
procedure TScreenSing.OnSentenceEnd(SentenceIndex: cardinal);
var
- PlayerIndex: byte;
- CurrentPlayer: PPLayer;
- CurrentScore: real;
- Line: PLine;
+ 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
+ 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
+ if Line.TotalNotes <= 0 then
Exit;
// set max song score
- if (Ini.LineBonus = 0) then
+ if Ini.LineBonus = 0 then
MaxSongScore := MAX_SONG_SCORE
else
MaxSongScore := MAX_SONG_SCORE - MAX_SONG_LINE_BONUS;
@@ -990,7 +1332,7 @@ begin
LineScore := CurrentScore - CurrentPlayer.ScoreLast;
// check for lines with low points
- if (MaxLineScore <= 2) then
+ if MaxLineScore <= 2 then
LinePerfection := 1
else
// determine LinePerfection
@@ -999,13 +1341,13 @@ begin
LinePerfection := LineScore / (MaxLineScore - 2);
// clamp LinePerfection to range [0..1]
- if (LinePerfection < 0) then
+ if LinePerfection < 0 then
LinePerfection := 0
- else if (LinePerfection > 1) then
+ else if LinePerfection > 1 then
LinePerfection := 1;
// add line-bonus if enabled
- if (Ini.LineBonus > 0) then
+ if Ini.LineBonus > 0 then
begin
// line-bonus points (same for each line, no matter how long the line is)
LineBonus := MAX_SONG_LINE_BONUS / (Length(Lines[0].Line) -
@@ -1028,7 +1370,7 @@ begin
Scores.RaiseScore(PlayerIndex, CurrentPlayer.ScoreTotalInt);
// PerfectLineTwinkle (effect), part 1
- if (Ini.EffectSing = 1) then
+ if Ini.EffectSing = 1 then
CurrentPlayer.LastSentencePerfect := (LinePerfection >= 1);
// refresh last score
@@ -1036,7 +1378,7 @@ begin
end;
// PerfectLineTwinkle (effect), part 2
- if (Ini.EffectSing = 1) then
+ if Ini.EffectSing = 1 then
GoldenRec.SpawnPerfectLineTwinkle;
end;
@@ -1052,7 +1394,7 @@ begin
(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
+ if Lyrics.LineCounter <= High(Lines[0].Line) then
Lyrics.AddLine(@Lines[0].Line[Lyrics.LineCounter])
else
Lyrics.AddLine(nil);
@@ -1069,5 +1411,60 @@ begin
Result := AudioPlayback.Position;
end;
-end.
+procedure TScreenSing.UpdateMedleyStats(medley_end: boolean);
+var
+ len, num, I: integer;
+
+begin
+ len := Length(PlaylistMedley.Stats);
+ num := PlaylistMedley.NumPlayer;
+
+ if (PlaylistMedley.CurrentMedleySong > len) and
+ (PlaylistMedley.CurrentMedleySong <= PlaylistMedley.NumMedleySongs) then
+ begin
+ inc(len);
+ SetLength(PlaylistMedley.Stats, len);
+ SetLength(PlaylistMedley.Stats[len - 1].Player, num);
+ PlaylistMedley.Stats[len-1].SongArtist := CurrentSong.Artist;
+ PlaylistMedley.Stats[len-1].SongTitle := CurrentSong.Title;
+ end;
+
+ if PlaylistMedley.CurrentMedleySong <= PlaylistMedley.NumMedleySongs then
+ for I := 0 to num - 1 do
+ PlaylistMedley.Stats[len - 1].Player[I] := Player[I];
+
+ if medley_end and not PlaylistMedley.ApplausePlayed and
+ (PlaylistMedley.CurrentMedleySong <= PlaylistMedley.NumMedleySongs) then
+ begin
+ PlaylistMedley.ApplausePlayed := true;
+ end;
+end;
+procedure TScreenSing.DrawMedleyCountdown();
+var
+ w, h: real;
+ timeDiff: real;
+ t: real;
+ CountDownText: UTF8String;
+
+begin
+ if AudioPlayback.Position < GetTimeFromBeat(CurrentSong.Medley.StartBeat) then
+ begin
+ timeDiff := GetTimeFromBeat(CurrentSong.Medley.StartBeat)-AudioPlayback.Position+1;
+ t := frac(timeDiff);
+
+ glColor4f(0.15, 0.30, 0.6, t);
+
+ h := 300 * t * ScreenH / RenderH;
+ SetFontStyle(ftBold);
+ SetFontItalic(false);
+ SetFontSize(h);
+ CountDownText := IntToStr(round(timeDiff - t));
+ w := glTextWidth(PChar(CountDownText));
+
+ SetFontPos (RenderW / 2 - w / 2, RenderH / 2 - h / 2);
+ glPrint(PChar(CountDownText));
+ end;
+end;
+
+end.
diff --git a/src/screens/UScreenSong.pas b/src/screens/UScreenSong.pas
index 6fe8d204..7558a59b 100644
--- a/src/screens/UScreenSong.pas
+++ b/src/screens/UScreenSong.pas
@@ -38,7 +38,6 @@ uses
SDL,
UCommon,
UDisplay,
- UPath,
UFiles,
UIni,
ULanguage,
@@ -46,6 +45,7 @@ uses
UMenu,
UMenuEqualizer,
UMusic,
+ UPath,
USong,
USongs,
UTexture,
@@ -53,6 +53,8 @@ uses
UTime;
type
+ TVisArr = array of integer;
+
TScreenSong = class(TMenu)
private
Equalizer: Tms_Equalizer;
@@ -161,6 +163,10 @@ type
//Extensions
procedure DrawExtensions;
+
+ //Medley
+ procedure StartMedley(NumSongs: integer; MinSource: TMedleySource);
+ function getVisibleMedleyArr(MinSource: TMedleySource): TVisArr;
end;
implementation
@@ -188,7 +194,7 @@ var
begin
if CatSongs.VisibleSongs > 0 then
begin
- I2:= 0;
+ I2 := 0;
for I := Low(CatSongs.Song) to High(Catsongs.Song) do
begin
if CatSongs.Song[I].Visible then
@@ -209,7 +215,7 @@ var
begin
if CatSongs.VisibleSongs > 0 then
begin
- I2:= 0;
+ I2 := 0;
for I := Low(CatSongs.Song) to High(Catsongs.Song) do
begin
if CatSongs.Song[I].Visible then
@@ -260,9 +266,9 @@ function TScreenSong.ParseInput(PressedKey: cardinal; CharCode: UCS4Char; Presse
var
I: integer;
I2: integer;
- SDL_ModState: word;
- UpperLetter: UCS4Char;
- TempStr: UTF8String;
+ SDL_ModState: word;
+ UpperLetter: UCS4Char;
+ TempStr: UTF8String;
begin
Result := true;
@@ -417,6 +423,39 @@ begin
Exit;
end;
+ Ord('S'):
+ begin
+ Log.LogError('SDL_ModState: ' + inttostr(SDL_ModState));
+ Log.LogError('KMOD_LSHIFT: ' + inttostr(KMOD_LSHIFT));
+ Log.LogError('CatSongs.Song[Interaction].Medley.Source: ' + inttostr(ord(CatSongs.Song[Interaction].Medley.Source)));
+ Log.LogError('msCalculated: ' + inttostr(ord(msCalculated)));
+ Log.LogError('msTag: ' + inttostr(ord(msTag)));
+ Log.LogError('Mode: ' + inttostr(ord(Mode)));
+ Log.LogError('smNormal: ' + inttostr(ord(smNormal)));
+ 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
+ Log.LogError('SDL_ModState: ' + inttostr(SDL_ModState));
+ Log.LogError('KMOD_LSHIFT: ' + inttostr(KMOD_LSHIFT));
+ Log.LogError('length(getVisibleMedleyArr(msCalculated)): ' + inttostr(length(getVisibleMedleyArr(msCalculated))));
+ Log.LogError('msCalculated: ' + inttostr(ord(msCalculated)));
+ Log.LogError('msTag: ' + inttostr(ord(msTag)));
+ Log.LogError('Length(getVisibleMedleyArr(msTag)): ' + inttostr(Length(getVisibleMedleyArr(msTag))));
+ Log.LogError('smNormal: ' + inttostr(ord(smNormal)));
+ Log.LogError('Mode: ' + inttostr(ord(Mode)));
+ 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
@@ -1518,8 +1557,15 @@ begin
// reset video playback engine
fCurrentVideo := nil;
- if Ini.Players <= 3 then PlayersPlay := Ini.Players + 1;
- if Ini.Players = 4 then PlayersPlay := 6;
+ // 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
@@ -1536,21 +1582,21 @@ begin
end;
//Playlist Mode
- if (Mode = smNormal) then
+ if Mode = smNormal then
begin
//If Playlist Shown -> Select Next automatically
- if (CatSongs.CatNumShow = -3) then
+ if CatSongs.CatNumShow = -3 then
begin
SelectNext;
end;
end
//Party Mode
- else if (Mode = smPartyMode) then
+ else if Mode = smPartyMode then
begin
SelectRandomSong;
//Show Menu directly in PartyMode
//But only if selected in Options
- if (Ini.PartyPopup = 1) then
+ if Ini.PartyPopup = 1 then
begin
ScreenSongMenu.MenuShow(SM_Party_Main);
end;
@@ -1810,14 +1856,18 @@ begin
begin
PreviewOpened := Interaction;
- PreviewPos := AudioPlayback.Length / 4;
+ if Song.PreviewStart > 0 then
+ PreviewPos := Song.PreviewStart
+ else
+ PreviewPos := AudioPlayback.Length / 4;
+
// fix for invalid music file lengths
- if (PreviewPos > 60.0) then
+ if (PreviewPos > 60.0) and (Song.PreviewStart = 0) then
PreviewPos := 60.0;
AudioPlayback.Position := PreviewPos;
// set preview volume
- if (Ini.PreviewFading = 0) then
+ if Ini.PreviewFading = 0 then
begin
// music fade disabled: start with full volume
AudioPlayback.SetVolume(IPreviewVolumeVals[Ini.PreviewVolume]);
@@ -2153,4 +2203,131 @@ begin
}
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.