Example #1
0
        public bool AddNote(CSongNote note, bool updateTimings = true)
        {
            int lineIndex = FindPreviousLine(note.StartBeat);

            if (lineIndex + 1 < _Lines.Count && _Lines[lineIndex + 1].FirstNoteBeat < note.EndBeat) //First note in next line starts before this one ends
            {
                return(false);
            }
            if (lineIndex < 0)
            {
                //Note is before ALL lines
                if (_Lines.Count > 0)
                {
                    //Add to first line
                    if (!_Lines[0].AddNote(note))
                    {
                        return(false);
                    }
                }
                else
                {
                    var line = new CSongLine();
                    line.AddNote(note);
                    _Lines.Add(line);
                }
            }
            else
            {
                if (!_Lines[lineIndex].AddNote(note))
                {
                    return(false);
                }
            }
            if (updateTimings)
            {
                UpdateTimings();
            }
            return(true);
        }
Example #2
0
            private bool _AddNote(int player, CSongNote note)
            {
                CVoice voice = _Song.Notes.GetVoice(player, true);

                return(voice.AddNote(note, false));
            }
Example #3
0
            /// <summary>
            ///     Read notes. First try to read notes normally (assume standard)<br />
            ///     If there are more than _MaxZeroNoteCt with length &lt; 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 &lt; 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':
                        case 'R':       // Read R (RAP) and G (Golden RAP) notes as Freestyle notes currently. Final implementation needed!
                        case 'G':       // Read R (RAP) and G (Golden RAP) notes as Freestyle notes currently. Final implementation needed!
                            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') || tag.Equals('R') || tag.Equals('G'))      // Read R (RAP) and G (Golden RAP) notes as Freestyle notes currently. Final implementation needed!
                                {
                                    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);
            }
Example #4
0
        /*Check this first for consistency (next line might be affected)
         * public bool InsertNote(CSongNote note, int lineIndex, bool updateTimings = false)
         * {
         *  if (_Lines.Count > lineIndex && _Lines[lineIndex].StartBeat <= note.StartBeat)
         *  {
         *      if (!_Lines[lineIndex].AddNote(note))
         *          return false;
         *      if (updateTimings)
         *          UpdateTimings();
         *      return true;
         *  }
         *  return false;
         * }*/

        public void UpdateTimings()
        {
            if (_Lines.Count == 0)
            {
                return;
            }
            _Lines[0].StartBeat = -10000;

            for (int i = 1; i < _Lines.Count; i++)
            {
                CSongNote lastNote  = _Lines[i - 1].LastNote;
                CSongNote firstNote = _Lines[i].FirstNote;

                if ((lastNote != null) && (firstNote != null))
                {
                    int min = lastNote.EndBeat;
                    int max = firstNote.StartBeat;

                    int s;
                    switch (max - min)
                    {
                    case 0:
                        s = max;
                        break;

                    case 1:
                        s = max;
                        break;

                    case 2:
                        s = max - 1;
                        break;

                    case 3:
                        s = max - 2;
                        break;

                    default:
                        s = min + 2;
                        break;
                    }

                    _Lines[i].StartBeat   = s;
                    _Lines[i - 1].EndBeat = min;
                }
                else if (firstNote != null)
                {
                    _Lines[i - 1].EndBeat = Math.Min(_Lines[i - 1].StartBeat, firstNote.StartBeat - 2);
                    _Lines[i].StartBeat   = Math.Max(_Lines[i - 1].EndBeat, firstNote.StartBeat - 2);
                }
                else if (lastNote != null)
                {
                    _Lines[i - 1].EndBeat = lastNote.EndBeat;
                    _Lines[i].StartBeat   = Math.Max(lastNote.EndBeat, _Lines[i].StartBeat); //Prefer current setting
                }
                else
                {
                    //No note
                    _Lines[i - 1].EndBeat = _Lines[i - 1].StartBeat; //Assume at least startbeats were set right
                }
            }

            _Lines[_Lines.Count - 1].EndBeat = Math.Max(_Lines[_Lines.Count - 1].LastNoteBeat, _Lines[_Lines.Count - 1].StartBeat); //Use note or (when not set) start beat
        }