Ejemplo n.º 1
0
        public static List <HitsoundLayer> ImportMidi(string path, double offset = 0, bool instruments = true, bool keysounds = true, bool lengths = true, double lengthRoughness = 1, bool velocities = true, double velocityRoughness = 1)
        {
            List <HitsoundLayer> hitsoundLayers = new List <HitsoundLayer>();

            var strictMode = false;
            var mf         = new MidiFile(path, strictMode);

            Console.WriteLine(
                $@"Format {mf.FileFormat}, " +
                $@"Tracks {mf.Tracks}, " +
                $@"Delta Ticks Per Quarter Note {mf.DeltaTicksPerQuarterNote}");

            List <TempoEvent> tempos = new List <TempoEvent>();

            foreach (var track in mf.Events)
            {
                tempos.AddRange(track.OfType <TempoEvent>());
            }
            tempos = tempos.OrderBy(o => o.AbsoluteTime).ToList();

            List <double> cumulativeTime = CalculateCumulativeTime(tempos, mf.DeltaTicksPerQuarterNote);

            Dictionary <int, int> channelBanks   = new Dictionary <int, int>();
            Dictionary <int, int> channelPatches = new Dictionary <int, int>();

            // Loop through every event of every track
            for (int track = 0; track < mf.Tracks; track++)
            {
                foreach (var midiEvent in mf.Events[track])
                {
                    if (midiEvent is PatchChangeEvent pc)
                    {
                        channelPatches[pc.Channel] = pc.Patch;
                    }
                    else if (midiEvent is ControlChangeEvent co)
                    {
                        if (co.Controller == MidiController.BankSelect)
                        {
                            channelBanks[co.Channel] = (co.ControllerValue * 128) + (channelBanks.ContainsKey(co.Channel) ? (byte)channelBanks[co.Channel] : 0);
                        }
                        else if (co.Controller == MidiController.BankSelectLsb)
                        {
                            channelBanks[co.Channel] = co.ControllerValue + (channelBanks.ContainsKey(co.Channel) ? channelBanks[co.Channel] >> 8 * 128 : 0);
                        }
                    }
                    else if (MidiEvent.IsNoteOn(midiEvent))
                    {
                        var on = midiEvent as NoteOnEvent;

                        double time   = CalculateTime(on.AbsoluteTime, tempos, cumulativeTime, mf.DeltaTicksPerQuarterNote);
                        double length = on.OffEvent != null
                            ? CalculateTime(on.OffEvent.AbsoluteTime,
                                            tempos,
                                            cumulativeTime,
                                            mf.DeltaTicksPerQuarterNote) -
                                        time
                            : -1;

                        length = RoundLength(length, lengthRoughness);

                        bool keys = keysounds || on.Channel == 10;

                        int bank = instruments
                            ? on.Channel == 10 ? 128 :
                                   channelBanks.ContainsKey(on.Channel) ? channelBanks[on.Channel] : 0
                            : -1;
                        int patch = instruments && channelPatches.ContainsKey(on.Channel)
                            ? channelPatches[on.Channel]
                            : -1;
                        int instrument = -1;
                        int key        = keys ? on.NoteNumber : -1;
                        length = lengths ? length : -1;
                        int velocity = velocities ? on.Velocity : -1;
                        velocity = (int)RoundVelocity(velocity, velocityRoughness);

                        string lengthString = Math.Round(length).ToString(CultureInfo.InvariantCulture);
                        string filename     = $"{bank}\\{patch}\\{instrument}\\{key}\\{lengthString}\\{velocity}.wav";

                        string instrumentName = on.Channel == 10 ? "Percussion" :
                                                patch >= 0 && patch <= 127 ? PatchChangeEvent.GetPatchName(patch) : "Undefined";
                        string keyName = on.NoteName;

                        string name = instrumentName;
                        if (keysounds)
                        {
                            name += "," + keyName;
                        }
                        if (lengths)
                        {
                            name += "," + lengthString;
                        }
                        if (velocities)
                        {
                            name += "," + velocity;
                        }


                        var sampleArgs = new SampleGeneratingArgs(filename, bank, patch, instrument, key, length, velocity);
                        var importArgs = new LayerImportArgs(ImportType.MIDI)
                        {
                            Path              = path,
                            Bank              = bank,
                            Patch             = patch,
                            Key               = key,
                            Length            = length,
                            LengthRoughness   = lengthRoughness,
                            Velocity          = velocity,
                            VelocityRoughness = velocityRoughness
                        };

                        // Find the hitsoundlayer with this path
                        HitsoundLayer layer = hitsoundLayers.Find(o => o.ImportArgs == importArgs);

                        if (layer != null)
                        {
                            // Find hitsound layer with this path and add this time
                            layer.Times.Add(time + offset);
                        }
                        else
                        {
                            // Add new hitsound layer with this path
                            HitsoundLayer newLayer = new HitsoundLayer(name, SampleSet.Normal, Hitsound.Normal, sampleArgs, importArgs);
                            newLayer.Times.Add(time + offset);

                            hitsoundLayers.Add(newLayer);
                        }
                    }
                }
            }
            // Stretch the velocities to reach 127
            int maxVelocity = hitsoundLayers.Max(o => o.SampleArgs.Velocity);

            foreach (var hsl in hitsoundLayers)
            {
                hsl.SampleArgs.Velocity = (int)Math.Round(hsl.SampleArgs.Velocity / (float)maxVelocity * 127);
            }

            // Sort the times
            hitsoundLayers.ForEach(o => o.Times = o.Times.OrderBy(t => t).ToList());

            // Sort layers by name
            hitsoundLayers = hitsoundLayers.OrderBy(o => o.Name).ToList();

            return(hitsoundLayers);
        }
Ejemplo n.º 2
0
        public List <MidiNote> ReadMidiEvents(double timeFromStartMS)
        {
            List <MidiNote> notes = null;

            try
            {
                EndMidiEvent = false;
                if (midifile != null)
                {
                    if (NextPosEvent < MidiSorted.Count)
                    {
                        // The BPM measures how many quarter notes happen in a minute. To work out the length of each pulse we can use the following formula:
                        // Pulse Length = 60 / (BPM * PPQN)
                        // Calculate current pulse to play
                        CurrentPulse += Convert.ToInt64((timeFromStartMS - LastTimeFromStartMS) / PulseLengthMs);

                        LastTimeFromStartMS = timeFromStartMS;

                        // From the last position played
                        for (int currentPosEvent = NextPosEvent; currentPosEvent < MidiSorted.Count; currentPosEvent++)
                        {
                            TrackMidiEvent trackEvent = MidiSorted[currentPosEvent];
                            if (Quantization != 0)
                            {
                                trackEvent.AbsoluteQuantize = ((trackEvent.Event.AbsoluteTime + Quantization / 2) / Quantization) * Quantization;
                            }
                            else
                            {
                                trackEvent.AbsoluteQuantize = trackEvent.Event.AbsoluteTime;
                            }

                            //Debug.Log("ReadMidiEvents - timeFromStartMS:" + Convert.ToInt32(timeFromStartMS) + " LastTimeFromStartMS:" + Convert.ToInt32(LastTimeFromStartMS) + " CurrentPulse:" + CurrentPulse + " AbsoluteQuantize:" + trackEvent.AbsoluteQuantize);

                            if (trackEvent.AbsoluteQuantize <= CurrentPulse)
                            {
                                NextPosEvent = currentPosEvent + 1;

                                if (trackEvent.Event.CommandCode == MidiCommandCode.NoteOn)
                                {
                                    if (((NoteOnEvent)trackEvent.Event).OffEvent != null)
                                    {
                                        NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event;
                                        // if (noteon.OffEvent != null)
                                        {
                                            if (notes == null)
                                            {
                                                notes = new List <MidiNote>();
                                            }

                                            //Debug.Log(string.Format("Track:{0} NoteNumber:{1,3:000} AbsoluteTime:{2,6:000000} NoteLength:{3,6:000000} OffDeltaTime:{4,6:000000} ", track, noteon.NoteNumber, noteon.AbsoluteTime, noteon.NoteLength, noteon.OffEvent.DeltaTime));
                                            MidiNote note = new MidiNote()
                                            {
                                                AbsoluteQuantize = trackEvent.AbsoluteQuantize,
                                                Midi             = noteon.NoteNumber,
                                                Channel          = trackEvent.Event.Channel,
                                                Velocity         = noteon.Velocity,
                                                Duration         = noteon.NoteLength * PulseLengthMs,
                                                Length           = noteon.NoteLength,
                                                Patch            = PatchChanel[trackEvent.Event.Channel - 1],
                                                Drum             = (trackEvent.Event.Channel == 10),
                                                Delay            = 0,
                                                Pan = EnablePanChange ? PanChanel[trackEvent.Event.Channel - 1] : -1,
                                            };
                                            if (VolumeChanel[note.Channel - 1] != 127)
                                            {
                                                note.Velocity = Mathf.RoundToInt(((float)note.Velocity) * ((float)VolumeChanel[trackEvent.Event.Channel - 1]) / 127f);
                                            }
                                            notes.Add(note);
                                            if (LogEvents)
                                            {
                                                Debug.Log(BuildInfoTrack(trackEvent) + string.Format("{0,-4} {1,3:000} Lenght:{2} {3} Veloc:{4}",
                                                                                                     noteon.NoteName, noteon.NoteNumber, noteon.NoteLength, NoteLength(note), noteon.Velocity));
                                            }
                                        }
                                    }
                                }
                                else if (trackEvent.Event.CommandCode == MidiCommandCode.NoteOff)
                                {
                                    // no need, noteoff are associated with noteon
                                }
                                else if (trackEvent.Event.CommandCode == MidiCommandCode.ControlChange)
                                {
                                    ControlChangeEvent controlchange = (ControlChangeEvent)trackEvent.Event;
                                    if (controlchange.Controller == MidiController.Expression)
                                    {
                                        VolumeChanel[trackEvent.Event.Channel - 1] = controlchange.ControllerValue;
                                    }
                                    else if (controlchange.Controller == MidiController.MainVolume)
                                    {
                                        VolumeChanel[trackEvent.Event.Channel - 1] = controlchange.ControllerValue;
                                    }
                                    else if (controlchange.Controller == MidiController.Pan)
                                    {
                                        PanChanel[trackEvent.Event.Channel - 1] = controlchange.ControllerValue;
                                    }
                                    // Other midi event
                                    if (LogEvents)
                                    {
                                        Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Control {0} {1}", controlchange.Controller, controlchange.ControllerValue));
                                    }
                                }
                                else if (trackEvent.Event.CommandCode == MidiCommandCode.PatchChange)
                                {
                                    PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event;
                                    PatchChanel[trackEvent.Event.Channel - 1] = trackEvent.Event.Channel == 10 ? 0 : change.Patch;
                                    if (LogEvents)
                                    {
                                        Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Patch   {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch)));
                                    }
                                }
                                else if (trackEvent.Event.CommandCode == MidiCommandCode.MetaEvent)
                                {
                                    MetaEvent meta = (MetaEvent)trackEvent.Event;
                                    switch (meta.MetaEventType)
                                    {
                                    case MetaEventType.SetTempo:
                                        if (EnableChangeTempo)
                                        {
                                            TempoEvent tempo = (TempoEvent)meta;
                                            //NewQuarterPerMinuteValue = tempo.Tempo;
                                            ChangeTempo(tempo.Tempo);
                                            //if (LogEvents)Debug.Log(BuildInfoTrack(trackEvent) + string.Format("SetTempo   {0} MicrosecondsPerQuarterNote:{1}", tempo.Tempo, tempo.MicrosecondsPerQuarterNote));
                                        }
                                        break;

                                    case MetaEventType.SequenceTrackName:
                                        if (!string.IsNullOrEmpty(SequenceTrackName))
                                        {
                                            SequenceTrackName += "\n";
                                        }
                                        SequenceTrackName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, ((TextEvent)meta).Text);
                                        if (LogEvents)
                                        {
                                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Sequence   '{0}'", ((TextEvent)meta).Text));
                                        }
                                        break;

                                    case MetaEventType.ProgramName:
                                        ProgramName += ((TextEvent)meta).Text + " ";
                                        if (LogEvents)
                                        {
                                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Program   '{0}'", ((TextEvent)meta).Text));
                                        }
                                        break;

                                    case MetaEventType.TrackInstrumentName:
                                        if (!string.IsNullOrEmpty(TrackInstrumentName))
                                        {
                                            TrackInstrumentName += "\n";
                                        }
                                        TrackInstrumentName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, ((TextEvent)meta).Text);
                                        if (LogEvents)
                                        {
                                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Text      '{0}'", ((TextEvent)meta).Text));
                                        }
                                        break;

                                    case MetaEventType.TextEvent:
                                        TextEvent += ((TextEvent)meta).Text + " ";
                                        if (LogEvents)
                                        {
                                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Sequence  '{0}'", ((TextEvent)meta).Text));
                                        }
                                        break;

                                    case MetaEventType.Copyright:
                                        Copyright += ((TextEvent)meta).Text + " ";
                                        if (LogEvents)
                                        {
                                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Copyright '{0}'", ((TextEvent)meta).Text));
                                        }
                                        break;

                                    case MetaEventType.Lyric:     // lyric
                                    case MetaEventType.Marker:    // marker
                                    case MetaEventType.CuePoint:  // cue point
                                    case MetaEventType.DeviceName:
                                        break;
                                    }
                                    //Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0} {1}", meta.MetaEventType, meta.ToString()));
                                }
                                else
                                {
                                    // Other midi event
                                    //Debug.Log(string.Format("Track:{0} Channel:{1,2:00} CommandCode:{2,3:000} AbsoluteTime:{3,6:000000}", track, e.Channel, e.CommandCode.ToString(), e.AbsoluteTime));
                                }
                            }
                            else
                            {
                                // Out of time, exit for loop
                                break;
                            }
                        }

                        if (notes != null)
                        {
                            //if (CancelNextReadEvents)
                            //{
                            //    notes = null;
                            //    //Debug.Log("CancelNextReadEvents");
                            //    CancelNextReadEvents = false;
                            //}
                            //else
                            //if (notes.Count > 3 && (notes[notes.Count - 1].AbsoluteQuantize - notes[0].AbsoluteQuantize) > midifile.DeltaTicksPerQuarterNote * 8)
                            //{
                            //    //notes.RemoveRange(0, notes.Count - 1);
                            //    Debug.Log("--> Too much notes " + notes.Count + " timeFromStartMS:" + Convert.ToInt32(timeFromStartMS) + " Start:" + notes[0].AbsoluteQuantize + " Ecart:" + (notes[notes.Count - 1].AbsoluteQuantize - notes[0].AbsoluteQuantize) + " CurrentPulse:" + CurrentPulse);
                            //    //notes = null;
                            //}
                        }
                    }
                    else
                    {
                        // End of midi events
                        EndMidiEvent = true;
                    }
                }
            }
            catch (System.Exception ex)
            {
                MidiPlayerGlobal.ErrorDetail(ex);
            }
            return(notes);
        }
Ejemplo n.º 3
0
        public void Load(string path)
        {
            LoadedMidi = new MidiFile(path, false);
            // Parse the midi for info; we want to start by getting a list of all the channels
            // We also need to know the highest and lowest note for each Instrument/Channel (screw tracks)
            // And of course, that gives us overall highest/lowest
            MidiChannelMap = new Dictionary <int, MidiChannel>();
            MidiTrackMap   = new Dictionary <int, MidiTrack>();
            MidiChannels   = new List <MidiChannel>();
            MidiTracks     = new List <MidiTrack>();

            for (int i = 0; i < LoadedMidi.Tracks; i++)
            {
                var newTrack = new MidiTrack("Untitled", i);
                MidiTrackMap[i] = newTrack;
                MidiTracks.Add(newTrack);
                var e = LoadedMidi.Events[i];
                foreach (var ie in e)
                {
                    if (ie is TextEvent)
                    {
                        var me = ie as TextEvent;
                        if (me.MetaEventType == MetaEventType.SequenceTrackName)
                        {
                            MidiTrackMap[i].TrackName = me.Text;
                        }
                    }
                    else if (ie is PatchChangeEvent)
                    {
                        // These are the correct events, they happen at the start to set the instrument for a channel
                        // Note that specifically channel 10 is usually interpreted as drums, and the instrument they set on it is arbitrary
                        var    patchChange    = ie as PatchChangeEvent;
                        string instrumentName = "Drums";
                        if (ie.Channel != 10)
                        {
                            instrumentName = PatchChangeEvent.GetPatchName(patchChange.Patch);
                        }
                        var channel = new MidiChannel(instrumentName, ie.Channel);
                        MidiChannelMap[ie.Channel] = channel;
                        MidiChannels.Add(channel);
                    }
                    else if (ie is NoteOnEvent)
                    {
                        var         noteEvent = ie as NoteOnEvent;
                        MidiChannel channel;
                        if (!MidiChannelMap.ContainsKey(ie.Channel))
                        {
                            // We got a note for a channel that never had an instrument set
                            // Initialize it as piano
                            channel = new MidiChannel("Piano (Default)", ie.Channel);
                            MidiChannelMap[ie.Channel] = channel;
                            MidiChannels.Add(channel);
                        }
                        else
                        {
                            channel = MidiChannelMap[ie.Channel];
                        }

                        // If the OffEvent is null, that means this is itself an off event... otherwise it links to the one that ends it
                        if (noteEvent.OffEvent != null && noteEvent.Velocity > 0)
                        {
                            if (channel.HighestNote == null || noteEvent.NoteNumber > channel.HighestNote.Number)
                            {
                                channel.HighestNote = new MidiNote(noteEvent.NoteNumber);
                            }
                            if (channel.LowestNote == null || noteEvent.NoteNumber < channel.LowestNote.Number)
                            {
                                channel.LowestNote = new MidiNote(noteEvent.NoteNumber);
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Return information about a midifile : patch change, copyright, ...
        /// </summary>
        /// <param name="pathfilename"></param>
        /// <param name="Info"></param>
        static public void GeneralInfo(string pathfilename, BuilderInfo Info)
        {
            try
            {
                int NumberBeatsMeasure;
                int NumberQuarterBeat;
                Debug.Log("Open midifile :" + pathfilename);
                MidiLoad midifile = new MidiLoad();
                midifile.Load(pathfilename);
                if (midifile != null)
                {
                    Info.Add(string.Format("Format: {0}", midifile.midifile.FileFormat));
                    Info.Add(string.Format("Tracks: {0}", midifile.midifile.Tracks));
                    Info.Add(string.Format("Ticks Quarter Note: {0}", midifile.midifile.DeltaTicksPerQuarterNote));

                    //if (false)
                    {
                        foreach (TrackMidiEvent trackEvent in midifile.MidiSorted)
                        {
                            if (trackEvent.Event.CommandCode == MidiCommandCode.NoteOn)
                            {
                                // Not used
                                //if (((NoteOnEvent)trackEvent.Event).OffEvent != null)
                                //{
                                //    //infoTrackMidi[e.Channel].Events.Add((NoteOnEvent)e);
                                //    NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event;
                                //}
                            }
                            else if (trackEvent.Event.CommandCode == MidiCommandCode.NoteOff)
                            {
                                Debug.Log("NoteOff");
                            }
                            else if (trackEvent.Event.CommandCode == MidiCommandCode.ControlChange)
                            {
                                // Not used
                                //ControlChangeEvent controlchange = (ControlChangeEvent)e;
                                //Debug.Log(string.Format("CtrlChange  Track:{0} Channel:{1,2:00} {2}", track, e.Channel, controlchange.ToString()));
                            }
                            else if (trackEvent.Event.CommandCode == MidiCommandCode.PatchChange)
                            {
                                PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event;
                                Info.Add(BuildInfoTrack(trackEvent) + string.Format("PatchChange {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch)), 2);
                            }
                            else if (trackEvent.Event.CommandCode == MidiCommandCode.MetaEvent)
                            {
                                MetaEvent meta = (MetaEvent)trackEvent.Event;
                                switch (meta.MetaEventType)
                                {
                                case MetaEventType.SetTempo:
                                    TempoEvent tempo = (TempoEvent)meta;
                                    Info.Add(BuildInfoTrack(trackEvent) + string.Format("SetTempo Tempo:{0} MicrosecondsPerQuarterNote:{1}", Math.Round(tempo.Tempo, 0), tempo.MicrosecondsPerQuarterNote), 2);
                                    //tempo.Tempo
                                    break;

                                case MetaEventType.TimeSignature:

                                    TimeSignatureEvent timesig = (TimeSignatureEvent)meta;
                                    // Numerator: counts the number of beats in a measure.
                                    // For example a numerator of 4 means that each bar contains four beats.

                                    // Denominator: number of quarter notes in a beat.0=ronde, 1=blanche, 2=quarter, 3=eighth, etc.
                                    // Set default value
                                    NumberBeatsMeasure = timesig.Numerator;
                                    NumberQuarterBeat  = System.Convert.ToInt32(System.Math.Pow(2, timesig.Denominator));
                                    Info.Add(BuildInfoTrack(trackEvent) + string.Format("TimeSignature Beats Measure:{0} Beat Quarter:{1}", NumberBeatsMeasure, NumberQuarterBeat), 2);
                                    break;

                                case MetaEventType.SequenceTrackName:   // Sequence / Track Name
                                case MetaEventType.ProgramName:
                                case MetaEventType.TrackInstrumentName: // Track instrument name
                                case MetaEventType.TextEvent:           // Text event
                                case MetaEventType.Copyright:           // Copyright
                                    Info.Add(BuildInfoTrack(trackEvent) + ((TextEvent)meta).Text, 1);
                                    break;

                                case MetaEventType.Lyric:     // lyric
                                case MetaEventType.Marker:    // marker
                                case MetaEventType.CuePoint:  // cue point
                                case MetaEventType.DeviceName:
                                    //Info.Add(BuildInfoTrack(trackEvent) + string.Format("{0} '{1}'", meta.MetaEventType.ToString(), ((TextEvent)meta).Text));
                                    break;
                                }
                            }
                            else
                            {
                                // Other midi event
                                //Debug.Log(string.Format("Track:{0} Channel:{1,2:00} CommandCode:{2,3:000} AbsoluteTime:{3,6:000000}", track, e.Channel, e.CommandCode.ToString(), e.AbsoluteTime));
                            }
                        }
                    }
                    //else DebugMidiSorted(midifile.MidiSorted);
                }
                else
                {
                    Info.Add("Error reading midi file");
                }
            }
            catch (System.Exception ex)
            {
                MidiPlayerGlobal.ErrorDetail(ex);
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Return information about a midifile : patch change, copyright, ...
        /// </summary>
        /// <param name="pathfilename"></param>
        /// <param name="Info"></param>
        static public List <string> GeneralInfo(string pathfilename, bool withNoteOn, bool withNoteOff, bool withControlChange, bool withPatchChange, bool withAfterTouch, bool withMeta, bool withOthers)
        {
            List <string> Info = new List <string>();

            try
            {
                int      NumberBeatsMeasure;
                int      NumberQuarterBeat;
                MidiLoad midifile = new MidiLoad();
                midifile.KeepNoteOff = withNoteOff;
                midifile.MPTK_Load(pathfilename);
                if (midifile != null)
                {
                    Info.Add(string.Format("Format: {0}", midifile.midifile.FileFormat));
                    Info.Add(string.Format("Tracks: {0}", midifile.midifile.Tracks));
                    Info.Add(string.Format("Events count: {0}", midifile.MidiSorted.Count()));
                    Info.Add(string.Format("Duration: {0} ({1} seconds) {2} Ticks", midifile.MPTK_RealDuration, midifile.MPTK_RealDuration.TotalSeconds, midifile.MPTK_TickLast));
                    Info.Add(string.Format("Initial Tempo: {0,0:F2} BPM", midifile.MPTK_InitialTempo));
                    Info.Add(string.Format("Beats in a measure: {0}", midifile.MPTK_NumberBeatsMeasure));
                    Info.Add(string.Format("Quarters count in a beat:{0}", midifile.MPTK_NumberQuarterBeat));
                    Info.Add(string.Format("Ticks per Quarter Note: {0}", midifile.midifile.DeltaTicksPerQuarterNote));
                    Info.Add("");
                    //if (false)
                    {
                        foreach (TrackMidiEvent trackEvent in midifile.MidiSorted)
                        {
                            switch (trackEvent.Event.CommandCode)
                            {
                            case MidiCommandCode.NoteOn:
                                if (withNoteOn)
                                {
                                    if (((NoteOnEvent)trackEvent.Event).OffEvent != null)
                                    {
                                        NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event;
                                        Info.Add(BuildInfoTrack(trackEvent) + string.Format("NoteOn {0,3} ({1,3}) Len:{2,3} Vel:{3,3}", noteon.NoteName, noteon.NoteNumber, noteon.NoteLength, noteon.Velocity));
                                    }
                                }
                                break;

                            case MidiCommandCode.NoteOff:
                                if (withNoteOff)
                                {
                                    NoteEvent noteoff = (NoteEvent)trackEvent.Event;
                                    Info.Add(BuildInfoTrack(trackEvent) + string.Format("NoteOff {0,3} ({1,3}) Vel:{2,3}", noteoff.NoteName, noteoff.NoteNumber, noteoff.Velocity));
                                }
                                break;

                            case MidiCommandCode.PitchWheelChange:
                                if (withOthers)
                                {
                                    PitchWheelChangeEvent aftertouch = (PitchWheelChangeEvent)trackEvent.Event;
                                    Info.Add(BuildInfoTrack(trackEvent) + string.Format("PitchWheelChange {0,3}", aftertouch.Pitch));
                                }
                                break;

                            case MidiCommandCode.KeyAfterTouch:
                                if (withAfterTouch)
                                {
                                    NoteEvent aftertouch = (NoteEvent)trackEvent.Event;
                                    Info.Add(BuildInfoTrack(trackEvent) + string.Format("KeyAfterTouch {0,3} ({1,3}) Pressure:{2,3}", aftertouch.NoteName, aftertouch.NoteNumber, aftertouch.Velocity));
                                }
                                break;

                            case MidiCommandCode.ChannelAfterTouch:
                                if (withAfterTouch)
                                {
                                    ChannelAfterTouchEvent aftertouch = (ChannelAfterTouchEvent)trackEvent.Event;
                                    Info.Add(BuildInfoTrack(trackEvent) + string.Format("ChannelAfterTouch Pressure:{0,3}", aftertouch.AfterTouchPressure));
                                }
                                break;

                            case MidiCommandCode.ControlChange:
                                if (withControlChange)
                                {
                                    ControlChangeEvent controlchange = (ControlChangeEvent)trackEvent.Event;
                                    Info.Add(BuildInfoTrack(trackEvent) + string.Format("ControlChange {0,3} ({1,3}) Value:{2,3}", controlchange.Controller, controlchange.Controller, controlchange.ControllerValue));
                                }
                                break;

                            case MidiCommandCode.PatchChange:
                                if (withPatchChange)
                                {
                                    PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event;
                                    Info.Add(BuildInfoTrack(trackEvent) + string.Format("PatchChange {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch)));
                                }
                                break;

                            case MidiCommandCode.MetaEvent:
                                if (withMeta)
                                {
                                    MetaEvent meta = (MetaEvent)trackEvent.Event;
                                    switch (meta.MetaEventType)
                                    {
                                    case MetaEventType.SetTempo:
                                        TempoEvent tempo = (TempoEvent)meta;
                                        Info.Add(BuildInfoTrack(trackEvent) + string.Format("SetTempo Tempo:{0} MicrosecondsPerQuarterNote:{1}", Math.Round(tempo.Tempo, 0), tempo.MicrosecondsPerQuarterNote));
                                        //tempo.Tempo
                                        break;

                                    case MetaEventType.TimeSignature:
                                        TimeSignatureEvent timesig = (TimeSignatureEvent)meta;
                                        // Numerator: counts the number of beats in a measure.
                                        // For example a numerator of 4 means that each bar contains four beats.

                                        // Denominator: number of quarter notes in a beat.0=ronde, 1=blanche, 2=quarter, 3=eighth, etc.
                                        // Set default value
                                        NumberBeatsMeasure = timesig.Numerator;
                                        NumberQuarterBeat  = System.Convert.ToInt32(Mathf.Pow(2, timesig.Denominator));
                                        Info.Add(BuildInfoTrack(trackEvent) + string.Format("TimeSignature Beats Measure:{0} Beat Quarter:{1}", NumberBeatsMeasure, NumberQuarterBeat));
                                        break;

                                    default:
                                        string text = meta is TextEvent ? " '" + ((TextEvent)meta).Text + "'" : "";
                                        Info.Add(BuildInfoTrack(trackEvent) + meta.MetaEventType.ToString() + text);
                                        break;
                                    }
                                }
                                break;

                            default:
                                // Other midi event
                                if (withOthers)
                                {
                                    Info.Add(BuildInfoTrack(trackEvent) + string.Format(" {0} ({1})", trackEvent.Event.CommandCode, (int)trackEvent.Event.CommandCode));
                                }
                                break;
                            }
                        }
                    }
                    //else DebugMidiSorted(midifile.MidiSorted);
                }
                else
                {
                    Info.Add("Error reading midi file");
                }
            }
            catch (System.Exception ex)
            {
                MidiPlayerGlobal.ErrorDetail(ex);
            }
            return(Info);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Add a TrackMidiEvent to a list of MPTKEvent.
        /// </summary>
        /// <param name="mptkEvents">Must be alloc before the call</param>
        /// <param name="trackEvent"></param>
        /// <returns></returns>

        private bool ConvertToEventForNote(List <MPTKEvent> mptkEvents, TrackMidiEvent trackEvent)
        {
            bool      exitLoop  = false;
            MPTKEvent midievent = null;

            switch (trackEvent.Event.CommandCode)
            {
            case MidiCommandCode.NoteOn:

                if (((NoteOnEvent)trackEvent.Event).OffEvent != null)
                {
                    NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event;
                    //Debug.Log(string.Format("Track:{0} NoteNumber:{1,3:000} AbsoluteTime:{2,6:000000} NoteLength:{3,6:000000} OffDeltaTime:{4,6:000000} ", track, noteon.NoteNumber, noteon.AbsoluteTime, noteon.NoteLength, noteon.OffEvent.DeltaTime));
                    if (noteon.NoteLength > 0)
                    {
                        midievent = new MPTKEvent()
                        {
                            Tick     = trackEvent.AbsoluteQuantize,
                            Command  = MPTKCommand.NoteOn,
                            Value    = noteon.NoteNumber,
                            Channel  = trackEvent.Event.Channel - 1,
                            Velocity = noteon.Velocity,
                            Duration = noteon.NoteLength * TickLengthMs,
                            Length   = noteon.NoteLength,
                        };
                        //mptkEvents.Add(midievent);

                        // show playing note
                        //Debug.Log(midievent.Channel);
                        if (midievent.Channel == selectedChannel)
                        {
                            Kbd_PKeyGen.instance.ShowMidiNoteOn(noteon.NoteNumber);
                        }

                        if (LogEvents)
                        {
                            string notename = (midievent.Channel != 9) ?
                                              String.Format("{0}{1}", NoteNames[midievent.Value % 12], midievent.Value / 12) : "Drum";
                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("NoteOn  {0,3:000}\t{1,-4}\tLenght:{2,5}\t{3}\tVeloc:{4,3}",
                                                                                 midievent.Value, notename, noteon.NoteLength, NoteLength(midievent), noteon.Velocity));
                        }
                    }
                    else if (KeepNoteOff)
                    {
                        midievent = CreateNoteOffForNote(mptkEvents, trackEvent);
                    }
                }
                break;

            case MidiCommandCode.NoteOff:
                midievent = CreateNoteOffForNote(mptkEvents, trackEvent);
                break;

            case MidiCommandCode.ControlChange:

                ControlChangeEvent controlchange = (ControlChangeEvent)trackEvent.Event;
                midievent = new MPTKEvent()
                {
                    Tick       = trackEvent.AbsoluteQuantize,
                    Command    = MPTKCommand.ControlChange,
                    Channel    = trackEvent.Event.Channel - 1,
                    Controller = (MPTKController)controlchange.Controller,
                    Value      = controlchange.ControllerValue,
                };
                mptkEvents.Add(midievent);

                // Other midi event
                if (LogEvents)
                {
                    Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Control {0} {1}", controlchange.Controller, controlchange.ControllerValue));
                }

                break;

            case MidiCommandCode.PatchChange:
                PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event;
                midievent = new MPTKEvent()
                {
                    Tick    = trackEvent.AbsoluteQuantize,
                    Command = MPTKCommand.PatchChange,
                    Channel = trackEvent.Event.Channel - 1,
                    Value   = change.Patch,
                };
                mptkEvents.Add(midievent);
                if (LogEvents)
                {
                    Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Patch   {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch)));
                }
                break;

            case MidiCommandCode.MetaEvent:
                MetaEvent meta = (MetaEvent)trackEvent.Event;
                midievent = new MPTKEvent()
                {
                    Tick    = trackEvent.AbsoluteQuantize,
                    Command = MPTKCommand.MetaEvent,
                    Channel = trackEvent.Event.Channel - 1,
                    Meta    = (MPTKMeta)meta.MetaEventType,
                };

                switch (meta.MetaEventType)
                {
                case MetaEventType.TimeSignature:
                    AnalyzeTimeSignature(meta);
                    break;

                case MetaEventType.SetTempo:
                    TempoEvent tempo = (TempoEvent)meta;
                    // Tempo change will be done in MidiFilePlayer
                    midievent.Duration = tempo.Tempo;
                    MPTK_MicrosecondsPerQuarterNote = tempo.MicrosecondsPerQuarterNote;
                    // Force exit loop
                    exitLoop = true;
                    break;

                case MetaEventType.SequenceTrackName:
                    midievent.Info = ((TextEvent)meta).Text;
                    if (!string.IsNullOrEmpty(SequenceTrackName))
                    {
                        SequenceTrackName += "\n";
                    }
                    SequenceTrackName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, midievent.Info);
                    //if (LogEvents) Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Sequence   '{0}'", note.Info));
                    break;

                case MetaEventType.ProgramName:
                    midievent.Info = ((TextEvent)meta).Text;
                    ProgramName   += midievent.Info + " ";
                    //if (LogEvents) Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Program   '{0}'", note.Info));
                    break;

                case MetaEventType.TrackInstrumentName:
                    midievent.Info = ((TextEvent)meta).Text;
                    if (!string.IsNullOrEmpty(TrackInstrumentName))
                    {
                        TrackInstrumentName += "\n";
                    }
                    TrackInstrumentName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, midievent.Info);
                    //if (LogEvents) Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Text      '{0}'", ((TextEvent)meta).Text));
                    break;

                case MetaEventType.TextEvent:
                    midievent.Info = ((TextEvent)meta).Text;
                    TextEvent     += midievent.Info + " ";
                    //if (LogEvents) Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Sequence  '{0}'", ((TextEvent)meta).Text));
                    break;

                case MetaEventType.Copyright:
                    midievent.Info = ((TextEvent)meta).Text;
                    Copyright     += midievent.Info + " ";
                    //if (LogEvents) Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Copyright '{0}'", ((TextEvent)meta).Text));
                    break;

                case MetaEventType.Lyric:         // lyric
                    midievent.Info = ((TextEvent)meta).Text;
                    break;

                case MetaEventType.Marker:         // marker
                case MetaEventType.CuePoint:       // cue point
                case MetaEventType.DeviceName:
                    break;
                }

                if (LogEvents && !string.IsNullOrEmpty(midievent.Info))
                {
                    Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta    {0,15} '{1}'", midievent.Meta, midievent.Info));
                }

                mptkEvents.Add(midievent);
                //Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0} {1}", meta.MetaEventType, meta.ToString()));
                break;

            default:
                // Other midi event
                if (LogEvents)
                {
                    Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Other   {0,15} Not handle by MPTK", trackEvent.Event.CommandCode));
                }
                break;
            }

            return(exitLoop);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Add a TrackMidiEvent to a list of MPTKEvent.
        /// </summary>
        /// <param name="mptkEvents">Must be alloc before the call</param>
        /// <param name="trackEvent"></param>
        /// <returns></returns>
        private void ConvertToEvent(List <MPTKEvent> mptkEvents, TrackMidiEvent trackEvent)
        {
            MPTKEvent midievent = null;

            switch (trackEvent.Event.CommandCode)
            {
            case MidiCommandCode.NoteOn:
                //if (((NoteOnEvent)trackEvent.Event).OffEvent != null)
            {
                NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event;
                //Debug.Log(string.Format("Track:{0} NoteNumber:{1,3:000} AbsoluteTime:{2,6:000000} NoteLength:{3,6:000000} OffDeltaTime:{4,6:000000} ", track, noteon.NoteNumber, noteon.AbsoluteTime, noteon.NoteLength, noteon.OffEvent.DeltaTime));
                if (noteon.OffEvent != null)
                {
                    midievent = new MPTKEvent()
                    {
                        Track    = trackEvent.IndexTrack,
                        Tick     = trackEvent.AbsoluteQuantize,
                        Command  = MPTKCommand.NoteOn,
                        Value    = noteon.NoteNumber,
                        Channel  = trackEvent.Event.Channel - 1,
                        Velocity = noteon.Velocity,
                        Duration = Convert.ToInt64(noteon.NoteLength * MPTK_PulseLenght),
                        Length   = noteon.NoteLength,
                    };
                    mptkEvents.Add(midievent);
                    if (LogEvents && seek_ticks < 0)
                    {
                        string notename = (midievent.Channel != 9) ?
                                          String.Format("{0}{1}", NoteNames[midievent.Value % 12], midievent.Value / 12) : "Drum";
                        Debug.Log(BuildInfoTrack(trackEvent) + string.Format("NoteOn  {0,3:000}\t{1,-4}\tLenght:{2,5}\t{3}\tVeloc:{4,3}",
                                                                             midievent.Value, notename, noteon.NoteLength, NoteLength(midievent), noteon.Velocity));
                    }
                }
                else         // It's a noteoff
                {
                    if (KeepNoteOff)
                    {
                        midievent = new MPTKEvent()
                        {
                            Track    = trackEvent.IndexTrack,
                            Tick     = trackEvent.AbsoluteQuantize,
                            Command  = MPTKCommand.NoteOff,
                            Value    = noteon.NoteNumber,
                            Channel  = trackEvent.Event.Channel - 1,
                            Velocity = noteon.Velocity,
                            Duration = Convert.ToInt64(noteon.NoteLength * MPTK_PulseLenght),
                            Length   = noteon.NoteLength,
                        };
                        mptkEvents.Add(midievent);

                        if (LogEvents && seek_ticks < 0)
                        {
                            string notename = (midievent.Channel != 9) ?
                                              String.Format("{0}{1}", NoteNames[midievent.Value % 12], midievent.Value / 12) : "Drum";
                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("NoteOff {0,3:000}\t{1,-4}\tLenght:{2}", midievent.Value, notename, " Note Off"));
                        }
                    }
                }
            }
            break;

            case MidiCommandCode.NoteOff:
                if (KeepNoteOff)
                {
                    NoteEvent noteoff = (NoteEvent)trackEvent.Event;
                    //Debug.Log(string.Format("Track:{0} NoteNumber:{1,3:000} AbsoluteTime:{2,6:000000} NoteLength:{3,6:000000} OffDeltaTime:{4,6:000000} ", track, noteon.NoteNumber, noteon.AbsoluteTime, noteon.NoteLength, noteon.OffEvent.DeltaTime));
                    midievent = new MPTKEvent()
                    {
                        Track    = trackEvent.IndexTrack,
                        Tick     = trackEvent.AbsoluteQuantize,
                        Command  = MPTKCommand.NoteOff,
                        Value    = noteoff.NoteNumber,
                        Channel  = trackEvent.Event.Channel - 1,
                        Velocity = noteoff.Velocity,
                        Duration = 0,
                        Length   = 0,
                    };

                    mptkEvents.Add(midievent);

                    if (LogEvents && seek_ticks < 0)
                    {
                        string notename = (midievent.Channel != 9) ?
                                          String.Format("{0}{1}", NoteNames[midievent.Value % 12], midievent.Value / 12) : "Drum";
                        Debug.Log(BuildInfoTrack(trackEvent) + string.Format("NoteOff {0,3:000}\t{1,-4}\tLenght:{2}", midievent.Value, notename, " Note Off"));
                    }
                }
                break;

            case MidiCommandCode.PitchWheelChange:
                PitchWheelChangeEvent pitch = (PitchWheelChangeEvent)trackEvent.Event;
                midievent = new MPTKEvent()
                {
                    Track   = trackEvent.IndexTrack,
                    Tick    = trackEvent.AbsoluteQuantize,
                    Command = MPTKCommand.PitchWheelChange,
                    Channel = trackEvent.Event.Channel - 1,
                    Value   = pitch.Pitch,    // Pitch Wheel Value 0 is minimum, 0x2000 (8192) is default, 0x3FFF (16383) is maximum
                };
                mptkEvents.Add(midievent);
                if (LogEvents && seek_ticks < 0)
                {
                    Debug.Log(BuildInfoTrack(trackEvent) + string.Format("PitchWheelChange {0}", pitch.Pitch));
                }
                break;

            case MidiCommandCode.ControlChange:
                ControlChangeEvent controlchange = (ControlChangeEvent)trackEvent.Event;
                midievent = new MPTKEvent()
                {
                    Track      = trackEvent.IndexTrack,
                    Tick       = trackEvent.AbsoluteQuantize,
                    Command    = MPTKCommand.ControlChange,
                    Channel    = trackEvent.Event.Channel - 1,
                    Controller = (MPTKController)controlchange.Controller,
                    Value      = controlchange.ControllerValue,
                };

                //if ((MPTKController)controlchange.Controller != MPTKController.Sustain)
                mptkEvents.Add(midievent);

                // Other midi event
                if (LogEvents && seek_ticks < 0)
                {
                    Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Control {0} {1}", controlchange.Controller, controlchange.ControllerValue));
                }

                break;

            case MidiCommandCode.PatchChange:
                PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event;
                midievent = new MPTKEvent()
                {
                    Track   = trackEvent.IndexTrack,
                    Tick    = trackEvent.AbsoluteQuantize,
                    Command = MPTKCommand.PatchChange,
                    Channel = trackEvent.Event.Channel - 1,
                    Value   = change.Patch,
                };
                mptkEvents.Add(midievent);
                if (LogEvents && seek_ticks < 0)
                {
                    Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Patch   {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch)));
                }
                break;

            case MidiCommandCode.MetaEvent:
                MetaEvent meta = (MetaEvent)trackEvent.Event;
                midievent = new MPTKEvent()
                {
                    Track   = trackEvent.IndexTrack,
                    Tick    = trackEvent.AbsoluteQuantize,
                    Command = MPTKCommand.MetaEvent,
                    Channel = trackEvent.Event.Channel - 1,
                    Meta    = (MPTKMeta)meta.MetaEventType,
                };

                switch (meta.MetaEventType)
                {
                case MetaEventType.EndTrack:
                    midievent.Info = "End Track";
                    break;

                case MetaEventType.TimeSignature:
                    AnalyzeTimeSignature(meta, trackEvent);
                    break;

                case MetaEventType.SetTempo:
                    if (EnableChangeTempo)
                    {
                        TempoEvent tempo = (TempoEvent)meta;
                        // Tempo change will be done in MidiFilePlayer
                        midievent.Duration = (long)tempo.Tempo;
                        MPTK_MicrosecondsPerQuarterNote = tempo.MicrosecondsPerQuarterNote;
                        fluid_player_set_midi_tempo(tempo.MicrosecondsPerQuarterNote);

                        // Force exit loop
                        if (LogEvents && seek_ticks < 0)
                        {
                            Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta     {0,-15} Tempo:{1} MicrosecondsPerQuarterNote:{2}", meta.MetaEventType, tempo.Tempo, tempo.MicrosecondsPerQuarterNote));
                        }
                    }
                    break;

                case MetaEventType.SequenceTrackName:
                    midievent.Info = ((TextEvent)meta).Text;
                    if (!string.IsNullOrEmpty(SequenceTrackName))
                    {
                        SequenceTrackName += "\n";
                    }
                    SequenceTrackName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, midievent.Info);
                    break;

                case MetaEventType.ProgramName:
                    midievent.Info = ((TextEvent)meta).Text;
                    ProgramName   += midievent.Info + " ";
                    break;

                case MetaEventType.TrackInstrumentName:
                    midievent.Info = ((TextEvent)meta).Text;
                    if (!string.IsNullOrEmpty(TrackInstrumentName))
                    {
                        TrackInstrumentName += "\n";
                    }
                    TrackInstrumentName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, midievent.Info);
                    break;

                case MetaEventType.TextEvent:
                    midievent.Info = ((TextEvent)meta).Text;
                    TextEvent     += midievent.Info + " ";
                    break;

                case MetaEventType.Copyright:
                    midievent.Info = ((TextEvent)meta).Text;
                    Copyright     += midievent.Info + " ";
                    break;

                case MetaEventType.Lyric:         // lyric
                    midievent.Info = ((TextEvent)meta).Text;
                    TextEvent     += midievent.Info + " ";
                    break;

                case MetaEventType.Marker:         // marker
                    midievent.Info = ((TextEvent)meta).Text;
                    TextEvent     += midievent.Info + " ";
                    break;

                case MetaEventType.CuePoint:         // cue point
                case MetaEventType.DeviceName:
                    break;
                }

                if (LogEvents && !string.IsNullOrEmpty(midievent.Info) && seek_ticks < 0)
                {
                    Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta     {0,-15} '{1}'", midievent.Meta, midievent.Info));
                }

                mptkEvents.Add(midievent);
                //Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0} {1}", meta.MetaEventType, meta.ToString()));
                break;

            default:
                // Other midi event
                if (LogEvents && seek_ticks < 0)
                {
                    Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Other    {0,-15} Not handle by MPTK", trackEvent.Event.CommandCode));
                }
                break;
            }
        }
Ejemplo n.º 8
0
 PatchInfo(int id)
 {
     Id      = id;
     Caption = PatchChangeEvent.GetPatchName(id);
 }
Ejemplo n.º 9
0
        private static List <TimeSlice> ReadMidiFile(MidiFile mf, ICollection <int> tracksToSkip, double tempoRatio, bool skipDrums)
        {
            var timeSliceList = new List <TimeSlice>();

            var tempo = (int)Math.Round(120 * tempoRatio);

            Console.WriteLine("Default Tempo: {0}", tempo);

            var trackNumber = 0;

            foreach (var midiEventList in mf.Events)
            {
                Console.WriteLine("");
                Console.WriteLine("Track #{0}", trackNumber);
                Console.WriteLine("---------");

                if (tracksToSkip.Contains(trackNumber))
                {
                    trackNumber++;
                    continue;
                }

                Console.WriteLine("Track length: {0}", midiEventList.Count);

                var drumFilteredMidiEventList = midiEventList.Where(midiEvent => !skipDrums || (midiEvent.Channel != 10));

                foreach (var midiEvent in drumFilteredMidiEventList)
                {
                    if (midiEvent is TextEvent textEvent) // : MetaEvent
                    {
                        Console.WriteLine("{0}: {1}", textEvent.MetaEventType.ToString(), textEvent.Text);
                    }
                    else if (midiEvent is TimeSignatureEvent timeSignatureEvent) // : MetaEvent
                    {
                        //WriteWarningLine("TimeSignatureEvent", timeSignatureEvent.ToString());
                    }
                    else if (midiEvent is TrackSequenceNumberEvent trackSequenceNumberEvent) // : MetaEvent
                    {
                        WriteWarningLine("TrackSequenceNumberEvent", trackSequenceNumberEvent.ToString());
                    }
                    else if (midiEvent is KeySignatureEvent keySignatureEvent) // : MetaEvent
                    {
                        //WriteWarningLine("KeySignatureEvent", keySignatureEvent.ToString());
                    }
                    else if (midiEvent is TempoEvent tempoEvent) // : MetaEvent
                    {
                        tempo = (int)Math.Round(tempoEvent.Tempo * tempoRatio);
                        Console.WriteLine("Tempo: {0}", tempo);
                    }
                    else if (midiEvent is MetaEvent metaEvent)
                    {
                        if ((metaEvent.MetaEventType != MetaEventType.SequencerSpecific) && (metaEvent.MetaEventType != MetaEventType.EndTrack) && (metaEvent.MetaEventType != MetaEventType.MidiChannel) && (metaEvent.MetaEventType != MetaEventType.MidiPort))
                        {
                            WriteWarningLine("MetaEvent", metaEvent.ToString());
                        }
                    }
                    else if (midiEvent is ControlChangeEvent controlChangeEvent)
                    {
                        //WriteWarningLine("ControlChangeEvent", controlChangeEvent.ToString());
                    }
                    else if (midiEvent is PatchChangeEvent patchChangeEvent)
                    {
                        Console.WriteLine("Patch: {0}", PatchChangeEvent.GetPatchName(patchChangeEvent.Patch));

                        if (skipDrums && (patchChangeEvent.Patch >= 112))
                        {
                            Console.WriteLine("Skipping track...");
                            break;
                        }
                    }
                    else if (midiEvent is NoteOnEvent noteEvent1)
                    {
                        if (MidiEvent.IsNoteOff(noteEvent1) == false)
                        {
                            if (noteEvent1.OffEvent != null)
                            {
                                var ticksPerMinute      = mf.DeltaTicksPerQuarterNote * tempo;
                                var millisecondsPerTick = 60.0 * 1000.0 / ticksPerMinute;

                                var start = (int)Math.Round(noteEvent1.AbsoluteTime * millisecondsPerTick);
                                var stop  = (int)Math.Round(noteEvent1.OffEvent.AbsoluteTime * millisecondsPerTick);

                                timeSliceList.Add(new TimeSlice(start, stop, new Note(noteEvent1.NoteNumber, noteEvent1.Velocity)));
                            }
                            else
                            {
                                WriteWarningLine("NoteOnEvent", "No Corresponding Note Off Event");
                            }
                        }
                    }
                    else if (midiEvent is NoteEvent noteEvent)
                    {
                        if (noteEvent.CommandCode != MidiCommandCode.NoteOff)
                        {
                            WriteWarningLine("NoteEvent", noteEvent.ToString());
                        }
                    }
                    else
                    {
                        WriteWarningLine("MIDI Event Type", midiEvent.GetType().ToString());
                    }
                }

                trackNumber++;
            }

            timeSliceList.Sort(CompareTimeSlicesByStartTime);

            return(timeSliceList);
        }