Example #1
0
        private void Decode(byte[] message)
        {
            byte status = message[0];

            switch (status & 0b1111_0000)
            {
            case Midi.Status.NoteOffBitmask:
                if (NoteOffMessage.TryDecode(message, out var noteOffMessage))
                {
                    NoteOff?.Invoke(this, in noteOffMessage);
                }
                break;

            case Midi.Status.NoteOnBitmask:
                if (NoteOnMessage.TryDecoce(message, out var noteOnMessage))
                {
                    NoteOn?.Invoke(this, in noteOnMessage);
                }
                break;

            case Midi.Status.PolyphonicKeyPressureBitmask:
                if (PolyphonicKeyPressureMessage.TryDecode(message, out var polyphonicKeyPressureMessage))
                {
                    PolyphonicKeyPressure?.Invoke(this, in polyphonicKeyPressureMessage);
                }
                break;

            case Midi.Status.ControlChangeBitmask:
                if (ControlChangeMessage.TryDecode(message, out var controlChangeMessage))
                {
                    _nrpnInterpreters[(int)controlChangeMessage.Channel].HandleControlChangeMessage(in controlChangeMessage);
                }
                break;

            case Midi.Status.ProgramChangeBitmask:
                if (ProgramChangeMessage.TryDecode(message, out var programChangeMessage))
                {
                    ProgramChange?.Invoke(this, in programChangeMessage);
                }
                break;

            case Midi.Status.ChannelPressureBitmask:
                if (ChannelPressureMessage.TryDecode(message, out var channelPressureMessage))
                {
                    ChannelPressure?.Invoke(this, in channelPressureMessage);
                }
                break;

            case Midi.Status.PitchBendChange:
                if (PitchBendMessage.TryDecode(message, out var pitchBendMessage))
                {
                    PitchBend?.Invoke(this, in pitchBendMessage);
                }
                break;

            default:
                Log.Error("Unknown message type {Bitmask}", $"{status & 0b1111_0000:X2}");
                break;
            }
        }
Example #2
0
        /// <summary>Parse a voice event from the data stream.</summary>
        /// <param name="deltaTime">The previously parsed delta-time for this event.</param>
        /// <param name="messageType">The previously parsed type of message we're expecting to find.</param>
        /// <param name="channel">The previously parsed channel for this message.</param>
        /// <param name="data">The data stream from which to read the event information.</param>
        /// <param name="pos">The position of the start of the event information.</param>
        /// <returns>The parsed voice MIDI event.</returns>
        private static MidiEvent ParseVoiceEvent(long deltaTime, byte messageType, byte channel, byte [] data, ref long pos)
        {
            try
            {
                MidiEvent tempEvent = null;

                // Create the correct voice event based on its message id/type
                switch (messageType)
                {
                // NOTE OFF
                case 0x8:
                    // **Adding this check seems to make GH1 mids work....GH2s are
                    //   a little more complicated**
                    if (pos < data.GetLength(0) - 1)
                    {
                        tempEvent = new NoteOff(deltaTime, channel, data[pos], data[pos + 1]);
                    }
                    pos += 2;
                    break;

                // NOTE ON
                case 0x9:
                    tempEvent = new NoteOn(deltaTime, channel, data[pos], data[pos + 1]);
                    pos      += 2;
                    break;

                // AFTERTOUCH
                case 0xA:
                    tempEvent = new Aftertouch(deltaTime, channel, data[pos], data[pos + 1]);
                    pos      += 2;
                    break;

                // CONTROLLER
                case 0xB:
                    tempEvent = new Controller(deltaTime, channel, data[pos], data[pos + 1]);
                    pos      += 2;
                    break;

                // PROGRAM CHANGE
                case 0xC:
                    tempEvent = new ProgramChange(deltaTime, channel, data[pos]);
                    pos      += 1;
                    break;

                // CHANNEL PRESSURE
                case 0xD:
                    tempEvent = new ChannelPressure(deltaTime, channel, data[pos]);
                    pos      += 1;
                    break;

                // PITCH WHEEL
                case 0xE:
                    int  position = ((data[pos] << 8) | data[pos + 1]);
                    byte upper, lower;
                    MidiEvent.Split14BitsToBytes(position, out upper, out lower);
                    tempEvent = new PitchWheel(deltaTime, channel, upper, lower);
                    pos      += 2;
                    break;

                // UH OH!
                default: throw new ArgumentOutOfRangeException("messageType", messageType, "Not a voice message.");
                }

                // Return the newly parsed event
                return(tempEvent);
            }
            // Something bad happened; wrap it in a parser exception
            catch (Exception exc) { throw new MidiParserException("Unable to parse voice MIDI event.", exc, pos); }
        }
Example #3
0
        private TrackEvent ReadTrackEvent()
        {
            var deltaTime = ReadVariableLengthEncoding();
            // "Running Status": The last status byte is implied
            var statusByte = _lastStatusByte;
            var firstByte  = _source.ReadByte();

            // Check for new status byte
            if ((firstByte & 0x80) == 1)
            {
                statusByte = firstByte;
                firstByte  = _source.ReadByte();
            }

            var statusUpper = statusByte >> 4;

            // Save running status
            if (statusUpper > 0x7 && statusUpper < 0xF)
            {
                _lastStatusByte = statusByte;
            }
            // Parse the event
            var       statusLower = (byte)(statusByte & 0xF);
            MidiEvent ev          = null;

            switch (statusUpper)
            {
            case 0x8:
                ev = new NoteOff(statusLower, firstByte, _source.ReadByte());
                break;

            case 0x9:
                ev = new NoteOn(statusLower, firstByte, _source.ReadByte());
                break;

            case 0xA:
                ev = new PolyphonicKeyPressure(statusLower, firstByte, _source.ReadByte());
                break;

            case 0xB:
                if (firstByte < 120)
                {
                    ev = new ControlChange(statusLower, firstByte, _source.ReadByte());
                }
                else
                {
                    ev = new ChannelMode(statusLower, firstByte, _source.ReadByte());
                }
                break;

            case 0xC:
                ev = new ProgramChange(statusLower, firstByte);
                break;

            case 0xD:
                ev = new ChannelPressure(statusLower, firstByte);
                break;

            case 0xE:
                ev = new PitchBend(statusLower, firstByte, _source.ReadByte());
                break;

            case 0xF:
                switch (statusLower)
                {
                case 0x0:
                case 0x7:
                    ev = new SysEx(statusLower == 0, _source.ReadBytes(ReadVariableLengthEncoding(firstByte)));
                    break;

                case 0xF:
                    var len  = ReadVariableLengthEncoding();
                    var data = _source.ReadBytes(len);
                    switch (firstByte)
                    {
                    case 0x01:
                    case 0x02:
                    case 0x03:
                    case 0x04:
                    case 0x05:
                    case 0x06:
                    case 0x07:
                    case 0x08:
                    case 0x09:
                    case 0x0A:
                    case 0x0B:
                    case 0x0C:
                    case 0x0D:
                    case 0x0E:
                    case 0x0F:
                        ev = new TextEvent(Encoding.UTF8.GetString(data));             // TODO: Let user choose encoding
                        break;

                    case 0x20:
                        ev = new ChannelPrefix(data[0]);
                        break;

                    case 0x2F:
                        ev = new EndOfTrack();
                        break;

                    case 0x51:
                        ev = new SetTempo(MidiBytesConverter.ReadBigEndian24Bit(data));
                        break;

                    case 0x54:
                        ev = new SmpteOffset((byte)((data[0] >> 5) & 0x3), (byte)(data[0] & 0x1F), data[1], data[2], data[3], data[4]);
                        break;

                    case 0x58:
                        ev = new TimeSignature(data[0], data[1], data[2], data[3]);
                        break;

                    case 0x59:
                        ev = new KeySignature((sbyte)data[0], data[1] == 1);
                        break;

                    case 0x7F:
                        ev = new SequencerSpecificMetaEvent(data);
                        break;

                    default:
                        // TODO: Unrecognized metadata kind, non-fatal error
                        break;
                    }
                    break;

                default:
                    // At this point, if the event was not recognized: FATAL ERROR!
                    throw new NotImplementedException();
                }
                break;

            default:
                // At this point, if the event was not recognized: FATAL ERROR!
                throw new NotImplementedException();
            }

            return(new TrackEvent(deltaTime, ev));
        }
Example #4
0
        /// <summary>Creates an object creation expression for an event.</summary>
        /// <param name="ev">The event to create.</param>
        /// <returns>The object creation expression for the event.</returns>
        private static CodeObjectCreateExpression CreateVoiceEvent(MidiEvent ev)
        {
            CodeObjectCreateExpression newEvent = null;
            CodeExpression             delta    = new CodePrimitiveExpression(ev.DeltaTime);

            // NOTE ON
            if (ev is NoteOn)
            {
                NoteOn midiEvent = (NoteOn)ev;
                newEvent = new CodeObjectCreateExpression(
                    typeof(NoteOn),
                    new CodeExpression[] {
                    delta,
                    new CodePrimitiveExpression(midiEvent.Channel),
                    new CodePrimitiveExpression(MidiEvent.GetNoteName(midiEvent.Note)),
                    new CodePrimitiveExpression(midiEvent.Velocity)
                });
            }

            // NOTE OFF
            else if (ev is NoteOff)
            {
                NoteOff midiEvent = (NoteOff)ev;
                newEvent = new CodeObjectCreateExpression(
                    typeof(NoteOff),
                    new CodeExpression[] {
                    delta,
                    new CodePrimitiveExpression(midiEvent.Channel),
                    new CodePrimitiveExpression(MidiEvent.GetNoteName(midiEvent.Note)),
                    new CodePrimitiveExpression(midiEvent.Velocity)
                });
            }

            // AFTERTOUCH
            else if (ev is Aftertouch)
            {
                Aftertouch midiEvent = (Aftertouch)ev;
                newEvent = new CodeObjectCreateExpression(
                    typeof(Aftertouch),
                    new CodeExpression[] {
                    delta,
                    new CodePrimitiveExpression(midiEvent.Channel),
                    new CodePrimitiveExpression(MidiEvent.GetNoteName(midiEvent.Note)),
                    new CodePrimitiveExpression(midiEvent.Pressure)
                });
            }

            // PROGRAM CHANGE
            else if (ev is ProgramChange)
            {
                ProgramChange midiEvent = (ProgramChange)ev;
                newEvent = new CodeObjectCreateExpression(
                    typeof(ProgramChange),
                    new CodeExpression[] {
                    delta,
                    new CodePrimitiveExpression(midiEvent.Channel),
                    new CodeCastExpression(typeof(GeneralMidiInstruments), new CodePrimitiveExpression(midiEvent.Number))
                });
            }

            // CONTROLLER
            else if (ev is Controller)
            {
                Controller midiEvent = (Controller)ev;
                newEvent = new CodeObjectCreateExpression(
                    typeof(Controller),
                    new CodeExpression[] {
                    delta,
                    new CodePrimitiveExpression(midiEvent.Channel),
                    new CodeCastExpression(typeof(Controllers), new CodePrimitiveExpression(midiEvent.Number)),
                    new CodePrimitiveExpression(midiEvent.Value),
                });
            }

            // CHANNEL PRESSURE
            else if (ev is ChannelPressure)
            {
                ChannelPressure midiEvent = (ChannelPressure)ev;
                newEvent = new CodeObjectCreateExpression(
                    typeof(ChannelPressure),
                    new CodeExpression[] {
                    delta,
                    new CodePrimitiveExpression(midiEvent.Channel),
                    new CodePrimitiveExpression(midiEvent.Pressure)
                });
            }

            // PITCH WHEEL
            else if (ev is PitchWheel)
            {
                PitchWheel midiEvent = (PitchWheel)ev;
                newEvent = new CodeObjectCreateExpression(
                    typeof(PitchWheel),
                    new CodeExpression[] {
                    delta,
                    new CodePrimitiveExpression(midiEvent.Channel),
                    new CodePrimitiveExpression(midiEvent.UpperBits),
                    new CodePrimitiveExpression(midiEvent.LowerBits)
                });
            }

            // Return the event
            return(newEvent);
        }
        private void Decode(byte[] message)
        {
            byte status = message[0];

            switch (status & 0b1111_0000)
            {
            case Midi.Status.NoteOffBitmask:
                if (NoteOffMessage.TryDecode(message, out var noteOffMessage))
                {
                    NoteOff?.Invoke(this, in noteOffMessage);
                }
                break;

            case Midi.Status.NoteOnBitmask:
                if (NoteOnMessage.TryDecode(message, out var noteOnMessage))
                {
                    NoteOn?.Invoke(this, in noteOnMessage);
                }
                break;

            case Midi.Status.PolyphonicKeyPressureBitmask:
                if (PolyphonicKeyPressureMessage.TryDecode(message, out var polyphonicKeyPressureMessage))
                {
                    PolyphonicKeyPressure?.Invoke(this, in polyphonicKeyPressureMessage);
                }
                break;

            case Midi.Status.ControlChangeBitmask:
                if (ControlChangeMessage.TryDecode(message, out var controlChangeMessage))
                {
                    _nrpnInterpreters[(int)controlChangeMessage.Channel].HandleControlChangeMessage(in controlChangeMessage);
                }
                break;

            case Midi.Status.ProgramChangeBitmask:
                if (ProgramChangeMessage.TryDecode(message, out var programChangeMessage))
                {
                    ProgramChange?.Invoke(this, in programChangeMessage);
                }
                break;

            case Midi.Status.ChannelPressureBitmask:
                if (ChannelPressureMessage.TryDecode(message, out var channelPressureMessage))
                {
                    ChannelPressure?.Invoke(this, in channelPressureMessage);
                }
                break;

            case Midi.Status.PitchBendChange:
                if (PitchBendMessage.TryDecode(message, out var pitchBendMessage))
                {
                    PitchBend?.Invoke(this, in pitchBendMessage);
                }
                break;

            case Midi.Status.System:
                switch (status)
                {
                case Midi.Status.SysExStart:
                    if (SysExMessage.TryDecode(message, out var sysExMessage))
                    {
                        SysEx?.Invoke(this, in sysExMessage);
                    }
                    break;

                case Midi.Status.MidiTimeCodeQuarterFrame:
                    if (MidiTimeCodeQuarterFrameMessage.TryDecode(message, out var timeCodeQuarterFrameMessage))
                    {
                        MidiTimeCodeQuarterFrame?.Invoke(this, in timeCodeQuarterFrameMessage);
                    }
                    break;

                case Midi.Status.SongPositionPointer:
                    if (SongPositionPointerMessage.TryDecode(message, out var songPositionPointerMessage))
                    {
                        SongPositionPointer?.Invoke(this, in songPositionPointerMessage);
                    }
                    break;

                case Midi.Status.SongSelect:
                    if (SongSelectMessage.TryDecode(message, out var songSelectMessage))
                    {
                        SongSelect?.Invoke(this, in songSelectMessage);
                    }
                    break;

                case Midi.Status.TuneRequest:
                    if (TuneRequestMessage.TryDecode(message, out var tuneRequestMessage))
                    {
                        TuneRequest?.Invoke(this, in tuneRequestMessage);
                    }
                    break;

                default:
                    Log.Error("Unknown system message type {Status}", $"{status:X2}");
                    break;
                }
                break;

            default:
                Log.Error("Unknown message type {Bitmask}", $"{status & 0b1111_0000:X2}");
                break;
            }
        }
Example #6
0
        private MIDI ConvertToFormat1(MIDI src)
        {
            try
            {
                Track srcTrack  = src.TrackList[0];
                var   newTracks = new List <Track>();
                int   cnt       = 0; // event counter

                var  eventlist = new LinkedList <Event>();
                uint deltaTime = 0;


                // Create Conductor track
                foreach (Event ev in srcTrack.EventList)
                {
                    deltaTime += ev.DeltaTime;

                    if (ev is MetaEvent)
                    {
                        MetaEvent modEv;
                        if (ev is SetTempo)
                        {
                            var st = (SetTempo)ev;
                            modEv = new SetTempo(deltaTime, st.Value);
                        }
                        else if (ev is TimeSignature)
                        {
                            var ts = (TimeSignature)ev;
                            modEv = new TimeSignature(deltaTime, ts.Numerator, ts.DenominatorBitShift, ts.MIDIClockPerMetronomeTick, ts.NumberOfNotesPerClocks);
                        }
                        else if (ev is KeySignature)
                        {
                            var ks = (KeySignature)ev;
                            modEv = new KeySignature(deltaTime, ks.SignatureNumber, ks.MinorFlagNumber);
                        }
                        else if (ev is SequenceTrackName)
                        {
                            var stn = (SequenceTrackName)ev;
                            modEv = new SequenceTrackName(deltaTime, stn.Name);
                        }
                        else if (ev is EndOfTrack)
                        {
                            modEv = new EndOfTrack(deltaTime);
                        }
                        else
                        {
                            modEv = new MetaEvent(deltaTime);
                        }
                        eventlist.AddLast(modEv);

                        deltaTime = 0;

                        if (!(ev is EndOfTrack))
                        {
                            cnt++;
                        }
                    }
                }
                newTracks.Add(new Track(eventlist));

                eventlist = new LinkedList <Event>();
                deltaTime = 0;


                // Create System Setup track
                foreach (Event ev in srcTrack.EventList)
                {
                    deltaTime += ev.DeltaTime;

                    if (ev is SysExEvent)
                    {
                        eventlist.AddLast(new SysExEvent(deltaTime));

                        deltaTime = 0;
                        cnt++;
                    }
                    else if (ev is EndOfTrack)
                    {
                        eventlist.AddLast(new EndOfTrack(deltaTime));
                    }
                }
                newTracks.Add(new Track(eventlist));


                // Create Notes track
                for (int ch = 0; cnt + 1 < srcTrack.EventList.Count; ch++)
                {
                    eventlist = new LinkedList <Event>();
                    deltaTime = 0;

                    foreach (Event ev in srcTrack.EventList)
                    {
                        deltaTime += ev.DeltaTime;

                        if (ev is MIDIEvent)
                        {
                            var midiEv = (MIDIEvent)ev;
                            if (midiEv.Channel == ch)
                            {
                                MIDIEvent modEv;
                                if (midiEv is NoteOn)
                                {
                                    var nton = (NoteOn)midiEv;
                                    modEv = new NoteOn(deltaTime, nton.Channel, nton.Number, nton.Velocity);
                                }
                                else if (midiEv is NoteOff)
                                {
                                    var ntoff = (NoteOff)midiEv;
                                    modEv = new NoteOff(deltaTime, ntoff.Channel, ntoff.Number, ntoff.Velocity);
                                }
                                else if (midiEv is ProgramChange)
                                {
                                    var pc = (ProgramChange)midiEv;
                                    modEv = new ProgramChange(deltaTime, pc.Channel, pc.Number);
                                }
                                else if (midiEv is Volume)
                                {
                                    var vol = (Volume)midiEv;
                                    modEv = new Volume(deltaTime, vol.Channel, vol.Value);
                                }
                                else if (midiEv is Pan)
                                {
                                    var pan = (Pan)midiEv;
                                    modEv = new Pan(deltaTime, pan.Channel, pan.Value);
                                }
                                else if (midiEv is ControlChange)
                                {
                                    var cc = (ControlChange)midiEv;
                                    modEv = new ControlChange(deltaTime, cc.Channel, cc.Value);
                                }
                                else
                                {
                                    modEv = new MIDIEvent(deltaTime, midiEv.Channel);
                                }
                                eventlist.AddLast(modEv);

                                deltaTime = 0;
                                cnt++;
                            }
                        }
                        else if (ev is EndOfTrack)
                        {
                            eventlist.AddLast(new EndOfTrack(deltaTime));
                        }
                    }
                    newTracks.Add(new Track(eventlist));
                }


                return(new MIDI(newTracks, 1, newTracks.Count, src.TimeDivision));
            }
            catch (Exception ex)
            {
                throw new Exception(Resources.ErrorMIDIFormat1, ex);
            }
        }