internal static BendValue[] Parse(Sng2014HSL.BendData32[] bendData)
        {
            var bendValues = (bendData.Where(t => t.Time > 0 && t.Step >= 0)
                .Select(t => new BendValue {Time = t.Time, Step = t.Step, Unk5 = t.Unk5})).ToArray();

            return (bendValues.Length > 0) ? bendValues : null;
        }
        internal static BendValue[] Parse(Sng2014HSL.BendData32[] bendData)
        {
            var bendValues = new List<BendValue>();

            for (var i = 0; i < bendData.Length; i++) {
                if (bendData[i].Time > 0 && bendData[i].Step > 0) {
                    var bend = new BendValue();
                    bend.Time = bendData[i].Time;
                    bend.Step = bendData[i].Step;
                    bend.Unk5 = bendData[i].Unk5;
                    bendValues.Add(bend);
                }
            }

            return (bendValues.Count > 0) ? bendValues.ToArray() : null;
        }
 internal static SongAnchor2014[] Parse(Sng2014HSL.AnchorSection anchorSection)
 {
     var anchors = new SongAnchor2014[anchorSection.Count];
     for (var i = 0; i < anchorSection.Count; i++) {
         var anchor = new SongAnchor2014();
         anchor.Time = anchorSection.Anchors[i].StartBeatTime;
         anchor.Fret = anchorSection.Anchors[i].FretId;
         anchor.Width = anchorSection.Anchors[i].Width;
         anchors[i] = anchor;
     }
     return anchors;
 }
        internal static SongTone2014[] Parse(Sng2014HSL.ToneSection toneSection, Attributes2014 attr = null)
        {
            var tones = new SongTone2014[toneSection.Count];
            for (var i = 0; i < toneSection.Count; i++) {
                var tone = new SongTone2014();
                tone.Id = toneSection.Tones[i].ToneId;
                tone.Time = toneSection.Tones[i].Time;

                if (attr != null) {
                    // Get tone name
                    switch (tone.Id) {
                        case 0:
                            tone.Name = attr.Tone_A;
                            break;
                        case 1:
                            tone.Name = attr.Tone_B;
                            break;
                        case 2:
                            tone.Name = attr.Tone_C;
                            break;
                        case 3:
                            tone.Name = attr.Tone_D;
                            break;
                        default:
                            tone.Name = "importedtone_" + tone.Id;
                            break;
                    }
                } else
                    tone.Name = "importedtone_" + tone.Id;

                tones[i] = tone;
            }
            return tones;
        }
 public static SongPhraseIteration2014[] Parse(Sng2014HSL.PhraseIterationSection piSection)
 {
     var piter = new SongPhraseIteration2014[piSection.Count];
     for (int i = 0; i < piSection.Count; i++) {
         var pi = new SongPhraseIteration2014();
         pi.PhraseId = piSection.PhraseIterations[i].PhraseId;
         pi.Time = piSection.PhraseIterations[i].StartTime;
         pi.Variation = "";
         if (!piSection.PhraseIterations[i].Difficulty.SequenceEqual(new Int32[] { 0,0,0 }))
             pi.HeroLevels = HeroLevel.Parse(piSection.PhraseIterations[i]);
         piter[i] = pi;
     }
     return piter;
 }
 internal static SongPhraseProperty[] Parse(Sng2014HSL.PhraseExtraInfoByLevelSection phraseExtraInfoByLevelSection)
 {
     var phraseProperties = new SongPhraseProperty[phraseExtraInfoByLevelSection.Count];
     for (var i = 0; i < phraseExtraInfoByLevelSection.Count; i++) {
         var spp = new SongPhraseProperty();
         spp.PhraseId = phraseExtraInfoByLevelSection.PhraseExtraInfoByLevel[i].PhraseId;
         spp.Redundant = phraseExtraInfoByLevelSection.PhraseExtraInfoByLevel[i].Redundant;
         spp.LevelJump = phraseExtraInfoByLevelSection.PhraseExtraInfoByLevel[i].LevelJump;
         spp.Empty = phraseExtraInfoByLevelSection.PhraseExtraInfoByLevel[i].Empty;
         spp.Difficulty = phraseExtraInfoByLevelSection.PhraseExtraInfoByLevel[i].Difficulty;
         phraseProperties[i] = spp;
     }
     return phraseProperties;
 }
 internal static HeroLevel[] Parse(Sng2014HSL.PhraseIteration phraseIteration)
 {
     var heroLevels = new HeroLevel[3];
     for(var i = 0; i < heroLevels.Length; i++) {
         var hero = new HeroLevel();
         hero.Hero = i + 1;
         hero.Difficulty = (byte)phraseIteration.Difficulty[i];
         heroLevels[i] = hero;
     }
     return heroLevels;
 }
        private void ParseChordNotes(Sng2014HSL.Chord template, Sng2014HSL.ChordNotes chordNotes = null)
        {
            var notes = new List<SongNote2014>();
            var notSetup = unchecked((sbyte)-1);

            for (var i = 0; i < 6; i++) {
                if ((chordNotes != null && chordNotes.NoteMask[i] != 0) || //notes with techniques
                    (chordNotes == null && template.Frets[i] != 255)) { // Notes without techniques

                    var cnote = new SongNote2014();

                    // SETUP DEFAULT VALUES
                    cnote.RightHand = notSetup;
                    cnote.LeftHand = notSetup;
                    cnote.SlideTo = notSetup;
                    cnote.SlideUnpitchTo = notSetup;
                    cnote.Tap = (byte)0;
                    cnote.Slap = notSetup;
                    cnote.Pluck = notSetup;

                    if ((chordNotes != null && chordNotes.NoteMask[i] != 0)) {
                        // SETUP FROM OWN PROPERTIES
                        cnote.parseNoteMask(chordNotes.NoteMask[i]);
                        cnote.SlideTo = (sbyte)chordNotes.SlideTo[i];
                        cnote.SlideUnpitchTo = (sbyte)chordNotes.SlideUnpitchTo[i];
                        cnote.Vibrato = chordNotes.Vibrato[i];
                        cnote.BendValues = BendValue.Parse(chordNotes.BendData[i].BendData32);
                        //Fix bend status from step in bendvalues
                        if (cnote.BendValues != null && cnote.BendValues.Length > 0)
                            foreach (var bend in cnote.BendValues)
                                if (cnote.Bend < bend.Step)
                                    cnote.Bend = (byte)Math.Round(bend.Step);
                    }

                    // BASIC INFO
                    cnote.Time = this.Time;
                    cnote.Fret = (sbyte)template.Frets[i];
                    cnote.LeftHand = (sbyte)template.Fingers[i];
                    cnote.String = (byte)i;

                    notes.Add(cnote);
                }
            }

            this.ChordNotes = notes.ToArray();
        }
 internal static SongAnchor2014[] Parse(Sng2014HSL.AnchorSection anchorSection)
 {
     var anchors = new SongAnchor2014[anchorSection.Count];
     for (var i = 0; i < anchorSection.Count; i++)
     {
         anchors[i] = new SongAnchor2014
         {
             Time = anchorSection.Anchors[i].StartBeatTime,
             Fret = anchorSection.Anchors[i].FretId,
             Width = anchorSection.Anchors[i].Width
         };
     }
     return anchors;
 }
        internal static SongHandShape[] Parse(Sng2014HSL.Arrangement arrangement)
        {
            var count = arrangement.Fingerprints1.Count + arrangement.Fingerprints2.Count;

            var fprints = new List<Sng2014HSL.Fingerprint>();
            fprints.AddRange(arrangement.Fingerprints1.Fingerprints);
            fprints.AddRange(arrangement.Fingerprints2.Fingerprints);
            fprints = fprints.OrderBy(e => e.StartTime).ToList<Sng2014HSL.Fingerprint>();

            var hshapes = new SongHandShape[count];
            for (var i = 0; i < count; i++) {
                var hs = new SongHandShape();
                hs.StartTime = fprints[i].StartTime;
                hs.EndTime = fprints[i].EndTime;
                hs.ChordId = fprints[i].ChordId;
                hshapes[i] = hs;
            }

            return hshapes;
        }
 internal static SongEvent[] Parse(Sng2014HSL.EventSection eventSection)
 {
     var songEvents = new SongEvent[eventSection.Count];
     for (var i = 0; i < eventSection.Count; i++) {
         var sevent = new SongEvent();
         sevent.Code = eventSection.Events[i].EventName.ToNullTerminatedAscii();
         sevent.Time = eventSection.Events[i].Time;
         songEvents[i] = sevent;
     }
     return songEvents;
 }
 internal static SongEbeat[] Parse(Sng2014HSL.BpmSection bpmSection)
 {
     var songEbeats = new SongEbeat[bpmSection.Count];
     for (var i = 0; i < bpmSection.Count; i++) {
         var sEbeat = new SongEbeat();
         sEbeat.Time = bpmSection.BPMs[i].Time;
         sEbeat.Measure = -1;
         if (bpmSection.BPMs[i].Mask != 0)
             sEbeat.Measure = bpmSection.BPMs[i].Measure;
         songEbeats[i] = sEbeat;
     }
     return songEbeats;
 }
 internal static SongSection[] Parse(Sng2014HSL.SectionSection sectionSection)
 {
     var songSections = new SongSection[sectionSection.Count];
     for (int i = 0; i < sectionSection.Count; i++) {
         var songSection = new SongSection();
         songSection.Name = sectionSection.Sections[i].Name.ToNullTerminatedAscii();
         songSection.Number = sectionSection.Sections[i].Number;
         songSection.StartTime = sectionSection.Sections[i].StartTime;
         songSections[i] = songSection;
     }
     return songSections;
 }
        internal static SongChord2014[] Parse(Sng2014HSL.Sng sngData, Sng2014HSL.NotesSection notesSection)
        {
            var chords = new List<SongChord2014>();

            for (var i = 0; i < notesSection.Count; i++) {
                if (notesSection.Notes[i].ChordId == -1)
                    continue; //Skip single notes (get only chord notes)

                var chord = new SongChord2014();
                chord.ChordId = notesSection.Notes[i].ChordId;
                chord.Time = notesSection.Notes[i].Time;

                // TECHNIQUES
                chord.parseChordMask(notesSection.Notes[i], notesSection.Notes[i].NoteMask);

                // CHORD NOTES (WITHOUT TECHNIQUES) + NOT HIGH DENSITY
                if (chord.HighDensity != 1) {
                    chord.ParseChordNotes(sngData.Chords.Chords[chord.ChordId]);
                }

                // CHORD NOTES (WITH TECHNIQUES)
                var cnId = notesSection.Notes[i].ChordNotesId;
                if (cnId != -1) {
                    if (sngData.ChordNotes.ChordNotes.Length > cnId)
                        chord.ParseChordNotes(sngData.Chords.Chords[chord.ChordId], sngData.ChordNotes.ChordNotes[cnId]);
                }

                chords.Add(chord);
            }

            return chords.ToArray();
        }
 public static SongNewLinkedDiff[] Parse(Sng2014HSL.NLinkedDifficultySection nlinkedDifficultySection)
 {
     var newLinkedDiff = new SongNewLinkedDiff[nlinkedDifficultySection.Count];
     for (int i = 0; i < nlinkedDifficultySection.Count; i++) {
         var nld = new SongNewLinkedDiff();
         nld.LevelBreak = nlinkedDifficultySection.NLinkedDifficulties[i].LevelBreak;
         nld.PhraseCount = nlinkedDifficultySection.NLinkedDifficulties[i].PhraseCount;
         nld.Nld_phrase = SongNld_phrase.Parse(nlinkedDifficultySection.NLinkedDifficulties[i].NLD_Phrase);
         nld.Ratio = ""; //TODO: ???
         newLinkedDiff[i] = nld;
     }
     return newLinkedDiff;
 }
        private void parseChordMask(Sng2014HSL.Notes notes, uint p)
        {
            // Remove flags from know techniques
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_CHORD) != 0)
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_CHORD;
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_CHORDNOTES) != 0)
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_CHORDNOTES;
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_SUSTAIN) != 0)
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_SUSTAIN;
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_DOUBLESTOP) != 0)
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_DOUBLESTOP;
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_ARPEGGIO) != 0)
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_ARPEGGIO;

            this.Strum = "down";
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_STRUM) != 0) {
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_STRUM;
                this.Strum = "up"; //TODO: Wrong, need research about it later
            }

            if (p == 0)
                return;

            // Setup techniques and remove flags
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_PARENT) != 0) {
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_PARENT;
                this.LinkNext = 1;
            }
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_ACCENT) != 0) {
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_ACCENT;
                this.Accent = 1;
            }
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_FRETHANDMUTE) != 0) {
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_FRETHANDMUTE;
                this.FretHandMute = 1;
            }
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_HIGHDENSITY) != 0) {
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_HIGHDENSITY;
                this.HighDensity = 1;
            }
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_IGNORE) != 0) {
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_IGNORE;
                this.Ignore = 1;
            }
            if ((p & Sng2014HSL.Sng2014FileWriter.NOTE_MASK_PALMMUTE) != 0) {
                p &= ~Sng2014HSL.Sng2014FileWriter.NOTE_MASK_PALMMUTE;
                this.PalmMute = 1;
            }
        }
        public Song2014(Sng2014HSL.Sng sngData, Attributes2014 attr = null)
        {
            Version = "7";
            CrowdSpeed = "1";

            if (attr != null) {
                // If manifest is passed, fill general song information
                Title = attr.SongName;
                Arrangement = ((ArrangementName)attr.ArrangementType).ToString();
                Part = (short)attr.SongPartition;
                Offset = attr.SongOffset;
                CentOffset = Convert.ToString(attr.CentOffset);
                SongLength = (float)attr.SongLength;
                SongNameSort = attr.SongNameSort;
                AverageTempo = attr.SongAverageTempo;
                Tuning = attr.Tuning;
                Capo = Convert.ToByte(attr.CapoFret);
                ArtistName = attr.ArtistName;
                ArtistNameSort = attr.ArtistNameSort;
                AlbumName = attr.AlbumName;
                AlbumNameSort = attr.AlbumNameSort;
                AlbumYear = Convert.ToString(attr.SongYear) ?? "";
                AlbumArt = attr.AlbumArt;
                ArrangementProperties = attr.ArrangementProperties;
                LastConversionDateTime = attr.LastConversionDateTime;

                ToneBase = attr.Tone_Base;
                ToneA = attr.Tone_A;
                ToneB = attr.Tone_B;
                ToneC = attr.Tone_C;
                ToneD = attr.Tone_D;
            } else {
                Part = sngData.Metadata.Part;
                SongLength = sngData.Metadata.SongLength;
                Tuning = new TuningStrings(sngData.Metadata.Tuning);
                Capo = (sngData.Metadata.CapoFretId >= 0) ? sngData.Metadata.CapoFretId : (byte)0;
                LastConversionDateTime = sngData.Metadata.LastConversionDateTime.ToNullTerminatedAscii();
            }

            Tones = (attr != null) ? SongTone2014.Parse(sngData.Tones, attr) : SongTone2014.Parse(sngData.Tones);
            if (attr == null) { // Fix tones slots for fake tone names if manifest was not entered
                foreach (var tone in Tones) {
                    if (tone.Name.EndsWith("_0"))
                        ToneBase = tone.Name;
                    if (tone.Name.EndsWith("_1")) {
                        ToneA = ToneBase;
                        ToneB = tone.Name;
                    }
                    if (tone.Name.EndsWith("_2"))
                        ToneC = tone.Name;
                    if (tone.Name.EndsWith("_3"))
                        ToneD = tone.Name;
                }
            }

            //Sections can be obtained from manifest or sng file (manifest preferred)
            Sections = (attr != null) ? SongSection.Parse(attr.Sections) : SongSection.Parse(sngData.Sections);

            //Can be obtained from manifest or sng file (sng preferred)
            Phrases = SongPhrase.Parse(sngData.Phrases);
            PhraseIterations = SongPhraseIteration2014.Parse(sngData.PhraseIterations);

            //Can be obtained from manifest or sng file (combined preferred)
            ChordTemplates = SongChordTemplate2014.Parse(sngData.Chords); // Only SNG have all ChordTemplates, manifest have only chord templates with name
            if (attr != null)
            {
                SongChordTemplate2014.AddChordIds(ChordTemplates, attr.ChordTemplates); // Only manifest has chordIds
            }

            //Only in SNG
            Ebeats = SongEbeat.Parse(sngData.BPMs);
            StartBeat = sngData.BPMs.BPMs[0].Time;
            Events = SongEvent.Parse(sngData.Events);
            Levels = SongLevel2014.Parse(sngData);

            //Not used in RS2014 customs at this time. Need to check official files
            NewLinkedDiff = SongNewLinkedDiff.Parse(sngData.NLD);
            PhraseProperties = SongPhraseProperty.Parse(sngData.PhraseExtraInfo);
            LinkedDiffs = new SongLinkedDiff[0];
            FretHandMuteTemplates = new SongFretHandMuteTemplate[0];
        }
        internal static SongChordTemplate2014[] Parse(Sng2014HSL.ChordSection chordSection)
        {
            var chordTemplates = new SongChordTemplate2014[chordSection.Count];
            for (int i = 0; i < chordSection.Count; i++) {
                var sct2014 = new SongChordTemplate2014();
                sct2014.ChordName = sct2014.DisplayName = chordSection.Chords[i].Name.ToNullTerminatedAscii();
                sct2014.Finger0 = (sbyte)chordSection.Chords[i].Fingers[0];
                sct2014.Finger1 = (sbyte)chordSection.Chords[i].Fingers[1];
                sct2014.Finger2 = (sbyte)chordSection.Chords[i].Fingers[2];
                sct2014.Finger3 = (sbyte)chordSection.Chords[i].Fingers[3];
                sct2014.Finger4 = (sbyte)chordSection.Chords[i].Fingers[4];
                sct2014.Finger5 = (sbyte)chordSection.Chords[i].Fingers[5];
                sct2014.Fret0 = (sbyte)chordSection.Chords[i].Frets[0];
                sct2014.Fret1 = (sbyte)chordSection.Chords[i].Frets[1];
                sct2014.Fret2 = (sbyte)chordSection.Chords[i].Frets[2];
                sct2014.Fret3 = (sbyte)chordSection.Chords[i].Frets[3];
                sct2014.Fret4 = (sbyte)chordSection.Chords[i].Frets[4];
                sct2014.Fret5 = (sbyte)chordSection.Chords[i].Frets[5];
                sct2014.ChordId = null;

                // Parse chord mask
                var mask = chordSection.Chords[i].Mask;
                if ((mask & Sng2014HSL.Sng2014FileWriter.CHORD_MASK_ARPEGGIO) != 0) {
                    mask &= ~Sng2014HSL.Sng2014FileWriter.CHORD_MASK_ARPEGGIO;
                    sct2014.DisplayName += "-arp";
                } else if ((mask & Sng2014HSL.Sng2014FileWriter.CHORD_MASK_NOP) != 0) {
                    mask &= ~Sng2014HSL.Sng2014FileWriter.CHORD_MASK_NOP;
                    sct2014.DisplayName += "-nop";
                }

                chordTemplates[i] = sct2014;
            }
            return chordTemplates;
        }
        internal static SongNote2014[] Parse(Sng2014HSL.NotesSection notesSection)
        {
            var notes = new List<SongNote2014>();

            for (var i = 0; i < notesSection.Count; i++) {
                if (notesSection.Notes[i].ChordId != -1)
                    continue; //Skip chord notes (get only single notes)

                var note = new SongNote2014();

                // BASIC INFO
                note.Time = notesSection.Notes[i].Time;
                note.Fret = (sbyte)notesSection.Notes[i].FretId;
                note.String = notesSection.Notes[i].StringIndex;

                // TECHNIQUES
                note.PickDirection = notesSection.Notes[i].PickDirection;
                note.parseNoteMask(notesSection.Notes[i].NoteMask); //NOTE MASK need to be setup previous get property values
                // Techniques with own properties
                if (notesSection.Notes[i].LeftHand != 255) note.LeftHand = (sbyte)notesSection.Notes[i].LeftHand;
                if (notesSection.Notes[i].SlideTo != 255) note.SlideTo = (sbyte)notesSection.Notes[i].SlideTo;
                if (notesSection.Notes[i].SlideUnpitchTo != 255) note.SlideUnpitchTo = (sbyte)notesSection.Notes[i].SlideUnpitchTo;
                if (notesSection.Notes[i].Tap != 255) note.Tap = notesSection.Notes[i].Tap;
                if (notesSection.Notes[i].Slap != 255) note.Slap = (sbyte)notesSection.Notes[i].Slap;
                if (notesSection.Notes[i].Pluck != 255) note.Pluck = (sbyte)notesSection.Notes[i].Pluck;
                if (notesSection.Notes[i].Vibrato != 0) note.Vibrato = notesSection.Notes[i].Vibrato;
                if (notesSection.Notes[i].Sustain != 0) note.Sustain = notesSection.Notes[i].Sustain;
                if (notesSection.Notes[i].MaxBend != 0) note.Bend = (byte)notesSection.Notes[i].MaxBend;
                note.BendValues = BendValue.Parse(notesSection.Notes[i].BendData.BendData);

                notes.Add(note);
            }

            return notes.ToArray();
        }
 internal static SongLevel2014[] Parse(Sng2014HSL.Sng sngData)
 {
     var levels = new SongLevel2014[sngData.Arrangements.Count];
     for (var i = 0; i < sngData.Arrangements.Count; i++) {
         var level = new SongLevel2014();
         level.Difficulty = sngData.Arrangements.Arrangements[i].Difficulty;
         level.Notes = SongNote2014.Parse(sngData.Arrangements.Arrangements[i].Notes);
         level.Chords = SongChord2014.Parse(sngData, sngData.Arrangements.Arrangements[i].Notes);
         level.Anchors = SongAnchor2014.Parse(sngData.Arrangements.Arrangements[i].Anchors);
         level.HandShapes = SongHandShape.Parse(sngData.Arrangements.Arrangements[i]);
         levels[i] = level;
     }
     return levels;
 }
 public static SongPhrase[] Parse(Sng2014HSL.PhraseSection sngPhraseSection)
 {
     var phrases = new SongPhrase[sngPhraseSection.Count];
     for (int i = 0; i < sngPhraseSection.Count; i++) {
         var phrase = new SongPhrase();
         phrase.Disparity = sngPhraseSection.Phrases[i].Disparity;
         phrase.Ignore = sngPhraseSection.Phrases[i].Ignore;
         phrase.MaxDifficulty = sngPhraseSection.Phrases[i].MaxDifficulty;
         phrase.Name = sngPhraseSection.Phrases[i].Name.ToNullTerminatedAscii();
         phrase.Solo = sngPhraseSection.Phrases[i].Solo;
         phrases[i] = phrase;
     }
     return phrases;
 }