From b26e06983118932c099bfe86fb623807c80bf082 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Sat, 9 May 2020 22:09:17 +0200 Subject: [PATCH] feat(MIDI): Support MidiInPort on iOS --- .../Midi/Internal/MidiMessageParser.cs | 53 +++++++++++++++---- .../Devices/Midi/MidiActiveSensingMessage.cs | 10 ++++ .../Midi/MidiChannelPressureMessage.cs | 5 +- .../Devices/Midi/MidiContinueMessage.cs | 10 ++++ .../Devices/Midi/MidiControlChangeMessage.cs | 5 +- src/Uno.UWP/Devices/Midi/MidiInPort.cs | 9 +++- .../Devices/Midi/MidiInPort.iOSmacOS.cs | 8 ++- .../Devices/Midi/MidiNoteOffMessage.cs | 5 +- src/Uno.UWP/Devices/Midi/MidiNoteOnMessage.cs | 3 +- .../Midi/MidiPitchBendChangeMessage.cs | 5 +- .../Midi/MidiPolyphonicKeyPressureMessage.cs | 5 +- .../Devices/Midi/MidiProgramChangeMessage.cs | 5 +- .../Midi/MidiSongPositionPointerMessage.cs | 3 +- .../Devices/Midi/MidiSongSelectMessage.cs | 3 +- src/Uno.UWP/Devices/Midi/MidiStartMessage.cs | 10 ++++ src/Uno.UWP/Devices/Midi/MidiStopMessage.cs | 10 ++++ .../Midi/MidiSystemExclusiveMessage.cs | 16 +++++- .../Devices/Midi/MidiSystemResetMessage.cs | 10 ++++ .../Devices/Midi/MidiTimeCodeMessage.cs | 5 +- .../Devices/Midi/MidiTimingClockMessage.cs | 10 ++++ .../Devices/Midi/MidiTuneRequestMessage.cs | 10 ++++ 21 files changed, 169 insertions(+), 31 deletions(-) diff --git a/src/Uno.UWP/Devices/Midi/Internal/MidiMessageParser.cs b/src/Uno.UWP/Devices/Midi/Internal/MidiMessageParser.cs index 1f9843eed329..caeb955237c3 100644 --- a/src/Uno.UWP/Devices/Midi/Internal/MidiMessageParser.cs +++ b/src/Uno.UWP/Devices/Midi/Internal/MidiMessageParser.cs @@ -22,23 +22,58 @@ public IMidiMessage Parse(byte[] bytes, TimeSpan timestamp) throw new ArgumentException(nameof(bytes), "MIDI message cannot be empty"); } + // Parsing logic based on + // https://www.midi.org/specifications-old/item/table-1-summary-of-midi-message + // Try to parse channel voice messages first // These start with a unique combination of four bits and the remaining // four represent the channel. var upperBits = (byte)(bytes[0] & 0b_1111_0000); - var lowerBits = (byte)(bytes[0] & 0b_0000_1111); - if (upperBits == (byte)MidiMessageType.NoteOff) + switch (upperBits) { - return new MidiNoteOffMessage(lowerBits, bytes[1], bytes[2]); + case (byte)MidiMessageType.NoteOff: + return new MidiNoteOffMessage(bytes, timestamp); + case (byte)MidiMessageType.NoteOn: + return new MidiNoteOnMessage(bytes, timestamp); + case (byte)MidiMessageType.PolyphonicKeyPressure: + return new MidiPolyphonicKeyPressureMessage(bytes, timestamp); + case (byte)MidiMessageType.ControlChange: + return new MidiControlChangeMessage(bytes, timestamp); + case (byte)MidiMessageType.ProgramChange: + return new MidiProgramChangeMessage(bytes, timestamp); + case (byte)MidiMessageType.ChannelPressure: + return new MidiChannelPressureMessage(bytes, timestamp); + case (byte)MidiMessageType.PitchBendChange: + return new MidiPitchBendChangeMessage(bytes, timestamp); } - } - - private static bool MatchesMessageType(byte firstByte, MidiMessageType messageType) - { - var encodedMessageType = (byte)messageType; - return (firstByte & encodedMessageType) == encodedMessageType; + // System common messages + switch (bytes[0]) + { + case (byte)MidiMessageType.MidiTimeCode: + return new MidiTimeCodeMessage(bytes, timestamp); + case (byte)MidiMessageType.SongPositionPointer: + return new MidiSongPositionPointerMessage(bytes, timestamp); + case (byte)MidiMessageType.SongSelect: + return new MidiSongSelectMessage(bytes, timestamp); + case (byte)MidiMessageType.TuneRequest: + return new MidiTuneRequestMessage(bytes, timestamp); + case (byte)MidiMessageType.TimingClock: + return new MidiTimingClockMessage(bytes, timestamp); + case (byte)MidiMessageType.Start: + return new MidiStartMessage(bytes, timestamp); + case (byte)MidiMessageType.Continue: + return new MidiContinueMessage(bytes, timestamp); + case (byte)MidiMessageType.Stop: + return new MidiStopMessage(bytes, timestamp); + case (byte)MidiMessageType.ActiveSensing: + return new MidiActiveSensingMessage(bytes, timestamp); + case (byte)MidiMessageType.SystemReset: + return new MidiSystemResetMessage(bytes, timestamp); + default: + return new MidiSystemExclusiveMessage(bytes, timestamp); + } } } } diff --git a/src/Uno.UWP/Devices/Midi/MidiActiveSensingMessage.cs b/src/Uno.UWP/Devices/Midi/MidiActiveSensingMessage.cs index fd48ba7e251c..cc07c1cf516a 100644 --- a/src/Uno.UWP/Devices/Midi/MidiActiveSensingMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiActiveSensingMessage.cs @@ -1,4 +1,5 @@ using System; +using Uno.Devices.Midi.Internal; using Windows.Storage.Streams; namespace Windows.Devices.Midi @@ -16,6 +17,15 @@ public MidiActiveSensingMessage() RawData = new InMemoryBuffer(new byte[] { (byte)Type }); } + internal MidiActiveSensingMessage(byte[] rawData, TimeSpan timestamp) + { + MidiMessageValidators.VerifyMessageLength(rawData, 1, Type); + MidiMessageValidators.VerifyMessageType(rawData[0], Type); + + RawData = new InMemoryBuffer(rawData); + Timestamp = timestamp; + } + /// /// Gets the type of this MIDI message. /// diff --git a/src/Uno.UWP/Devices/Midi/MidiChannelPressureMessage.cs b/src/Uno.UWP/Devices/Midi/MidiChannelPressureMessage.cs index edf48744198a..32a162c47db1 100644 --- a/src/Uno.UWP/Devices/Midi/MidiChannelPressureMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiChannelPressureMessage.cs @@ -28,7 +28,7 @@ public MidiChannelPressureMessage(byte channel, byte pressure) }); } - internal MidiChannelPressureMessage(byte[] rawData) + internal MidiChannelPressureMessage(byte[] rawData, TimeSpan timestamp) { MidiMessageValidators.VerifyMessageLength(rawData, 2, MidiMessageType.ChannelPressure); MidiMessageValidators.VerifyMessageType(rawData[0], MidiMessageType.ChannelPressure); @@ -36,6 +36,7 @@ internal MidiChannelPressureMessage(byte[] rawData) MidiMessageValidators.VerifyRange(rawData[1], MidiMessageParameter.Pressure); _buffer = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// @@ -62,6 +63,6 @@ internal MidiChannelPressureMessage(byte[] rawData) /// Gets the duration from when the MidiInPort was created to the time the message was received. /// For messages being sent to a MidiOutPort, this value has no meaning. /// - public TimeSpan Timestamp { get; internal set; } = TimeSpan.Zero; + public TimeSpan Timestamp { get; } = TimeSpan.Zero; } } diff --git a/src/Uno.UWP/Devices/Midi/MidiContinueMessage.cs b/src/Uno.UWP/Devices/Midi/MidiContinueMessage.cs index 68888be7aede..00e4875cb49d 100644 --- a/src/Uno.UWP/Devices/Midi/MidiContinueMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiContinueMessage.cs @@ -1,4 +1,5 @@ using System; +using Uno.Devices.Midi.Internal; using Windows.Storage.Streams; namespace Windows.Devices.Midi @@ -16,6 +17,15 @@ public MidiContinueMessage() RawData = new InMemoryBuffer(new byte[] { (byte)Type }); } + internal MidiContinueMessage(byte[] rawData, TimeSpan timestamp) + { + MidiMessageValidators.VerifyMessageLength(rawData, 1, Type); + MidiMessageValidators.VerifyMessageType(rawData[0], Type); + + RawData = new InMemoryBuffer(rawData); + Timestamp = timestamp; + } + /// /// Gets the type of this MIDI message. /// diff --git a/src/Uno.UWP/Devices/Midi/MidiControlChangeMessage.cs b/src/Uno.UWP/Devices/Midi/MidiControlChangeMessage.cs index 686511739e61..1166cf3493bd 100644 --- a/src/Uno.UWP/Devices/Midi/MidiControlChangeMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiControlChangeMessage.cs @@ -31,7 +31,7 @@ public MidiControlChangeMessage(byte channel, byte controller, byte controlValue }); } - internal MidiControlChangeMessage(byte[] rawData) + internal MidiControlChangeMessage(byte[] rawData, TimeSpan timestamp) { MidiMessageValidators.VerifyMessageLength(rawData, 3, MidiMessageType.ControlChange); MidiMessageValidators.VerifyMessageType(rawData[0], MidiMessageType.ControlChange); @@ -40,6 +40,7 @@ internal MidiControlChangeMessage(byte[] rawData) MidiMessageValidators.VerifyRange(rawData[2], MidiMessageParameter.ControlValue); _buffer = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// @@ -71,6 +72,6 @@ internal MidiControlChangeMessage(byte[] rawData) /// Gets the duration from when the MidiInPort was created to the time the message was received. /// For messages being sent to a MidiOutPort, this value has no meaning. /// - public TimeSpan Timestamp { get; internal set; } = TimeSpan.Zero; + public TimeSpan Timestamp { get; } = TimeSpan.Zero; } } diff --git a/src/Uno.UWP/Devices/Midi/MidiInPort.cs b/src/Uno.UWP/Devices/Midi/MidiInPort.cs index 37f62731ad00..8d7b75219101 100644 --- a/src/Uno.UWP/Devices/Midi/MidiInPort.cs +++ b/src/Uno.UWP/Devices/Midi/MidiInPort.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Uno.Devices.Enumeration.Internal; +using Uno.Devices.Midi.Internal; using Windows.Foundation; namespace Windows.Devices.Midi @@ -15,6 +16,8 @@ public sealed partial class MidiInPort : IDisposable private readonly object _syncLock = new object(); + private MidiMessageParser _parser = new MidiMessageParser(); + /// /// Gets the id of the device that was used to initialize the MidiInPort. /// @@ -70,8 +73,10 @@ private void OnMessageReceived(byte[] message, TimeSpan timestamp) return; } - //read message type - + // parse message + var parsedMessage = _parser.Parse(message, timestamp); + var eventArgs = new MidiMessageReceivedEventArgs(parsedMessage); + MessageReceived?.Invoke(this, eventArgs); } } } diff --git a/src/Uno.UWP/Devices/Midi/MidiInPort.iOSmacOS.cs b/src/Uno.UWP/Devices/Midi/MidiInPort.iOSmacOS.cs index a08124b74930..c278d331170c 100644 --- a/src/Uno.UWP/Devices/Midi/MidiInPort.iOSmacOS.cs +++ b/src/Uno.UWP/Devices/Midi/MidiInPort.iOSmacOS.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using System.Runtime.InteropServices.WindowsRuntime; using System.Text; using System.Threading.Tasks; @@ -32,7 +33,12 @@ internal void Open() private void NativePortMessageReceived(object sender, MidiPacketsEventArgs e) { - throw new NotImplementedException(); + foreach (var packet in e.Packets) + { + var bytes = new byte[packet.Length]; + Marshal.Copy(packet.Bytes, bytes, 0, packet.Length); + OnMessageReceived(bytes, TimeSpan.FromMilliseconds(packet.TimeStamp)); + } } public void Dispose() diff --git a/src/Uno.UWP/Devices/Midi/MidiNoteOffMessage.cs b/src/Uno.UWP/Devices/Midi/MidiNoteOffMessage.cs index a6eb8d2ecdda..d575e0023a4d 100644 --- a/src/Uno.UWP/Devices/Midi/MidiNoteOffMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiNoteOffMessage.cs @@ -30,7 +30,7 @@ public MidiNoteOffMessage(byte channel, byte note, byte velocity) }); } - internal MidiNoteOffMessage(byte[] rawData) + internal MidiNoteOffMessage(byte[] rawData, TimeSpan timestamp) { MidiMessageValidators.VerifyMessageLength(rawData, 3, Type); MidiMessageValidators.VerifyMessageType(rawData[0], Type); @@ -39,6 +39,7 @@ internal MidiNoteOffMessage(byte[] rawData) MidiMessageValidators.VerifyRange(rawData[2], MidiMessageParameter.Velocity); _buffer = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// @@ -70,6 +71,6 @@ internal MidiNoteOffMessage(byte[] rawData) /// Gets the duration from when the MidiInPort was created to the time the message was received. /// For messages being sent to a MidiOutPort, this value has no meaning. /// - public TimeSpan Timestamp { get; internal set; } = TimeSpan.Zero; + public TimeSpan Timestamp { get; } = TimeSpan.Zero; } } diff --git a/src/Uno.UWP/Devices/Midi/MidiNoteOnMessage.cs b/src/Uno.UWP/Devices/Midi/MidiNoteOnMessage.cs index ddedc0ca7068..06a04ad70523 100644 --- a/src/Uno.UWP/Devices/Midi/MidiNoteOnMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiNoteOnMessage.cs @@ -30,7 +30,7 @@ public MidiNoteOnMessage(byte channel, byte note, byte velocity) }); } - internal MidiNoteOnMessage(byte[] rawData) + internal MidiNoteOnMessage(byte[] rawData, TimeSpan timestamp) { MidiMessageValidators.VerifyMessageLength(rawData, 3, Type); MidiMessageValidators.VerifyMessageType(rawData[0], Type); @@ -39,6 +39,7 @@ internal MidiNoteOnMessage(byte[] rawData) MidiMessageValidators.VerifyRange(rawData[2], MidiMessageParameter.Velocity); _buffer = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// diff --git a/src/Uno.UWP/Devices/Midi/MidiPitchBendChangeMessage.cs b/src/Uno.UWP/Devices/Midi/MidiPitchBendChangeMessage.cs index 76a59825d63b..7a5530716002 100644 --- a/src/Uno.UWP/Devices/Midi/MidiPitchBendChangeMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiPitchBendChangeMessage.cs @@ -29,7 +29,7 @@ public MidiPitchBendChangeMessage(byte channel, ushort bend) }); } - internal MidiPitchBendChangeMessage(byte[] rawData) + internal MidiPitchBendChangeMessage(byte[] rawData, TimeSpan timestamp) { MidiMessageValidators.VerifyMessageLength(rawData, 3, Type); MidiMessageValidators.VerifyMessageType(rawData[0], Type); @@ -37,6 +37,7 @@ internal MidiPitchBendChangeMessage(byte[] rawData) MidiMessageValidators.VerifyRange(MidiHelpers.GetBend(rawData[1], rawData[2]), MidiMessageParameter.Bend); _buffer = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// @@ -63,6 +64,6 @@ internal MidiPitchBendChangeMessage(byte[] rawData) /// Gets the duration from when the MidiInPort was created to the time the message was received. /// For messages being sent to a MidiOutPort, this value has no meaning. /// - public TimeSpan Timestamp { get; internal set; } = TimeSpan.Zero; + public TimeSpan Timestamp { get; } = TimeSpan.Zero; } } diff --git a/src/Uno.UWP/Devices/Midi/MidiPolyphonicKeyPressureMessage.cs b/src/Uno.UWP/Devices/Midi/MidiPolyphonicKeyPressureMessage.cs index 5c7a9b961d09..ddc6baa91282 100644 --- a/src/Uno.UWP/Devices/Midi/MidiPolyphonicKeyPressureMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiPolyphonicKeyPressureMessage.cs @@ -31,7 +31,7 @@ public MidiPolyphonicKeyPressureMessage(byte channel, byte note, byte pressure) }); } - internal MidiPolyphonicKeyPressureMessage(byte[] rawData) + internal MidiPolyphonicKeyPressureMessage(byte[] rawData, TimeSpan timestamp) { MidiMessageValidators.VerifyMessageLength(rawData, 3, Type); MidiMessageValidators.VerifyMessageType(rawData[0], Type); @@ -40,6 +40,7 @@ internal MidiPolyphonicKeyPressureMessage(byte[] rawData) MidiMessageValidators.VerifyRange(rawData[2], MidiMessageParameter.Pressure); _buffer = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// @@ -71,6 +72,6 @@ internal MidiPolyphonicKeyPressureMessage(byte[] rawData) /// Gets the duration from when the MidiInPort was created to the time the message was received. /// For messages being sent to a MidiOutPort, this value has no meaning. /// - public TimeSpan Timestamp { get; internal set; } = TimeSpan.Zero; + public TimeSpan Timestamp { get; } = TimeSpan.Zero; } } diff --git a/src/Uno.UWP/Devices/Midi/MidiProgramChangeMessage.cs b/src/Uno.UWP/Devices/Midi/MidiProgramChangeMessage.cs index 59b5c2f7e2d2..45466c2180f1 100644 --- a/src/Uno.UWP/Devices/Midi/MidiProgramChangeMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiProgramChangeMessage.cs @@ -28,7 +28,7 @@ public MidiProgramChangeMessage(byte channel, byte program) }); } - internal MidiProgramChangeMessage(byte[] rawData) + internal MidiProgramChangeMessage(byte[] rawData, TimeSpan timestamp) { MidiMessageValidators.VerifyMessageLength(rawData, 2, Type); MidiMessageValidators.VerifyMessageType(rawData[0], Type); @@ -36,6 +36,7 @@ internal MidiProgramChangeMessage(byte[] rawData) MidiMessageValidators.VerifyRange(rawData[1], MidiMessageParameter.Program); _buffer = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// @@ -62,6 +63,6 @@ internal MidiProgramChangeMessage(byte[] rawData) /// Gets the duration from when the MidiInPort was created to the time the message was received. /// For messages being sent to a MidiOutPort, this value has no meaning. /// - public TimeSpan Timestamp { get; internal set; } = TimeSpan.Zero; + public TimeSpan Timestamp { get; } = TimeSpan.Zero; } } diff --git a/src/Uno.UWP/Devices/Midi/MidiSongPositionPointerMessage.cs b/src/Uno.UWP/Devices/Midi/MidiSongPositionPointerMessage.cs index 505ecb5d7f09..c380303a5564 100644 --- a/src/Uno.UWP/Devices/Midi/MidiSongPositionPointerMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiSongPositionPointerMessage.cs @@ -27,13 +27,14 @@ public MidiSongPositionPointerMessage(ushort beats) }); } - internal MidiSongPositionPointerMessage(byte[] rawData) + internal MidiSongPositionPointerMessage(byte[] rawData, TimeSpan timestamp) { MidiMessageValidators.VerifyMessageLength(rawData, 3, Type); MidiMessageValidators.VerifyMessageType(rawData[0], Type); MidiMessageValidators.VerifyRange(MidiHelpers.GetBeats(rawData[1], rawData[2]), MidiMessageParameter.Beats); _buffer = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// diff --git a/src/Uno.UWP/Devices/Midi/MidiSongSelectMessage.cs b/src/Uno.UWP/Devices/Midi/MidiSongSelectMessage.cs index ca2c3973ada3..03592254b73b 100644 --- a/src/Uno.UWP/Devices/Midi/MidiSongSelectMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiSongSelectMessage.cs @@ -27,13 +27,14 @@ public MidiSongSelectMessage(byte song) }); } - internal MidiSongSelectMessage(byte[] rawData) + internal MidiSongSelectMessage(byte[] rawData, TimeSpan timestamp) { MidiMessageValidators.VerifyMessageLength(rawData, 2, Type); MidiMessageValidators.VerifyMessageType(rawData[0], Type); MidiMessageValidators.VerifyRange(rawData[1], MidiMessageParameter.Song); _buffer = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// diff --git a/src/Uno.UWP/Devices/Midi/MidiStartMessage.cs b/src/Uno.UWP/Devices/Midi/MidiStartMessage.cs index 045d6af2e566..78d412a4f1e1 100644 --- a/src/Uno.UWP/Devices/Midi/MidiStartMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiStartMessage.cs @@ -1,4 +1,5 @@ using System; +using Uno.Devices.Midi.Internal; using Windows.Storage.Streams; namespace Windows.Devices.Midi @@ -19,6 +20,15 @@ public MidiStartMessage() }); } + internal MidiStartMessage(byte[] rawData, TimeSpan timestamp) + { + MidiMessageValidators.VerifyMessageLength(rawData, 1, Type); + MidiMessageValidators.VerifyMessageType(rawData[0], Type); + + RawData = new InMemoryBuffer(rawData); + Timestamp = timestamp; + } + /// /// Gets the type of this MIDI message. /// diff --git a/src/Uno.UWP/Devices/Midi/MidiStopMessage.cs b/src/Uno.UWP/Devices/Midi/MidiStopMessage.cs index c027423958c4..1712bf872410 100644 --- a/src/Uno.UWP/Devices/Midi/MidiStopMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiStopMessage.cs @@ -1,4 +1,5 @@ using System; +using Uno.Devices.Midi.Internal; using Windows.Storage.Streams; namespace Windows.Devices.Midi @@ -19,6 +20,15 @@ public MidiStopMessage() }); } + internal MidiStopMessage(byte[] rawData, TimeSpan timestamp) + { + MidiMessageValidators.VerifyMessageLength(rawData, 1, Type); + MidiMessageValidators.VerifyMessageType(rawData[0], Type); + + RawData = new InMemoryBuffer(rawData); + Timestamp = timestamp; + } + /// /// Gets the type of this MIDI message. /// diff --git a/src/Uno.UWP/Devices/Midi/MidiSystemExclusiveMessage.cs b/src/Uno.UWP/Devices/Midi/MidiSystemExclusiveMessage.cs index 4e9d657ab04c..b91f6b0e9954 100644 --- a/src/Uno.UWP/Devices/Midi/MidiSystemExclusiveMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiSystemExclusiveMessage.cs @@ -24,10 +24,16 @@ public MidiSystemExclusiveMessage(IBuffer rawData) throw new ArgumentException("Buffer must not be empty", nameof(rawData)); } + if (rawData is InMemoryBuffer inMemory && + inMemory.Data[0] == (byte)MidiMessageType.EndSystemExclusive) + { + Type = MidiMessageType.EndSystemExclusive; + } + RawData = rawData; } - internal MidiSystemExclusiveMessage(byte[] rawData) + internal MidiSystemExclusiveMessage(byte[] rawData, TimeSpan timestamp) { if (rawData == null) { @@ -39,13 +45,19 @@ internal MidiSystemExclusiveMessage(byte[] rawData) throw new ArgumentException("Buffer must not be empty", nameof(rawData)); } + if (rawData[0] == (byte)MidiMessageType.EndSystemExclusive) + { + Type = MidiMessageType.EndSystemExclusive; + } + RawData = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// /// Gets the type of this MIDI message. /// - public MidiMessageType Type => MidiMessageType.SystemExclusive; + public MidiMessageType Type { get; } = MidiMessageType.SystemExclusive; /// /// Gets the array of bytes associated with the MIDI message, including status byte. diff --git a/src/Uno.UWP/Devices/Midi/MidiSystemResetMessage.cs b/src/Uno.UWP/Devices/Midi/MidiSystemResetMessage.cs index 85191eec9fe5..8d27bd329de5 100644 --- a/src/Uno.UWP/Devices/Midi/MidiSystemResetMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiSystemResetMessage.cs @@ -1,4 +1,5 @@ using System; +using Uno.Devices.Midi.Internal; using Windows.Storage.Streams; namespace Windows.Devices.Midi @@ -19,6 +20,15 @@ public MidiSystemResetMessage() }); } + internal MidiSystemResetMessage(byte[] rawData, TimeSpan timestamp) + { + MidiMessageValidators.VerifyMessageLength(rawData, 1, Type); + MidiMessageValidators.VerifyMessageType(rawData[0], Type); + + RawData = new InMemoryBuffer(rawData); + Timestamp = timestamp; + } + /// /// Gets the type of this MIDI message. /// diff --git a/src/Uno.UWP/Devices/Midi/MidiTimeCodeMessage.cs b/src/Uno.UWP/Devices/Midi/MidiTimeCodeMessage.cs index 82772596c1b1..edfa6844fcd3 100644 --- a/src/Uno.UWP/Devices/Midi/MidiTimeCodeMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiTimeCodeMessage.cs @@ -28,7 +28,7 @@ public MidiTimeCodeMessage(byte frameType, byte values) }); } - internal MidiTimeCodeMessage(byte[] rawData) + internal MidiTimeCodeMessage(byte[] rawData, TimeSpan timestamp) { MidiMessageValidators.VerifyMessageLength(rawData, 2, Type); MidiMessageValidators.VerifyMessageType(rawData[0], Type); @@ -36,6 +36,7 @@ internal MidiTimeCodeMessage(byte[] rawData) MidiMessageValidators.VerifyRange(MidiHelpers.GetFrameValues(rawData[1]), MidiMessageParameter.FrameValues); _buffer = new InMemoryBuffer(rawData); + Timestamp = timestamp; } /// @@ -62,6 +63,6 @@ internal MidiTimeCodeMessage(byte[] rawData) /// Gets the duration from when the MidiInPort was created to the time the message was received. /// For messages being sent to a MidiOutPort, this value has no meaning. /// - public TimeSpan Timestamp { get; internal set; } = TimeSpan.Zero; + public TimeSpan Timestamp { get; } = TimeSpan.Zero; } } diff --git a/src/Uno.UWP/Devices/Midi/MidiTimingClockMessage.cs b/src/Uno.UWP/Devices/Midi/MidiTimingClockMessage.cs index 997aa37aea1f..63ac2a4c46ec 100644 --- a/src/Uno.UWP/Devices/Midi/MidiTimingClockMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiTimingClockMessage.cs @@ -1,4 +1,5 @@ using System; +using Uno.Devices.Midi.Internal; using Windows.Storage.Streams; namespace Windows.Devices.Midi @@ -19,6 +20,15 @@ public MidiTimingClockMessage() }); } + internal MidiTimingClockMessage(byte[] rawData, TimeSpan timestamp) + { + MidiMessageValidators.VerifyMessageLength(rawData, 1, Type); + MidiMessageValidators.VerifyMessageType(rawData[0], Type); + + RawData = new InMemoryBuffer(rawData); + Timestamp = timestamp; + } + /// /// Gets the type of this MIDI message. /// diff --git a/src/Uno.UWP/Devices/Midi/MidiTuneRequestMessage.cs b/src/Uno.UWP/Devices/Midi/MidiTuneRequestMessage.cs index d9a01ee85f93..806c32edca18 100644 --- a/src/Uno.UWP/Devices/Midi/MidiTuneRequestMessage.cs +++ b/src/Uno.UWP/Devices/Midi/MidiTuneRequestMessage.cs @@ -1,4 +1,5 @@ using System; +using Uno.Devices.Midi.Internal; using Windows.Storage.Streams; namespace Windows.Devices.Midi @@ -19,6 +20,15 @@ public MidiTuneRequestMessage() }); } + internal MidiTuneRequestMessage(byte[] rawData, TimeSpan timestamp) + { + MidiMessageValidators.VerifyMessageLength(rawData, 1, Type); + MidiMessageValidators.VerifyMessageType(rawData[0], Type); + + RawData = new InMemoryBuffer(rawData); + Timestamp = timestamp; + } + /// /// Gets the type of this MIDI message. ///