private SongNote GetNote(Chord chord, Chord nextChord)
 {
     SongNote note = new SongNote();
     Note zNote = chord.Notes[0];
     note.Fret = (sbyte)zNote.Fret;
     note.String = (byte)zNote.StringNo;
     note.Bend = 0;
     note.HammerOn = (zNote.IsTapNote || chord.IsHammerOn) ? (byte)1 : (byte)0;
     note.Harmonic = 0;
     note.Hopo = note.HammerOn;
     note.Ignore = 0;
     note.PalmMute = (zNote.IsXNote || chord.IsMute) ? (byte)1 : (byte)0;
     note.Sustain = (chord.EndTime - chord.StartTime > .5) ? chord.EndTime - chord.StartTime : 0;
     note.Time = (float)chord.StartTime;
     note.Tremolo = 0;
     if (chord.IsSlide && nextChord != null)
     {
         note.SlideTo = (sbyte)Math.Max(nextChord.Notes[0].Fret, 1);
         note.Sustain = chord.EndTime - chord.StartTime;
         note.HammerOn = note.Hopo = note.PalmMute = 0;
     }
     else
     {
         note.SlideTo = -1;
     }
     return note;
 }
        // COMPLETE except hardcoded fields
        private static void WriteRocksmithSngLevelNotes(EndianBinaryWriter w, List<PhraseIterationInfo> iterationInfo, SongNote[] notes, SongChord[] chords, Single songLength, ArrangementType arrangementType)
        {
            List<TimeLinkedEntity> notesChords = new List<TimeLinkedEntity>();

            // add notes to combined note/chord array
            if (notes != null && notes.Length != 0)
            {
                notesChords.AddRange(notes.Select(note =>
                    new TimeLinkedEntity
                    {
                        Time = note.Time,
                        Entity = note
                    }));
            }

            // add chords to combined note/chord array
            if (chords != null && chords.Length != 0)
            {
                notesChords.AddRange(chords.Select(chord =>
                    new TimeLinkedEntity
                    {
                        Time = chord.Time,
                        Entity = chord
                    }));
            }

            // sort the notes and chords by time
            notesChords.Sort((s1, s2) => s1.Time.CompareTo(s2.Time));

            // write empty header if no notes or chords
            if (notesChords.Count == 0)
            {
                w.Write(new byte[4]); // empty header
                return;
            }

            // output notes and chords header count
            w.Write(notesChords.Count);

            // ouput notes and chords
            for (int i = 0; i < (notesChords.Count); i++)
            {
                // note time tag
                w.Write(notesChords[i].Time);

                // string tag
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).String : -1);

                // fret tag
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).Fret : -1);

                // chord id
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? -1 : ((SongChord)notesChords[i].Entity).ChordId);

                // unknown
                w.Write(Convert.ToInt32(-1));

                // sustain time
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).Sustain : 0);

                // bend
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).Bend : 0);

                // slideTo
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).SlideTo : -1);

                // tremolo
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).Tremolo : new byte());

                // harmonic
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).Harmonic : new byte());

                // palm mute
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).PalmMute : new byte());

                if (arrangementType == ArrangementType.Bass)
                {
                    w.Write(new byte());//unknownB

                    //Bass only - Slap
                    w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).Slap : -1);

                    //Bass only - Pluck
                    w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).Pluck : -1);
                }

                // hopo
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).Hopo : new byte());

                // hammerOn
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).HammerOn : new byte());

                // pullOff
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).PullOff : new byte());

                // ignore
                w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? ((SongNote)notesChords[i].Entity).Ignore : ((SongChord)notesChords[i].Entity).Ignore);

                // high density chord
                if (arrangementType == ArrangementType.Bass)
                {
                    w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? new byte() : ((SongChord)notesChords[i].Entity).HighDensity);
                    w.Write(new byte());
                    w.Write((byte)140);
                    w.Write(new byte());
                }
                else
                {
                    w.Write(notesChords[i].Entity.GetType() == typeof(SongNote) ? new byte() : ((SongChord)notesChords[i].Entity).HighDensity);
                    w.Write(new byte[4]);
                }

                //w.Write(Convert.ToInt16(246));
                //w.Write(Convert.ToInt16(7472));

                // phrase iteration start index and id ????
                bool phraseStartIterationFound = false;
                foreach (var iteration in iterationInfo)
                {
                    if (notesChords[i].Time >= iteration.StartTime && notesChords[i].Time < iteration.EndTime)
                    {
                        w.Write(iteration.IterationId); // phrase iteration
                        w.Write(iteration.PhraseId);
                        phraseStartIterationFound = true;
                        break;
                    }
                }
                if (!phraseStartIterationFound)
                {
                    throw new Exception(string.Format("No phrase start iteration found with matching time for note {0}.", i.ToString()));
                }
            }
        }
        private SongNote2014 GetNoteInfo(SongNote songNote)
        {
            SongNote2014 songNote2014 = new SongNote2014();
            songNote2014.Bend = (float)songNote.Bend;

            // tested ... BendValue time causing in game hangs if off by 0.001f
            if (songNote.Bend > 0)
            {
                var bendValues = new List<BendValue>();
                // CRITICAL CALCULATION - DO NOT CHANGE - MULTIPLIER VALUE MUST BE 0.3333 TO ACHEIVE PROPER ACCURACY AND MATCH EOF OUTPUT
                bendValues.Add(new BendValue { Step = songNote.Bend, Time = (float)Math.Round((songNote.Sustain * 0.3333 / songNote.Bend) + songNote.Time, 3), Unk5 = 0 });
                songNote2014.BendValues = bendValues.ToArray();
            }

            songNote2014.Fret = (sbyte)songNote.Fret;
            songNote2014.HammerOn = (byte)songNote.HammerOn;
            songNote2014.Harmonic = (byte)songNote.Harmonic;
            songNote2014.Hopo = (byte)songNote.Hopo;
            songNote2014.Ignore = (byte)songNote.Ignore;
            songNote2014.PalmMute = (byte)songNote.PalmMute;
            songNote2014.Pluck = (sbyte)songNote.Pluck; // -1; // EOF is non-compliant
            songNote2014.PullOff = (byte)songNote.PullOff;
            songNote2014.Slap = (sbyte)songNote.Slap; //  -1; // EOF is non-compliant
            songNote2014.SlideTo = (sbyte)songNote.SlideTo;
            songNote2014.String = (byte)songNote.String;
            songNote2014.Sustain = (float)songNote.Sustain;
            songNote2014.Time = (float)songNote.Time;
            songNote2014.Tremolo = (byte)songNote.Tremolo;
            // initialize elements not present in RS1
            songNote2014.LinkNext = 0;
            songNote2014.Accent = 0;
            songNote2014.LeftHand = -1;
            songNote2014.Mute = 0;
            songNote2014.HarmonicPinch = 0;
            songNote2014.PickDirection = 0;
            songNote2014.RightHand = -1;
            songNote2014.SlideUnpitchTo = -1;
            songNote2014.Tap = 0;
            songNote2014.Vibrato = 0;

            return songNote2014;
        }
        // COMPLETE
        private static void WriteRockmithSngLevelSlideProperties(EndianBinaryWriter w, SongNote[] notes)
        {
            if (notes == null || notes.Length == 0)
            {
                w.Write(new byte[4]);
                return;
            }

            // count of number of slides in level
            w.Write(notes.Count(x => x.SlideTo > -1));

            foreach (SongNote note in notes)
            {
                if (note.SlideTo > -1)
                {
                    // slide end time
                    if (note.Sustain > 0)
                    {
                        w.Write(note.Time + note.Sustain);
                    }
                    else
                    { // default sustain if user forgets it
                        w.Write(note.Time + (float)0.125);
                    }

                    // slide end fret
                    w.Write(note.SlideTo);
                }
            }
        }