From 52becec3d23472698fc94be8d015fed8155e4879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20K=C3=BCpper?= Date: Tue, 21 Nov 2017 10:20:15 +0100 Subject: [PATCH] Restructered screen-sing for better readability --- Vocaluxe/Screens/CScreenSing.cs | 1719 ++++++++++++++++--------------- 1 file changed, 881 insertions(+), 838 deletions(-) diff --git a/Vocaluxe/Screens/CScreenSing.cs b/Vocaluxe/Screens/CScreenSing.cs index d2e4f120..6ec8ea18 100644 --- a/Vocaluxe/Screens/CScreenSing.cs +++ b/Vocaluxe/Screens/CScreenSing.cs @@ -316,6 +316,73 @@ namespace Vocaluxe.Screens return true; } + #region screen-handling + public override void OnShow() + { + base.OnShow(); + + _InitiatePlayerStatics(); + _InitiatePlayerStrings(); + _InitiateProgressBars(); + if (_StaticsExtra == null) + _CreateExtraStatics(); + if (_TextsExtra == null) + _CreateExtraTexts(); + + _FadeOut = false; + + _CurrentVideo = null; + _CurrentWebcamFrameTexture = null; + _CurrentBeat = -100; + _CurrentTime = 0f; + _FinishTime = 0f; + _Length = -1f; + _TimeToFirstNote = 0f; + _TimeToFirstNoteDuet = 0f; + _SetPause(false); + + _TimeRects.Clear(); + + _SingNotes[_SingBars].Init(0); + _AssignPlayerElements(); + + foreach (CLyric lyric in _Lyrics) + lyric.LyricStyle = CConfig.Config.Theme.LyricStyle; + + for (int p = 0; p < CGame.NumPlayers; p++) + { + _Statics[_PlayerStaticAvatar[p]].Aspect = EAspect.Crop; + _Texts[_PlayerTextScore[p]].Color = new SColorF(CBase.Themes.GetPlayerColor(p + 1), _Texts[_PlayerTextScore[p]].Color.A); + } + + _SetVisibility(); + + _UpdateAvatars(); + _UpdateNames(); + + _CloseSong(); + } + + public override void OnShowFinish() + { + base.OnShowFinish(); + + CGame.Start(); + _NextSong(); + } + + public override void OnClose() + { + base.OnClose(); + _CloseSong(); + if (_Webcam) + CWebcam.Stop(); + CBackgroundMusic.Disabled = false; + } + #endregion + + #region update game + public override bool UpdateGame() { bool finish = false; @@ -412,364 +479,6 @@ namespace Vocaluxe.Screens return true; } - public override void OnShow() - { - base.OnShow(); - - _InitiatePlayerStatics(); - _InitiatePlayerStrings(); - _InitiateProgressBars(); - if (_StaticsExtra == null) - _CreateExtraStatics(); - if (_TextsExtra == null) - _CreateExtraTexts(); - - _FadeOut = false; - - _CurrentVideo = null; - _CurrentWebcamFrameTexture = null; - _CurrentBeat = -100; - _CurrentTime = 0f; - _FinishTime = 0f; - _Length = -1f; - _TimeToFirstNote = 0f; - _TimeToFirstNoteDuet = 0f; - _SetPause(false); - - _TimeRects.Clear(); - - _SingNotes[_SingBars].Init(0); - _AssignPlayerElements(); - - foreach (CLyric lyric in _Lyrics) - lyric.LyricStyle = CConfig.Config.Theme.LyricStyle; - - for (int p = 0; p < CGame.NumPlayers; p++) - { - _Statics[_PlayerStaticAvatar[p]].Aspect = EAspect.Crop; - _Texts[_PlayerTextScore[p]].Color = new SColorF(CBase.Themes.GetPlayerColor(p + 1), _Texts[_PlayerTextScore[p]].Color.A); - } - - _SetVisibility(); - - _UpdateAvatars(); - _UpdateNames(); - - _CloseSong(); - } - - public override void OnShowFinish() - { - base.OnShowFinish(); - - CGame.Start(); - _NextSong(); - } - - public override void Draw() - { - if (_Active) - { - CTextureRef background; - var aspect = EAspect.Crop; - if (_CurrentVideo != null && CConfig.Config.Video.VideosInSongs == EOffOn.TR_CONFIG_ON && !_Webcam) - { - background = _CurrentVideo.Texture; - aspect = _VideoAspect; - } - else if (_Webcam) - { - background = _CurrentWebcamFrameTexture; - aspect = _VideoAspect; - } - else - background = _Background; - if (background != null) - { - SRectF bounds = CSettings.RenderRect; - SRectF rect = CHelper.FitInBounds(bounds, background.OrigAspect, aspect); - CDraw.DrawTexture(background, rect, background.Color, bounds); - } - else if (_SlideShow != null) - _SlideShow.Draw(); - } - - base.Draw(); - - switch (CConfig.Config.Theme.TimerLook) - { - case ETimerLook.TR_CONFIG_TIMERLOOK_NORMAL: - CDraw.DrawTexture(_Statics[_StaticTimeLine].Texture, _Statics[_StaticTimeLine].Rect, new SColorF(1, 1, 1, 1), _TimeLineRect); - break; - case ETimerLook.TR_CONFIG_TIMERLOOK_EXPANDED: - for (int i = 0; i < _TimeRects.Count; i++) - CDraw.DrawTexture(_TimeRects[i].Rect.Texture, _Statics[_StaticTimeLine].Rect, _TimeRects[i].Rect.Color, _TimeRects[i].Rect.Rect); - break; - } - - _DrawLyricHelper(); - } - - public override void OnClose() - { - base.OnClose(); - _CloseSong(); - if (_Webcam) - CWebcam.Stop(); - CBackgroundMusic.Disabled = false; - } - - private void _CloseSong() - { - if (_CurrentStream > -1) - { - CSound.FadeAndClose(_CurrentStream, 0, 0.5f); - _CurrentStream = -1; - } - CRecord.Stop(); - if (_CurrentVideo != null) - CVideo.Close(ref _CurrentVideo); - CDraw.RemoveTexture(ref _Background); - - if (_SlideShow != null) - _SlideShow.RemoveSlideShowTextures(); - - _Lyrics[_LyricMain].Clear(); - _Lyrics[_LyricSub].Clear(); - _Lyrics[_LyricMainDuet].Clear(); - _Lyrics[_LyricSubDuet].Clear(); - _Lyrics[_LyricMainTop].Clear(); - _Lyrics[_LyricSubTop].Clear(); - _Texts[_TextSongName].Text = String.Empty; - _Texts[_TextDuetName1].Text = String.Empty; - _Texts[_TextDuetName2].Text = String.Empty; - _Texts[_TextMedleyCountdown].Visible = false; - _Texts[_TextMedleyCountdown].Text = String.Empty; - } - - private void _RestartRound() - { - _CloseSong(); - - CGame.ResetPlayer(); - _LoadCurrentSong(); - - _StartSong(); - } - - private void _RestartGame() - { - _CloseSong(); - - CGame.Reset(); - CGame.ResetPlayer(); - CGame.NextRound(); - _LoadCurrentSong(); - - _StartSong(); - } - - private void _NextSong() - { - _CloseSong(); - - CGame.NextRound(); - _LoadCurrentSong(); - - _StartSong(); - } - - private void _LoadCurrentSong() - { - if (CGame.IsFinished()) - { - _FinishedSinging(); - return; - } - - CSong song = CGame.GetSong(); - - if (song == null) - { - CLog.LogError("Critical Error! ScreenSing.LoadNextSong() song is null!"); - return; - } - - string songname = song.Artist + " - " + song.Title; - int rounds = CGame.GetNumSongs(); - if (rounds > 1) - songname += " (" + CGame.RoundNr + "/" + rounds + ")"; - _Texts[_TextSongName].Text = songname; - - _CurrentStream = CSound.Load(song.GetMP3(), false, true, CConfig.Config.Sound.KaraokeEffect == EOffOn.TR_CONFIG_ON ? EAudioEffect.Karaoke : EAudioEffect.None); - CSound.SetStreamVolume(_CurrentStream, 100); - CSound.SetPosition(_CurrentStream, song.Start); - _CurrentTime = song.Start; - _FinishTime = song.Finish; - _TimeToFirstNote = 0f; - _TimeToFirstNoteDuet = 0f; - _Length = -1f; - var voiceAssignments = new int[CGame.NumPlayers]; - if (song.IsDuet) - { - //Save duet-assignment before resetting - for (int i = 0; i < voiceAssignments.Length; i++) - voiceAssignments[i] = CGame.Players[i].VoiceNr; - } - CGame.ResetPlayer(); - - if (!String.IsNullOrEmpty(song.VideoFileName)) - { - _CurrentVideo = CVideo.Load(Path.Combine(song.Folder, song.VideoFileName)); - CVideo.Skip(_CurrentVideo, song.Start, song.VideoGap); - _VideoAspect = song.VideoAspect; - } - - CDraw.RemoveTexture(ref _Background); - if (song.BackgroundFileNames.Count > 1) - { - _SlideShow = GetNewBackground(); - foreach (string bgFile in song.BackgroundFileNames) - _SlideShow.AddSlideShowTexture(Path.Combine(song.Folder, bgFile)); - } - else if (song.BackgroundFileNames.Count == 1) - { - if (!String.IsNullOrEmpty(song.BackgroundFileNames[0])) - _Background = CDraw.AddTexture(Path.Combine(song.Folder, song.BackgroundFileNames[0])); - } - - if (song.IsDuet) - { - //TODO: Show more than 2 voicenames - _Texts[_TextDuetName1].Text = song.Notes.VoiceNames[0]; - _Texts[_TextDuetName2].Text = song.Notes.VoiceNames[1]; - //More than one song: Player is not assigned to line by user - //Otherwise, this is done by CScreenNames - if (CGame.GetNumSongs() > 1) - { - for (int i = 0; i < CGame.NumPlayers; i++) - CGame.Players[i].VoiceNr = (i + 1) % 2; - } - else - { - for (int i = 0; i < CGame.NumPlayers; i++) - CGame.Players[i].VoiceNr = voiceAssignments[i]; - } - } - - //Attention: This needs to be done after player-assignment! - _SingNotes[_SingBars].Init(CGame.NumPlayers, CConfig.Config.Graphics.NumScreens); - - _DynamicLyricsTop = false; - _DynamicLyricsBottom = false; - - foreach (CNoteBars notes in _SingNotes[_SingBars].PlayerNotes) - { - if (notes.Rect.Bottom >= CSettings.RenderH / 2) - _DynamicLyricsBottom = true; - else - _DynamicLyricsTop = true; - } - - for (int p = 0; p < CGame.NumPlayers; p++) - _ProgressBars[_PlayerProgressBarRating[p]].Reset(); - - _SetNormalLyricsVisibility(); - - _TimerSongText.Reset(); - _TimerDuetText1.Reset(); - _TimerDuetText2.Reset(); - - if (!song.IsDuet) - _TimerSongText.Start(); - } - - private void _SetNormalLyricsVisibility() - { - bool bottomLyricsVisible = CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_BOTTOM - || CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_BOTH - || (CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_DYNAMIC && _DynamicLyricsBottom); - - bool topLyricsVisible = CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_TOP - || CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_BOTH - || (CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_DYNAMIC && _DynamicLyricsTop); - - bool duetLyricsVisible = false; - - if (CGame.GetSong() != null && CGame.GetSong().IsDuet) - { - bottomLyricsVisible = true; - topLyricsVisible = false; - duetLyricsVisible = true; - } - - _Lyrics[_LyricMain].Visible = bottomLyricsVisible; - _Lyrics[_LyricSub].Visible = bottomLyricsVisible; - _Statics[_StaticLyrics].Visible = bottomLyricsVisible; - - _Lyrics[_LyricMainTop].Visible = topLyricsVisible; - _Lyrics[_LyricSubTop].Visible = topLyricsVisible; - _Statics[_StaticLyricsTop].Visible = topLyricsVisible; - - _Lyrics[_LyricMainDuet].Visible = duetLyricsVisible; - _Lyrics[_LyricSubDuet].Visible = duetLyricsVisible; - _Statics[_StaticLyricsDuet].Visible = duetLyricsVisible; - } - - private void _StartSong() - { - _PrepareTimeLine(); - CSound.Play(_CurrentStream); - CRecord.Start(); - if (_Webcam) - CWebcam.Start(); - } - - private void _Stop() - { - //Need this to set other songs to points-var - while (!CGame.IsFinished()) - { - CGame.NextRound(); - CGame.ResetPlayer(); - } - - _FinishedSinging(); - } - - private void _FinishedSinging() - { - _FadeOut = true; - CParty.FinishedSinging(); - - if (_Webcam) - CWebcam.Stop(); - } - - private int _FindCurrentLine(CVoice voice, CSongLine[] lines, CSong song) - { - float currentTime = _CurrentTime - song.Gap; - //We are only interested in the last matching line, so either do not check further after line[j].StartBeat > _CurrentBeat or go backwards! - int j = voice.FindPreviousLine(_CurrentBeat); - for (; j >= 0; j--) - { - float firstNoteTime = CGame.GetTimeFromBeats(lines[j].FirstNoteBeat, song.BPM); - //Earlist possible line break is 10s before first note - if (firstNoteTime <= currentTime + 10f) - { - //First line has no predecessor or line has to be shown - if (j == 0 || firstNoteTime - CConfig.Config.Game.MinLineBreakTime <= currentTime) - return j; - float lastNoteTime = CGame.GetTimeFromBeats(lines[j - 1].LastNoteBeat, song.BPM); - //No line break if last line is not fully evaluated (with 50% tolerance -> tested so notes are drawn) - if (lastNoteTime + CConfig.Config.Record.MicDelay / 1000f * 1.5f >= currentTime) - return j - 1; - return j; - } - } - return -1; - } - private void _UpdateLyrics() { if (_FadeOut) @@ -860,7 +569,423 @@ namespace Vocaluxe.Screens } } + private void _UpdateMedleyCountdown() + { + CSong song = CGame.GetSong(); + if (song == null) + return; + float timeToFirstMedleyNote = CGame.GetTimeFromBeats(song.Medley.StartBeat, song.BPM) + song.Gap; + if (_CurrentTime < timeToFirstMedleyNote) + { + float timeDiff = timeToFirstMedleyNote - _CurrentTime + 1; + var fullSeconds = (float)Math.Truncate(timeDiff); + float partSeconds = timeDiff - fullSeconds; + _Texts[_TextMedleyCountdown].Visible = true; + _Texts[_TextMedleyCountdown].Text = fullSeconds.ToString(); + _Texts[_TextMedleyCountdown].Font.Height = partSeconds * CSettings.RenderH; + RectangleF textBounds = CFonts.GetTextBounds(_Texts[_TextMedleyCountdown]); + float x = CSettings.RenderW / 2 - textBounds.Width / 2; + float y = CSettings.RenderH / 2 - textBounds.Height / 2; + _Texts[_TextMedleyCountdown].X = x; + _Texts[_TextMedleyCountdown].Y = y; + } + else + _Texts[_TextMedleyCountdown].Visible = false; + } + + private void _UpdateSongText() + { + if (_TimerSongText.IsRunning && !_Lyrics[_LyricMainDuet].Visible && !_Lyrics[_LyricMainTop].Visible) + { + float t = _TimerSongText.ElapsedMilliseconds / 1000f; + if (t < 10f) + { + _Statics[_StaticSongText].Visible = true; + _Texts[_TextSongName].Visible = true; + + if (t < 7f) + { + _Statics[_StaticSongText].Color.A = 1f; + _Texts[_TextSongName].Color.A = 1f; + } + else + { + _Statics[_StaticSongText].Color.A = (10f - t) / 3f; + _Texts[_TextSongName].Color.A = (10f - t) / 3f; + } + } + else + { + _Statics[_StaticSongText].Visible = false; + _Texts[_TextSongName].Visible = false; + _TimerSongText.Stop(); + } + } + else + { + _Statics[_StaticSongText].Visible = false; + _Texts[_TextSongName].Visible = false; + } + } + + private void _UpdateDuetNames(CText textName, Stopwatch timer) + { + if (timer.IsRunning) + { + float t = timer.ElapsedMilliseconds / 1000f; + if (t < 10f) + { + textName.Visible = true; + + if (t < 3f) + textName.Color.A = t / 3f; + else if (t < 7f) + textName.Color.A = 1f; + else + textName.Color.A = (10f - t) / 3f; + } + else + { + textName.Visible = false; + timer.Stop(); + } + } + else if (!timer.IsRunning && timer.ElapsedMilliseconds == 0 && _Lyrics[_LyricMainDuet].Alpha > 0 && CGame.GetSong().IsDuet) + timer.Start(); + else + textName.Visible = false; + } + + private void _UpdateDuetNames() + { + if (CGame.GetSong() == null) + return; + //Timer for first duet-part + _UpdateDuetNames(_Texts[_TextDuetName1], _TimerDuetText1); + //Timer for second duet-part + if (_TimerDuetText2.IsRunning) + { + float t = _TimerDuetText2.ElapsedMilliseconds / 1000f; + if (t < 10f) + { + _Texts[_TextDuetName2].Visible = true; + + if (t < 3f) + _Texts[_TextDuetName2].Color.A = (3f - (3f - t)) / 3f; + else if (t < 7f) + _Texts[_TextDuetName2].Color.A = 1f; + else + _Texts[_TextDuetName2].Color.A = (3f - (t - 7f)) / 3f; + } + else + { + _Texts[_TextDuetName2].Visible = false; + _TimerDuetText2.Stop(); + } + } + else if (!_TimerDuetText2.IsRunning && _TimerDuetText2.ElapsedMilliseconds == 0 && _Lyrics[_LyricMain].Alpha > 0 && CGame.GetSong().IsDuet) + _TimerDuetText2.Start(); + else + _Texts[_TextDuetName2].Visible = false; + } + + private void _UpdateTimeLine() + { + CSong song = CGame.GetSong(); + + if (song == null) + return; + + float totalTime = CSound.GetLength(_CurrentStream); + if (Math.Abs(song.Finish) > 0.001) + totalTime = song.Finish; + + float remainingTime = totalTime - _CurrentTime; + totalTime -= song.Start; + float currentTime = _CurrentTime - song.Start; + + if (_Length < 0 && totalTime > 0) + _PrepareTimeLine(); + + if (totalTime <= 0f) + return; + + switch (CConfig.Config.Game.TimerMode) + { + case ETimerMode.TR_CONFIG_TIMERMODE_CURRENT: + var min = (int)Math.Floor(currentTime / 60f); + var sec = (int)(currentTime - min * 60f); + _Texts[_TextTime].Text = min.ToString("00") + ":" + sec.ToString("00"); + break; + + case ETimerMode.TR_CONFIG_TIMERMODE_REMAINING: + min = (int)Math.Floor(remainingTime / 60f); + sec = (int)(remainingTime - min * 60f); + _Texts[_TextTime].Text = "-" + min.ToString("00") + ":" + sec.ToString("00"); + break; + + case ETimerMode.TR_CONFIG_TIMERMODE_TOTAL: + min = (int)Math.Floor(totalTime / 60f); + sec = (int)(totalTime - min * 60f); + _Texts[_TextTime].Text = "#" + min.ToString("00") + ":" + sec.ToString("00"); + break; + } + + + switch (CConfig.Config.Theme.TimerLook) + { + case ETimerLook.TR_CONFIG_TIMERLOOK_NORMAL: + _TimeLineRect.W = _Statics[_StaticTimeLine].Rect.W * (currentTime / totalTime); + break; + + case ETimerLook.TR_CONFIG_TIMERLOOK_EXPANDED: + CStatic stat = _Statics[_StaticTimeLine]; + int currentBeat = CGame.CurrentBeat; + for (int i = 0; i < _TimeRects.Count; i++) + { + if (currentBeat >= _TimeRects[i].StartBeat && currentBeat <= _TimeRects[i].EndBeat) + { + _TimeRects[i].Rect.Texture = _Statics[_StaticTimeLineExpandedHighlighted].Texture; + _TimeRects[i].Rect.Color = _Statics[_StaticTimeLineExpandedHighlighted].Color; + } + else + { + _TimeRects[i].Rect.Texture = _Statics[_StaticTimeLineExpandedNormal].Texture; + _TimeRects[i].Rect.Color = _Statics[_StaticTimeLineExpandedNormal].Color; + } + } + _Statics[_StaticTimePointer].X = stat.X + stat.W * (currentTime / totalTime); + break; + } + } + + private void _UpdateRatingBars() + { + for (int i = 0; i < CGame.NumPlayers; i++) + { + _ProgressBars[_PlayerProgressBarRating[i]].Progress = (float)CGame.Players[i].Rating; + } + } + + #endregion + + #region drawing + public override void Draw() + { + if (_Active) + { + CTextureRef background; + var aspect = EAspect.Crop; + if (_CurrentVideo != null && CConfig.Config.Video.VideosInSongs == EOffOn.TR_CONFIG_ON && !_Webcam) + { + background = _CurrentVideo.Texture; + aspect = _VideoAspect; + } + else if (_Webcam) + { + background = _CurrentWebcamFrameTexture; + aspect = _VideoAspect; + } + else + background = _Background; + if (background != null) + { + SRectF bounds = CSettings.RenderRect; + SRectF rect = CHelper.FitInBounds(bounds, background.OrigAspect, aspect); + CDraw.DrawTexture(background, rect, background.Color, bounds); + } + else if (_SlideShow != null) + _SlideShow.Draw(); + } + + base.Draw(); + + switch (CConfig.Config.Theme.TimerLook) + { + case ETimerLook.TR_CONFIG_TIMERLOOK_NORMAL: + CDraw.DrawTexture(_Statics[_StaticTimeLine].Texture, _Statics[_StaticTimeLine].Rect, new SColorF(1, 1, 1, 1), _TimeLineRect); + break; + case ETimerLook.TR_CONFIG_TIMERLOOK_EXPANDED: + for (int i = 0; i < _TimeRects.Count; i++) + CDraw.DrawTexture(_TimeRects[i].Rect.Texture, _Statics[_StaticTimeLine].Rect, _TimeRects[i].Rect.Color, _TimeRects[i].Rect.Rect); + break; + } + + _DrawLyricHelper(); + } + + private void _DrawLyricHelper() + { + if (_FadeOut) + return; + + if (!CSound.IsPlaying(_CurrentStream) && !CSound.IsPaused(_CurrentStream)) + return; + + CSong song = CGame.GetSong(); + + if (song == null) + return; + + float alpha = (float)((Math.Cos(_CurrentTime * Math.PI * 2) + 1) / 2.0) / 2f + 0.5f; + + if (_TimeToFirstNote > CSettings.LyricHelperMinTime && _RemainingTimeToFirstNote > 0f && _RemainingTimeToFirstNote < CSettings.LyricHelperEnableTime) + { + float time = _RemainingTimeToFirstNote; + float totaltime = CSettings.LyricHelperMoveTime; + + if (totaltime > _TimeToFirstNote) + totaltime = _TimeToFirstNote; + + if (time > totaltime) + time = totaltime; + + if (_Statics[_StaticLyrics].Visible) + { + SRectF rect = _Statics[_StaticLyricHelper].Rect; + var color = new SColorF( + _Statics[_StaticLyricHelper].Color.R, + _Statics[_StaticLyricHelper].Color.G, + _Statics[_StaticLyricHelper].Color.B, + _Statics[_StaticLyricHelper].Color.A * _Statics[_StaticLyricHelper].Alpha * alpha); + + float distance = _Lyrics[_LyricMain].GetCurrentLyricPosX() - rect.X - rect.W; + CDraw.DrawTexture(_Statics[_StaticLyricHelper].Texture, + new SRectF(rect.X + distance * (1f - time / totaltime), rect.Y, rect.W, rect.H, rect.Z), color); + } + + if (_Statics[_StaticLyricsTop].Visible) + { + SRectF rect = _Statics[_StaticLyricHelperTop].Rect; + var color = new SColorF( + _Statics[_StaticLyricHelperTop].Color.R, + _Statics[_StaticLyricHelperTop].Color.G, + _Statics[_StaticLyricHelperTop].Color.B, + _Statics[_StaticLyricHelperTop].Color.A * _Statics[_StaticLyricHelper].Alpha * alpha); + + float distance = _Lyrics[_LyricMainTop].GetCurrentLyricPosX() - rect.X - rect.W; + CDraw.DrawTexture(_Statics[_StaticLyricHelperTop].Texture, + new SRectF(rect.X + distance * (1f - time / totaltime), rect.Y, rect.W, rect.H, rect.Z), color); + } + } + + if (song.IsDuet) + { + if (_TimeToFirstNoteDuet > CSettings.LyricHelperMinTime && _RemainingTimeToFirstNoteDuet > 0f && _RemainingTimeToFirstNoteDuet < CSettings.LyricHelperEnableTime) + { + float time = _RemainingTimeToFirstNoteDuet; + float totaltime = CSettings.LyricHelperMoveTime; + + if (totaltime > _TimeToFirstNoteDuet) + totaltime = _TimeToFirstNoteDuet; + + if (time > totaltime) + time = totaltime; + + SRectF rect = _Statics[_StaticLyricHelperDuet].Rect; + + var color = new SColorF( + _Statics[_StaticLyricHelperDuet].Color.R, + _Statics[_StaticLyricHelperDuet].Color.G, + _Statics[_StaticLyricHelperDuet].Color.B, + _Statics[_StaticLyricHelperDuet].Color.A * _Statics[_StaticLyricHelperDuet].Alpha * alpha); + + float distance = _Lyrics[_LyricMainDuet].GetCurrentLyricPosX() - rect.X - rect.W; + CDraw.DrawTexture(_Statics[_StaticLyricHelperDuet].Texture, + new SRectF(rect.X + distance * (1f - time / totaltime), rect.Y, rect.W, rect.H, rect.Z), + color); + } + } + } + #endregion + + #region game-handling + + /// + /// Start recording and playing current loaded song. + /// + private void _StartSong() + { + _PrepareTimeLine(); + CSound.Play(_CurrentStream); + CRecord.Start(); + if (_Webcam) + CWebcam.Start(); + } + + /// + /// Stop singing and skip all possible unsung songs. + /// + private void _Stop() + { + _CloseSong(); + + //Need this to set other songs to points-var + while (!CGame.IsFinished()) + { + CGame.NextRound(); + CGame.ResetPlayer(); + } + + _FinishedSinging(); + } + + /// + /// Singing is finished, stop webcam and call PartyMode method. + /// + private void _FinishedSinging() + { + _FadeOut = true; + CParty.FinishedSinging(); + + if (_Webcam) + CWebcam.Stop(); + } + + /// + /// Restart current round: Only sing current song again. + /// + private void _RestartRound() + { + _CloseSong(); + + CGame.ResetPlayer(); + _LoadCurrentSong(); + + _StartSong(); + } + + /// + /// Restart complete game: If there is more than one song, sing every song again. + /// + private void _RestartGame() + { + _CloseSong(); + + CGame.Reset(); + CGame.ResetPlayer(); + CGame.NextRound(); + + _LoadCurrentSong(); + + _StartSong(); + } + + /// + /// Load next song. + /// + private void _NextSong() + { + _CloseSong(); + + CGame.NextRound(); + CGame.ResetPlayer(); + + _LoadCurrentSong(); + + _StartSong(); + } private void _TogglePause() { _SetPause(!_Pause); @@ -870,10 +995,10 @@ namespace Vocaluxe.Screens { _Pause = paused; - foreach(String s in _StaticsPause) + foreach (String s in _StaticsPause) _Statics[s].Visible = _Pause; - foreach(String s in _TextsPause) + foreach (String s in _TextsPause) _Texts[s].Visible = _Pause; _Buttons[_ButtonCancel].Visible = _Pause; @@ -885,7 +1010,386 @@ namespace Vocaluxe.Screens else CSound.Play(_CurrentStream); } + #endregion + #region song-handling + /// + /// Prepare streams and screen for current song. + /// + private void _LoadCurrentSong() + { + if (CGame.IsFinished()) + { + _FinishedSinging(); + return; + } + + CSong song = CGame.GetSong(); + + if (song == null) + { + CLog.LogError("Critical Error! ScreenSing.LoadNextSong() song is null!"); + return; + } + + string songname = song.Artist + " - " + song.Title; + int rounds = CGame.GetNumSongs(); + if (rounds > 1) + songname += " (" + CGame.RoundNr + "/" + rounds + ")"; + _Texts[_TextSongName].Text = songname; + + _CurrentStream = CSound.Load(song.GetMP3(), false, true, CConfig.Config.Sound.KaraokeEffect == EOffOn.TR_CONFIG_ON ? EAudioEffect.Karaoke : EAudioEffect.None); + CSound.SetStreamVolume(_CurrentStream, 100); + CSound.SetPosition(_CurrentStream, song.Start); + _CurrentTime = song.Start; + _FinishTime = song.Finish; + _TimeToFirstNote = 0f; + _TimeToFirstNoteDuet = 0f; + _Length = -1f; + var voiceAssignments = new int[CGame.NumPlayers]; + if (song.IsDuet) + { + //Save duet-assignment before resetting + for (int i = 0; i < voiceAssignments.Length; i++) + voiceAssignments[i] = CGame.Players[i].VoiceNr; + } + + if (!String.IsNullOrEmpty(song.VideoFileName)) + { + _CurrentVideo = CVideo.Load(Path.Combine(song.Folder, song.VideoFileName)); + CVideo.Skip(_CurrentVideo, song.Start, song.VideoGap); + _VideoAspect = song.VideoAspect; + } + + CDraw.RemoveTexture(ref _Background); + if (song.BackgroundFileNames.Count > 1) + { + _SlideShow = GetNewBackground(); + foreach (string bgFile in song.BackgroundFileNames) + _SlideShow.AddSlideShowTexture(Path.Combine(song.Folder, bgFile)); + } + else if (song.BackgroundFileNames.Count == 1) + { + if (!String.IsNullOrEmpty(song.BackgroundFileNames[0])) + _Background = CDraw.AddTexture(Path.Combine(song.Folder, song.BackgroundFileNames[0])); + } + + if (song.IsDuet) + { + //TODO: Show more than 2 voicenames + _Texts[_TextDuetName1].Text = song.Notes.VoiceNames[0]; + _Texts[_TextDuetName2].Text = song.Notes.VoiceNames[1]; + //More than one song: Player is not assigned to line by user + //Otherwise, this is done by CScreenNames + if (CGame.GetNumSongs() > 1) + { + for (int i = 0; i < CGame.NumPlayers; i++) + CGame.Players[i].VoiceNr = (i + 1) % 2; + } + else + { + for (int i = 0; i < CGame.NumPlayers; i++) + CGame.Players[i].VoiceNr = voiceAssignments[i]; + } + } + + //Attention: This needs to be done after player-assignment! + _SingNotes[_SingBars].Init(CGame.NumPlayers, CConfig.Config.Graphics.NumScreens); + + _DynamicLyricsTop = false; + _DynamicLyricsBottom = false; + + foreach (CNoteBars notes in _SingNotes[_SingBars].PlayerNotes) + { + if (notes.Rect.Bottom >= CSettings.RenderH / 2) + _DynamicLyricsBottom = true; + else + _DynamicLyricsTop = true; + } + + for (int p = 0; p < CGame.NumPlayers; p++) + _ProgressBars[_PlayerProgressBarRating[p]].Reset(); + + _SetNormalLyricsVisibility(); + + _TimerSongText.Reset(); + _TimerDuetText1.Reset(); + _TimerDuetText2.Reset(); + + if (!song.IsDuet) + _TimerSongText.Start(); + } + + /// + /// Stop playing audio/video, recording and clear some ui-elements. + /// + private void _CloseSong() + { + if (_CurrentStream > -1) + { + CSound.FadeAndClose(_CurrentStream, 0, 0.5f); + _CurrentStream = -1; + } + CRecord.Stop(); + if (_CurrentVideo != null) + CVideo.Close(ref _CurrentVideo); + CDraw.RemoveTexture(ref _Background); + + if (_SlideShow != null) + _SlideShow.RemoveSlideShowTextures(); + + _Lyrics[_LyricMain].Clear(); + _Lyrics[_LyricSub].Clear(); + _Lyrics[_LyricMainDuet].Clear(); + _Lyrics[_LyricSubDuet].Clear(); + _Lyrics[_LyricMainTop].Clear(); + _Lyrics[_LyricSubTop].Clear(); + _Texts[_TextSongName].Text = String.Empty; + _Texts[_TextDuetName1].Text = String.Empty; + _Texts[_TextDuetName2].Text = String.Empty; + _Texts[_TextMedleyCountdown].Visible = false; + _Texts[_TextMedleyCountdown].Text = String.Empty; + } + #endregion + + #region visibility and fading + private void _SetNormalLyricsVisibility() + { + bool bottomLyricsVisible = CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_BOTTOM + || CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_BOTH + || (CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_DYNAMIC && _DynamicLyricsBottom); + + bool topLyricsVisible = CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_TOP + || CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_BOTH + || (CConfig.Config.Game.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_DYNAMIC && _DynamicLyricsTop); + + bool duetLyricsVisible = false; + + if (CGame.GetSong() != null && CGame.GetSong().IsDuet) + { + bottomLyricsVisible = true; + topLyricsVisible = false; + duetLyricsVisible = true; + } + + _Lyrics[_LyricMain].Visible = bottomLyricsVisible; + _Lyrics[_LyricSub].Visible = bottomLyricsVisible; + _Statics[_StaticLyrics].Visible = bottomLyricsVisible; + + _Lyrics[_LyricMainTop].Visible = topLyricsVisible; + _Lyrics[_LyricSubTop].Visible = topLyricsVisible; + _Statics[_StaticLyricsTop].Visible = topLyricsVisible; + + _Lyrics[_LyricMainDuet].Visible = duetLyricsVisible; + _Lyrics[_LyricSubDuet].Visible = duetLyricsVisible; + _Statics[_StaticLyricsDuet].Visible = duetLyricsVisible; + } + + private void _SetVisibility() + { + _Statics[_StaticLyricsDuet].Visible = false; + _Statics[_StaticLyricHelper].Visible = false; + _Statics[_StaticLyricHelperDuet].Visible = false; + _Statics[_StaticLyricHelperTop].Visible = false; + _Lyrics[_LyricMainDuet].Visible = false; + _Lyrics[_LyricSubDuet].Visible = false; + + _Statics[_StaticSongText].Visible = false; + _Texts[_TextSongName].Visible = false; + _Texts[_TextDuetName1].Visible = false; + _Texts[_TextDuetName2].Visible = false; + + int screenPlayers = CGame.NumPlayers / CConfig.GetNumScreens(); + int remainingScreenPlayers = CGame.NumPlayers - (screenPlayers * CConfig.GetNumScreens()); + + for (int screen = 0; screen < CSettings.MaxNumScreens; screen++) + { + int currentScreenPlayers = screenPlayers; + + if (remainingScreenPlayers > 0) + { + currentScreenPlayers++; + remainingScreenPlayers--; + } + + string curN = "N" + currentScreenPlayers; + string curS = "S" + (screen + 1); + + foreach (string se in _StaticsExtra[screen]) + { + string n = se.Substring(se.Length - 2); + string s = se.Substring(0, 2); + //Make StaticExtra elements with matching player number and active screen visible + if (n == curN && s == curS && screen < CConfig.GetNumScreens()) + _Statics[se].Visible = true; + else + _Statics[se].Visible = false; + } + + foreach (string te in _TextsExtra[screen]) + { + string n = te.Substring(te.Length - 2); + string s = te.Substring(0, 2); + //Make TextExtra elements with matching player number and active screen visible + if (n == curN && s == curS && screen < CConfig.GetNumScreens()) + _Texts[te].Visible = true; + else + _Texts[te].Visible = false; + } + + for (int numplayer = 0; numplayer < CSettings.MaxNumPlayer; numplayer++) + { + for (int player = 0; player < CSettings.MaxNumPlayer && player <= numplayer; player++) + { + _Texts[_TextScores[screen, player, numplayer]].AllMonitors = false; + _Texts[_TextScores[screen, player, numplayer]].Visible = false; + _Texts[_TextNames[screen, player, numplayer]].AllMonitors = false; + _Texts[_TextNames[screen, player, numplayer]].Visible = false; + _Statics[_StaticScores[screen, player, numplayer]].AllMonitors = false; + _Statics[_StaticScores[screen, player, numplayer]].Visible = false; + _Statics[_StaticAvatars[screen, player, numplayer]].AllMonitors = false; + _Statics[_StaticAvatars[screen, player, numplayer]].Visible = false; + _ProgressBars[_ProgressBarsRating[screen, player, numplayer]].AllMonitors = false; + _ProgressBars[_ProgressBarsRating[screen, player, numplayer]].Visible = false; + } + } + } + + for (int player = 0; player < CGame.NumPlayers; player++) + { + _Texts[_PlayerTextScore[player]].Visible = true; + _Texts[_PlayerTextName[player]].Visible = (CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH || + CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_NAME); + _Statics[_PlayerStaticScore[player]].Visible = true; + _Statics[_PlayerStaticAvatar[player]].Visible = (CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH || + CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_AVATAR); + _ProgressBars[_PlayerProgressBarRating[player]].Visible = true; + } + + _Lyrics[_LyricMain].Alpha = 0f; + _Lyrics[_LyricSub].Alpha = 0f; + + _Lyrics[_LyricMainTop].Alpha = 0f; + _Lyrics[_LyricSubTop].Alpha = 0f; + + _Statics[_StaticLyrics].Alpha = 0f; + _Statics[_StaticLyricsTop].Alpha = 0f; + + _Statics[_StaticLyricHelper].Alpha = 0f; + _Statics[_StaticLyricHelperTop].Alpha = 0f; + + _Lyrics[_LyricMainDuet].Alpha = 0f; + _Lyrics[_LyricSubDuet].Alpha = 0f; + + _Statics[_StaticLyricsDuet].Alpha = 0f; + _Statics[_StaticLyricHelperDuet].Alpha = 0f; + + _Statics[_StaticTimeLine].Visible = CConfig.Config.Theme.TimerLook == ETimerLook.TR_CONFIG_TIMERLOOK_NORMAL; + _Statics[_StaticTimeLineExpandedHighlighted].Visible = false; + _Statics[_StaticTimeLineExpandedNormal].Visible = false; + } + + private float[] _CalcFadingAlpha() + { + const float dt = 4f; + const float rt = dt * 0.8f; + + CSong song = CGame.GetSong(); + if (song == null || !song.NotesLoaded) + return null; + + var alpha = new float[song.Notes.VoiceCount * 2]; + float currentTime = _CurrentTime - song.Gap; + + for (int i = 0; i < song.Notes.VoiceCount; i++) + { + CVoice voice = song.Notes.GetVoice(i); + CSongLine[] lines = voice.Lines; + + // find current line for lyric sub fading + int currentLineSub = _FindCurrentLine(voice, lines, song); + + // find current line for lyric main fading + int currentLine = 0; + for (int j = 0; j < lines.Length; j++) + { + if (lines[j].FirstNoteBeat <= _CurrentBeat) + currentLine = j; + } + + // default values + alpha[i * 2] = 1f; + alpha[i * 2 + 1] = 1f; + + // main line alpha + if (currentLine == 0 && currentTime < CGame.GetTimeFromBeats(lines[currentLine].FirstNoteBeat, song.BPM)) + { + // first main line and fist note is not reached + // => fade in + float diff = CGame.GetTimeFromBeats(lines[currentLine].FirstNoteBeat, song.BPM) - currentTime; + if (diff > dt) + alpha[i * 2] = 1f - (diff - dt) / rt; + } + else if (currentLine < lines.Length - 1 && CGame.GetTimeFromBeats(lines[currentLine].LastNoteBeat, song.BPM) < currentTime && + CGame.GetTimeFromBeats(lines[currentLine + 1].FirstNoteBeat, song.BPM) > currentTime) + { + // current position is between two lines + + // time between the to lines + float diff = CGame.GetTimeFromBeats(lines[currentLine + 1].FirstNoteBeat, song.BPM) - + CGame.GetTimeFromBeats(lines[currentLine].LastNoteBeat, song.BPM); + + // fade only if there is enough time for fading + if (diff > 3.3f * dt) + { + // time elapsed since last line + float last = currentTime - CGame.GetTimeFromBeats(lines[currentLine].LastNoteBeat, song.BPM); + + // time to next line + float next = CGame.GetTimeFromBeats(lines[currentLine + 1].FirstNoteBeat, song.BPM) - currentTime; + + if (last < next) + { + // fade out + alpha[i * 2] = 1f - last / rt; + } + else + { + // fade in if it is time for + if (next > dt) + alpha[i * 2] = 1f - (next - dt) / rt; + } + } + } + else if (currentLine == lines.Length - 1 && CGame.GetTimeFromBeats(lines[currentLine].LastNoteBeat, song.BPM) < currentTime) + { + // last main line and last note was reached + // => fade out + float diff = currentTime - CGame.GetTimeFromBeats(lines[currentLine].LastNoteBeat, song.BPM); + alpha[i * 2] = 1f - diff / rt; + } + + // sub + if (currentLineSub < lines.Length - 2) + { + float diff = CGame.GetTimeFromBeats(lines[currentLineSub + 1].FirstNoteBeat, song.BPM) - currentTime; + + if (diff > dt) + alpha[i * 2 + 1] = 1f - (diff - dt) / rt; + } + + if (alpha[i * 2] < 0f) + alpha[i * 2] = 0f; + + if (alpha[i * 2 + 1] < 0f) + alpha[i * 2 + 1] = 0f; + } + + return alpha; + } + #endregion + + #region theme loading private void _BuildTextStrings(List texts) { _TextScores = new string[CSettings.MaxNumScreens, CSettings.MaxNumPlayer, CSettings.MaxNumPlayer]; @@ -1141,483 +1645,30 @@ namespace Vocaluxe.Screens } } + #endregion - private void _SetVisibility() + private int _FindCurrentLine(CVoice voice, CSongLine[] lines, CSong song) { - _Statics[_StaticLyricsDuet].Visible = false; - _Statics[_StaticLyricHelper].Visible = false; - _Statics[_StaticLyricHelperDuet].Visible = false; - _Statics[_StaticLyricHelperTop].Visible = false; - _Lyrics[_LyricMainDuet].Visible = false; - _Lyrics[_LyricSubDuet].Visible = false; - - _Statics[_StaticSongText].Visible = false; - _Texts[_TextSongName].Visible = false; - _Texts[_TextDuetName1].Visible = false; - _Texts[_TextDuetName2].Visible = false; - - int screenPlayers = CGame.NumPlayers / CConfig.GetNumScreens(); - int remainingScreenPlayers = CGame.NumPlayers - (screenPlayers * CConfig.GetNumScreens()); - - for (int screen = 0; screen < CSettings.MaxNumScreens; screen++) - { - int currentScreenPlayers = screenPlayers; - - if (remainingScreenPlayers > 0) - { - currentScreenPlayers++; - remainingScreenPlayers--; - } - - string curN = "N" + currentScreenPlayers; - string curS = "S" + (screen + 1); - - foreach (string se in _StaticsExtra[screen]) - { - string n = se.Substring(se.Length - 2); - string s = se.Substring(0, 2); - //Make StaticExtra elements with matching player number and active screen visible - if (n == curN && s == curS && screen < CConfig.GetNumScreens()) - _Statics[se].Visible = true; - else - _Statics[se].Visible = false; - } - - foreach (string te in _TextsExtra[screen]) - { - string n = te.Substring(te.Length - 2); - string s = te.Substring(0, 2); - //Make TextExtra elements with matching player number and active screen visible - if (n == curN && s == curS && screen < CConfig.GetNumScreens()) - _Texts[te].Visible = true; - else - _Texts[te].Visible = false; - } - - for (int numplayer = 0; numplayer < CSettings.MaxNumPlayer; numplayer++) - { - for (int player = 0; player < CSettings.MaxNumPlayer && player <= numplayer; player++) - { - _Texts[_TextScores[screen, player, numplayer]].AllMonitors = false; - _Texts[_TextScores[screen, player, numplayer]].Visible = false; - _Texts[_TextNames[screen, player, numplayer]].AllMonitors = false; - _Texts[_TextNames[screen, player, numplayer]].Visible = false; - _Statics[_StaticScores[screen, player, numplayer]].AllMonitors = false; - _Statics[_StaticScores[screen, player, numplayer]].Visible = false; - _Statics[_StaticAvatars[screen, player, numplayer]].AllMonitors = false; - _Statics[_StaticAvatars[screen, player, numplayer]].Visible = false; - _ProgressBars[_ProgressBarsRating[screen, player, numplayer]].AllMonitors = false; - _ProgressBars[_ProgressBarsRating[screen, player, numplayer]].Visible = false; - } - } - } - - for (int player = 0; player < CGame.NumPlayers; player++) - { - _Texts[_PlayerTextScore[player]].Visible = true; - _Texts[_PlayerTextName[player]].Visible = (CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH || - CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_NAME); - _Statics[_PlayerStaticScore[player]].Visible = true; - _Statics[_PlayerStaticAvatar[player]].Visible = (CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH || - CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_AVATAR); - _ProgressBars[_PlayerProgressBarRating[player]].Visible = true; - } - - _Lyrics[_LyricMain].Alpha = 0f; - _Lyrics[_LyricSub].Alpha = 0f; - - _Lyrics[_LyricMainTop].Alpha = 0f; - _Lyrics[_LyricSubTop].Alpha = 0f; - - _Statics[_StaticLyrics].Alpha = 0f; - _Statics[_StaticLyricsTop].Alpha = 0f; - - _Statics[_StaticLyricHelper].Alpha = 0f; - _Statics[_StaticLyricHelperTop].Alpha = 0f; - - _Lyrics[_LyricMainDuet].Alpha = 0f; - _Lyrics[_LyricSubDuet].Alpha = 0f; - - _Statics[_StaticLyricsDuet].Alpha = 0f; - _Statics[_StaticLyricHelperDuet].Alpha = 0f; - - _Statics[_StaticTimeLine].Visible = CConfig.Config.Theme.TimerLook == ETimerLook.TR_CONFIG_TIMERLOOK_NORMAL; - _Statics[_StaticTimeLineExpandedHighlighted].Visible = false; - _Statics[_StaticTimeLineExpandedNormal].Visible = false; - } - - private void _UpdateMedleyCountdown() - { - CSong song = CGame.GetSong(); - if (song == null) - return; - float timeToFirstMedleyNote = CGame.GetTimeFromBeats(song.Medley.StartBeat, song.BPM) + song.Gap; - if (_CurrentTime < timeToFirstMedleyNote) - { - float timeDiff = timeToFirstMedleyNote - _CurrentTime + 1; - var fullSeconds = (float)Math.Truncate(timeDiff); - float partSeconds = timeDiff - fullSeconds; - _Texts[_TextMedleyCountdown].Visible = true; - _Texts[_TextMedleyCountdown].Text = fullSeconds.ToString(); - _Texts[_TextMedleyCountdown].Font.Height = partSeconds * CSettings.RenderH; - - RectangleF textBounds = CFonts.GetTextBounds(_Texts[_TextMedleyCountdown]); - float x = CSettings.RenderW / 2 - textBounds.Width / 2; - float y = CSettings.RenderH / 2 - textBounds.Height / 2; - _Texts[_TextMedleyCountdown].X = x; - _Texts[_TextMedleyCountdown].Y = y; - } - else - _Texts[_TextMedleyCountdown].Visible = false; - } - - private void _DrawLyricHelper() - { - if (_FadeOut) - return; - - if (!CSound.IsPlaying(_CurrentStream) && !CSound.IsPaused(_CurrentStream)) - return; - - CSong song = CGame.GetSong(); - - if (song == null) - return; - - float alpha = (float)((Math.Cos(_CurrentTime * Math.PI * 2) + 1) / 2.0) / 2f + 0.5f; - - if (_TimeToFirstNote > CSettings.LyricHelperMinTime && _RemainingTimeToFirstNote > 0f && _RemainingTimeToFirstNote < CSettings.LyricHelperEnableTime) - { - float time = _RemainingTimeToFirstNote; - float totaltime = CSettings.LyricHelperMoveTime; - - if (totaltime > _TimeToFirstNote) - totaltime = _TimeToFirstNote; - - if (time > totaltime) - time = totaltime; - - if (_Statics[_StaticLyrics].Visible) - { - SRectF rect = _Statics[_StaticLyricHelper].Rect; - var color = new SColorF( - _Statics[_StaticLyricHelper].Color.R, - _Statics[_StaticLyricHelper].Color.G, - _Statics[_StaticLyricHelper].Color.B, - _Statics[_StaticLyricHelper].Color.A * _Statics[_StaticLyricHelper].Alpha * alpha); - - float distance = _Lyrics[_LyricMain].GetCurrentLyricPosX() - rect.X - rect.W; - CDraw.DrawTexture(_Statics[_StaticLyricHelper].Texture, - new SRectF(rect.X + distance * (1f - time / totaltime), rect.Y, rect.W, rect.H, rect.Z), color); - } - - if (_Statics[_StaticLyricsTop].Visible) - { - SRectF rect = _Statics[_StaticLyricHelperTop].Rect; - var color = new SColorF( - _Statics[_StaticLyricHelperTop].Color.R, - _Statics[_StaticLyricHelperTop].Color.G, - _Statics[_StaticLyricHelperTop].Color.B, - _Statics[_StaticLyricHelperTop].Color.A * _Statics[_StaticLyricHelper].Alpha * alpha); - - float distance = _Lyrics[_LyricMainTop].GetCurrentLyricPosX() - rect.X - rect.W; - CDraw.DrawTexture(_Statics[_StaticLyricHelperTop].Texture, - new SRectF(rect.X + distance * (1f - time / totaltime), rect.Y, rect.W, rect.H, rect.Z), color); - } - } - - if (song.IsDuet) - { - if (_TimeToFirstNoteDuet > CSettings.LyricHelperMinTime && _RemainingTimeToFirstNoteDuet > 0f && _RemainingTimeToFirstNoteDuet < CSettings.LyricHelperEnableTime) - { - float time = _RemainingTimeToFirstNoteDuet; - float totaltime = CSettings.LyricHelperMoveTime; - - if (totaltime > _TimeToFirstNoteDuet) - totaltime = _TimeToFirstNoteDuet; - - if (time > totaltime) - time = totaltime; - - SRectF rect = _Statics[_StaticLyricHelperDuet].Rect; - - var color = new SColorF( - _Statics[_StaticLyricHelperDuet].Color.R, - _Statics[_StaticLyricHelperDuet].Color.G, - _Statics[_StaticLyricHelperDuet].Color.B, - _Statics[_StaticLyricHelperDuet].Color.A * _Statics[_StaticLyricHelperDuet].Alpha * alpha); - - float distance = _Lyrics[_LyricMainDuet].GetCurrentLyricPosX() - rect.X - rect.W; - CDraw.DrawTexture(_Statics[_StaticLyricHelperDuet].Texture, - new SRectF(rect.X + distance * (1f - time / totaltime), rect.Y, rect.W, rect.H, rect.Z), - color); - } - } - } - - private float[] _CalcFadingAlpha() - { - const float dt = 4f; - const float rt = dt * 0.8f; - - CSong song = CGame.GetSong(); - if (song == null || !song.NotesLoaded) - return null; - - var alpha = new float[song.Notes.VoiceCount * 2]; float currentTime = _CurrentTime - song.Gap; - - for (int i = 0; i < song.Notes.VoiceCount; i++) + //We are only interested in the last matching line, so either do not check further after line[j].StartBeat > _CurrentBeat or go backwards! + int j = voice.FindPreviousLine(_CurrentBeat); + for (; j >= 0; j--) { - CVoice voice = song.Notes.GetVoice(i); - CSongLine[] lines = voice.Lines; - - // find current line for lyric sub fading - int currentLineSub = _FindCurrentLine(voice, lines, song); - - // find current line for lyric main fading - int currentLine = 0; - for (int j = 0; j < lines.Length; j++) + float firstNoteTime = CGame.GetTimeFromBeats(lines[j].FirstNoteBeat, song.BPM); + //Earlist possible line break is 10s before first note + if (firstNoteTime <= currentTime + 10f) { - if (lines[j].FirstNoteBeat <= _CurrentBeat) - currentLine = j; - } - - // default values - alpha[i * 2] = 1f; - alpha[i * 2 + 1] = 1f; - - // main line alpha - if (currentLine == 0 && currentTime < CGame.GetTimeFromBeats(lines[currentLine].FirstNoteBeat, song.BPM)) - { - // first main line and fist note is not reached - // => fade in - float diff = CGame.GetTimeFromBeats(lines[currentLine].FirstNoteBeat, song.BPM) - currentTime; - if (diff > dt) - alpha[i * 2] = 1f - (diff - dt) / rt; - } - else if (currentLine < lines.Length - 1 && CGame.GetTimeFromBeats(lines[currentLine].LastNoteBeat, song.BPM) < currentTime && - CGame.GetTimeFromBeats(lines[currentLine + 1].FirstNoteBeat, song.BPM) > currentTime) - { - // current position is between two lines - - // time between the to lines - float diff = CGame.GetTimeFromBeats(lines[currentLine + 1].FirstNoteBeat, song.BPM) - - CGame.GetTimeFromBeats(lines[currentLine].LastNoteBeat, song.BPM); - - // fade only if there is enough time for fading - if (diff > 3.3f * dt) - { - // time elapsed since last line - float last = currentTime - CGame.GetTimeFromBeats(lines[currentLine].LastNoteBeat, song.BPM); - - // time to next line - float next = CGame.GetTimeFromBeats(lines[currentLine + 1].FirstNoteBeat, song.BPM) - currentTime; - - if (last < next) - { - // fade out - alpha[i * 2] = 1f - last / rt; - } - else - { - // fade in if it is time for - if (next > dt) - alpha[i * 2] = 1f - (next - dt) / rt; - } - } - } - else if (currentLine == lines.Length - 1 && CGame.GetTimeFromBeats(lines[currentLine].LastNoteBeat, song.BPM) < currentTime) - { - // last main line and last note was reached - // => fade out - float diff = currentTime - CGame.GetTimeFromBeats(lines[currentLine].LastNoteBeat, song.BPM); - alpha[i * 2] = 1f - diff / rt; - } - - // sub - if (currentLineSub < lines.Length - 2) - { - float diff = CGame.GetTimeFromBeats(lines[currentLineSub + 1].FirstNoteBeat, song.BPM) - currentTime; - - if (diff > dt) - alpha[i * 2 + 1] = 1f - (diff - dt) / rt; - } - - if (alpha[i * 2] < 0f) - alpha[i * 2] = 0f; - - if (alpha[i * 2 + 1] < 0f) - alpha[i * 2 + 1] = 0f; - } - - return alpha; - } - - private void _UpdateSongText() - { - if (_TimerSongText.IsRunning && !_Lyrics[_LyricMainDuet].Visible && !_Lyrics[_LyricMainTop].Visible) - { - float t = _TimerSongText.ElapsedMilliseconds / 1000f; - if (t < 10f) - { - _Statics[_StaticSongText].Visible = true; - _Texts[_TextSongName].Visible = true; - - if (t < 7f) - { - _Statics[_StaticSongText].Color.A = 1f; - _Texts[_TextSongName].Color.A = 1f; - } - else - { - _Statics[_StaticSongText].Color.A = (10f - t) / 3f; - _Texts[_TextSongName].Color.A = (10f - t) / 3f; - } - } - else - { - _Statics[_StaticSongText].Visible = false; - _Texts[_TextSongName].Visible = false; - _TimerSongText.Stop(); + //First line has no predecessor or line has to be shown + if (j == 0 || firstNoteTime - CConfig.Config.Game.MinLineBreakTime <= currentTime) + return j; + float lastNoteTime = CGame.GetTimeFromBeats(lines[j - 1].LastNoteBeat, song.BPM); + //No line break if last line is not fully evaluated (with 50% tolerance -> tested so notes are drawn) + if (lastNoteTime + CConfig.Config.Record.MicDelay / 1000f * 1.5f >= currentTime) + return j - 1; + return j; } } - else - { - _Statics[_StaticSongText].Visible = false; - _Texts[_TextSongName].Visible = false; - } - } - - private void _UpdateDuetNames(CText textName, Stopwatch timer) - { - if (timer.IsRunning) - { - float t = timer.ElapsedMilliseconds / 1000f; - if (t < 10f) - { - textName.Visible = true; - - if (t < 3f) - textName.Color.A = t / 3f; - else if (t < 7f) - textName.Color.A = 1f; - else - textName.Color.A = (10f - t) / 3f; - } - else - { - textName.Visible = false; - timer.Stop(); - } - } - else if (!timer.IsRunning && timer.ElapsedMilliseconds == 0 && _Lyrics[_LyricMainDuet].Alpha > 0 && CGame.GetSong().IsDuet) - timer.Start(); - else - textName.Visible = false; - } - - private void _UpdateDuetNames() - { - if (CGame.GetSong() == null) - return; - //Timer for first duet-part - _UpdateDuetNames(_Texts[_TextDuetName1], _TimerDuetText1); - //Timer for second duet-part - if (_TimerDuetText2.IsRunning) - { - float t = _TimerDuetText2.ElapsedMilliseconds / 1000f; - if (t < 10f) - { - _Texts[_TextDuetName2].Visible = true; - - if (t < 3f) - _Texts[_TextDuetName2].Color.A = (3f - (3f - t)) / 3f; - else if (t < 7f) - _Texts[_TextDuetName2].Color.A = 1f; - else - _Texts[_TextDuetName2].Color.A = (3f - (t - 7f)) / 3f; - } - else - { - _Texts[_TextDuetName2].Visible = false; - _TimerDuetText2.Stop(); - } - } - else if (!_TimerDuetText2.IsRunning && _TimerDuetText2.ElapsedMilliseconds == 0 && _Lyrics[_LyricMain].Alpha > 0 && CGame.GetSong().IsDuet) - _TimerDuetText2.Start(); - else - _Texts[_TextDuetName2].Visible = false; - } - - private void _UpdateTimeLine() - { - CSong song = CGame.GetSong(); - - if (song == null) - return; - - float totalTime = CSound.GetLength(_CurrentStream); - if (Math.Abs(song.Finish) > 0.001) - totalTime = song.Finish; - - float remainingTime = totalTime - _CurrentTime; - totalTime -= song.Start; - float currentTime = _CurrentTime - song.Start; - - if (_Length < 0 && totalTime > 0) - _PrepareTimeLine(); - - if (totalTime <= 0f) - return; - - switch (CConfig.Config.Game.TimerMode) - { - case ETimerMode.TR_CONFIG_TIMERMODE_CURRENT: - var min = (int)Math.Floor(currentTime / 60f); - var sec = (int)(currentTime - min * 60f); - _Texts[_TextTime].Text = min.ToString("00") + ":" + sec.ToString("00"); - break; - - case ETimerMode.TR_CONFIG_TIMERMODE_REMAINING: - min = (int)Math.Floor(remainingTime / 60f); - sec = (int)(remainingTime - min * 60f); - _Texts[_TextTime].Text = "-" + min.ToString("00") + ":" + sec.ToString("00"); - break; - - case ETimerMode.TR_CONFIG_TIMERMODE_TOTAL: - min = (int)Math.Floor(totalTime / 60f); - sec = (int)(totalTime - min * 60f); - _Texts[_TextTime].Text = "#" + min.ToString("00") + ":" + sec.ToString("00"); - break; - } - - - switch (CConfig.Config.Theme.TimerLook) - { - case ETimerLook.TR_CONFIG_TIMERLOOK_NORMAL: - _TimeLineRect.W = _Statics[_StaticTimeLine].Rect.W * (currentTime / totalTime); - break; - - case ETimerLook.TR_CONFIG_TIMERLOOK_EXPANDED: - CStatic stat = _Statics[_StaticTimeLine]; - int currentBeat = CGame.CurrentBeat; - for (int i = 0; i < _TimeRects.Count; i++) - { - if (currentBeat >= _TimeRects[i].StartBeat && currentBeat <= _TimeRects[i].EndBeat) - { - _TimeRects[i].Rect.Texture = _Statics[_StaticTimeLineExpandedHighlighted].Texture; - _TimeRects[i].Rect.Color = _Statics[_StaticTimeLineExpandedHighlighted].Color; - } - else - { - _TimeRects[i].Rect.Texture = _Statics[_StaticTimeLineExpandedNormal].Texture; - _TimeRects[i].Rect.Color = _Statics[_StaticTimeLineExpandedNormal].Color; - } - } - _Statics[_StaticTimePointer].X = stat.X + stat.W * (currentTime / totalTime); - break; - } + return -1; } private void _PrepareTimeLine() @@ -1747,13 +1798,5 @@ namespace Vocaluxe.Screens } } } - - private void _UpdateRatingBars() - { - for (int i = 0; i < CGame.NumPlayers; i++) - { - _ProgressBars[_PlayerProgressBarRating[i]].Progress = (float)CGame.Players[i].Rating; - } - } } } \ No newline at end of file