private static void AddSongMetadata(Song2014 rsSong, ZpeSong zigSong, string arrangment)
        {
            // standard meta header data
            rsSong.Version                = "7";
            rsSong.Arrangement            = arrangment;
            rsSong.Part                   = 1;
            rsSong.Offset                 = 0;
            rsSong.CentOffset             = "0";
            rsSong.StartBeat              = 0;
            rsSong.Capo                   = 0;
            rsSong.AlbumName              = "Unknown Album";
            rsSong.AlbumYear              = DateTime.Now.ToString("yyyy");
            rsSong.CrowdSpeed             = "1";
            rsSong.LastConversionDateTime = DateTime.Now.ToString();
            rsSong.SongLength             = zigSong.Length;

            Regex regex = new Regex(" - ");

            string[] artistTitle = regex.Split(zigSong.Name);
            rsSong.ArtistName = artistTitle[0] == null ? zigSong.Name : artistTitle[0];
            rsSong.Title      = artistTitle[1] == null ? zigSong.Name : artistTitle[1];

            ZpeTempo tempo = zigSong.Tracks[0].Tempos[0];
            float    BPM   = (float)Math.Round((float)60000000 / tempo.RawTempo, 3);

            rsSong.AverageTempo = BPM;

            ZpeTuning tuning = null;

            for (int i = 0; i < zigSong.Tunings.Tuning.Count; i++)
            {
                if (arrangment == "Lead" || arrangment == "Rhythm")
                {
                    if (zigSong.Tunings.Tuning[i].IsGuitarTuning)
                    {
                        tuning = zigSong.Tunings.Tuning[i];
                        break;
                    }
                }

                if (arrangment == "Bass")
                {
                    if (zigSong.Tunings.Tuning[i].IsBassTuning)
                    {
                        tuning = zigSong.Tunings.Tuning[i];
                        break;
                    }
                }
            }

            if (tuning == null)
            {
                throw new Exception("ZPE XML does not contain tuning");
            }

            rsSong.Tuning = new TuningStrings {
                String0 = tuning.E, String1 = tuning.A, String2 = tuning.D, String3 = tuning.G, String4 = tuning.B, String5 = tuning.HighE
            };
        }
        ZpeTrack GetTrack(ZpeSong song)
        {
            var guitarTrack = song.Tracks.SingleOrDefault(tr => "PART REAL_GUITAR_22".Equals(tr.Name));

            if (guitarTrack == null)
            {
                guitarTrack = song.Tracks.SingleOrDefault(tr => "PART REAL_GUITAR".Equals(tr.Name));
            }
            return(guitarTrack);
        }
        private void AddSongMetadata(Song rsSong, ZpeSong zigSong)
        {
            rsSong.Arrangement            = "Combo";
            rsSong.Artist                 = "Unknown Artist";
            rsSong.Title                  = zigSong.Name;
            rsSong.Offset                 = 0;
            rsSong.Part                   = 1;
            rsSong.LastConversionDateTime = DateTime.Now.ToString();
            rsSong.SongLength             = zigSong.Length;

            ZpeTempo tempo = zigSong.Tracks[0].Tempos[0];
            float    BPM   = (float)Math.Round((float)60000000 / tempo.RawTempo, 3);

            rsSong.AverageTempo = BPM;

            ZpeTuning tuning = null;

            for (int i = 0; i < zigSong.Tunings.Tuning.Count - 1; i++)
            {
                if (zigSong.Tunings.Tuning[i].IsGuitarTuning)
                {
                    tuning = zigSong.Tunings.Tuning[i];
                    break;
                }
            }

            if (tuning == null)
            {
                throw new Exception("ZPE XML does not contain guitar tuning");
            }

            rsSong.Tuning = new TuningStrings
            {
                String0 = tuning.E,
                String1 = tuning.A,
                String2 = tuning.D,
                String3 = tuning.G,
                String4 = tuning.B,
                String5 = tuning.HighE
            };
        }
        private static void AddNotes(Song2014 rsSong, ZpeSong zigSong, string arrangement)
        {
            int spread     = 3;
            int width      = spread;
            var notes      = new Dictionary <string, List <SongNote2014> >();
            var chords     = new Dictionary <string, List <SongChord2014> >();
            var anchors    = new Dictionary <string, List <SongAnchor2014> >();
            var handShapes = new Dictionary <string, List <SongHandShape> >();
            var chordTemps = new Dictionary <string, Tuple <int, SongChordTemplate2014> >();

            var guitarTrack     = zigSong.Tracks.SingleOrDefault(tr => arrangement.Equals(tr.Name));
            var difficultyCount = guitarTrack.Chords.GroupBy(chord => chord.Difficulty).Count();

            foreach (var group in guitarTrack.Chords.GroupBy(chord => chord.Difficulty))
            {
                var gNotes      = notes[group.Key] = new List <SongNote2014>();
                var gChords     = chords[group.Key] = new List <SongChord2014>();
                var gAnchors    = anchors[group.Key] = new List <SongAnchor2014>();
                var gHandShapes = handShapes[group.Key] = new List <SongHandShape>();
                var zChords     = group.OrderBy(chord => chord.StartTime).ToList();
                var lastMeasure = 0;
                int highFret    = -1;
                //bool lastWasChord = false;
                SongAnchor2014 curAnchor = null;
                // dont see any tempo, time sig note or chord time adjustment here because
                // start end times have already been tempo timsig map adjusted
                for (int i = 0; i < zChords.Count; i++)
                {
                    var zChord = zChords[i];
                    if (zChord.Notes.Count > 1)  // cord
                    {
                        Tuple <int, SongChordTemplate2014> val = GetChordTemplate(zChord, chordTemps);

                        int minCFret = Math.Min(DeZero(val.Item2.Fret0), Math.Min(DeZero(val.Item2.Fret1), Math.Min(DeZero(val.Item2.Fret2), Math.Min(DeZero(val.Item2.Fret3), Math.Min(DeZero(val.Item2.Fret4), DeZero(val.Item2.Fret5))))));

                        if (minCFret != int.MaxValue)
                        {
                            if (curAnchor == null)
                            {
                                if (gAnchors.Count == 0 || gAnchors[gAnchors.Count - 1].Fret != minCFret)
                                {
                                    gAnchors.Add(new SongAnchor2014 {
                                        Fret = Math.Min(18, minCFret), Time = (float)Math.Round(zChord.StartTime, 3), Width = spread
                                    });
                                }
                            }
                            else
                            {
                                if (minCFret + spread <= highFret)
                                {
                                    curAnchor.Fret = minCFret;
                                }
                                gAnchors.Add(curAnchor);
                                if (curAnchor.Fret != minCFret)
                                {
                                    gAnchors.Add(new SongAnchor2014 {
                                        Fret = Math.Min(18, minCFret), Time = (float)Math.Round(zChord.StartTime, 3), Width = spread
                                    });
                                }
                                curAnchor = null;
                            }
                        }

                        SongHandShape handShape = new SongHandShape {
                            ChordId = val.Item1, StartTime = (float)Math.Round(zChord.StartTime, 3)
                        };

                        do
                        {
                            SongChord2014 chord = new SongChord2014();
                            chord.Time    = (float)Math.Round(zChord.StartTime, 3);
                            chord.ChordId = val.Item1;
                            chord.Strum   = "down"; // required by CST

                            List <SongNote2014> noteList = new List <SongNote2014>();
                            for (int zNoteIndex = 0; zNoteIndex < zChord.Notes.Count; zNoteIndex++)
                            {
                                var note = GetNote(zChord, null, zNoteIndex);
                                noteList.Add(note);
                            }
                            chord.ChordNotes = noteList.ToArray();

                            var measure = rsSong.Ebeats.FirstOrDefault(ebeat => ebeat.Time >= chord.Time);
                            if (measure == null || measure.Measure > lastMeasure)
                            {
                                lastMeasure       = measure == null ? lastMeasure : measure.Measure;
                                chord.HighDensity = 0;
                            }
                            else if (gChords.Count == 0 || gChords[gChords.Count - 1].ChordId != chord.ChordId)
                            {
                                chord.HighDensity = 0;
                            }
                            else
                            {
                                chord.HighDensity = 1;
                            }

                            gChords.Add(chord);

                            if (i + 1 < zChords.Count)
                            {
                                zChord = zChords[i + 1];
                            }
                        } while (i + 1 < zChords.Count && zChord.Notes.Count > 1 && val.Item1 == GetChordTemplate(zChord, chordTemps).Item1&& ++i != -1);


                        handShape.EndTime = zChord.StartTime;

                        if (handShape.EndTime > handShape.StartTime)
                        {
                            handShape.EndTime -= (handShape.EndTime - zChords[i].EndTime) / 2;
                        }
                        gHandShapes.Add(handShape);
                    }
                    else // single notes
                    {
                        var note = GetNote(zChord, i == zChords.Count - 1 ? null : zChords[i + 1]);
                        if (note.Fret > 0)
                        {
                            if (curAnchor == null)
                            {
                                curAnchor = new SongAnchor2014 {
                                    Fret = Math.Min(18, (int)note.Fret), Time = note.Time, Width = spread
                                };
                                highFret = note.Fret;
                            }
                            else if (note.Fret < curAnchor.Fret)
                            {
                                if (note.Fret + spread >= highFret)
                                {
                                    curAnchor.Fret = note.Fret;
                                }
                                else
                                {
                                    gAnchors.Add(curAnchor);
                                    curAnchor = new SongAnchor2014 {
                                        Fret = Math.Min(18, (int)note.Fret), Time = note.Time, Width = spread
                                    };
                                    highFret = note.Fret;
                                }
                            }
                            else if (note.Fret > highFret)
                            {
                                if (note.Fret - spread <= curAnchor.Fret)
                                {
                                    highFret = note.Fret;
                                }
                                else
                                {
                                    gAnchors.Add(curAnchor);
                                    curAnchor = new SongAnchor2014 {
                                        Fret = Math.Min(18, (int)note.Fret), Time = note.Time, Width = spread
                                    };
                                    highFret = note.Fret;
                                }
                            }
                        }
                        gNotes.Add(note);

                        //if (note.Fret > width)
                        //    width = note.Fret;
                    }
                }

                //if (width > 8)
                //{
                //    string msgText = zigSong.Name + "  " + guitarTrack.Name + ": has a note spread of " + width + " frets   " +
                //        "\r\nThis exceed the useful intended capicity of this program\r\n" +
                //        "and the Rocksmith note highway will be very wide for this song.\r\n\r\n " +
                //        "I understand it could look like crap, but I want to continue anyhow.";

                //    if (MessageBox.Show(new Form { TopMost = true },
                //        msgText, @"Midi File: Fret Spread Warning",
                //        MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
                //    {
                //        Application.Exit();
                //        // Application.Restart();
                //        Environment.Exit(-1);
                //    }
                //}

                if (curAnchor != null)
                {
                    gAnchors.Add(curAnchor);
                }
            }

            if (difficultyCount == 1)
            {
                rsSong.Levels = new SongLevel2014[]
                {
                    new SongLevel2014 {
                        Difficulty = 0, Notes = notes["Easy"].ToArray(), Chords = chords["Easy"].ToArray(), Anchors = anchors["Easy"].ToArray(), HandShapes = handShapes["Easy"].ToArray()
                    }
                };
            }
            else
            {
                rsSong.Levels = new SongLevel2014[]
                {
                    new SongLevel2014 {
                        Difficulty = 0,
                        Notes      = notes["Easy"].ToArray(),
                        Chords     = chords["Easy"].ToArray(),
                        Anchors    = anchors["Easy"].ToArray(),
                        HandShapes = handShapes["Easy"].ToArray()
                    },
                    new SongLevel2014 {
                        Difficulty = 1,
                        Notes      = notes["Medium"].ToArray(),
                        Chords     = chords["Medium"].ToArray(),
                        Anchors    = anchors["Medium"].ToArray(),
                        HandShapes = handShapes["Medium"].ToArray()
                    },
                    new SongLevel2014 {
                        Difficulty = 2,
                        Notes      = notes["Hard"].ToArray(),
                        Chords     = chords["Hard"].ToArray(),
                        Anchors    = anchors["Hard"].ToArray(),
                        HandShapes = handShapes["Hard"].ToArray()
                    },
                    new SongLevel2014 {
                        Difficulty = 3,
                        Notes      = notes["Expert"].ToArray(),
                        Chords     = chords["Expert"].ToArray(),
                        Anchors    = anchors["Expert"].ToArray(),
                        HandShapes = handShapes["Expert"].ToArray()
                    }
                };
            }
            rsSong.ChordTemplates = chordTemps.Values.OrderBy(v => v.Item1).Select(v => v.Item2).ToArray();
        }
        private static void AddEbeats(Song2014 rsSong, ZpeSong zigSong, string arrangement)
        {
            var ebeats  = new List <SongEbeat>();
            var phrases = new List <SongPhraseIteration2014>();

            //  var tempoTrack = zigSong.Tracks.Single(tr => "Tempo".Equals(tr.Name));
            ZpeTrack tempoTrack = zigSong.Tracks[0];

            var       tempoIndex = 0;
            var       tsIndex    = 0;
            var       tempo      = tempoTrack.Tempos[0];
            var       signature  = tempoTrack.TimeSignatures[0];
            float     time       = 0;
            int       beat       = 1;
            short     measure    = 1;
            const int MU         = 1000000;

            // float secondsPerQuarter = tempo.SecondsPerBar / signature.Numerator;
            float secondsPerQuarter = (float)tempo.RawTempo / MU;

            // var end = tempoTrack.MetaEvents.Single(ev => "EndOfTrack".Equals(ev.MetaType)).StartTime;
            Single end = zigSong.Length;

            while (time < end)
            {
                ebeats.Add(new SongEbeat {
                    Measure = (beat == 1) ? measure : (short)-1, Time = (float)Math.Round(time, 3)
                });
                // denominator already converted by ZPE
                var delta = secondsPerQuarter * ((float)4 / signature.Denominator);
                time += delta;
                var changed = false;
                if (tsIndex + 1 != tempoTrack.TimeSignatures.Count && time + delta / 2 >= tempoTrack.TimeSignatures[tsIndex + 1].StartTime)
                {
                    signature = tempoTrack.TimeSignatures[++tsIndex];
                    time      = signature.StartTime;
                    changed   = true;
                }
                if (tempoIndex + 1 != tempoTrack.Tempos.Count && time + delta / 2 >= tempoTrack.Tempos[tempoIndex + 1].StartTime)
                {
                    changed = true;
                    tempo   = tempoTrack.Tempos[++tempoIndex];
                    time    = tempo.StartTime;

                    // secondsPerQuarter = tempo.SecondsPerBar / signature.Numerator;
                    secondsPerQuarter = (float)tempo.RawTempo / MU;
                }
                if (changed || ++beat > signature.Numerator)
                {
                    beat = 1;
                    ++measure;
                }
                // Console.WriteLine("Getting Ebeats for bar: " + measure);
            }
            rsSong.Ebeats = ebeats.ToArray();

            var guitarTrack     = zigSong.Tracks.SingleOrDefault(tr => arrangement.Equals(tr.Name));
            var difficultyCount = guitarTrack.Chords.GroupBy(chord => chord.Difficulty).Count();

            var firstNote = (float)Math.Round(guitarTrack.Chords.Min(c => c.StartTime), 3);
            var lastNote = (float)Math.Round(guitarTrack.Chords.Max(c => c.EndTime), 3);
            int measOffset = ebeats.Where(eb => eb.Measure != -1 && eb.Time <= firstNote).Last().Measure, phraseId = 0;

            measure = (short)measOffset;
            SongEbeat ebeat = null;

            //count in
            phrases.Add(new SongPhraseIteration2014 {
                PhraseId = phraseId++, Time = 0
            });

            while (null != (ebeat = ebeats.FirstOrDefault(eb => eb.Measure == measure)))
            {
                if (ebeat.Time >= lastNote)
                {
                    break;
                }
                phrases.Add(new SongPhraseIteration2014 {
                    PhraseId = phraseId++, Time = ebeat.Time
                });
                measure += 12;
            }
            //end
            phrases.Add(new SongPhraseIteration2014 {
                PhraseId = phraseId++, Time = lastNote + .001f
            });
            // phrases.Add(new SongPhraseIteration2014 { PhraseId = phraseId++, Time = end + .001f });
            rsSong.PhraseIterations = phrases.ToArray();
            rsSong.Phrases          = phrases.Select(it => new SongPhrase {
                MaxDifficulty = it.PhraseId == 0 || it.PhraseId == phrases.Count - 1 ? 0 : difficultyCount - 1, Name = it.PhraseId == 0 ? "COUNT" : it.PhraseId == phrases.Count - 1 ? "END" : it.PhraseId.ToString()
            }).ToArray();
            phrases.RemoveAt(0);
            phrases.RemoveAt(phrases.Count - 1);
            rsSong.Sections = phrases.Select(it => new SongSection {
                Name = "verse", Number = 1, StartTime = it.Time
            }).ToArray();
        }
        private void AddNotes(Song rsSong, ZpeSong zigSong)
        {
            int spread     = 3;
            var notes      = new Dictionary <string, List <SongNote> >();
            var chords     = new Dictionary <string, List <SongChord> >();
            var anchors    = new Dictionary <string, List <SongAnchor> >();
            var handShapes = new Dictionary <string, List <SongHandShape> >();

            var chordTemps      = new Dictionary <string, Tuple <int, SongChordTemplate> >();
            var guitarTrack     = GetTrack(zigSong);
            var difficultyCount = guitarTrack.Chords.GroupBy(chord => chord.Difficulty).Count();

            foreach (var group in guitarTrack.Chords.GroupBy(chord => chord.Difficulty))
            {
                var gNotes      = notes[group.Key] = new List <SongNote>();
                var gChords     = chords[group.Key] = new List <SongChord>();
                var gAnchors    = anchors[group.Key] = new List <SongAnchor>();
                var gHandShapes = handShapes[group.Key] = new List <SongHandShape>();
                var zChords     = group.OrderBy(chord => chord.StartTime).ToList();
                var lastMeasure = 0;
                int highFret    = -1;
                //bool lastWasChord = false;
                SongAnchor curAnchor = null;
                // dont see any tempo, time sig note or chord time adjustment here, why?
                for (int i = 0; i < zChords.Count; i++)
                {
                    var zChord = zChords[i];
                    if (zChord.Notes.Count > 1)
                    {
                        Tuple <int, SongChordTemplate> val = GetChordTemplate(zChord, chordTemps);

                        int minCFret = Math.Min(DeZero(val.Item2.Fret0),
                                                Math.Min(DeZero(val.Item2.Fret1),
                                                         Math.Min(DeZero(val.Item2.Fret2),
                                                                  Math.Min(DeZero(val.Item2.Fret3),
                                                                           Math.Min(DeZero(val.Item2.Fret4), DeZero(val.Item2.Fret5))))));

                        if (minCFret != int.MaxValue)
                        {
                            if (curAnchor == null)
                            {
                                if (gAnchors.Count == 0 || gAnchors[gAnchors.Count - 1].Fret != minCFret)
                                {
                                    gAnchors.Add(new SongAnchor {
                                        Fret = Math.Min(18, minCFret), Time = zChord.StartTime
                                    });
                                }
                            }
                            else
                            {
                                if (minCFret + spread <= highFret)
                                {
                                    curAnchor.Fret = minCFret;
                                }
                                gAnchors.Add(curAnchor);
                                if (curAnchor.Fret != minCFret)
                                {
                                    gAnchors.Add(new SongAnchor {
                                        Fret = Math.Min(18, minCFret), Time = zChord.StartTime
                                    });
                                }
                                curAnchor = null;
                            }
                        }
                        SongHandShape handShape = new SongHandShape {
                            ChordId = val.Item1, StartTime = zChord.StartTime
                        };
                        do
                        {
                            SongChord chord = new SongChord();
                            chord.Time    = zChord.StartTime;
                            chord.ChordId = val.Item1;

                            var measure = rsSong.Ebeats.FirstOrDefault(ebeat => ebeat.Time >= chord.Time);
                            if (measure == null || measure.Measure > lastMeasure)
                            {
                                lastMeasure       = measure == null ? lastMeasure : measure.Measure;
                                chord.HighDensity = 0;
                            }
                            else if (gChords.Count == 0 || gChords[gChords.Count - 1].ChordId != chord.ChordId)
                            {
                                chord.HighDensity = 0;
                            }
                            else
                            {
                                chord.HighDensity = 1;
                            }
                            gChords.Add(chord);
                            if (i + 1 < zChords.Count)
                            {
                                zChord = zChords[i + 1];
                            }
                        } while (i + 1 < zChords.Count && zChord.Notes.Count > 1 && val.Item1 == GetChordTemplate(zChord, chordTemps).Item1&& ++i != -1);
                        handShape.EndTime = zChord.StartTime;
                        if (handShape.EndTime > handShape.StartTime)
                        {
                            handShape.EndTime -= (handShape.EndTime - zChords[i].EndTime) / 2;
                        }
                        gHandShapes.Add(handShape);
                    }
                    else
                    {
                        var note = GetNote(zChord, i == zChords.Count - 1 ? null : zChords[i + 1]);
                        if (note.Fret > 0)
                        {
                            if (curAnchor == null)
                            {
                                curAnchor = new SongAnchor {
                                    Fret = Math.Min(18, (int)note.Fret), Time = note.Time
                                };
                                highFret = note.Fret;
                            }
                            else if (note.Fret < curAnchor.Fret)
                            {
                                if (note.Fret + spread >= highFret)
                                {
                                    curAnchor.Fret = note.Fret;
                                }
                                else
                                {
                                    gAnchors.Add(curAnchor);
                                    curAnchor = new SongAnchor {
                                        Fret = Math.Min(18, (int)note.Fret), Time = note.Time
                                    };
                                    highFret = note.Fret;
                                }
                            }
                            else if (note.Fret > highFret)
                            {
                                if (note.Fret - spread <= curAnchor.Fret)
                                {
                                    highFret = note.Fret;
                                }
                                else
                                {
                                    gAnchors.Add(curAnchor);
                                    curAnchor = new SongAnchor {
                                        Fret = Math.Min(18, (int)note.Fret), Time = note.Time
                                    };
                                    highFret = note.Fret;
                                }
                            }
                        }
                        gNotes.Add(note);
                    }
                }
                if (curAnchor != null)
                {
                    gAnchors.Add(curAnchor);
                }
            }

            if (difficultyCount == 1)
            {
                rsSong.Levels = new SongLevel[]
                {
                    new SongLevel {
                        Difficulty = 0,
                        Notes      = notes["Easy"].ToArray(),
                        Chords     = chords["Easy"].ToArray(),
                        Anchors    = anchors["Easy"].ToArray(),
                        HandShapes = handShapes["Easy"].ToArray()
                    }
                };
            }
            else
            {
                rsSong.Levels = new SongLevel[]
                {
                    new SongLevel {
                        Difficulty = 0,
                        Notes      = notes["Easy"].ToArray(),
                        Chords     = chords["Easy"].ToArray(),
                        Anchors    = anchors["Easy"].ToArray(),
                        HandShapes = handShapes["Easy"].ToArray()
                    },
                    new SongLevel {
                        Difficulty = 1,
                        Notes      = notes["Medium"].ToArray(),
                        Chords     = chords["Medium"].ToArray(),
                        Anchors    = anchors["Medium"].ToArray(),
                        HandShapes = handShapes["Medium"].ToArray()
                    },
                    new SongLevel {
                        Difficulty = 2,
                        Notes      = notes["Hard"].ToArray(),
                        Chords     = chords["Hard"].ToArray(),
                        Anchors    = anchors["Hard"].ToArray(),
                        HandShapes = handShapes["Hard"].ToArray()
                    },
                    new SongLevel {
                        Difficulty = 3,
                        Notes      = notes["Expert"].ToArray(),
                        Chords     = chords["Expert"].ToArray(),
                        Anchors    = anchors["Expert"].ToArray(),
                        HandShapes = handShapes["Expert"].ToArray()
                    }
                };
            }
            rsSong.ChordTemplates = chordTemps.Values.OrderBy(v => v.Item1).Select(v => v.Item2).ToArray();
        }