public static void GetSongDifficulty(AttributesHeader2014 attribute, Song2014 song)
        {
            var easyArray   = new List <int>();
            var mediumArray = new List <int>();
            var hardArray   = new List <int>();

            for (int i = 0; i < song.PhraseIterations.Length; i++)
            {
                var pt   = song.PhraseIterations[i];
                var hard = song.Phrases[pt.PhraseId].MaxDifficulty;
                if (pt.HeroLevels != null)
                {
                    foreach (var h in pt.HeroLevels)
                    {
                        switch (h.Hero)
                        {
                        case 1:
                            easyArray.Add(h.Difficulty);
                            break;

                        case 2:
                            mediumArray.Add(h.Difficulty);
                            break;

                        case 3:
                            hard = h.Difficulty;
                            break;
                        }
                        hardArray.Add(hard);
                    }
                }
            }

            // Is not the way of official are calculated, but is a way to calculate unique values for custom
            // Could be rewritten with the correct way or a best way to get this value
            var itCount = song.PhraseIterations.Length;
            var ifAny   = easyArray.Count > 0;

            // TODO: round to 9 decimal places and improve calculation
            attribute.SongDiffEasy   = ifAny ? easyArray.Average() / itCount : 0;
            attribute.SongDiffMed    = ifAny ? mediumArray.Average() / itCount : 0;
            attribute.SongDiffHard   = ifAny ? hardArray.Average() / itCount : 0;
            attribute.SongDifficulty = attribute.SongDiffHard;
        }
        public static void GetSongDifficulty(AttributesHeader2014 attribute, Song2014 song)
        {
            // This is not the way official values are calculated, but sometimes gets pretty close
            // TODO: improve calculation

            var arrProrp  = song.ArrangementProperties;
            int techCoeff = arrProrp.NonStandardChords +
                            3 * arrProrp.BarreChords +
                            (arrProrp.PowerChords | arrProrp.DoubleStops) +
                            arrProrp.DropDPower +
                            2 * arrProrp.OpenChords +
                            arrProrp.FingerPicking +
                            arrProrp.TwoFingerPicking +
                            arrProrp.PalmMutes +
                            2 * arrProrp.Harmonics +
                            3 * arrProrp.PinchHarmonics +
                            arrProrp.Hopo +
                            arrProrp.Tremolo +
                            (arrProrp.PathBass == 1 ? 4 : 1) * arrProrp.Slides +
                            arrProrp.UnpitchedSlides +
                            3 * arrProrp.Bends +
                            4 * arrProrp.Tapping +
                            2 * arrProrp.Vibrato +
                            arrProrp.FretHandMutes +
                            arrProrp.SlapPop +
                            arrProrp.Sustain +
                            arrProrp.FifthsAndOctaves +
                            arrProrp.Syncopation;

            // Arrangements with few/no techniques get very low values otherwise
            if (techCoeff <= 5)
            {
                techCoeff += 4;
            }

            // In official content maximum value for SongDiffHard is 1.0
            attribute.SongDiffHard   = Math.Round(techCoeff * (double)attribute.NotesHard / song.SongLength / 100, 9);
            attribute.SongDiffMed    = Math.Round(techCoeff * (double)attribute.NotesMedium / song.SongLength / 50, 9);
            attribute.SongDiffEasy   = Math.Round(techCoeff * (double)attribute.NotesEasy / song.SongLength / 25, 9);
            attribute.SongDifficulty = attribute.SongDiffHard;
        }