Example #1
0
        public void HandleEvent(int track, MidiEvent e)
        {
            if (e.status == 0xff && e.type == 0x51)                // meta tempo
            {
                int i = e.dataLoc;
                // 24-bit value specifying the tempo as the number of microseconds per beat
                int microsecondsPerBeat = BitBe.ReadInt24(file.bytes, ref i);
                beatsPerSecond = (1000000f / microsecondsPerBeat);
                Debug.LogFormat("meta: {0} tempo", microsecondsPerBeat);
            }

            byte channel = (byte)(e.status & 0xf);

            DispatchChannelEvent(channel, e.status, e.b1, e.b2);

            for (int i = 0, count = routes.Count; i < count; i += 1)
            {
                var r = routes[i];
                if (r.trackIn == track && r.channelIn == channel)
                {
                    DispatchChannelEvent(r.channelOut, e.status, e.b1, e.b2);
                }
            }
        }
Example #2
0
        public MidiFile(byte[] bytes)
        {
            this.bytes = bytes;

            int i = 0;

            // "MThd" 4 bytes
            i += 4;
            // <header_length> 4 bytes
            int length = BitBe.ReadInt32(bytes, ref i);
            int ii     = i;

            // <format> 2 bytes
            format = BitBe.ReadInt16(bytes, ref i);
            // <n> 2 bytes
            trackCount   = BitBe.ReadInt16(bytes, ref i);
            tracks       = new MidiEvent[trackCount][];
            trackLengths = new int[trackCount];
            trackTicks   = new int[trackCount];
            // <division> 2 bytes
            ticksPerBeat = BitBe.ReadInt16(bytes, ref i);
            // end chunk
            i = ii + length;

            byte runingStatus = 0;

            for (short j = 0, count = trackCount; j < count; j += 1)
            {
                var trackEventList = new List <MidiEvent>();

                // "MTrk" 4 bytes
                i += 4;
                // <length> 4 bytes
                length = BitBe.ReadInt32(bytes, ref i);
                ii     = i;
                // <track_event>
                int k = 0;
                while (i < ii + length)
                {
                    int delta = BitBe.ReadVlv(bytes, ref i);
                    trackTicks[j] += delta;
                    int  trackTick  = trackTicks[j];
                    byte statusByte = Bit.ReadByte(bytes, ref i);
                    int  dataLength;
                    if (statusByte < 0x80)                        // running status
                    {
                        dataLength = GetMidiEventLength(runingStatus);
                        trackEventList.Add(new MidiEvent(j, k, delta, trackTick, runingStatus, 0, i - 1, dataLength, bytes));
                        dataLength -= 1;
                    }
                    else if (statusByte < 0xf0)                          // midi events
                    {
                        runingStatus = statusByte;
                        dataLength   = GetMidiEventLength(statusByte);
                        trackEventList.Add(new MidiEvent(j, k, delta, trackTick, statusByte, 0, i, dataLength, bytes));
                    }
                    else if (statusByte == 0xf0 || statusByte == 0xf7)                          // sysex events | escape sequences
                    {
                        dataLength = BitBe.ReadVlv(bytes, ref i);
                        trackEventList.Add(new MidiEvent(j, k, delta, trackTick, statusByte, 0, i, dataLength, bytes));
                    }
                    else if (statusByte == 0xff)                          // meta events
                    {
                        byte type = Bit.ReadByte(bytes, ref i);
                        dataLength = BitBe.ReadVlv(bytes, ref i);
                        trackEventList.Add(new MidiEvent(j, k, delta, trackTick, statusByte, type, i, dataLength, bytes));
                    }
                    else
                    {
                        return;
                    }
                    i += dataLength;
                    k += 1;
                }
                tracks[j]       = trackEventList.ToArray();
                trackLengths[j] = trackEventList.Count;
                // end chunk
                i = ii + length;
            }

            var combinedEventList = new List <MidiEvent>();

            for (int j = 0; j < trackCount; j++)
            {
                combinedEventList.AddRange(tracks[j]);
            }
            combinedEventList.Sort((a, b) => {
                if (a.tick == b.tick)
                {
                    if (a.track == b.track)
                    {
                        return(a.index.CompareTo(b.index));
                    }
                    return(a.track.CompareTo(b.track));
                }
                return(a.tick.CompareTo(b.tick));
            });
            combinedTrack = combinedEventList.ToArray();
        }
Example #3
0
        void Parse()
        {
            var seq = new Sequence();

            // default tempo 120 bpm
            float beatsPerSecond = 2;
            int   ticks          = 0;
            float seconds        = 0;

            byte[] channelPrograms = new byte[16];

            for (int i = 0; i < file.combinedTrack.Length; i++)
            {
                var  e       = file.combinedTrack[i];
                byte channel = (byte)(e.status & 0xf);
                seq = SwitchWorkingSequence(seq, e.track, channel, channelPrograms[channel]);
                int tickDiff = e.tick - ticks;
                ticks    = e.tick;
                seconds += tickDiff / (beatsPerSecond * file.ticksPerBeat);


                switch (e.status >> 4)
                {
                case 0x8:                          // note off
                    //UnityEngine.Debug.LogFormat("off {3} track {0} tick {1} seconds {2}", e.track, e.tick, seconds, e.b1);
                    NoteOff(seq, e.tick, seconds, e.b1);
                    break;

                case 0x9:                          // note on
                    //UnityEngine.Debug.LogFormat("on {3} track {0} tick {1} seconds {2}", e.track, e.tick, seconds, e.b1);
                    if (e.b2 == 0)
                    {
                        NoteOff(seq, e.tick, seconds, e.b1);
                    }
                    else
                    {
                        seq.notes.Add(new Note {
                            track = e.track, channel = channel, note = e.b1, velocity = e.b2, start = e.tick, startSeconds = seconds
                        });
                    }
                    break;

                case 0xc:                          // program change
                    //UnityEngine.Debug.LogFormat("prog track {0} tick {1} seconds {2}", e.track, e.tick, seconds);
                    channelPrograms[channel] = e.b1;
                    seq = SwitchWorkingSequence(seq, e.track, seq.channel, e.b1);
                    break;

                case 0xff:                          // meta
                    if (e.type == 0x51)             // tempo
                    //UnityEngine.Debug.LogFormat("temp track {0} tick {1} seconds {2}", e.track, e.tick, seconds);
                    {
                        int start = e.dataLoc;
                        // 24-bit value specifying the tempo as the number of microseconds per beat
                        int microsecondsPerBeat = BitBe.ReadInt24(file.bytes, ref start);
                        beatsPerSecond = 1000000f / microsecondsPerBeat;
                    }
                    break;
                }
            }

            if (seq.notes.Count > 0 && !sequences.Contains(seq))
            {
                sequences.Add(seq);
            }
            sequences.Sort((a, b) => {
                if (a.track == b.track)
                {
                    if (a.channel == b.channel)
                    {
                        return(a.program.CompareTo(b.program));
                    }
                    return(a.channel.CompareTo(b.channel));
                }
                return(a.track.CompareTo(b.track));
            });

            int  trackGroupIndex   = 0;
            byte channelGroupIndex = 0;
            byte programGroupIndex = 0;
            var  trackGroupDict    = new Dictionary <int, int>();
            var  channelGroupDict  = new Dictionary <byte, byte>();
            var  programGroupDict  = new Dictionary <byte, byte>();

            start = end = -1;
            for (int i = 0; i < sequences.Count; i++)
            {
                seq = sequences[i];

                if (!trackGroupDict.ContainsKey(seq.track))
                {
                    trackGroupDict.Add(seq.track, trackGroupIndex);
                    trackGroupIndex += 1;
                }
                if (!channelGroupDict.ContainsKey(seq.channel))
                {
                    channelGroupDict.Add(seq.channel, channelGroupIndex);
                    channelGroupIndex += 1;
                }
                if (!programGroupDict.ContainsKey(seq.program))
                {
                    programGroupDict.Add(seq.program, programGroupIndex);
                    programGroupIndex += 1;
                }
                seq.trackGroup   = trackGroupDict[seq.track];
                seq.channelGroup = channelGroupDict[seq.channel];
                seq.programGroup = programGroupDict[seq.program];

                noteCount += seq.notes.Count;

                seq.start = seq.notes[0].start;
                if (start == -1 || seq.start < start)
                {
                    start = seq.start;
                }
                int seqEnd = seq.notes[0].end;
                for (int j = 0; j < seq.notes.Count; j++)
                {
                    var n = seq.notes[j];
                    if (seqEnd < n.end)
                    {
                        seqEnd = n.end;
                    }
                    if (n.end == 0)
                    {
                        UnityEngine.Debug.LogErrorFormat("Note is never off: {0} tr {1} ch {2} start {3} seq {4} tr {5} ch {6} prog {7}",
                                                         n.note, n.track, n.channel, n.start, seq.index, seq.track, seq.channel, seq.program);
                    }
                }
                seq.end = seqEnd;
                if (end == -1 || seq.end > end)
                {
                    end = seq.end;
                }
            }

            trackGroups   = trackGroupDict.Keys.ToArray();
            channelGroups = channelGroupDict.Keys.ToArray();
            programGroups = programGroupDict.Keys.ToArray();
        }