private void _CalcMedley() { if (IsDuet) { Medley.Source = EDataSource.None; return; } if (!_CalculateMedley || Medley.Source != EDataSource.None) { return; } List <SSeries> series = _GetSeries(); if (series == null) { return; } // search for longest series int longest = 0; for (int i = 0; i < series.Count; i++) { if (series[i].Length > series[longest].Length) { longest = i; } } CVoice voice = Notes.GetVoice(0); // set medley vars if (series.Count > 0 && series[longest].Length > CBase.Settings.GetMedleyMinSeriesLength()) { Medley.StartBeat = voice.Lines[series[longest].Start].FirstNoteBeat; Medley.EndBeat = voice.Lines[series[longest].End].LastNoteBeat; bool foundEnd = CBase.Game.GetTimeFromBeats(Medley.EndBeat, BPM) - CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) < CBase.Settings.GetMedleyMinDuration(); // set end if duration < MedleyMinDuration if (!foundEnd) { for (int i = series[longest].End + 1; i < voice.NumLines - 1; i++) { if (CBase.Game.GetTimeFromBeats(voice.Lines[i].LastNoteBeat, BPM) - CBase.Game.GetTimeFromBeats(Medley.StartBeat, BPM) < CBase.Settings.GetMedleyMinDuration()) { foundEnd = true; Medley.EndBeat = voice.Lines[i].LastNoteBeat; break; } } } if (foundEnd) { Medley.Source = EDataSource.Calculated; Medley.FadeInTime = CBase.Settings.GetDefaultMedleyFadeInTime(); Medley.FadeOutTime = CBase.Settings.GetDefaultMedleyFadeOutTime(); } } }
private bool _AddNote(int player, CSongNote note) { CVoice voice = _Song.Notes.GetVoice(player, true); return(voice.AddNote(note, false)); }
private bool _NewSentence(int player, int start) { CVoice voice = _Song.Notes.GetVoice(player, true); return(voice.AddLine(start)); }
/// <summary> /// Read notes. First try to read notes normally (assume standard)<br /> /// If there are more than _MaxZeroNoteCt with length < 1, try to read notes adding 1 to length<br /> /// Then if there are more than _MaxOverlapNoteCt fallback to first version ignoring notes with length < 1 /// </summary> /// <param name="forceReload"></param> /// <returns></returns> public bool ReadNotes(bool forceReload = false) { //Skip loading if already done and no reload is forced if (_Song.NotesLoaded && !forceReload) { return(true); } string filePath = Path.Combine(_Song.Folder, _Song.FileName); if (!File.Exists(filePath)) { CLog.CSongLog.Error("[{SongFileName}] The file songfile does not exist", CLog.Params(_Song.FileName)); return(false); } int currentBeat = 0; //Used for relative songs CSongNote lastNote = null; //Holds last parsed note. Get's reset on player change bool endFound = false; // True if end tag was found int player = 1; _LineNr = 0; char[] trimChars = { ' ', ':' }; char[] splitChars = { ' ' }; var changesMade = new CAutoChanges(); StreamReader sr = null; try { sr = new StreamReader(filePath, _Song.Encoding, true); _Song.Notes.Reset(); //Search for Note Beginning while (!sr.EndOfStream && !endFound) { string line = sr.ReadLine(); _LineNr++; if (String.IsNullOrEmpty(line)) { continue; } char tag = line[0]; //Remove tag and potential space line = (line.Length >= 2 && line[1] == ' ') ? line.Substring(2) : line.Substring(1); int beat, length; switch (tag) { case '#': continue; case 'E': endFound = true; break; case 'P': line = line.Trim(trimChars); if (!int.TryParse(line, out player)) { CLog.CSongLog.Error("[{SongFileName}] Wrong or missing number after \"P\" (in line {LineNr})", CLog.Params(_Song.FileName, _LineNr)); return(false); } currentBeat = 0; lastNote = null; break; case ':': case '*': case 'F': string[] noteData = line.Split(splitChars, 4); if (noteData.Length < 4) { if (noteData.Length == 3) { CLog.CSongLog.Warning("[{SongFileName}] Ignored note without text (in line {LineNr})", CLog.Params(_Song.FileName, _LineNr)); changesMade.NoTextNoteCt++; continue; } CLog.CSongLog.Error("[{SongFileName}] Invalid note found (in line {LineNr}): {noteData}", CLog.Params(_Song.FileName, _LineNr, noteData)); sr.Dispose(); return(false); } int tone; if (!int.TryParse(noteData[0], out beat) || !int.TryParse(noteData[1], out length) || !int.TryParse(noteData[2], out tone)) { CLog.CSongLog.Error("[{SongFileName}] Invalid note found (non-numeric values) (in line {LineNr}): {noteData}", CLog.Params(_Song.FileName, _LineNr, noteData)); sr.Dispose(); return(false); } string text = noteData[3].TrimMultipleWs(); if (text == "") { CLog.CSongLog.Warning("[{SongFileName}] Ignored note without text (in line {LineNr})", CLog.Params(_Song.FileName, _LineNr)); changesMade.NoTextNoteCt++; continue; } if (_CurrentReadMode == ENoteReadMode.ZeroBased) { length++; } if (length < 1) { changesMade.ZeroLengthNoteCt++; if (_CurrentReadMode == ENoteReadMode.Normal && changesMade.ZeroLengthNoteCt > _MaxZeroNoteCt && changesMade.OverlapNoteCt <= _MaxOverlapNoteCt) { CLog.CSongLog.Warning("[{SongFileName}] Found more than {MaxZeroNoteCt} notes with length < 1. Trying alternative read mode.", CLog.Params(_Song.FileName, _MaxZeroNoteCt)); _CurrentReadMode = ENoteReadMode.ZeroBased; sr.Dispose(); return(ReadNotes(true)); } CLog.CSongLog.Warning("[{SongFileName}] Ignored note with length < 1 (in line {LineNr})", CLog.Params(_Song.FileName, _LineNr)); } else { ENoteType noteType; if (tag.Equals('*')) { noteType = ENoteType.Golden; } else if (tag.Equals('F')) { noteType = ENoteType.Freestyle; } else { noteType = ENoteType.Normal; } if (_Song.Relative) { beat += currentBeat; } bool ignored = false; foreach (int curPlayer in player.GetSetBits()) { //Create the note here as we want independent instances in the lines. Otherwhise we can't modify them later lastNote = new CSongNote(beat, length, tone, text, noteType); if (!_AddNote(curPlayer, lastNote)) { if (!ignored) { ignored = true; changesMade.OverlapNoteCt++; if (changesMade.OverlapNoteCt > _MaxOverlapNoteCt && _CurrentReadMode == ENoteReadMode.ZeroBased) { CLog.CSongLog.Warning("[{SongFileName}] Found more than {MaxOverlapNoteCt} overlapping notes. Using standard mode.", CLog.Params(_Song.FileName, _MaxOverlapNoteCt)); _CurrentReadMode = ENoteReadMode.OneBased; sr.Dispose(); return(ReadNotes(true)); } } CLog.CSongLog.Warning("[{SongFileName}] Ignored note for player {CurrentPlayerNumber} because it overlaps with other note (in line {LineNr})", CLog.Params(_Song.FileName, (curPlayer + 1), _LineNr)); } } } break; case '-': string[] lineBreakData = line.Split(splitChars); if (lineBreakData.Length < 1) { CLog.CSongLog.Error("[{SongFileName}] Invalid line break found (No beat) (in line {LineNr}): {LineBreakData}", CLog.Params(_Song.FileName, _LineNr, lineBreakData)); sr.Dispose(); return(false); } if (!int.TryParse(lineBreakData[0], out beat)) { CLog.CSongLog.Error("[{SongFileName}] Invalid line break found (Non-numeric value) (in line {LineNr}): {LineBreakData}", CLog.Params(_Song.FileName, _LineNr, lineBreakData)); sr.Dispose(); return(false); } if (_Song.Relative) { beat += currentBeat; if (lineBreakData.Length < 2 || !int.TryParse(lineBreakData[1], out length)) { CLog.CSongLog.Warning("[{SongFileName}] Missing line break length (in line {LineNr}):{LineBreakData}", CLog.Params(_Song.FileName, _LineNr, lineBreakData)); changesMade.NoLengthBreakCt++; currentBeat = beat; } else { currentBeat += length; } } if (lastNote != null && beat <= lastNote.EndBeat) { CLog.CSongLog.Warning("[{SongFileName}] Line break is before previous note end. Adjusted. (in line {LineNr})", CLog.Params(_Song.FileName, _LineNr)); changesMade.AjustedBreakCt++; if (_Song.Relative) { currentBeat += lastNote.EndBeat - beat + 1; } beat = lastNote.EndBeat + 1; } if (beat < 1) { CLog.CSongLog.Warning("[{SongFileName}] Ignored line break because position is < 1 (in line {LineNr})", CLog.Params(_Song.FileName, _LineNr)); changesMade.InvalidPosBreakCt++; } else { foreach (int curPlayer in player.GetSetBits()) { if (!_NewSentence(curPlayer, beat)) { CLog.CSongLog.Warning("[{SongFileName}] Ignored line break for player {CurPlayerNr} (Overlapping or duplicate) (in line {LineNr})", CLog.Params(_Song.FileName, (curPlayer + 1), _LineNr)); } } } break; default: CLog.CSongLog.Error("[{SongFileName}] Unexpected or missing character ({Tag})", CLog.Params(_Song.FileName, tag)); return(false); } } for (int i = 0; i < _Song.Notes.VoiceCount; i++) { CVoice voice = _Song.Notes.GetVoice(i); int emptyLines = voice.RemoveEmptyLines(); if (emptyLines > 0) { CLog.CSongLog.Warning("[{SongFileName}] Removed {NumEmptyLines} empty lines from P .This often indicates a problem with the line breaks in the file", CLog.Params(_Song.FileName, emptyLines)); } voice.UpdateTimings(); } } catch (Exception e) { CLog.CSongLog.Error(e, "[{SongFileName}] An unhandled exception occured: {ExceptionMessage}", CLog.Params(_Song.FileName, e.Message)); if (sr != null) { sr.Dispose(); } return(false); } sr.Dispose(); try { _Song._CalcMedley(); _Song._CheckPreview(); _Song._FindShortEnd(); _Song.NotesLoaded = true; if (_Song.IsDuet) { _Song._CheckDuet(); } } catch (Exception e) { CLog.CSongLog.Error(e, "[{SongFileName}] An unhandled exception occured: {ExceptionMessage}", CLog.Params(_Song.FileName, e.Message)); return(false); } if (changesMade.IsModified) { CLog.Warning("Automatic changes have been made to {FilePath} Please check result!\r\n{ChangesMade}", CLog.Params(filePath, changesMade)); if (CBase.Config.GetSaveModifiedSongs() == EOffOn.TR_CONFIG_ON) { string name = Path.GetFileNameWithoutExtension(_Song.FileName); _Song.Save(Path.Combine(_Song.Folder, name + ".fix")); } } return(true); }