public static void LoadChart(Chart chart, string[] data, Song.Instrument instrument = Song.Instrument.Guitar)
    {
#if TIMING_DEBUG
        float time = Time.realtimeSinceStartup;
#endif
        List <NoteFlag> flags = new List <NoteFlag>();

        chart.SetCapacity(data.Length);

        const int SPLIT_POSITION = 0;
        const int SPLIT_EQUALITY = 1;
        const int SPLIT_TYPE     = 2;
        const int SPLIT_VALUE    = 3;
        const int SPLIT_LENGTH   = 4;

        try
        {
            // Load notes, collect flags
            foreach (string line in data)
            {
                try
                {
                    string[] splitString = line.Split(' ');
                    uint     tick        = uint.Parse(splitString[SPLIT_POSITION]);
                    string   type        = splitString[SPLIT_TYPE].ToLower();

                    switch (type)
                    {
                    case ("n"):
                        // Split string to get note information
                        string[] digits = splitString;

                        int  fret_type = int.Parse(digits[SPLIT_VALUE]);
                        uint length    = uint.Parse(digits[SPLIT_LENGTH]);

                        if (instrument == Song.Instrument.Unrecognised)
                        {
                            Note newNote = new Note(tick, fret_type, length);
                            chart.Add(newNote, false);
                        }
                        else if (instrument == Song.Instrument.Drums)
                        {
                            LoadDrumNote(chart, tick, fret_type, length);
                        }
                        else if (instrument == Song.Instrument.GHLiveGuitar || instrument == Song.Instrument.GHLiveBass)
                        {
                            LoadGHLiveNote(chart, tick, fret_type, length, flags);
                        }
                        else
                        {
                            LoadStandardNote(chart, tick, fret_type, length, flags);
                        }
                        break;

                    case ("s"):
                        fret_type = int.Parse(splitString[SPLIT_VALUE]);

                        if (fret_type != 2)
                        {
                            continue;
                        }

                        length = uint.Parse(splitString[SPLIT_LENGTH]);

                        chart.Add(new Starpower(tick, length), false);
                        break;

                    case ("e"):
                        string[] strings   = splitString;
                        string   eventName = strings[SPLIT_VALUE];
                        chart.Add(new ChartEvent(tick, eventName), false);
                        break;

                    default:
                        break;
                    }
                }
                catch (System.Exception e)
                {
                    Logger.LogException(e, "Error parsing chart reader line \"" + line);
                }
            }
            chart.UpdateCache();

            // Load flags
            foreach (NoteFlag flag in flags)
            {
                int index, length;
                SongObjectHelper.FindObjectsAtPosition(flag.tick, chart.notes, out index, out length);
                if (length > 0)
                {
                    NoteFunctions.GroupAddFlags(chart.notes, flag.flag, index, length);
                }
            }
#if TIMING_DEBUG
            Debug.Log("Chart load time: " + (Time.realtimeSinceStartup - time));
#endif
        }
        catch (System.Exception e)
        {
            // Bad load, most likely a parsing error
            Logger.LogException(e, "Error parsing chart reader chart data");
            chart.Clear();
        }
    }
    public static void LoadChart(Chart chart, string[] data, Song.Instrument instrument = Song.Instrument.Guitar)
    {
#if TIMING_DEBUG
        float time = Time.realtimeSinceStartup;
#endif
        List <NoteFlag> flags = new List <NoteFlag>();

        chart.SetCapacity(data.Length);

        const int SPLIT_POSITION = 0;
        const int SPLIT_EQUALITY = 1;
        const int SPLIT_TYPE     = 2;
        const int SPLIT_VALUE    = 3;
        const int SPLIT_LENGTH   = 4;

        try
        {
            // Load notes, collect flags
            foreach (string line in data)
            {
                try
                {
                    string[] splitString = line.Split(' ');
                    uint     tick        = uint.Parse(splitString[SPLIT_POSITION]);
                    string   type        = splitString[SPLIT_TYPE].ToLower();

                    switch (type)
                    {
                    case ("n"):
                        // Split string to get note information
                        string[] digits = splitString;

                        int  fret_type = int.Parse(digits[SPLIT_VALUE]);
                        uint length    = uint.Parse(digits[SPLIT_LENGTH]);

                        if (instrument == Song.Instrument.Unrecognised)
                        {
                            Note newNote = new Note(tick, fret_type, length);
                            chart.Add(newNote, false);
                        }
                        else if (instrument == Song.Instrument.Drums)
                        {
                            LoadDrumNote(chart, tick, fret_type, length, flags);
                        }
                        else if (instrument == Song.Instrument.GHLiveGuitar || instrument == Song.Instrument.GHLiveBass)
                        {
                            LoadGHLiveNote(chart, tick, fret_type, length, flags);
                        }
                        else
                        {
                            LoadStandardNote(chart, tick, fret_type, length, flags);
                        }
                        break;

                    case ("s"):
                        fret_type = int.Parse(splitString[SPLIT_VALUE]);

                        if (fret_type != 2)
                        {
                            continue;
                        }

                        length = uint.Parse(splitString[SPLIT_LENGTH]);

                        chart.Add(new Starpower(tick, length), false);
                        break;

                    case ("e"):
                        string[] strings   = splitString;
                        string   eventName = strings[SPLIT_VALUE];
                        chart.Add(new ChartEvent(tick, eventName), false);
                        break;

                    default:
                        break;
                    }
                }
                catch (System.Exception e)
                {
                    Logger.LogException(e, "Error parsing chart reader line \"" + line);
                }
            }
            chart.UpdateCache();

            // Load flags
            foreach (NoteFlag flag in flags)
            {
                if (flag.flag == Note.Flags.ProDrums_Cymbal)
                {
                    // The note number indicates which note it should attach to
                    int noteNumber = flag.noteNumber - ChartIOHelper.c_proDrumsOffset;
                    Debug.Assert(noteNumber >= 0, "Incorrectly parsed a note flag as a pro-drums flag. Note number was " + flag.noteNumber);

                    int index, length;
                    SongObjectHelper.FindObjectsAtPosition(flag.tick, chart.notes, out index, out length);
                    if (length > 0)
                    {
                        for (int i = index; i < index + length; ++i)
                        {
                            Note note = chart.notes[i];

                            int saveNoteNum;
                            if (!ChartIOHelper.c_drumNoteToSaveNumberLookup.TryGetValue(note.rawNote, out saveNoteNum))
                            {
                                continue;
                            }

                            if (noteNumber == saveNoteNum)
                            {
                                // Reverse cymbal flag
                                note.flags ^= Note.Flags.ProDrums_Cymbal;
                            }
                        }
                    }
                }
                else
                {
                    int index, length;
                    SongObjectHelper.FindObjectsAtPosition(flag.tick, chart.notes, out index, out length);
                    if (length > 0)
                    {
                        NoteFunctions.GroupAddFlags(chart.notes, flag.flag, index, length);
                    }
                }
            }
#if TIMING_DEBUG
            Debug.Log("Chart load time: " + (Time.realtimeSinceStartup - time));
#endif
        }
        catch (System.Exception e)
        {
            // Bad load, most likely a parsing error
            Logger.LogException(e, "Error parsing chart reader chart data");
            chart.Clear();
        }
    }