public void NameFromStringsTest()
        {
            string tName = string.Empty; 
            var t = new TuningDefinition();
            var Estd = new TuningStrings(new Int16[] { 0, 0, 0, 0, 0, 0 });
            tName = t.NameFromStrings(Estd, false);
            Assert.AreEqual("E Standard", tName);

            var Ebstd = new TuningStrings(new Int16[] { -1, -1, -1, -1, -1, -1 });
            tName = t.NameFromStrings(Ebstd, true);
            Assert.AreEqual("Eb Standard", tName);

            var EbstdB = new TuningStrings(new Int16[] { -1, -1, -1, -1 }); //TODO: support bass
            tName = t.NameFromStrings(EbstdB, true);
            //Assert.AreEqual("Eb Standard", tName);

            var Ccstd = new TuningStrings(new Int16[] { -3, -3, -3, -3, -3, -3 });
            tName = t.NameFromStrings(Ccstd, false);
            Assert.AreEqual("C# Standard", tName);

            var DropEb = new TuningStrings(new Int16[] { -3, -1, -1, -1, -1, -1 });
            tName = t.NameFromStrings(DropEb, true);
            Assert.AreEqual("Eb Drop Db", tName);

            var DropA = new TuningStrings(new Int16[] { 5, 7, 7, 7, 7, 7 });
            tName = t.NameFromStrings(DropA, false);
            Assert.AreEqual("B Drop A", tName);
        }
        static string NoteName(TuningStrings tuning, byte s, bool flats = false)
        {
            String[] notesNamesHi = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
            String[] notesNamesLo = { "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B" };

            var id = Sng2014FileWriter.GetMidiNote(tuning.ToArray(), s, 0, false, 0)%12;
            return flats ? notesNamesLo[id] : notesNamesHi[id];
        }
        public TuningDefinition(TuningStrings tStrings, GameVersion rsVersion, string name = "", bool custom = true)
        {
            Custom = custom;
            Tuning = tStrings;
            GameVersion = rsVersion;

            UIName = Name = !string.IsNullOrEmpty(name) ? name : NameFromStrings(tStrings);
        }
        private static string GetTuningName(TuningStrings tuning, bool isBass, bool inBem = true)
        {
            List<Int32> Notes = new List<Int32>();
            List<String> NoteNames = new List<String>();
            String[] notesNames = new String[] { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
            String[] notesNamesHi = new String[] { "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B" };
            for (Byte s = 0; s < (isBass ? 4 : 6); s++)
                Notes.Add(Sng2014FileWriter.GetMidiNote(tuning.ToShortArray(), s, 0, isBass));
            foreach (var mNote in Notes)
                if (inBem) NoteNames.Add(notesNamesHi[mNote % 12]); //oct = mNote / 12 - 1
                else NoteNames.Add(notesNames[mNote % 12]); //oct = mNote / 12 - 1

            return String.Join(" ",NoteNames);
        }
        public static TuningStrings Convert2Bass(TuningStrings guitarTuning)
        {
            var bassTuning = new TuningStrings
            {
                String0 = guitarTuning.String0,
                String1 = guitarTuning.String1,
                String2 = guitarTuning.String2,
                String3 = guitarTuning.String3,
                String4 = 0,
                String5 = 0
            };

            return bassTuning;
        }
        public void TuningStringsEqualsTest()
        {
            //Object\regular equality
            var expected = new TuningStrings(new Int16[] { -2, 0, 0, 0, 0, 0 });
            var actual = new TuningStrings(new Int16[] { 0, 0, 0, 0, 0, 0 });
            Assert.AreNotEqual(expected, actual);

            //LINQ equality
            var list = new List<TuningStrings> { expected, expected, actual };
            var distinct = list.Union(new List<TuningStrings> { actual, actual, expected }).ToList();
            if (list.Count == distinct.Count)
            {
                Assert.Fail();
            }
        }
        public string NameFromStrings(TuningStrings tuning, bool isBass, bool inBem = true)
        {
            List<Int32> Notes = new List<Int32>();
            List<String> NoteNames = new List<String>();
            String[] notesNames = new String[] { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
            String[] notesNamesHi = new String[] { "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B" };
            for (Byte s = 0; s < 6; s++)
                Notes.Add(Sng2014FileWriter.GetMidiNote(tuning.ToShortArray(), s, 0, isBass, 0));
            foreach (var mNote in Notes)
                if(inBem) NoteNames.Add(notesNamesHi[mNote % 12]); //oct = mNote / 12 - 1
                else NoteNames.Add(notesNames[mNote % 12]); //oct = mNote / 12 - 1

            return String.Format("{0}{1}{2}{3}{4}{5}", NoteNames[0], NoteNames[1], NoteNames[2],
                                                       NoteNames[3], NoteNames[4], NoteNames[5]);
        }
 public string NameFromStrings(TuningStrings tuning, bool flats = true)
 {
     var t = tuning.ToArray();
     var noteNames = String.Empty;
     switch (GetTuningFamily(t))
     {
         case TuningFamily.Standard:
             noteNames = string.Format("{0} Standard", NoteName(tuning, 0, flats));
             break;
         case TuningFamily.Drop:
             noteNames = string.Format("{0} Drop {1}", NoteName(tuning, 5, true), NoteName(tuning, 0, flats));
             break;
         case TuningFamily.Open:
             break;
         default:
             for (Byte s = 0; s < 6; s++)
                 noteNames += NoteName(tuning, s, flats);
             break;
     }
     return noteNames;
 }
        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                 = (float)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                   = (byte)((sngData.Metadata.CapoFretId == 0xFF) ? 0x00 : sngData.Metadata.CapoFretId);
                LastConversionDateTime = sngData.Metadata.LastConversionDateTime.ToNullTerminatedAscii();
            }

            Tones = SongTone2014.Parse(sngData.Tones, attr);
            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];
            //ddc
            TranscriptionTrack = TranscriptionTrack2014.GetDefault();
        }
        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];
        }
        private void SetTuningCombo(TuningStrings tuningStrings, bool isBass = false)
        {
            //Detect tuning
            TuningDefinition tuning = TuningDefinitionRepository.Instance().SelectAny(tuningStrings, currentGameVersion);
            //Create tuning
            if (tuning == null) {
                using (var form = new TuningForm()) {
                    tuning = new TuningDefinition();
                    tuning.Tuning = tuningStrings;
                    tuning.Custom = true;
                    tuning.GameVersion = currentGameVersion;
                    tuning.Name = tuning.UIName = tuning.NameFromStrings(tuningStrings, isBass);

                    form.Tuning = tuning;
                    form.IsBass = isBass;
                    if (DialogResult.OK != form.ShowDialog()) {
                        return;
                    }

                    FillTuningCombo();
                }
            }
            //Set tuning
            tuningComboBox.SelectedItem = tuning;
        }
        public static string TuningToName(TuningStrings songTuning, GameVersion gameVersion = GameVersion.RS2014, List<TuningDefinition> tuningXml = null)
        {
            // speed hack ... use preloaded TuningDefinitionRepository if available
            if (tuningXml == null)
                tuningXml = TuningDefinitionRepository.Instance.LoadTuningDefinitions(gameVersion);

            foreach (var tuning in tuningXml)
                if (tuning.Tuning.String0 == songTuning.String0 &&
                    tuning.Tuning.String1 == songTuning.String1 &&
                    tuning.Tuning.String2 == songTuning.String2 &&
                    tuning.Tuning.String3 == songTuning.String3 &&
                    tuning.Tuning.String4 == songTuning.String4 &&
                    tuning.Tuning.String5 == songTuning.String5)
                    return tuning.UIName;

            return "Other";
        }