Skip to content

Commit

Permalink
chore: Updating message classes to make parsing input easier
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinZikmund committed May 21, 2020
1 parent 82de0e8 commit 671c70a
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 79 deletions.
25 changes: 25 additions & 0 deletions src/Uno.UWP/Devices/Midi/Internal/MidiHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,30 @@ internal static byte GetChannel(byte firstMessageByte)
{
return (byte)(firstMessageByte & 0b0000_1111);
}

/// <summary>
/// Returns the MIDI bend value from two bytes in message.
/// </summary>
/// <param name="firstByte">First byte of the value in MIDI message order.</param>
/// <param name="secondByte">Second byte of the value in MIDI message order.</param>
/// <returns>Bend.</returns>
internal static ushort GetBend(byte firstByte, byte secondByte) => GetUshort(firstByte, secondByte);

/// <summary>
/// Returns the MIDI beats value from two bytes in message.
/// </summary>
/// <param name="firstByte">First byte of the value in MIDI message order.</param>
/// <param name="secondByte">Second byte of the value in MIDI message order.</param>
/// <returns>Beats.</returns>
internal static ushort GetBeats(byte firstByte, byte secondByte) => GetUshort(firstByte, secondByte);

/// <summary>
/// Reads an ushort value from two bytes (used for beats and bend).
/// The parameter value is encoded as using 7 bits of each byte.
/// </summary>
/// <param name="firstByte">First byte.</param>
/// <param name="secondByte">Second byte.</param>
/// <returns>Ushort value</returns>
private static ushort GetUshort(byte firstByte, byte secondByte) => (ushort)((secondByte << 7) | firstByte);
}
}
19 changes: 19 additions & 0 deletions src/Uno.UWP/Devices/Midi/Internal/MidiMessageParameter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Uno.Devices.Midi.Internal
{
internal enum MidiMessageParameter
{
Channel = 15,
Velocity = 127,
Pressure = 127,
Note = 127,
Controller = 127,
Control = 127,
Bend = 16383
}
}
25 changes: 19 additions & 6 deletions src/Uno.UWP/Devices/Midi/Internal/MidiMessageValidators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,36 @@ namespace Uno.Devices.Midi.Internal
{
internal static class MidiMessageValidators
{
internal static void VerifyMessageType(byte firstMessageByte, MidiMessageType type)
internal static void VerifyMessageLength(byte[] messageData, int expectedLength, MidiMessageType type)
{
if (messageData is null)
{
throw new ArgumentNullException(nameof(messageData));
}
if (messageData.Length != expectedLength)
{
throw new ArgumentException(
$"MIDI message of type {type} must have length of {expectedLength} bytes",
nameof(messageData));
}
}

internal static void VerifyMessageType(byte firstByte, MidiMessageType type)
{
var typeByte = (byte)type;
if ((firstMessageByte & typeByte) != typeByte)
if ((firstByte & typeByte) != typeByte)
{
throw new ArgumentException(
$"The message does not match expected type of {type}");
}
}

internal static void VerifyRange(int value, int max, string paramName)
internal static void VerifyRange(int value, MidiMessageParameter parameter)
{
if (value > max)
if (value > (int)parameter)
{
throw new ArgumentException(
$"{nameof(paramName)} must be a number in the range 0 - {max}",
paramName);
$"{parameter} must be a number in the range 0 - {(int)parameter}");
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UWP/Devices/Midi/MidiActiveSensingMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ public MidiActiveSensingMessage()
/// 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.
/// </summary>
public TimeSpan Timestamp { get; } = TimeSpan.Zero;
public TimeSpan Timestamp { get; internal set; } = TimeSpan.Zero;
}
}
33 changes: 20 additions & 13 deletions src/Uno.UWP/Devices/Midi/MidiChannelPressureMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,30 @@ namespace Windows.Devices.Midi
/// </summary>
public partial class MidiChannelPressureMessage : IMidiMessage
{
private readonly InMemoryBuffer _buffer;

/// <summary>
/// Creates a new MidiChannelPressureMessage object.
/// </summary>
/// <param name="channel">The channel from 0-15 that this message applies to.</param>
/// <param name="pressure">The pressure from 0-127.</param>
public MidiChannelPressureMessage(byte channel, byte pressure)
: this(new byte[]
{
(byte)((byte)MidiMessageType.ChannelPressure | channel),
pressure
})
{
}

internal MidiChannelPressureMessage(byte[] rawData)
{
MidiMessageValidators.VerifyRange(channel, 15, nameof(channel));
MidiMessageValidators.VerifyRange(pressure, 127, nameof(pressure));
MidiMessageValidators.VerifyMessageLength(rawData, 2, MidiMessageType.ChannelPressure);
MidiMessageValidators.VerifyMessageType(rawData[0], MidiMessageType.ChannelPressure);
MidiMessageValidators.VerifyRange(MidiHelpers.GetChannel(rawData[0]), MidiMessageParameter.Channel);
MidiMessageValidators.VerifyRange(rawData[1], MidiMessageParameter.Pressure);

Channel = channel;
Pressure = pressure;
RawData = new InMemoryBuffer(new byte[]
{
(byte)((byte)Type | Channel),
Pressure
});
_buffer = new InMemoryBuffer(rawData);
}

/// <summary>
Expand All @@ -36,22 +43,22 @@ public MidiChannelPressureMessage(byte channel, byte pressure)
/// <summary>
/// Gets the channel from 0-15 that this message applies to.
/// </summary>
public byte Channel { get; }
public byte Channel => MidiHelpers.GetChannel(_buffer.Data[0]);

/// <summary>
/// Gets the pressure from 0-127.
/// </summary>
public byte Pressure { get; }
public byte Pressure => _buffer.Data[1];

/// <summary>
/// Gets the array of bytes associated with the MIDI message, including status byte.
/// </summary>
public IBuffer RawData { get; }
public IBuffer RawData => _buffer;

/// <summary>
/// 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.
/// </summary>
public TimeSpan Timestamp { get; } = TimeSpan.Zero;
public TimeSpan Timestamp { get; internal set; } = TimeSpan.Zero;
}
}
40 changes: 23 additions & 17 deletions src/Uno.UWP/Devices/Midi/MidiControlChangeMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,33 @@ namespace Windows.Devices.Midi
/// </summary>
public partial class MidiControlChangeMessage : IMidiMessage
{
private readonly InMemoryBuffer _buffer;

/// <summary>
/// Creates a new MidiControlChangeMessage object.
/// </summary>
/// <param name="channel">The channel from 0-15 that this message applies to.</param>
/// <param name="controller">The controller from 0-127 to receive this message.</param>
/// <param name="controlValue">The value from 0-127 to apply to the controller.</param>
public MidiControlChangeMessage(byte channel, byte controller, byte controlValue)
: this(new byte[]
{
(byte)((byte)MidiMessageType.ControlChange | channel),
controller,
controlValue
})
{
}

internal MidiControlChangeMessage(byte[] rawData)
{
MidiMessageValidators.VerifyRange(channel, 15, nameof(channel));
MidiMessageValidators.VerifyRange(controller, 127, nameof(controller));
MidiMessageValidators.VerifyRange(controlValue, 127, nameof(controlValue));
MidiMessageValidators.VerifyMessageLength(rawData, 3, MidiMessageType.ControlChange);
MidiMessageValidators.VerifyMessageType(rawData[0], MidiMessageType.ControlChange);
MidiMessageValidators.VerifyRange(MidiHelpers.GetChannel(rawData[0]), MidiMessageParameter.Channel);
MidiMessageValidators.VerifyRange(rawData[1], MidiMessageParameter.Controller);
MidiMessageValidators.VerifyRange(rawData[2], MidiMessageParameter.Control);

Channel = channel;
Controller = controller;
ControlValue = controlValue;
RawData = new InMemoryBuffer(new byte[]
{
(byte)((byte)Type | Channel),
Controller,
ControlValue
});
_buffer = new InMemoryBuffer(rawData);
}

/// <summary>
Expand All @@ -40,27 +46,27 @@ public MidiControlChangeMessage(byte channel, byte controller, byte controlValue
/// <summary>
/// Gets the channel from 0-15 that this message applies to.
/// </summary>
public byte Channel { get; }
public byte Channel => MidiHelpers.GetChannel(_buffer.Data[0]);

/// <summary>
/// Gets the value from 0-127 to apply to the controller.
/// </summary>
public byte ControlValue { get; }
public byte ControlValue => _buffer.Data[2];

/// <summary>
/// Gets controller from 0-127 to receive this message.
/// </summary>
public byte Controller { get; }
public byte Controller => _buffer.Data[1];

/// <summary>
/// Gets the array of bytes associated with the MIDI message, including status byte.
/// </summary>
public IBuffer RawData { get; }
public IBuffer RawData => _buffer;

/// <summary>
/// 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.
/// </summary>
public TimeSpan Timestamp { get; } = TimeSpan.Zero;
public TimeSpan Timestamp { get; internal set; } = TimeSpan.Zero;
}
}
21 changes: 7 additions & 14 deletions src/Uno.UWP/Devices/Midi/MidiNoteOffMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,13 @@ public MidiNoteOffMessage(byte channel, byte note, byte velocity)

internal MidiNoteOffMessage(byte[] rawData)
{
if ((rawData[0] & (byte)MidiMessageType.NoteOff) == (byte)MidiMessageType.NoteOff)
{
MidiMessageValidators.VerifyMessageLength(rawData, 3, Type);
MidiMessageValidators.VerifyMessageType(rawData[0], Type);
MidiMessageValidators.VerifyRange(MidiHelpers.GetChannel(rawData[0]), MidiMessageParameter.Channel);
MidiMessageValidators.VerifyRange(rawData[1], MidiMessageParameter.Note);
MidiMessageValidators.VerifyRange(rawData[2], MidiMessageParameter.Velocity);

}
MidiMessageValidators.VerifyRange(channel, 15, nameof(channel));
MidiMessageValidators.VerifyRange(note, 127, nameof(note));
MidiMessageValidators.VerifyRange(velocity, 127, nameof(velocity));

_buffer = new InMemoryBuffer(new byte[]
{
(byte)((byte)Type | Channel),
Note,
Velocity
};
_buffer = new InMemoryBuffer(rawData);
}

/// <summary>
Expand All @@ -62,7 +55,7 @@ internal MidiNoteOffMessage(byte[] rawData)
/// <summary>
/// Gets the value of the velocity from 0-127.
/// </summary>
public byte Velocity { get; }
public byte Velocity => _buffer.Data[2];

/// <summary>
/// Gets the array of bytes associated with the MIDI message, including status byte.
Expand Down
26 changes: 16 additions & 10 deletions src/Uno.UWP/Devices/Midi/MidiNoteOnMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,33 @@ namespace Windows.Devices.Midi
/// </summary>
public partial class MidiNoteOnMessage : IMidiMessage
{
private readonly InMemoryBuffer _buffer;

/// <summary>
/// Creates a new MidiNoteOnMessage object.
/// </summary>
/// <param name="channel">The channel from 0-15 that this message applies to.</param>
/// <param name="note">The note which is specified as a value from 0-127.</param>
/// <param name="velocity">The velocity which is specified as a value from 0-127.</param>
public MidiNoteOnMessage(byte channel, byte note, byte velocity)
{
MidiMessageValidators.VerifyRange(channel, 15, nameof(channel));
MidiMessageValidators.VerifyRange(note, 127, nameof(note));
MidiMessageValidators.VerifyRange(velocity, 127, nameof(velocity));

Channel = channel;
Note = note;
Velocity = velocity;
RawData = new InMemoryBuffer(new byte[]
: this(new byte[]
{
(byte)((byte)Type | Channel),
Note,
Velocity
});
})
{
}

internal MidiNoteOnMessage(byte[] rawData)
{
MidiMessageValidators.VerifyMessageLength(rawData, 3, Type);
MidiMessageValidators.VerifyMessageType(rawData[0], Type);
MidiMessageValidators.VerifyRange(MidiHelpers.GetChannel(rawData[0]), MidiMessageParameter.Channel);
MidiMessageValidators.VerifyRange(rawData[1], MidiMessageParameter.Note);
MidiMessageValidators.VerifyRange(rawData[2], MidiMessageParameter.Velocity);

_buffer = new InMemoryBuffer(rawData);
}

/// <summary>
Expand Down
Loading

0 comments on commit 671c70a

Please sign in to comment.