Files
Vocaluxe/Vocaluxe/Screens/CScreenSing.cs
T

1430 lines
56 KiB
C#

#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Vocaluxe.Base;
using Vocaluxe.Base.Fonts;
using VocaluxeLib;
using VocaluxeLib.Draw;
using VocaluxeLib.Menu;
using VocaluxeLib.Songs;
namespace Vocaluxe.Screens
{
class CScreenSing : CMenu
{
// Version number for theme files. Increment it, if you've changed something on the theme files!
protected override int _ScreenVersion
{
get { return 7; }
}
private struct STimeRect
{
public CStatic Rect;
public float StartBeat;
public float EndBeat;
}
private const string _TextSongName = "TextSongName";
private const string _TextTime = "TextTime";
private const string _TextPause = "TextPause";
private const string _TextDuetName1 = "TextDuetName1";
private const string _TextDuetName2 = "TextDuetName2";
private const string _TextMedleyCountdown = "TextMedleyCountdown";
private string[,] _TextScores;
private string[,] _TextNames;
private const string _StaticSongText = "StaticSongText";
private const string _StaticLyrics = "StaticLyrics";
private const string _StaticLyricsDuet = "StaticLyricsDuet";
private const string _StaticLyricsTop = "StaticLyricsTop";
private const string _StaticTimeBar = "StaticTimeBar";
private const string _StaticTimeLine = "StaticTimeLine";
private const string _StaticTimeLineExpandedNormal = "StaticTimeLineExpandedNormal";
private const string _StaticTimeLineExpandedHighlighted = "StaticTimeLineExpandedHighlighted";
private const string _StaticTimePointer = "StaticTimePointer";
private const string _StaticLyricHelper = "StaticLyricHelper";
private const string _StaticLyricHelperDuet = "StaticLyricHelperDuet";
private const string _StaticLyricHelperTop = "StaticLyricHelperTop";
private const string _StaticPauseBG = "StaticPauseBG";
private string[,] _StaticScores;
private string[,] _StaticAvatars;
private const string _ButtonCancel = "ButtonCancel";
private const string _ButtonContinue = "ButtonContinue";
private const string _ButtonSkip = "ButtonSkip";
private const string _LyricMain = "LyricMain";
private const string _LyricSub = "LyricSub";
private const string _LyricMainDuet = "LyricMainDuet";
private const string _LyricSubDuet = "LyricSubDuet";
private const string _LyricMainTop = "LyricMainTop";
private const string _LyricSubTop = "LyricSubTop";
private const string _SingBars = "SingBars";
private bool _DynamicLyricsTop;
private bool _DynamicLyricsBottom;
private SRectF _TimeLineRect;
private List<STimeRect> _TimeRects;
private bool _FadeOut;
private int _CurrentBeat;
private int _CurrentStream = -1;
private float _Length = -1f;
//private int _NextStream = -1;
private const float _Volume = 100f;
private int _CurrentVideo = -1;
private EAspect _VideoAspect = EAspect.Crop;
private CTexture _CurrentVideoTexture;
private CTexture _CurrentWebcamFrameTexture;
private CTexture _Background;
private float _CurrentTime;
private float _FinishTime;
private float _TimeToFirstNote;
private float _RemainingTimeToFirstNote;
private float _TimeToFirstNoteDuet;
private float _RemainingTimeToFirstNoteDuet;
private readonly int[] _NoteLines = new int[CSettings.MaxNumPlayer];
private Stopwatch _TimerSongText;
private Stopwatch _TimerDuetText1;
private Stopwatch _TimerDuetText2;
private bool _Pause;
private bool _Webcam;
private CBackground _SlideShow;
public override void Init()
{
base.Init();
var texts = new List<string> {_TextSongName, _TextTime, _TextPause, _TextDuetName1, _TextDuetName2, _TextMedleyCountdown};
_BuildTextStrings(texts);
_ThemeTexts = texts.ToArray();
var statics = new List<string>
{
_StaticSongText,
_StaticLyrics,
_StaticLyricsDuet,
_StaticLyricsTop,
_StaticTimeBar,
_StaticTimeLine,
_StaticTimeLineExpandedNormal,
_StaticTimeLineExpandedHighlighted,
_StaticTimePointer,
_StaticLyricHelper,
_StaticLyricHelperDuet,
_StaticLyricHelperTop,
_StaticPauseBG
};
_BuildStaticStrings(ref statics);
_ThemeStatics = statics.ToArray();
var buttons = new List<string> {_ButtonCancel, _ButtonContinue, _ButtonSkip};
_ThemeButtons = buttons.ToArray();
_ThemeLyrics = new string[] {_LyricMain, _LyricSub, _LyricMainDuet, _LyricSubDuet, _LyricMainTop, _LyricSubTop};
_ThemeSingNotes = new string[] {_SingBars};
_TimeRects = new List<STimeRect>();
_TimerSongText = new Stopwatch();
_TimerDuetText1 = new Stopwatch();
_TimerDuetText2 = new Stopwatch();
}
public override void LoadTheme(string xmlPath)
{
base.LoadTheme(xmlPath);
_Statics[_StaticTimeLine].Visible = false;
_Statics[_StaticTimeLineExpandedNormal].Visible = false;
_Statics[_StaticTimeLineExpandedHighlighted].Visible = false;
_Statics[_StaticPauseBG].Visible = false;
_Texts[_TextPause].Visible = false;
_Statics[_StaticPauseBG].Visible = false;
_Texts[_TextPause].Visible = false;
_Buttons[_ButtonCancel].Visible = false;
_Buttons[_ButtonContinue].Visible = false;
}
public override bool HandleInput(SKeyEvent keyEvent)
{
base.HandleInput(keyEvent);
if (keyEvent.KeyPressed)
{
//
}
else
{
switch (keyEvent.Key)
{
case Keys.Escape:
_TogglePause();
if (_Pause)
_SetInteractionToButton(_Buttons[_ButtonCancel]);
break;
case Keys.P:
_TogglePause();
if (_Pause)
_SetInteractionToButton(_Buttons[_ButtonContinue]);
break;
case Keys.T:
var mode = (int)CConfig.TimerMode;
mode++;
if (mode > Enum.GetNames(typeof(ETimerMode)).Length - 1)
mode = 0;
CConfig.TimerMode = (ETimerMode)mode;
CConfig.SaveConfig();
break;
case Keys.I:
mode = (int)CConfig.PlayerInfo;
mode++;
if (mode > Enum.GetNames(typeof(EPlayerInfo)).Length - 1)
mode = 0;
CConfig.PlayerInfo = (EPlayerInfo)mode;
CConfig.SaveConfig();
_SetVisibility();
if (CGame.GetSong() != null)
_SetDuetLyricsVisibility(CGame.GetSong().IsDuet); //make sure duet lyrics remain visible
break;
case Keys.S:
if (CGame.NumRounds > CGame.RoundNr)
{
if (keyEvent.ModCtrl)
_LoadNextSong();
}
break;
case Keys.W:
if (CWebcam.IsDeviceAvailable())
{
_Webcam = !CWebcam.IsCapturing();
if (_Webcam)
CWebcam.Start();
else
CWebcam.Stop();
}
break;
case Keys.Enter:
if (_Buttons[_ButtonContinue].Selected && _Pause)
_TogglePause();
if (_Buttons[_ButtonCancel].Selected && _Pause)
_Stop();
if (_Buttons[_ButtonSkip].Selected && _Pause)
{
_LoadNextSong();
_TogglePause();
}
break;
case Keys.Add:
case Keys.PageUp:
if (keyEvent.ModShift)
{
CConfig.GameMusicVolume += 5;
CSound.SetGlobalVolume(CConfig.GameMusicVolume);
}
break;
case Keys.Subtract:
case Keys.PageDown:
if (keyEvent.ModShift)
{
CConfig.GameMusicVolume -= 5;
CSound.SetGlobalVolume(CConfig.GameMusicVolume);
}
break;
}
}
return true;
}
public override bool HandleMouse(SMouseEvent mouseEvent)
{
base.HandleMouse(mouseEvent);
if (mouseEvent.RB)
{
_TogglePause();
if (_Pause)
_SetInteractionToButton(_Buttons[_ButtonContinue]);
}
if (mouseEvent.LB && _IsMouseOver(mouseEvent) && _Pause)
{
if (_Buttons[_ButtonContinue].Selected && _Pause)
_TogglePause();
if (_Buttons[_ButtonCancel].Selected && _Pause)
_Stop();
if (_Buttons[_ButtonSkip].Selected && _Pause)
{
_LoadNextSong();
_TogglePause();
}
}
return true;
}
public override bool UpdateGame()
{
bool finish = false;
if (CSound.IsPlaying(_CurrentStream) || CSound.IsPaused(_CurrentStream))
{
_CurrentTime = CSound.GetPosition(_CurrentStream);
if (_FinishTime > 0.001 && _CurrentTime >= _FinishTime)
finish = true;
}
else
finish = true;
if (finish)
_LoadNextSong();
_UpdateSongText();
_UpdateDuetNames();
if (_FadeOut)
return true;
_UpdateTimeLine();
CGame.UpdatePoints(_CurrentTime);
_UpdateLyrics();
float[] alpha = _CalcFadingAlpha();
if (alpha != null)
{
_Lyrics[_LyricMain].Alpha = alpha[0];
_Lyrics[_LyricSub].Alpha = alpha[1];
_Lyrics[_LyricMainTop].Alpha = alpha[0];
_Lyrics[_LyricSubTop].Alpha = alpha[1];
_Statics[_StaticLyrics].Alpha = alpha[0];
_Statics[_StaticLyricsTop].Alpha = alpha[0];
_Statics[_StaticLyricHelper].Alpha = alpha[0];
_Statics[_StaticLyricHelperTop].Alpha = alpha[0];
for (int p = 0; p < CGame.NumPlayer; p++)
{
_SingNotes[_SingBars].SetAlpha(_NoteLines[p], alpha[CGame.Players[p].VoiceNr * 2]);
if (CConfig.FadePlayerInfo == EFadePlayerInfo.TR_CONFIG_FADEPLAYERINFO_INFO || CConfig.FadePlayerInfo == EFadePlayerInfo.TR_CONFIG_FADEPLAYERINFO_ALL)
{
_Statics[_StaticAvatars[p, CGame.NumPlayer - 1]].Alpha = alpha[CGame.Players[p].VoiceNr * 2];
_Texts[_TextNames[p, CGame.NumPlayer - 1]].Alpha = alpha[CGame.Players[p].VoiceNr * 2];
}
if (CConfig.FadePlayerInfo == EFadePlayerInfo.TR_CONFIG_FADEPLAYERINFO_ALL)
{
_Statics[_StaticScores[p, CGame.NumPlayer - 1]].Alpha = alpha[CGame.Players[p].VoiceNr * 2];
_Statics[_StaticAvatars[p, CGame.NumPlayer - 1]].Alpha = alpha[CGame.Players[p].VoiceNr * 2];
_Texts[_TextNames[p, CGame.NumPlayer - 1]].Alpha = alpha[CGame.Players[p].VoiceNr * 2];
_Texts[_TextScores[p, CGame.NumPlayer - 1]].Alpha = alpha[CGame.Players[p].VoiceNr * 2];
}
}
if (alpha.Length > 2)
{
_Lyrics[_LyricMainDuet].Alpha = alpha[0];
_Lyrics[_LyricSubDuet].Alpha = alpha[1];
_Statics[_StaticLyricsDuet].Alpha = alpha[0];
_Statics[_StaticLyricHelperDuet].Alpha = alpha[0];
_Lyrics[_LyricMain].Alpha = alpha[2];
_Lyrics[_LyricSub].Alpha = alpha[3];
_Statics[_StaticLyrics].Alpha = alpha[2];
_Statics[_StaticLyricHelper].Alpha = alpha[2];
}
}
for (int p = 0; p < CGame.NumPlayer; p++)
{
string fmtString = (CGame.Players[p].Points < 10000) ? "0000" : "00000";
_Texts[_TextScores[p, CGame.NumPlayer - 1]].Text = CGame.Players[p].Points.ToString(fmtString);
}
if (_CurrentVideo != -1 && !_FadeOut && CConfig.VideosInSongs == EOffOn.TR_CONFIG_ON)
{
float vtime;
CVideo.GetFrame(_CurrentVideo, ref _CurrentVideoTexture, _CurrentTime, out vtime);
}
if (_Webcam)
CWebcam.GetFrame(ref _CurrentWebcamFrameTexture);
return true;
}
public override void OnShow()
{
base.OnShow();
_FadeOut = false;
_CurrentVideo = -1;
_CurrentVideoTexture = null;
_CurrentWebcamFrameTexture = null;
_CurrentBeat = -100;
_CurrentTime = 0f;
_FinishTime = 0f;
_Length = -1f;
_TimeToFirstNote = 0f;
_TimeToFirstNoteDuet = 0f;
_Pause = false;
_TimeRects.Clear();
_SingNotes[_SingBars].Reset();
for (int i = 0; i < CSettings.MaxNumPlayer; i++)
_NoteLines[i] = -1;
foreach (CLyric lyric in _Lyrics)
lyric.LyricStyle = CConfig.LyricStyle;
for (int p = 0; p < CGame.NumPlayer; p++)
_Statics[_StaticAvatars[p, CGame.NumPlayer - 1]].Aspect = EAspect.Crop;
_SetVisibility();
_UpdateAvatars();
_UpdateNames();
_CloseSong();
CSound.SetGlobalVolume(CConfig.GameMusicVolume);
}
public override void OnShowFinish()
{
base.OnShowFinish();
CBackgroundMusic.Disabled = true;
CGame.Start();
_LoadNextSong();
}
public override bool Draw()
{
if (_Active)
{
CTexture background;
var aspect = EAspect.Crop;
if (_CurrentVideo != -1 && CConfig.VideosInSongs == EOffOn.TR_CONFIG_ON && !_Webcam)
{
background = _CurrentVideoTexture;
aspect = _VideoAspect;
}
else if (_Webcam)
{
background = _CurrentWebcamFrameTexture;
aspect = _VideoAspect;
}
else
background = _Background;
if (background != null)
{
var bounds = new RectangleF(0, 0, CSettings.RenderW, CSettings.RenderH);
RectangleF rect;
CHelper.SetRect(bounds, out rect, background.OrigAspect, aspect);
CDraw.DrawTexture(background, new SRectF(rect.X, rect.Y, rect.Width, rect.Height, 0f),
background.Color, new SRectF(bounds.X, bounds.Y, bounds.Width, bounds.Height, 0f));
}
else if (_SlideShow != null)
_SlideShow.Draw();
}
_DrawBG();
foreach (CStatic stat in _Statics)
stat.Draw();
foreach (CText text in _Texts)
text.Draw();
switch (CConfig.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;
}
_Lyrics[_LyricSub].Draw(-100);
_Lyrics[_LyricMain].Draw(CGame.CurrentBeatF);
_Lyrics[_LyricSubDuet].Draw(-100);
_Lyrics[_LyricMainDuet].Draw(CGame.CurrentBeatF);
_Lyrics[_LyricSubTop].Draw(-100);
_Lyrics[_LyricMainTop].Draw(CGame.CurrentBeatF);
for (int i = 0; i < CGame.NumPlayer; i++)
_SingNotes[_SingBars].Draw(_NoteLines[i], CGame.Players[i].SungLines, i);
_DrawLyricHelper();
if (CGame.GameMode == EGameMode.TR_GAMEMODE_MEDLEY)
{
_UpdateMedleyCountdown();
_Texts[_TextMedleyCountdown].Draw();
}
if (_Pause)
{
_Statics[_StaticPauseBG].Draw(true);
_Texts[_TextPause].Draw(true);
foreach (CButton button in _Buttons)
button.Draw();
foreach (CSelectSlide slide in _SelectSlides)
slide.Draw();
}
return true;
}
public override void OnClose()
{
base.OnClose();
_CloseSong();
if (_Webcam)
CWebcam.Stop();
CBackgroundMusic.Disabled = false;
CSound.SetGlobalVolume(CConfig.BackgroundMusicVolume);
}
private void _CloseSong()
{
if (_CurrentStream > -1)
{
CSound.FadeAndClose(_CurrentStream, 0f, 0.5f);
_CurrentStream = -1;
}
CRecord.Stop();
if (_CurrentVideo != -1)
{
CVideo.Close(_CurrentVideo);
_CurrentVideo = -1;
CDraw.RemoveTexture(ref _CurrentVideoTexture);
}
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 _LoadNextSong()
{
_CloseSong();
CGame.NextRound();
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);
CSound.SetStreamVolume(_CurrentStream, _Volume);
CSound.SetPosition(_CurrentStream, song.Start);
_CurrentTime = song.Start;
_FinishTime = song.Finish;
_TimeToFirstNote = 0f;
_TimeToFirstNoteDuet = 0f;
_Length = -1f;
var voiceAssignments = new int[CGame.NumPlayer];
if (song.IsDuet)
{
//Save duet-assignment before resetting
for (int i = 0; i < voiceAssignments.Length; i++)
voiceAssignments[i] = CGame.Players[i].VoiceNr;
}
CGame.ResetPlayer();
CDraw.RemoveTexture(ref _CurrentVideoTexture);
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]));
}
_SingNotes[_SingBars].Reset();
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.NumPlayer; i++)
CGame.Players[i].VoiceNr = (i + 1) % 2;
}
else
{
for (int i = 0; i < CGame.NumPlayer; i++)
CGame.Players[i].VoiceNr = voiceAssignments[i];
}
}
_DynamicLyricsTop = false;
_DynamicLyricsBottom = false;
for (int p = 0; p < CGame.NumPlayer; p++)
{
_NoteLines[p] = _SingNotes[_SingBars].AddPlayer(_SingNotes[_SingBars].BarPos[p, CGame.NumPlayer - 1], CTheme.GetPlayerColor(p + 1), p);
if (_SingNotes[_SingBars].BarPos[p, CGame.NumPlayer - 1].Y + _SingNotes[_SingBars].BarPos[p, CGame.NumPlayer - 1].H >= CSettings.RenderH / 2)
_DynamicLyricsBottom = true;
else
_DynamicLyricsTop = true;
}
_SetDuetLyricsVisibility(song.IsDuet);
_SetNormalLyricsVisibility();
/*
case 4:
NoteLines[0] = SingNotes[SingBars].AddPlayer(new SRectF(35f, 100f, 590f, 200f, -0.5f), CTheme.ThemeColors.Player[0]);
NoteLines[1] = SingNotes[SingBars].AddPlayer(new SRectF(35f, 350f, 590f, 200f, -0.5f), CTheme.ThemeColors.Player[1]);
NoteLines[2] = SingNotes[SingBars].AddPlayer(new SRectF(640f, 100f, 590f, 200f, -0.5f), CTheme.ThemeColors.Player[2]);
NoteLines[3] = SingNotes[SingBars].AddPlayer(new SRectF(640f, 350f, 590f, 200f, -0.5f), CTheme.ThemeColors.Player[3]);
break;
*/
_TimerSongText.Reset();
_TimerDuetText1.Reset();
_TimerDuetText2.Reset();
if (!song.IsDuet)
_TimerSongText.Start();
_StartSong();
}
private void _SetDuetLyricsVisibility(bool isDuet)
{
_Statics[_StaticLyricsDuet].Visible = isDuet;
_Lyrics[_LyricMainDuet].Visible = isDuet;
_Lyrics[_LyricSubDuet].Visible = isDuet;
if (isDuet)
{
_Lyrics[_LyricMainTop].Visible = false;
_Lyrics[_LyricSubTop].Visible = false;
_Statics[_StaticLyricsTop].Visible = false;
}
else
{
bool lyricsOnTop = CConfig.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_TOP
|| CConfig.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_BOTH
|| (CConfig.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_DYNAMIC && _DynamicLyricsTop);
_Lyrics[_LyricMainTop].Visible = lyricsOnTop;
_Lyrics[_LyricSubTop].Visible = lyricsOnTop;
_Statics[_StaticLyricsTop].Visible = lyricsOnTop;
}
}
private void _SetNormalLyricsVisibility()
{
bool visible = CConfig.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_BOTTOM
|| CConfig.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_BOTH
|| (CConfig.LyricsPosition == ELyricsPosition.TR_CONFIG_LYRICSPOSITION_DYNAMIC && _DynamicLyricsBottom);
_Lyrics[_LyricMain].Visible = visible;
_Lyrics[_LyricSub].Visible = visible;
_Statics[_StaticLyrics].Visible = visible;
}
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();
_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.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.MicDelay / 1000f * 1.5f >= currentTime)
return j - 1;
return j;
}
}
return -1;
}
private void _UpdateLyrics()
{
if (_FadeOut)
return;
CSong song = CGame.GetSong();
if (song == null)
return;
_CurrentBeat = CGame.CurrentBeat;
for (int i = 0; i < song.Notes.VoiceCount; i++)
{
if (i > 1)
break; // for later
CVoice voice = song.Notes.GetVoice(i);
CSongLine[] lines = voice.Lines;
// find current line
int nr = _FindCurrentLine(voice, lines, song);
if (nr != -1)
{
for (int j = 0; j < CGame.NumPlayer; j++)
{
if (CGame.Players[j].VoiceNr == i)
_SingNotes[_SingBars].SetLines(_NoteLines[j], lines, nr);
}
if (i == 0 && !song.IsDuet || i == 1 && song.IsDuet)
{
_Lyrics[_LyricMain].SetLine(lines[nr]);
_Lyrics[_LyricMainTop].SetLine(lines[nr]);
_TimeToFirstNote = CGame.GetTimeFromBeats(lines[nr].FirstNoteBeat - lines[nr].StartBeat, song.BPM);
_RemainingTimeToFirstNote = CGame.GetTimeFromBeats(lines[nr].FirstNoteBeat - CGame.GetBeatFromTime(_CurrentTime, song.BPM, song.Gap), song.BPM);
if (lines.Length >= nr + 2)
{
_Lyrics[_LyricSub].SetLine(lines[nr + 1]);
_Lyrics[_LyricSubTop].SetLine(lines[nr + 1]);
}
else
{
_Lyrics[_LyricSub].Clear();
_Lyrics[_LyricSubTop].Clear();
}
}
if (i == 0 && song.IsDuet)
{
_Lyrics[_LyricMainDuet].SetLine(lines[nr]);
_TimeToFirstNoteDuet = CGame.GetTimeFromBeats(lines[nr].FirstNoteBeat - lines[nr].StartBeat, song.BPM);
_RemainingTimeToFirstNoteDuet = CGame.GetTimeFromBeats(lines[nr].FirstNoteBeat - CGame.GetBeatFromTime(_CurrentTime, song.BPM, song.Gap), song.BPM);
if (lines.Length >= nr + 2)
_Lyrics[_LyricSubDuet].SetLine(lines[nr + 1]);
else
_Lyrics[_LyricSubDuet].Clear();
}
}
else
{
if (i == 0 && !song.IsDuet || i == 1 && song.IsDuet)
{
_Lyrics[_LyricMain].Clear();
_Lyrics[_LyricSub].Clear();
_Lyrics[_LyricMainTop].Clear();
_Lyrics[_LyricSubTop].Clear();
_TimeToFirstNote = 0f;
}
if (i == 0 && song.IsDuet)
{
_Lyrics[_LyricMainDuet].Clear();
_Lyrics[_LyricSubDuet].Clear();
_TimeToFirstNoteDuet = 0f;
}
}
}
}
private void _TogglePause()
{
_Pause = !_Pause;
if (_Pause)
{
_Buttons[_ButtonCancel].Visible = true;
_Buttons[_ButtonContinue].Visible = true;
if (CGame.NumRounds > CGame.RoundNr && CGame.NumRounds > 1)
_Buttons[_ButtonSkip].Visible = true;
else
_Buttons[_ButtonSkip].Visible = false;
CSound.Pause(_CurrentStream);
}
else
{
//CGame.ResetToLastLine(_CurrentStream, _CurrentVideo);
_Buttons[_ButtonCancel].Visible = false;
_Buttons[_ButtonContinue].Visible = false;
_Buttons[_ButtonSkip].Visible = false;
CSound.Play(_CurrentStream);
if (_Webcam)
CWebcam.Start();
}
}
private void _BuildTextStrings(List<string> texts)
{
_TextScores = new string[CSettings.MaxNumPlayer,CSettings.MaxNumPlayer];
_TextNames = new string[CSettings.MaxNumPlayer,CSettings.MaxNumPlayer];
for (int numplayer = 0; numplayer < CSettings.MaxNumPlayer; numplayer++)
{
for (int player = 0; player < CSettings.MaxNumPlayer; player++)
{
if (player <= numplayer)
{
string target = "P" + (player + 1) + "N" + (numplayer + 1);
_TextScores[player, numplayer] = "TextScore" + target;
_TextNames[player, numplayer] = "TextName" + target;
texts.Add(_TextScores[player, numplayer]);
texts.Add(_TextNames[player, numplayer]);
}
}
}
}
private void _BuildStaticStrings(ref List<string> statics)
{
_StaticScores = new string[CSettings.MaxNumPlayer,CSettings.MaxNumPlayer];
_StaticAvatars = new string[CSettings.MaxNumPlayer,CSettings.MaxNumPlayer];
for (int numplayer = 0; numplayer < CSettings.MaxNumPlayer; numplayer++)
{
for (int player = 0; player < CSettings.MaxNumPlayer; player++)
{
if (player <= numplayer)
{
string target = "P" + (player + 1) + "N" + (numplayer + 1);
_StaticScores[player, numplayer] = "StaticScore" + target;
_StaticAvatars[player, numplayer] = "StaticAvatar" + target;
statics.Add(_StaticScores[player, numplayer]);
statics.Add(_StaticAvatars[player, numplayer]);
}
}
}
}
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;
for (int numplayer = 0; numplayer < CSettings.MaxNumPlayer; numplayer++)
{
for (int player = 0; player < CSettings.MaxNumPlayer; player++)
{
if (player <= numplayer)
{
_Texts[_TextScores[player, numplayer]].Visible = numplayer + 1 == CGame.NumPlayer;
_Texts[_TextNames[player, numplayer]].Visible = (numplayer + 1 == CGame.NumPlayer)
&&
(CConfig.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH ||
CConfig.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_NAME);
_Statics[_StaticScores[player, numplayer]].Visible = numplayer + 1 == CGame.NumPlayer;
_Statics[_StaticAvatars[player, numplayer]].Visible = (numplayer + 1 == CGame.NumPlayer)
&&
(CConfig.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH ||
CConfig.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_AVATAR);
}
}
}
_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;
}
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();
float h = partSeconds * CSettings.RenderH;
float w = CFonts.GetTextBounds(_Texts[_TextMedleyCountdown], h).Width;
float x = CSettings.RenderW / 2 - w / 2;
float y = CSettings.RenderH / 2 - h / 2;
_Texts[_TextMedleyCountdown].X = x;
_Texts[_TextMedleyCountdown].Y = y;
_Texts[_TextMedleyCountdown].Height = h;
}
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++)
{
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;
}
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.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.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].Rect.X = stat.Rect.X + stat.Rect.W * (currentTime / totalTime);
break;
}
}
private void _PrepareTimeLine()
{
CStatic stat = _Statics[_StaticTimeLine];
switch (CConfig.TimerLook)
{
case ETimerLook.TR_CONFIG_TIMERLOOK_NORMAL:
_TimeLineRect = new SRectF(stat.Rect.X, stat.Rect.Y, 0f, stat.Rect.H, stat.Rect.Z);
_Statics[_StaticTimePointer].Visible = false;
break;
case ETimerLook.TR_CONFIG_TIMERLOOK_EXPANDED:
_TimeRects.Clear();
_Statics[_StaticTimePointer].Visible = true;
CSong song = CGame.GetSong();
if (song == null)
return;
float totalTime = CSound.GetLength(_CurrentStream);
if (Math.Abs(song.Finish) > 0.001)
totalTime = song.Finish;
totalTime -= song.Start;
if (totalTime <= 0f)
return;
_Length = totalTime;
foreach (CVoice voice in song.Notes.Voices)
{
foreach (CSongLine line in voice.Lines.Where(line => line.VisibleInTimeLine))
{
var trect = new STimeRect {StartBeat = line.FirstNoteBeat, EndBeat = line.EndBeat};
trect.Rect = GetNewStatic(null,
new SColorF(1f, 1f, 1f, 1f),
new SRectF(
stat.Rect.X + stat.Rect.W * ((CGame.GetTimeFromBeats(trect.StartBeat, song.BPM) + song.Gap - song.Start) / totalTime),
stat.Rect.Y,
stat.Rect.W * (CGame.GetTimeFromBeats(trect.EndBeat - trect.StartBeat, song.BPM) / totalTime),
stat.Rect.H,
stat.Rect.Z));
_TimeRects.Add(trect);
}
}
break;
}
}
private void _UpdateAvatars()
{
for (int i = 0; i < CGame.NumPlayer; i++)
{
if (CProfiles.IsProfileIDValid(CGame.Players[i].ProfileID))
_Statics[_StaticAvatars[i, CGame.NumPlayer - 1]].Texture = CProfiles.GetAvatarTextureFromProfile(CGame.Players[i].ProfileID);
else
_Statics[_StaticAvatars[i, CGame.NumPlayer - 1]].Visible = false;
}
}
private void _UpdateNames()
{
for (int i = 0; i < CGame.NumPlayer; i++)
{
if (CProfiles.IsProfileIDValid(CGame.Players[i].ProfileID))
_Texts[_TextNames[i, CGame.NumPlayer - 1]].Text = CProfiles.GetPlayerName(CGame.Players[i].ProfileID);
else
_Texts[_TextNames[i, CGame.NumPlayer - 1]].Visible = false;
}
}
}
}