diff --git a/Vocaluxe/Base/CGame.cs b/Vocaluxe/Base/CGame.cs index 514c8543..f0a3c23f 100644 --- a/Vocaluxe/Base/CGame.cs +++ b/Vocaluxe/Base/CGame.cs @@ -304,7 +304,8 @@ namespace Vocaluxe.Base TonePlayer = Tone; _Player[p].NoteDiff = Math.Abs(Tone - TonePlayer); - if (_Player[p].NoteDiff <= (2 - (int)_Player[p].Difficulty)) + bool Hit=_Player[p].NoteDiff <= (2 - (int)_Player[p].Difficulty); + if (Hit) { // valid //CSound.RecordSetTone(p, Tone); @@ -318,7 +319,7 @@ namespace Vocaluxe.Base if (_Player[p].SingLine[Line].NoteCount > 0) { CNote nt = _Player[p].SingLine[Line].LastNote; - if (notes[Note].StartBeat == beat || nt.EndBeat + 1 != beat || nt.Tone != Tone) + if (notes[Note].StartBeat == beat || nt.EndBeat + 1 != beat || nt.Tone != Tone || !nt.Hit) _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, Tone, String.Empty, true, notes[Note].NoteType)); else { @@ -338,18 +339,13 @@ namespace Vocaluxe.Base if (_Player[p].SingLine[Line].NoteCount > 0) { CNote nt = _Player[p].SingLine[Line].LastNote; - if (nt.EndBeat + 1 != beat || nt.Hit) - _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, ENoteType.Freestyle)); + if (nt.Tone == TonePlayer && nt.EndBeat + 1 == beat && !nt.Hit) + { + _Player[p].SingLine[Line].IncLastNoteLength(); + } else { - if (nt.Tone == TonePlayer && nt.EndBeat + 1 == beat) - { - _Player[p].SingLine[Line].IncLastNoteLength(); - } - else - { - _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, ENoteType.Freestyle)); - } + _Player[p].SingLine[Line].AddNote(new CNote(beat, 1, TonePlayer, String.Empty, false, ENoteType.Freestyle)); } } else diff --git a/Vocaluxe/Base/CGraphics.cs b/Vocaluxe/Base/CGraphics.cs index 18329bd8..d28a4abd 100644 --- a/Vocaluxe/Base/CGraphics.cs +++ b/Vocaluxe/Base/CGraphics.cs @@ -325,7 +325,7 @@ namespace Vocaluxe.Base CInput.Update(); if (CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_DYNAMIC && _CurrentScreen != EScreens.ScreenSing) - CSongs.LoadCover(30L, 1); + CSongs.LoadCover(); if (CSettings.GameState != EGameState.EditTheme) { diff --git a/Vocaluxe/Base/CMain.cs b/Vocaluxe/Base/CMain.cs index 27769a67..ef7e5aa0 100644 --- a/Vocaluxe/Base/CMain.cs +++ b/Vocaluxe/Base/CMain.cs @@ -609,15 +609,20 @@ namespace Vocaluxe.Base return null; CSong song = CSongs.VisibleSongs[VisibleIndex]; - if (song == null) - return null; + //Flamefire: Why copy the song-instance??? Cover and stuff will be loaded twice! + //And for unknown reason causes no-big-cover bug if covers are not loaded on startup + return song; + //if (song == null) + // return null; - return new CSong(song); + //return new CSong(song); } public CSong GetSongByID(int SongID) { - return new CSong(CSongs.GetSong(SongID)); + //Flamefire: Why copy? + //return new CSong(CSongs.GetSong(SongID)); + return CSongs.GetSong(SongID); } public CSong[] GetSongs() diff --git a/Vocaluxe/Base/CSongs.cs b/Vocaluxe/Base/CSongs.cs index bfc46035..789b741f 100644 --- a/Vocaluxe/Base/CSongs.cs +++ b/Vocaluxe/Base/CSongs.cs @@ -55,7 +55,7 @@ namespace Vocaluxe.Base private static ESongSorting _SongSorting = CConfig.SongSorting; private static bool _ShowDuetSongs = true; - private static Thread _CoverLoaderThread = new Thread(new ThreadStart(_LoadCover)); + private static Thread _CoverLoaderThread = null; public static string SearchFilter { @@ -197,28 +197,26 @@ namespace Vocaluxe.Base if (!_SongsLoaded) return; - if (SongIndex <= _Songs.Count) + if (SongIndex < _Songs.Count) { _Songs[SongIndex].CoverTextureSmall = Texture; - //_Songs[SongIndex].CoverSmallLoaded = true; + if (SongIndex == _Songs.Count - 1) + _CoverLoaded = true; } - if (SongIndex == _Songs.Count - 1) - _CoverLoaded = true; } public static void SetCoverBig(int SongIndex, STexture Texture) { if (!_SongsLoaded) return; - if (SongIndex <= _Songs.Count) + if (SongIndex < _Songs.Count) { _Songs[SongIndex].CoverTextureBig = Texture; - _Songs[SongIndex].CoverBigLoaded = true; + if (SongIndex == _Songs.Count - 1) + _CoverLoaded = true; } - if (SongIndex == _Songs.Count - 1) - _CoverLoaded = true; } public static string GetCurrentCategoryName() @@ -1022,11 +1020,14 @@ namespace Vocaluxe.Base CLog.StartBenchmark(2, "Read TXTs"); foreach (string file in files) { - CSong Song = new CSong(); - if (Song.ReadTXTSong(file)) + CSong Song = CSong.LoadSong(file); + if (Song != null) { Song.ID = _Songs.Count; _Songs.Add(Song); + //Workaround to load notes if they are not loaded with the covers as there is no seperate progress indicator + if (CConfig.CoverLoading != ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART) + Song.ReadNotes(); } } CLog.StopBenchmark(2, "Read TXTs"); @@ -1037,100 +1038,43 @@ namespace Vocaluxe.Base Category = -1; _SongsLoaded = true; - if (CConfig.Renderer != ERenderer.TR_CONFIG_SOFTWARE && CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART) + if (CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART) { - CLog.StartBenchmark(2, "Load Cover"); - for (int i = 0; i < _Songs.Count; i++) - { - CSong song = _Songs[i]; - - song.ReadNotes(); - STexture texture = song.CoverTextureSmall; - song.CoverTextureBig = texture; - _CoverLoadIndex++; - - if (i % 100 == 0) - { - CDataBase.CommitCovers(); - GC.Collect(); - } - } - - _CoverLoaded = true; - CDataBase.CommitCovers(); - CLog.StopBenchmark(2, "Load Cover"); + CLog.StartBenchmark(2, "Load Covers/Notes"); + _LoadCover(); + CLog.StopBenchmark(2, "Load Covers/Notes"); } CLog.StopBenchmark(1, "Load Songs "); GC.Collect(); } - public static void LoadCover(long WaitTime, int NumLoads) + public static void LoadCover() { if (CConfig.Renderer == ERenderer.TR_CONFIG_SOFTWARE) - return; //should be removed as soon as the other renderer are ready for queque - - if (!SongsLoaded) return; - if (CoverLoaded) + if (!SongsLoaded || CoverLoaded) return; - if (_CoverLoaderThread.ThreadState == System.Threading.ThreadState.Unstarted) + if (_CoverLoaderThread == null) { + _CoverLoaderThread = new Thread(new ThreadStart(_LoadCover)); _CoverLoaderThread.Name = "CoverLoader"; _CoverLoaderThread.Priority = ThreadPriority.BelowNormal; _CoverLoaderThread.IsBackground = true; _CoverLoaderThread.Start(); } - - /* - - - if (!_CoverLoadTimer.IsRunning) - { - _CoverLoadTimer.Reset(); - _CoverLoadTimer.Start(); - } - - STexture texture = new STexture(-1); - if (_CoverLoadTimer.ElapsedMilliseconds >= WaitTime) - { - for (int i = 0; i < NumLoads; i++) - { - CSong song = new CSong(); - int n = GetNextSongWithoutCover(ref song); - - if (n < 0) - return; - - song.ReadNotes(); - texture = song.CoverTextureSmall; - - SetCoverSmall(n, texture); - SetCoverBig(n, texture); - - if (CoverLoaded) - CDataBase.CommitCovers(); - - _CoverLoadTimer.Reset(); - _CoverLoadTimer.Start(); - } - } - * */ } private static void _LoadCover() { - for (int i = 0; i < _Songs.Count; i++) + foreach(CSong song in _Songs) { - CSong song = _Songs[i]; - song.ReadNotes(); - STexture texture = song.CoverTextureSmall; - song.CoverTextureBig = texture; + song.LoadSmallCover(); _CoverLoadIndex++; } - + GC.Collect(); _CoverLoaded = true; CDataBase.CommitCovers(); } diff --git a/Vocaluxe/Screens/CScreenLoad.cs b/Vocaluxe/Screens/CScreenLoad.cs index f7e28732..6b83f4fb 100644 --- a/Vocaluxe/Screens/CScreenLoad.cs +++ b/Vocaluxe/Screens/CScreenLoad.cs @@ -137,7 +137,7 @@ namespace Vocaluxe.Screens } } - CLog.StartBenchmark(3, "Load Cover"); + CLog.StartBenchmark(0, "Load Songs Full"); _SongLoaderThread.IsBackground = true; _SongLoaderThread.Start(); _timer.Start(); @@ -165,8 +165,7 @@ namespace Vocaluxe.Screens else _timer.Start(); - bool next = ((CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART && CSongs.CoverLoaded) || - CConfig.CoverLoading != ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART); + bool next = (CConfig.CoverLoading != ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART || CSongs.CoverLoaded); if ((_IntroOutPlayed || _SkipIntro) && next && CSettings.GameState != EGameState.EditTheme && CSongs.SongsLoaded) { @@ -221,7 +220,7 @@ namespace Vocaluxe.Screens CBackgroundMusic.CanSing = true; - CLog.StopBenchmark(3, "Load Cover"); + CLog.StopBenchmark(0, "Load Songs Full"); //Init Playlists CLog.StartBenchmark(0, "Init Playlists"); @@ -244,23 +243,17 @@ namespace Vocaluxe.Screens { _CurrentIntroVideoNr = 0; _Intros[0].Start(); - } - - if (_CurrentIntroVideoNr == 0 && _Intros[0].IsFinished && CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART) + }else if (_CurrentIntroVideoNr == 0 && _Intros[0].IsFinished && CConfig.CoverLoading == ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART) { _CurrentIntroVideoNr = 1; _Intros[1].Loop = true; _Intros[1].Start(); - } - - if ((_CurrentIntroVideoNr == 1 && CSongs.CoverLoaded) || - (_CurrentIntroVideoNr == 0 && _Intros[0].IsFinished && CConfig.CoverLoading != ECoverLoading.TR_CONFIG_COVERLOADING_ATSTART)) + }else if ((_CurrentIntroVideoNr == 1 && CSongs.CoverLoaded) || + (_CurrentIntroVideoNr == 0 && _Intros[0].IsFinished)) { _CurrentIntroVideoNr = 2; _Intros[2].Start(); - } - - if (_CurrentIntroVideoNr == 2 && _Intros[2].IsFinished) + }else if (_CurrentIntroVideoNr == 2 && _Intros[2].IsFinished) _IntroOutPlayed = true; } } diff --git a/Vocaluxe/Screens/CScreenSing.cs b/Vocaluxe/Screens/CScreenSing.cs index 61424a98..0273cc9a 100644 --- a/Vocaluxe/Screens/CScreenSing.cs +++ b/Vocaluxe/Screens/CScreenSing.cs @@ -209,7 +209,7 @@ namespace Vocaluxe.Screens } CConfig.PlayerInfo = (EPlayerInfo)mode; CConfig.SaveConfig(); - SetVisuability(); + SetVisibility(); break; case Keys.S: @@ -432,7 +432,7 @@ namespace Vocaluxe.Screens { Statics[htStatics(StaticAvatars[p, CGame.NumPlayer - 1])].Aspect = EAspect.Crop; } - SetVisuability(); + SetVisibility(); UpdateAvatars(); UpdateNames(); @@ -592,7 +592,7 @@ namespace Vocaluxe.Screens return; } - if (!song.CoverSmallLoaded) + if (!song.NotesLoaded) song.ReadNotes(); string songname = song.Artist + " - " + song.Title; @@ -738,25 +738,23 @@ namespace Vocaluxe.Screens CWebcam.Close(); } - private int FindCurrentLine(CLine[] line, CSong song) + private int FindCurrentLine(CLines lines, CLine[] line, 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! - for (int j = line.Length - 1; j >= 0; j--) + int j = lines.FindPreviousLine(_CurrentBeat); + for (; j >= 0; j--) { - if (line[j].StartBeat <= _CurrentBeat) + float FirstNoteTime = CGame.GetTimeFromBeats(line[j].FirstNoteBeat, song.BPM); + //Earlist possible line break is 10s before first note + if (FirstNoteTime <= CurrentTime + 10f) { - float FirstNoteTime = CGame.GetTimeFromBeats(line[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(line[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; - } + //First line has no predecessor or line has to be shown + if(j == 0 || FirstNoteTime - CConfig.MinLineBreakTime <= CurrentTime) return j; + float LastNoteTime = CGame.GetTimeFromBeats(line[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; @@ -772,19 +770,18 @@ namespace Vocaluxe.Screens if (song == null) return; - CLines[] lines = new CLines[song.Notes.Lines.Length]; _CurrentBeat = CGame.CurrentBeat; - for (int i = 0; i < lines.Length; i++) + for (int i = 0; i < song.Notes.LinesCount; i++) { if (i > 1) break; // for later - lines[i] = song.Notes.GetLines(i); - CLine[] line = lines[i].Line; + CLines lines = song.Notes.GetLines(i); + CLine[] line = lines.Line; // find current line - int nr = FindCurrentLine(line, song); + int nr = FindCurrentLine(lines, line, song); if (nr != -1) { @@ -911,7 +908,7 @@ namespace Vocaluxe.Screens } } - private void SetVisuability() + private void SetVisibility() { Statics[htStatics(StaticLyricsDuet)].Visible = false; Statics[htStatics(StaticLyricHelper)].Visible = false; @@ -1054,16 +1051,15 @@ namespace Vocaluxe.Screens return null; float[] Alpha = new float[Song.Notes.Lines.Length * 2]; - CLines[] lines = new CLines[Song.Notes.Lines.Length]; float CurrentTime = _CurrentTime - Song.Gap; - for (int i = 0; i < lines.Length; i++) + for (int i = 0; i < Song.Notes.LinesCount; i++) { - lines[i] = Song.Notes.GetLines(i); - CLine[] line = lines[i].Line; + CLines lines = Song.Notes.GetLines(i); + CLine[] line = lines.Line; // find current line for lyric sub fading - int CurrentLineSub = FindCurrentLine(line, Song); + int CurrentLineSub = FindCurrentLine(lines, line, Song); // find current line for lyric main fading int CurrentLine = 0; diff --git a/VocaluxeLib/Menu/CHelper.cs b/VocaluxeLib/Menu/CHelper.cs index 5d3fc59a..c6f49b82 100644 --- a/VocaluxeLib/Menu/CHelper.cs +++ b/VocaluxeLib/Menu/CHelper.cs @@ -58,12 +58,13 @@ namespace Vocaluxe.Menu try { - chr = (char)sr.Peek(); - while ((chr.CompareTo(' ') != 0) && ((int)chr != 19) && ((int)chr != 16) && ((int)chr != 13)) + int tmp = sr.Peek(); + //Check for ' ', ?, ?, \n, \r + while (tmp != 32 && tmp != 19 && tmp != 16 && tmp != 13 && tmp != 10) { chr = (char)sr.Read(); value += chr.ToString(); - chr = (char)sr.Peek(); + tmp = sr.Peek(); } } catch (Exception) diff --git a/VocaluxeLib/Menu/SingNotes/CNotes.cs b/VocaluxeLib/Menu/SingNotes/CNotes.cs index 98b93b24..79923569 100644 --- a/VocaluxeLib/Menu/SingNotes/CNotes.cs +++ b/VocaluxeLib/Menu/SingNotes/CNotes.cs @@ -19,6 +19,11 @@ namespace Vocaluxe.Menu.SingNotes { } + public int LinesCount + { + get { return _Lines.Count; } + } + public CNotes(CNotes notes) { foreach (CLines lines in notes._Lines) @@ -270,10 +275,10 @@ namespace Vocaluxe.Menu.SingNotes public class CLine { - private int _StartBeat; - private int _EndBeat; - private bool _PerfectLine; // for drawing perfect line effect - private bool _VisibleInTimeLine; + private int _StartBeat = int.MinValue; + private int _EndBeat = int.MinValue; + private bool _PerfectLine = false; // for drawing perfect line effect + private bool _VisibleInTimeLine = true; private int _MinBeat = int.MaxValue; private int _MaxBeat = int.MinValue; @@ -282,10 +287,6 @@ namespace Vocaluxe.Menu.SingNotes #region Constructors public CLine() { - StartBeat = int.MinValue; - EndBeat = int.MaxValue; - _PerfectLine = false; - _VisibleInTimeLine = true; } public CLine(CLine line) @@ -338,18 +339,12 @@ namespace Vocaluxe.Menu.SingNotes public int FirstNoteBeat { - get - { - return _MinBeat; - } + get { return _MinBeat; } } public int LastNoteBeat { - get - { - return _MaxBeat; - } + get { return _MaxBeat; } } public string Lyrics @@ -385,10 +380,7 @@ namespace Vocaluxe.Menu.SingNotes public CNote[] Notes { - get - { - return _Notes.ToArray(); - } + get { return _Notes.ToArray(); } } public CNote FirstNote @@ -418,15 +410,11 @@ namespace Vocaluxe.Menu.SingNotes get { int Min = int.MaxValue; + int Max = int.MinValue; foreach (CNote note in _Notes) { if (note.Tone < Min) Min = note.Tone; - } - - int Max = int.MinValue; - foreach (CNote note in _Notes) - { if (note.Tone > Max) Max = note.Tone; } @@ -452,21 +440,49 @@ namespace Vocaluxe.Menu.SingNotes return _PerfectLine; } - public void AddNote(CNote Note) + public int FindPreviousNote(int Beat) { - _Notes.Add(Note); - updateMinMaxBeat(Note); - } - - public bool InsertNote(CNote Note, int Index) - { - if (_Notes.Count >= Index) + //If no notes -> No previous note + if (_Notes.Count == 0) + return -1; + int start = 0; + int end = _Notes.Count - 1; + //Ensure that start.StartBeat<=Beat && end.StartBeat>Beat + if (_Notes[0].StartBeat > Beat) + return -1; + if (_Notes[end].StartBeat <= Beat) + return end; + //Binary search + while (end - start > 1) { - _Notes.Insert(Index, Note); - updateMinMaxBeat(Note); - return true; + int mid = (start + end) / 2; + if (_Notes[mid].StartBeat <= Beat) + start = mid; + else + end = mid; } - return false; + return start; + } + + public bool AddNote(CNote Note) + { + if (_Notes.Count == 0) + _Notes.Add(Note); + else + { + int insPos = FindPreviousNote(Note.StartBeat); + //Flamefire: May be a performance hit as notes are also used for sung notes + //But for song loading this might be very helpful! + //Check for overlapping notes + /*if (insPos >= 0 && _Notes[insPos].EndBeat > Note.StartBeat) + return false; + if (insPos < _Notes.Count - 1 && _Notes[insPos+1].StartBeat > Note.EndBeat) + return false; + * */ + _Notes.Insert(insPos + 1, Note); + } + updateMinMaxBeat(Note); + return true; } public bool DeleteNote(int Index) @@ -474,7 +490,8 @@ namespace Vocaluxe.Menu.SingNotes if (_Notes.Count > Index) { _Notes.RemoveAt(Index); - updateMinMaxBeat(); + if (Index == 0 || Index == _Notes.Count - 1) + updateMinMaxBeat(); return true; } return false; @@ -485,9 +502,7 @@ namespace Vocaluxe.Menu.SingNotes if (_Notes.Count > Index) { _Notes.RemoveAt(Index); - _Notes.Insert(Index, Note); - updateMinMaxBeat(); - return true; + return AddNote(Note); } return false; } @@ -497,7 +512,7 @@ namespace Vocaluxe.Menu.SingNotes if (_Notes.Count > 0) { _Notes[_Notes.Count - 1].Duration++; - updateMinMaxBeat(); + _MaxBeat++; } return false; } @@ -505,8 +520,7 @@ namespace Vocaluxe.Menu.SingNotes public void DeleteAllNotes() { _Notes.Clear(); - _MinBeat = int.MaxValue; - _MaxBeat = int.MinValue; + updateMinMaxBeat(); } public void SetMedley(int StartBeat, int EndBeat) @@ -535,11 +549,15 @@ namespace Vocaluxe.Menu.SingNotes private void updateMinMaxBeat() { - _MinBeat = int.MaxValue; - _MaxBeat = int.MinValue; - foreach (CNote note in _Notes) + if (_Notes.Count > 0) { - updateMinMaxBeat(note); + _MinBeat = _Notes[0].StartBeat; + _MaxBeat = _Notes[_Notes.Count - 1].EndBeat; + } + else + { + _MinBeat = int.MaxValue; + _MaxBeat = int.MinValue; } } @@ -631,28 +649,40 @@ namespace Vocaluxe.Menu.SingNotes } #region Methods - public void AddLine(CLine Line) + //Find last line with StartBeat<=Beat + public int FindPreviousLine(int Beat) { - AddLine(Line, false); - } - public void AddLine(CLine Line, bool updateTimings) - { - _Lines.Add(Line); - if (updateTimings) + //If no line -> No previous line + if (_Lines.Count == 0) + return -1; + int start = 0; + int end = _Lines.Count - 1; + //Ensure that start.StartBeat<=Beat && end.StartBeat>Beat + if (_Lines[0].StartBeat > Beat) + return -1; + if (_Lines[end].StartBeat <= Beat) + return end; + //Binary search + while (end - start > 1) { - UpdateTimings(); + int mid = (start + end) / 2; + if (_Lines[mid].StartBeat <= Beat) + start = mid; + else + end = mid; } + return start; } - public bool InsertLine(CLine Line, int Index) + public void AddLine(CLine Line) { - if (_Lines.Count >= Index) + if (_Lines.Count == 0) + _Lines.Add(Line); + else { - _Lines.Insert(Index, Line); - UpdateTimings(); - return true; + int insPos = FindPreviousLine(Line.StartBeat); + _Lines.Insert(insPos + 1, Line); } - return false; } public bool DeleteLine(int Index) @@ -671,34 +701,38 @@ namespace Vocaluxe.Menu.SingNotes _Lines.Clear(); } - public bool AddNote(CNote Note, int LineIndex, bool updateTimings) + public bool AddNote(CNote Note, bool updateTimings = false) { - if (_Lines.Count > LineIndex) + int LineIndex = FindPreviousLine(Note.StartBeat); + if (LineIndex < 0) + { + //Note is before ALL lines + CLine Line = new CLine(); + Line.StartBeat = Note.StartBeat; + Line.AddNote(Note); + _Lines.Insert(0, Line); + } + else + { + if (!_Lines[LineIndex].AddNote(Note)) + return false; + } + if (updateTimings) + UpdateTimings(); + return true; + } + + public bool InsertNote(CNote Note, int LineIndex, bool updateTimings = false) + { + if (_Lines.Count > LineIndex && _Lines[LineIndex].StartBeat <= Note.StartBeat) { _Lines[LineIndex].AddNote(Note); if (updateTimings) - { UpdateTimings(); - } return true; } return false; } - public bool AddNote(CNote Note, int LineIndex) - { - return AddNote(Note, LineIndex, true); - } - - public bool InsertNote(CNote Note, int LineIndex, int NoteIndex) - { - if (_Lines.Count > LineIndex) - { - bool res = _Lines[LineIndex].InsertNote(Note, NoteIndex); - UpdateTimings(); - return res; - } - return false; - } public void UpdateTimings() { CNote LastNote, FirstNote; @@ -706,7 +740,7 @@ namespace Vocaluxe.Menu.SingNotes if (_Lines.Count > 0) { - _Lines[0].StartBeat = -10000; + _Lines[0].StartBeat = -10000; } for (int i = 1; i < _Lines.Count; i++) @@ -719,7 +753,6 @@ namespace Vocaluxe.Menu.SingNotes min = LastNote.EndBeat; max = FirstNote.StartBeat; - s = 0; switch (max - min) { case 0: diff --git a/VocaluxeLib/Menu/SongMenu/CSong.cs b/VocaluxeLib/Menu/SongMenu/CSong.cs index 785a62bf..c8832dfd 100644 --- a/VocaluxeLib/Menu/SongMenu/CSong.cs +++ b/VocaluxeLib/Menu/SongMenu/CSong.cs @@ -31,8 +31,38 @@ namespace Vocaluxe.Menu.SongMenu public class CCategory { public string Name = String.Empty; - public STexture CoverTextureSmall = new STexture(); - public STexture CoverTextureBig = new STexture(); + private STexture _CoverTextureSmall = new STexture(); + private STexture _CoverTextureBig = new STexture(); + private bool _CoverBigLoaded = false; + + public STexture CoverTextureSmall + { + get { return _CoverTextureSmall; } + + set + { + _CoverTextureSmall = value; + } + } + + public STexture CoverTextureBig + { + get + { + if (_CoverBigLoaded) + return _CoverTextureBig; + else + return _CoverTextureSmall; + } + set + { + if (value.index != -1) + { + _CoverTextureBig = value; + _CoverBigLoaded = true; + } + } + } public CCategory(string name, STexture CoverSmall, STexture CoverBig) { @@ -69,7 +99,8 @@ namespace Vocaluxe.Menu.SongMenu public class CSong { - private bool _CoverLoaded = false; + private bool _CoverSmallLoaded = false; + private bool _CoverBigLoaded = false; private bool _NotesLoaded = false; private STexture _CoverTextureSmall = new STexture(-1); private STexture _CoverTextureBig = new STexture(-1); @@ -96,33 +127,24 @@ namespace Vocaluxe.Menu.SongMenu public bool CoverSmallLoaded { - get { return _CoverLoaded; } + get { return _CoverSmallLoaded; } + } + public bool CoverBigLoaded + { + get { return _CoverBigLoaded; } } public bool NotesLoaded { get { return _NotesLoaded; } } - public bool CoverBigLoaded = false; - public STexture CoverTextureSmall { get { - if (!_CoverLoaded) + if (!_CoverSmallLoaded) { - if (!_NotesLoaded) - this.ReadNotes(); - - if (this.CoverFileName != String.Empty) - { - if (!CBase.DataBase.GetCover(Path.Combine(this.Folder, this.CoverFileName), ref _CoverTextureSmall, CBase.Config.GetCoverSize())) - _CoverTextureSmall = CBase.Cover.GetNoCover(); - } - else - _CoverTextureSmall = CBase.Cover.GetNoCover(); - - _CoverLoaded = true; + LoadSmallCover(); } return _CoverTextureSmall; } @@ -130,14 +152,23 @@ namespace Vocaluxe.Menu.SongMenu set { _CoverTextureSmall = value; - _CoverLoaded = true; + _CoverSmallLoaded = true; } } public STexture CoverTextureBig { - get { return _CoverTextureBig; } - set { _CoverTextureBig = value; } + get + { + if (_CoverBigLoaded) + return _CoverTextureBig; + else + return _CoverTextureSmall; + } + set { + _CoverTextureBig = value; + _CoverBigLoaded = true; + } } public string Title = String.Empty; @@ -193,10 +224,19 @@ namespace Vocaluxe.Menu.SongMenu } } - public CSong() + //No point creating a song without a text file --> Use factory method LoadSong + private CSong() { } + public static CSong LoadSong(string FilePath) + { + CSong Song = new CSong(); + if (Song.ReadHeader(FilePath)) + return Song; + return null; + } + public CSong(CSong song) { this._CoverTextureSmall = song._CoverTextureSmall; @@ -228,8 +268,8 @@ namespace Vocaluxe.Menu.SongMenu this.VideoFileName = song.VideoFileName; this.VideoAspect = song.VideoAspect; - this._CoverLoaded = song._CoverLoaded; - this.CoverBigLoaded = song.CoverBigLoaded; + this._CoverSmallLoaded = song._CoverSmallLoaded; + this._CoverBigLoaded = song._CoverBigLoaded; this._NotesLoaded = song._NotesLoaded; this.Artist = song.Artist; @@ -286,18 +326,7 @@ namespace Vocaluxe.Menu.SongMenu return Path.Combine(Folder, VideoFileName); } - public bool ReadTXTSong(string FilePath) - { - if (!File.Exists(FilePath)) - return false; - - if (!ReadTXTHeader(FilePath)) - return false; - - return true; - } - - public bool ReadTXTHeader(string FilePath) + public bool ReadHeader(string FilePath) { if (!File.Exists(FilePath)) return false; @@ -314,17 +343,11 @@ namespace Vocaluxe.Menu.SongMenu { this.FolderName = this.Folder.Substring(folder.Length + 1, this.Folder.Length - folder.Length - 1); - string str = this.FolderName; - try - { - str = this.FolderName.Substring(0, this.FolderName.IndexOf("\\")); - } - catch (Exception) - { - - } - this.FolderName = str; + int pos = this.FolderName.IndexOf("\\"); + if (pos >= 0) + this.FolderName = this.FolderName.Substring(0, pos); } + break; } } @@ -337,16 +360,19 @@ namespace Vocaluxe.Menu.SongMenu sr = new StreamReader(FilePath, Encoding.Default, true); - string line = sr.ReadLine(); - if (line.Length == 0) - return false; + string line; int pos = -1; string Identifier = String.Empty; string Value = String.Empty; - while ((line.Length == 0) || (line[0].ToString().Equals("#"))) + while (!sr.EndOfStream) { + line = sr.ReadLine(); + if (line.Length == 0) + continue; + if (!line[0].ToString().Equals("#")) break; + pos = line.IndexOf(":"); if (pos > 0) @@ -362,26 +388,22 @@ namespace Vocaluxe.Menu.SongMenu this.Encoding = CEncoding.GetEncoding(Value); sr = new StreamReader(FilePath, this.Encoding); Identifier = String.Empty; - line = sr.ReadLine(); - while ((line.Length == 0) || (line[0].ToString().Equals("#")) && (Identifier != "ENCODING")) + //Scip everything till encoding + while (!sr.EndOfStream) { + line = sr.ReadLine(); + if (line.Length == 0) + continue; + if(!line[0].ToString().Equals("#")) break; + pos = line.IndexOf(":"); if (pos > 0) { Identifier = line.Substring(1, pos - 1).Trim().ToUpper(); - Value = line.Substring(pos + 1, line.Length - pos - 1).Trim(); - } - - if (!sr.EndOfStream) if (Identifier == "ENCODING") break; - else - line = sr.ReadLine(); - else - { - return false; } } break; @@ -482,7 +504,6 @@ namespace Vocaluxe.Menu.SongMenu this.VideoFileName = Value; else CBase.Log.LogError("Can't find video file: " + Path.Combine(this.Folder, Value)); - break; case "VIDEOGAP": CHelper.TryParse(Value, out this.VideoGap); @@ -520,21 +541,18 @@ namespace Vocaluxe.Menu.SongMenu if (Value.ToUpper() == "YES" && Value.ToUpper() != "NO") this.Relative = EOffOn.TR_CONFIG_ON; break; - default: - ; - break; } } } - - if (!sr.EndOfStream) - line = sr.ReadLine(); - else - { - return false; - } } //end of while + if (sr.EndOfStream) + { + //No other data then header + CBase.Log.LogError("Lyrics/Notes missing: " + FilePath); + return false; + } + if ((HeaderFlags & EHeaderFlags.Title) == 0) { CBase.Log.LogError("Title tag missing: " + FilePath); @@ -616,8 +634,12 @@ namespace Vocaluxe.Menu.SongMenu { return ReadNotes(Path.Combine(this.Folder, this.FileName)); } - public bool ReadNotes(string FilePath) + public bool ReadNotes(string FilePath, bool forceReload=false) { + //Skip loading if already done and no reload is forced + if (_NotesLoaded && !forceReload) + return true; + if (!File.Exists(FilePath)) { CBase.Log.LogError("Error loading song. The file does not exist: " + FilePath); @@ -645,119 +667,131 @@ namespace Vocaluxe.Menu.SongMenu this.Notes.Reset(); //Search for Note Beginning - do + while(!sr.EndOfStream) { line = sr.ReadLine(); FileLineNo++; - if (sr.EndOfStream || (line.Length == 0)) + TempC = (char)sr.Peek(); + if ((TempC == '#') || (TempC == '\r') || (TempC == '\n')) + continue; + if ((TempC == ':') || (TempC == 'F') || (TempC == '*') || (TempC == 'P')) { - CBase.Log.LogError("Error loading song. Line No.: " + FileLineNo.ToString() + ". The file is empty or it starts with an empty line: " + FilePath); - return false; + TempC = (char)sr.Read(); + break; } - - TempC = (char)sr.Read(); - } while ((TempC.CompareTo(':') != 0) && (TempC.CompareTo('F') != 0) && (TempC.CompareTo('*') != 0) && (TempC.CompareTo('P') != 0)); + } - while (!sr.EndOfStream && (TempC.CompareTo('E') != 0)) + if (sr.EndOfStream) { - FileLineNo++; - if (TempC.CompareTo('P') == 0) + CBase.Log.LogError("Error loading song. Line No.: " + FileLineNo.ToString() + ". No lyrics/notes found: " + FilePath); + return false; + } + + do + { + + char chr; + switch (TempC) { - char chr; - while ((chr = (char)sr.Read()) == ' '){ } + case 'P': + while ((chr = (char)sr.Read()) == ' ') { } - int.TryParse(chr.ToString(), out Param1); - if (Param1 == 1) - Player = 0; - else if (Param1 == 2) - Player = 1; - else if (Param1 == 3) - Player = 2; - else - { - CBase.Log.LogError("Error loading song. Line No.: " + FileLineNo.ToString() + ". Wrong or missing number after \"P\": " + FilePath); - return false; - } - } + int.TryParse(chr.ToString(), out Param1); + if (Param1 == 1) + Player = 0; + else if (Param1 == 2) + Player = 1; + else if (Param1 == 3) + Player = 2; + else + { + CBase.Log.LogError("Error loading song. Line No.: " + FileLineNo.ToString() + ". Wrong or missing number after \"P\": " + FilePath); + return false; + } + sr.ReadLine(); + break; + case ':': + case '*': + case 'F': + sr.Read(); + Param1 = CHelper.TryReadInt(sr); - if ((TempC.CompareTo(':') == 0) || (TempC.CompareTo('*') == 0) || (TempC.CompareTo('F') == 0)) - { - char chr = (char)sr.Read(); - Param1 = CHelper.TryReadInt(sr); - - chr = (char)sr.Read(); - Param2 = CHelper.TryReadInt(sr); - - chr = (char)sr.Read(); - Param3 = CHelper.TryReadInt(sr); - - chr = (char)sr.Read(); - ParamS = sr.ReadLine(); - - ENoteType NoteType; - - if (TempC.CompareTo('*') == 0) - NoteType = ENoteType.Golden; - else if (TempC.CompareTo('F') == 0) - NoteType = ENoteType.Freestyle; - else - NoteType = ENoteType.Normal; - - if (this.Relative == EOffOn.TR_CONFIG_ON) - Param1 += currentPos; - - if (Player != 2) - // one singer - ParseNote(Player, NoteType, Param1, Param2, Param3, ParamS); - else - { - // both singer - ParseNote(0, NoteType, Param1, Param2, Param3, ParamS); - ParseNote(1, NoteType, Param1, Param2, Param3, ParamS); - } - isNewSentence = false; - } - - if (TempC.CompareTo('-') == 0) - { - if (isNewSentence) - { - CBase.Log.LogError("Error loading song. Line No.: " + FileLineNo.ToString() + ". Double sentence break: " + FilePath); - return false; - } - - char chr = (char)sr.Read(); - Param1 = CHelper.TryReadInt(sr); - - if (this.Relative == EOffOn.TR_CONFIG_ON) - { - Param1 += currentPos; - chr = (char)sr.Read(); + sr.Read(); Param2 = CHelper.TryReadInt(sr); - currentPos += Param2; - } - - if(Player != 2) - // one singer - NewSentence(Player, Param1); - else - { - // both singer - NewSentence(0, Param1); - NewSentence(1, Param1); - } - - isNewSentence = true; - } + sr.Read(); + Param3 = CHelper.TryReadInt(sr); + + sr.Read(); + ParamS = sr.ReadLine(); + + ENoteType NoteType; + + if (TempC.CompareTo('*') == 0) + NoteType = ENoteType.Golden; + else if (TempC.CompareTo('F') == 0) + NoteType = ENoteType.Freestyle; + else + NoteType = ENoteType.Normal; + + if (this.Relative == EOffOn.TR_CONFIG_ON) + Param1 += currentPos; + + if (Player != 2) + // one singer + ParseNote(Player, NoteType, Param1, Param2, Param3, ParamS); + else + { + // both singer + ParseNote(0, NoteType, Param1, Param2, Param3, ParamS); + ParseNote(1, NoteType, Param1, Param2, Param3, ParamS); + } + isNewSentence = false; + break; + case '-': + if (isNewSentence) + { + CBase.Log.LogError("Error loading song. Line No.: " + FileLineNo.ToString() + ". Double sentence break: " + FilePath); + return false; + } + sr.Read(); + Param1 = CHelper.TryReadInt(sr); + + if (this.Relative == EOffOn.TR_CONFIG_ON) + { + Param1 += currentPos; + sr.Read(); + Param2 = CHelper.TryReadInt(sr); + currentPos += Param2; + } + + if (Player != 2) + // one singer + NewSentence(Player, Param1); + else + { + // both singer + NewSentence(0, Param1); + NewSentence(1, Param1); + } + + isNewSentence = true; + sr.ReadLine(); + break; + default: + CBase.Log.LogError("Error loading song. Line No.: " + FileLineNo.ToString() + ". Unexpected or missing character (" + TempC + "): " + FilePath); + return false; + } int c = 0; do { c = sr.Read(); - TempC = (char)c; - } while ((TempC.CompareTo('E') != 0) && !sr.EndOfStream && (c == 19 || c == 16 || c == 13 || c==10)); - } + } while (!sr.EndOfStream && (c == 19 || c == 16 || c == 13 || c == 10)); + TempC = (char)c; + FileLineNo++; + }while(!sr.EndOfStream && (TempC != 'E')); + foreach(CLines lines in this.Notes.Lines) { lines.UpdateTimings(); @@ -776,21 +810,11 @@ namespace Vocaluxe.Menu.SongMenu return true; } - private void ParseNote(int Player, ENoteType NoteType, int Start, int Length, int Tone, string Text) + private bool ParseNote(int Player, ENoteType NoteType, int Start, int Length, int Tone, string Text) { CNote note = new CNote(Start, Length, Tone, Text, NoteType); CLines lines = this.Notes.GetLines(Player); - - if (lines.LineCount == 0) - { - CLine line = new CLine(); - line.AddNote(note); - lines.AddLine(line, false); - } - else - { - lines.AddNote(note, lines.LineCount - 1, false); - } + return lines.AddNote(note); } private void NewSentence(int Player, int Start) @@ -798,14 +822,22 @@ namespace Vocaluxe.Menu.SongMenu CLines lines = Notes.GetLines(Player); CLine line = new CLine(); line.StartBeat = Start; - if (lines.LineCount == 0) + lines.AddLine(line); + } + + public void LoadSmallCover() + { + if (_CoverSmallLoaded) + return; + if (this.CoverFileName != String.Empty) { - lines.AddLine(line); + if (!CBase.DataBase.GetCover(Path.Combine(this.Folder, this.CoverFileName), ref _CoverTextureSmall, CBase.Config.GetCoverSize())) + _CoverTextureSmall = CBase.Cover.GetNoCover(); } else - { - lines.AddLine(line); - } + _CoverTextureSmall = CBase.Cover.GetNoCover(); + + _CoverSmallLoaded = true; } private void CheckFiles() @@ -860,24 +892,12 @@ namespace Vocaluxe.Menu.SongMenu public int length; } - private void FindRefrain() + private List GetSeries() { - if (this.IsDuet) - { - this.Medley.Source = EMedleySource.None; - return; - } - - if (this.Medley.Source == EMedleySource.Tag) - return; - - if (!this.CalculateMedley) - return; - CLines lines = this.Notes.GetLines(0); if (lines.LineCount == 0) - return; + return null; // build sentences list List sentences = new List(); @@ -920,6 +940,26 @@ namespace Vocaluxe.Menu.SongMenu } } } + return series; + } + + private void FindRefrain() + { + if (this.IsDuet) + { + this.Medley.Source = EMedleySource.None; + return; + } + + if (this.Medley.Source == EMedleySource.Tag) + return; + + if (!this.CalculateMedley) + return; + + List series = GetSeries(); + if (series == null) + return; // search for longest series int longest = 0; @@ -929,6 +969,8 @@ namespace Vocaluxe.Menu.SongMenu longest = i; } + CLines lines = this.Notes.GetLines(0); + // set medley vars if (series.Count > 0 && series[longest].length > CBase.Settings.GetMedleyMinSeriesLength()) { @@ -971,52 +1013,11 @@ namespace Vocaluxe.Menu.SongMenu } private void FindShortEnd(){ - CLines lines = this.Notes.GetLines(0); - - if (lines.LineCount == 0) + List series = GetSeries(); + if (series == null) return; - // build sentences list - List sentences = new List(); - foreach (CLine line in lines.Line) - { - if (line.Points != 0) - sentences.Add(line.Lyrics); - else - sentences.Add(String.Empty); - } - - // find equal sentences series - List series = new List(); - for (int i = 0; i < lines.LineCount - 1; i++) - { - for (int j = i + 1; j < lines.LineCount; j++) - { - if (sentences[i] == sentences[j] && sentences[i] != String.Empty) - { - Series tempSeries = new Series(); - tempSeries.start = i; - tempSeries.end = i; - - int max = 0; - if (j + j - i - 1 > lines.LineCount - 1) - max = lines.LineCount - 1 - j; - else - max = j - i - 1; - - for (int k = 1; k <= max; k++) - { - if (sentences[i + k] == sentences[j + k] && sentences[i + k] != String.Empty) - tempSeries.end = i + k; - else - break; - } - - tempSeries.length = tempSeries.end - tempSeries.start + 1; - series.Add(tempSeries); - } - } - } + CLines lines = this.Notes.GetLines(0); //Calculate length of singing int stop = (lines.Line[lines.Line.Length - 1].LastNoteBeat - lines.Line[0].FirstNoteBeat) / 2 + lines.Line[0].StartBeat; diff --git a/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs b/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs index 4caccbd7..89a26d3c 100644 --- a/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs +++ b/VocaluxeLib/Menu/SongMenu/CSongMenuTileBoard.cs @@ -132,7 +132,7 @@ namespace Vocaluxe.Menu.SongMenu int actcat = _PreviewSelected; if ((CBase.Songs.GetNumCategories() > 0) && (actcat < 0)) { - _CoverBig.Texture = CBase.Songs.GetCategory(0).CoverTextureSmall; + _CoverBig.Texture = CBase.Songs.GetCategory(0).CoverTextureBig; _Artist.Text = CBase.Songs.GetCategory(0).Name; _Title.Text = String.Empty; _SongLength.Text = String.Empty; @@ -456,7 +456,7 @@ namespace Vocaluxe.Menu.SongMenu { CSong song = CBase.Songs.GetVisibleSong(actsong); - _CoverBig.Texture = song.CoverTextureSmall; + _CoverBig.Texture = song.CoverTextureBig; _Artist.Text = song.Artist; _Title.Text = song.Title; _DuetIcon.Visible = song.IsDuet; @@ -479,7 +479,7 @@ namespace Vocaluxe.Menu.SongMenu int actcat = _PreviewSelected; if ((CBase.Songs.GetNumCategories() > actcat) && (actcat >= 0)) { - _CoverBig.Texture = CBase.Songs.GetCategory(actcat).CoverTextureSmall; + _CoverBig.Texture = CBase.Songs.GetCategory(actcat).CoverTextureBig; _Artist.Text = CBase.Songs.GetCategory(actcat).Name; int num = CBase.Songs.NumSongsInCategory(actcat); @@ -498,21 +498,21 @@ namespace Vocaluxe.Menu.SongMenu _TextBG.Draw(); - _CoverBig.Draw(1f, EAspect.Crop); - if (_vidtex.color.A < 1) - _CoverBig.Draw(1f, EAspect.Crop); if (_vidtex.index != -1 && _Video != -1) { + if (_vidtex.color.A < 1) + _CoverBig.Draw(1f, EAspect.Crop); RectangleF bounds = new RectangleF(_CoverBig.Rect.X, _CoverBig.Rect.Y, _CoverBig.Rect.W, _CoverBig.Rect.H); RectangleF rect = new RectangleF(0f, 0f, _vidtex.width, _vidtex.height); CHelper.SetRect(bounds, ref rect, rect.Width / rect.Height, EAspect.Crop); + SRectF vidRect = new SRectF(rect.X, rect.Y, rect.Width, rect.Height, _CoverBig.Rect.Z); + SRectF vidRectBounds = new SRectF(bounds.X, bounds.Y, bounds.Width, bounds.Height, 0f); - CBase.Drawing.DrawTexture(_vidtex, new SRectF(rect.X, rect.Y, rect.Width, rect.Height, _CoverBig.Rect.Z), - _vidtex.color, new SRectF(bounds.X, bounds.Y, bounds.Width, bounds.Height, 0f), false); - CBase.Drawing.DrawTextureReflection(_vidtex, new SRectF(rect.X, rect.Y, rect.Width, rect.Height, _CoverBig.Rect.Z), - _vidtex.color, new SRectF(bounds.X, bounds.Y, bounds.Width, bounds.Height, 0f), _CoverBig.ReflectionSpace, _CoverBig.ReflectionHeight); - } + CBase.Drawing.DrawTexture(_vidtex, vidRect, _vidtex.color, vidRectBounds, false); + CBase.Drawing.DrawTextureReflection(_vidtex, vidRect, _vidtex.color, vidRectBounds, _CoverBig.ReflectionSpace, _CoverBig.ReflectionHeight); + }else + _CoverBig.Draw(1f, EAspect.Crop);