From 5e7b446a6bf176b8c9634b6ffcbbd4c01bfbf16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Qui=C3=B1ones?= Date: Wed, 6 Sep 2023 14:20:04 +0200 Subject: [PATCH 1/2] Updated to RtMidi v6.0 --- RtMidi.Net/Enums/MidiApi.cs | 4 +- RtMidi.Net/InteropServices/RtMidiBase.cs | 11 + RtMidi.Net/InteropServices/RtMidiInterop.cs | 531 ++++++++++---------- RtMidi.Net/MidiManager.cs | 2 +- RtMidi.Net/RtMidi.Net.csproj | 7 +- WorkerTest/Worker.cs | 12 +- WorkerTest/WorkerTest.csproj | 2 + 7 files changed, 297 insertions(+), 272 deletions(-) diff --git a/RtMidi.Net/Enums/MidiApi.cs b/RtMidi.Net/Enums/MidiApi.cs index 6a255d3..9b89f62 100644 --- a/RtMidi.Net/Enums/MidiApi.cs +++ b/RtMidi.Net/Enums/MidiApi.cs @@ -7,6 +7,8 @@ public enum MidiApi : byte LinuxAlsa, UnixJack, WindowsMultimediaMidi, - WindowsKernelStreaming, RtMidiDummy, + WebMidi, + WindowsUwp, + Android, } \ No newline at end of file diff --git a/RtMidi.Net/InteropServices/RtMidiBase.cs b/RtMidi.Net/InteropServices/RtMidiBase.cs index d0e0977..75fe21c 100644 --- a/RtMidi.Net/InteropServices/RtMidiBase.cs +++ b/RtMidi.Net/InteropServices/RtMidiBase.cs @@ -203,6 +203,17 @@ public static string GetApiDisplayName(MidiApi api) return name ?? string.Empty; } + /// + /// Return the version of the RtMidi library. + /// + /// The version of the RtMidi library + public static string GetRtMidiVersion() + { + var ptr = RtMidiInterop.rtmidi_get_version(); + var name = Marshal.PtrToStringUTF8(ptr); + return name ?? string.Empty; + } + /// /// Return the compiled MIDI API having the given name. /// diff --git a/RtMidi.Net/InteropServices/RtMidiInterop.cs b/RtMidi.Net/InteropServices/RtMidiInterop.cs index d0e381d..23bdc95 100644 --- a/RtMidi.Net/InteropServices/RtMidiInterop.cs +++ b/RtMidi.Net/InteropServices/RtMidiInterop.cs @@ -1,5 +1,5 @@ -using System.Runtime.InteropServices; -using RtMidi.Net.Enums; +using RtMidi.Net.Enums; +using System.Runtime.InteropServices; namespace RtMidi.Net.InteropServices; @@ -7,264 +7,271 @@ namespace RtMidi.Net.InteropServices; internal static class RtMidiInterop { - private const string RtMidiLibrary = "rtmidi"; - - #region RtMidi - - /// - /// Determine the available compiled MIDI APIs. - /// - /// If the given `apis` parameter is null, returns the number of available APIs. - /// Otherwise, fill the given apis array with the values. - /// - /// - /// An array or a null value. - /// Number of elements pointed to by apis - /// - /// Number of items needed for apis array if apis==NULL, or - /// number of items written to apis array otherwise. A negative - /// return value indicates an error. - /// - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int rtmidi_get_compiled_api (IntPtr apis, uint apisSize); - - /// - /// Return the name of a specified compiled MIDI API. - /// - /// This obtains a short lower-case name used for identification purposes. - /// This value is guaranteed to remain identical across library versions. - /// - /// - /// The API - /// - /// The API name - /// If the API is unknown, this function will return the empty string. - /// - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr rtmidi_api_name (MidiApi api); - - /// - /// Return the display name of a specified compiled MIDI API. - /// - /// This obtains a long name used for display purposes. - /// - /// - /// The API - /// - /// The API display name - /// If the API is unknown, this function will return the empty string. - /// - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr rtmidi_api_display_name (MidiApi api); - - /// - /// Return the compiled MIDI API having the given name. - /// - /// A case insensitive comparison will check the specified name - /// against the list of compiled APIs. - /// - /// - /// - /// - /// Return the one which matches. - /// On failure, the function returns . - /// - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] - internal static extern MidiApi rtmidi_compiled_api_by_name (string name); - - /// - /// Open a MIDI port. - /// - /// Pointer to object - /// Must be greater than 0 - /// Name for the application port. - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] - internal static extern void rtmidi_open_port (RtMidiPtr rtMidiObject, uint portNumber, string portName); - - /// - /// Creates a virtual MIDI port to which other software applications can connect. - /// - /// Pointer to object - /// Name for the application port. - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] - internal static extern void rtmidi_open_virtual_port (RtMidiPtr rtMidiObject, string portName); - - /// - /// Close a MIDI connection. - /// - /// Pointer to object - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void rtmidi_close_port (RtMidiPtr rtMidiObject); - - /// - /// Return the number of available MIDI ports. - /// - /// Pointer to object - /// This function returns the number of MIDI ports of the selected API. - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern uint rtmidi_get_port_count (RtMidiPtr rtMidiObject); - - /// - /// Access a string identifier for the specified MIDI port number. - /// - /// To prevent memory leaks a char buffer must be passed to this function. - /// NULL can be passed as bufOut parameter, and that will write the required buffer length in the bufLen. - /// - /// - /// Pointer to object - /// MIDI port number - /// OUT value with the name - /// OUT value with the name size - /// - /// The name of the port with the given Id is returned. - /// - /// An empty string is returned if an invalid port specifier - /// is provided. User code should assume a UTF-8 encoding. - /// - /// - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] - public static extern int rtmidi_get_port_name (RtMidiPtr rtMidiObject, uint portNumber, IntPtr bufOut, ref uint bufLen); - - #endregion - - #region RtMidiIn - - /// - /// Create a default RtMidiInPtr value, with no initialization. - /// - /// The RtMidiPtr created - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern RtMidiPtr rtmidi_in_create_default (); - - /// - /// Create a RtMidiInPtr value, with given api, clientName and queueSizeLimit. - /// - /// An optional API id can be specified. - /// - /// An optional client name can be specified. This - /// will be used to group the ports that are created - /// by the application. - /// - /// An optional size of the MIDI input queue can be - /// specified. - /// The RtMidiPtr created - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] - internal static extern RtMidiPtr rtmidi_in_create (MidiApi api, string clientName, uint queueSizeLimit); - - /// - /// Free the given RtMidiInPtr - /// - /// Pointer to object - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void rtmidi_in_free (RtMidiPtr rtMidiObject); - - /// - /// Returns the MIDI API specifier for the given instance of RtMidiIn. - /// - /// Pointer to object - /// The value - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern MidiApi rtmidi_in_get_current_api (RtMidiPtr rtMidiObject); - - /// - /// Set a callback function to be invoked for incoming MIDI messages. - /// - /// Pointer to object - /// A callback function must be given. - /// Optionally, a pointer to additional data can be - /// passed to the callback function whenever it is called. - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void rtmidi_in_set_callback (RtMidiPtr rtMidiObject, RtMidiCallback callback, byte[]? userData); - - /// - /// Cancel use of the current callback function (if one exists). - /// - /// Pointer to object - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void rtmidi_in_cancel_callback (RtMidiPtr rtMidiObject); - - /// - /// Specify whether certain MIDI message types should be queued or ignored during input. - /// - /// By default, MIDI timing and active sensing messages are ignored - /// during message input because of their relative high data rates. - /// MIDI sysex messages are ignored by default as well. Variable - /// values of "true" imply that the respective message type will be - /// ignored. - /// - /// - /// Pointer to object - /// Ignore midi Sysex messages? - /// Ignore midi Time messages? - /// Ignore midi Sense messages? - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void rtmidi_in_ignore_types (RtMidiPtr rtMidiObject, bool midiSysex, bool midiTime, bool midiSense); - - /// - /// Fill the user-provided array with the data bytes for the next available - /// MIDI message in the input queue and return the event delta-time in seconds. - /// - /// Pointer to object - /// Must point to a char* that is already allocated. - /// SYSEX messages maximum size being 1024, a statically - /// allocated array could be sufficient. - /// Is used to return the size of the message obtained. - /// Must be set to the size of when calling. - /// Timestamp of messages - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern double rtmidi_in_get_message (RtMidiPtr rtMidiObject, IntPtr message, ref int size); - - #endregion - - #region RtMidiOut - - /// - /// Create a default RtMidiOutPtr value, with no initialization. - /// - /// The RtMidiOutPtr created - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern RtMidiPtr rtmidi_out_create_default (); - - /// - /// Create a RtMidiOutPtr value, with given and clientName. - /// - /// An optional API id can be specified. - /// An optional client name can be specified. This - /// will be used to group the ports that are created - /// by the application. - /// The RtMidiOutPtr created - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] - internal static extern RtMidiPtr rtmidi_out_create (MidiApi api, string clientName); - - /// - /// Free the given RtMidiOutPtr. - /// - /// Pointer to object - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern void rtmidi_out_free (RtMidiPtr rtMidiObject); - - /// - /// Returns the MIDI API specifier for the given instance of RtMidiOut. - /// - /// Pointer to object - /// The value - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern MidiApi rtmidi_out_get_current_api (RtMidiPtr rtMidiObject); - - /// - /// Immediately send a single message out an open MIDI output port. - /// - /// - /// An exception is thrown if an error occurs during output or an - /// output connection was not previously established. - /// - /// Pointer to object - /// A pointer to the MIDI message as raw bytes - /// Length of the MIDI message in bytes - /// - [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] - internal static extern int rtmidi_out_send_message (RtMidiPtr rtMidiObject, byte[] message, int length); - - #endregion - + private const string RtMidiLibrary = "rtmidi"; + + #region RtMidi + + /// + /// Determine the available compiled MIDI APIs. + /// + /// If the given `apis` parameter is null, returns the number of available APIs. + /// Otherwise, fill the given apis array with the values. + /// + /// + /// An array or a null value. + /// Number of elements pointed to by apis + /// + /// Number of items needed for apis array if apis==NULL, or + /// number of items written to apis array otherwise. A negative + /// return value indicates an error. + /// + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern int rtmidi_get_compiled_api(IntPtr apis, uint apisSize); + + /// + /// Return the name of a specified compiled MIDI API. + /// + /// This obtains a short lower-case name used for identification purposes. + /// This value is guaranteed to remain identical across library versions. + /// + /// + /// The API + /// + /// The API name + /// If the API is unknown, this function will return the empty string. + /// + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr rtmidi_api_name(MidiApi api); + + /// + /// Return the display name of a specified compiled MIDI API. + /// + /// This obtains a long name used for display purposes. + /// + /// + /// The API + /// + /// The API display name + /// If the API is unknown, this function will return the empty string. + /// + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr rtmidi_api_display_name(MidiApi api); + + /// + /// Return the current RtMidi version. + /// + /// RtMidi version. + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr rtmidi_get_version(); + + /// + /// Return the compiled MIDI API having the given name. + /// + /// A case insensitive comparison will check the specified name + /// against the list of compiled APIs. + /// + /// + /// + /// + /// Return the one which matches. + /// On failure, the function returns . + /// + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern MidiApi rtmidi_compiled_api_by_name(string name); + + /// + /// Open a MIDI port. + /// + /// Pointer to object + /// Must be greater than 0 + /// Name for the application port. + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void rtmidi_open_port(RtMidiPtr rtMidiObject, uint portNumber, string portName); + + /// + /// Creates a virtual MIDI port to which other software applications can connect. + /// + /// Pointer to object + /// Name for the application port. + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern void rtmidi_open_virtual_port(RtMidiPtr rtMidiObject, string portName); + + /// + /// Close a MIDI connection. + /// + /// Pointer to object + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern void rtmidi_close_port(RtMidiPtr rtMidiObject); + + /// + /// Return the number of available MIDI ports. + /// + /// Pointer to object + /// This function returns the number of MIDI ports of the selected API. + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint rtmidi_get_port_count(RtMidiPtr rtMidiObject); + + /// + /// Access a string identifier for the specified MIDI port number. + /// + /// To prevent memory leaks a char buffer must be passed to this function. + /// NULL can be passed as bufOut parameter, and that will write the required buffer length in the bufLen. + /// + /// + /// Pointer to object + /// MIDI port number + /// OUT value with the name + /// OUT value with the name size + /// + /// The name of the port with the given Id is returned. + /// + /// An empty string is returned if an invalid port specifier + /// is provided. User code should assume a UTF-8 encoding. + /// + /// + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern int rtmidi_get_port_name(RtMidiPtr rtMidiObject, uint portNumber, IntPtr bufOut, ref uint bufLen); + + #endregion + + #region RtMidiIn + + /// + /// Create a default RtMidiInPtr value, with no initialization. + /// + /// The RtMidiPtr created + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern RtMidiPtr rtmidi_in_create_default(); + + /// + /// Create a RtMidiInPtr value, with given api, clientName and queueSizeLimit. + /// + /// An optional API id can be specified. + /// + /// An optional client name can be specified. This + /// will be used to group the ports that are created + /// by the application. + /// + /// An optional size of the MIDI input queue can be + /// specified. + /// The RtMidiPtr created + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern RtMidiPtr rtmidi_in_create(MidiApi api, string clientName, uint queueSizeLimit); + + /// + /// Free the given RtMidiInPtr + /// + /// Pointer to object + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern void rtmidi_in_free(RtMidiPtr rtMidiObject); + + /// + /// Returns the MIDI API specifier for the given instance of RtMidiIn. + /// + /// Pointer to object + /// The value + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern MidiApi rtmidi_in_get_current_api(RtMidiPtr rtMidiObject); + + /// + /// Set a callback function to be invoked for incoming MIDI messages. + /// + /// Pointer to object + /// A callback function must be given. + /// Optionally, a pointer to additional data can be + /// passed to the callback function whenever it is called. + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern void rtmidi_in_set_callback(RtMidiPtr rtMidiObject, RtMidiCallback callback, byte[]? userData); + + /// + /// Cancel use of the current callback function (if one exists). + /// + /// Pointer to object + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern void rtmidi_in_cancel_callback(RtMidiPtr rtMidiObject); + + /// + /// Specify whether certain MIDI message types should be queued or ignored during input. + /// + /// By default, MIDI timing and active sensing messages are ignored + /// during message input because of their relative high data rates. + /// MIDI sysex messages are ignored by default as well. Variable + /// values of "true" imply that the respective message type will be + /// ignored. + /// + /// + /// Pointer to object + /// Ignore midi Sysex messages? + /// Ignore midi Time messages? + /// Ignore midi Sense messages? + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern void rtmidi_in_ignore_types(RtMidiPtr rtMidiObject, bool midiSysex, bool midiTime, bool midiSense); + + /// + /// Fill the user-provided array with the data bytes for the next available + /// MIDI message in the input queue and return the event delta-time in seconds. + /// + /// Pointer to object + /// Must point to a char* that is already allocated. + /// SYSEX messages maximum size being 1024, a statically + /// allocated array could be sufficient. + /// Is used to return the size of the message obtained. + /// Must be set to the size of when calling. + /// Timestamp of messages + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern double rtmidi_in_get_message(RtMidiPtr rtMidiObject, IntPtr message, ref int size); + + #endregion + + #region RtMidiOut + + /// + /// Create a default RtMidiOutPtr value, with no initialization. + /// + /// The RtMidiOutPtr created + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern RtMidiPtr rtmidi_out_create_default(); + + /// + /// Create a RtMidiOutPtr value, with given and clientName. + /// + /// An optional API id can be specified. + /// An optional client name can be specified. This + /// will be used to group the ports that are created + /// by the application. + /// The RtMidiOutPtr created + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern RtMidiPtr rtmidi_out_create(MidiApi api, string clientName); + + /// + /// Free the given RtMidiOutPtr. + /// + /// Pointer to object + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern void rtmidi_out_free(RtMidiPtr rtMidiObject); + + /// + /// Returns the MIDI API specifier for the given instance of RtMidiOut. + /// + /// Pointer to object + /// The value + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern MidiApi rtmidi_out_get_current_api(RtMidiPtr rtMidiObject); + + /// + /// Immediately send a single message out an open MIDI output port. + /// + /// + /// An exception is thrown if an error occurs during output or an + /// output connection was not previously established. + /// + /// Pointer to object + /// A pointer to the MIDI message as raw bytes + /// Length of the MIDI message in bytes + /// + [DllImport(RtMidiLibrary, CallingConvention = CallingConvention.Cdecl)] + internal static extern int rtmidi_out_send_message(RtMidiPtr rtMidiObject, byte[] message, int length); + + #endregion + } \ No newline at end of file diff --git a/RtMidi.Net/MidiManager.cs b/RtMidi.Net/MidiManager.cs index 720cf01..6e60b65 100644 --- a/RtMidi.Net/MidiManager.cs +++ b/RtMidi.Net/MidiManager.cs @@ -7,8 +7,8 @@ public static class MidiManager { public static IReadOnlyCollection GetAvailableApis() => RtMidiBase.GetCompiledApi(); public static string GetApiName(MidiApi api) => RtMidiBase.GetApiName(api); - public static string GetApiDisplayName(MidiApi api) => RtMidiBase.GetApiDisplayName(api); + public static string GetRtMidiVersion() => RtMidiBase.GetRtMidiVersion(); public static List GetAvailableDevices() { diff --git a/RtMidi.Net/RtMidi.Net.csproj b/RtMidi.Net/RtMidi.Net.csproj index 8a94757..276064b 100644 --- a/RtMidi.Net/RtMidi.Net.csproj +++ b/RtMidi.Net/RtMidi.Net.csproj @@ -5,6 +5,7 @@ enable LICENSE.md + README.md https://github.com/Daniel127/RtMidi.Net https://github.com/Daniel127/RtMidi.Net git @@ -18,9 +19,7 @@ - - True - - + + diff --git a/WorkerTest/Worker.cs b/WorkerTest/Worker.cs index d9c2319..ba19229 100644 --- a/WorkerTest/Worker.cs +++ b/WorkerTest/Worker.cs @@ -23,13 +23,17 @@ public Worker(ILogger logger) public override async Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation("Starting"); + var rtMidiVersion = MidiManager.GetRtMidiVersion(); + _logger.LogInformation("RtMidi version: {rtMidiVersion}", rtMidiVersion); var devices = MidiManager.GetAvailableDevices(); - foreach (var d in devices) - { - _logger.LogInformation($"{d.Port}) {d.Name} - {d.Type}"); - } if (devices.Any()) { + _logger.LogInformation("Available devices:"); + foreach (var d in devices.OrderBy(info => info.Port)) + { + _logger.LogInformation("{port}) {name} - {type}", d.Port, d.Name, d.Type); + } + var devicePort = 1u; //Change device to test var device = MidiManager.GetDeviceInfo(devicePort, MidiDeviceType.Input); _midiInputClient = new MidiInputClient(device); diff --git a/WorkerTest/WorkerTest.csproj b/WorkerTest/WorkerTest.csproj index f8c5662..b513fa7 100644 --- a/WorkerTest/WorkerTest.csproj +++ b/WorkerTest/WorkerTest.csproj @@ -4,6 +4,8 @@ net7.0 enable enable + AnyCPU + linux-arm dotnet-WorkerTest-B41C8CE5-6C97-4BF3-90FB-7FB7452FA332 From 44ad55ebe1ded17bc39245081ced0f437e90e83a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Qui=C3=B1ones?= Date: Wed, 6 Sep 2023 14:22:00 +0200 Subject: [PATCH 2/2] Applied Code Cleanup --- RtMidi.Net/Clients/MidiInputClient.cs | 18 +-- RtMidi.Net/Clients/MidiOutputClient.cs | 8 +- RtMidi.Net/Enums/MidiMessageType.cs | 2 +- RtMidi.Net/Enums/MusicNote.cs | 2 +- RtMidi.Net/InteropServices/RtMidiBase.cs | 8 +- RtMidi.Net/InteropServices/RtMidiCallback.cs | 2 +- RtMidi.Net/InteropServices/RtMidiIn.cs | 6 +- RtMidi.Net/InteropServices/RtMidiOut.cs | 4 +- RtMidi.Net/MidiNote.cs | 12 +- WorkerTest/Worker.cs | 139 +++++++++---------- 10 files changed, 100 insertions(+), 101 deletions(-) diff --git a/RtMidi.Net/Clients/MidiInputClient.cs b/RtMidi.Net/Clients/MidiInputClient.cs index f3f41b2..f8ee07e 100644 --- a/RtMidi.Net/Clients/MidiInputClient.cs +++ b/RtMidi.Net/Clients/MidiInputClient.cs @@ -1,7 +1,7 @@ -using System.Diagnostics; using RtMidi.Net.Enums; using RtMidi.Net.Events; using RtMidi.Net.InteropServices; +using System.Diagnostics; namespace RtMidi.Net.Clients; @@ -46,7 +46,7 @@ public bool IgnoreSenseMessages public MidiInputClient(MidiDeviceInfo deviceInfo) : base(deviceInfo, new RtMidiIn()) { - _rtMidiInClient = (RtMidiIn) RtMidiClient; + _rtMidiInClient = (RtMidiIn)RtMidiClient; } public void ActivateMessageReceivedEvent() @@ -66,8 +66,8 @@ private void IgnoreMessageTypes(bool sysex, bool time, bool sense) private void InternalMessageReceived(double timestamp, IntPtr messagePtr, UIntPtr messageSize, IntPtr userDataPtr) { - var messageData = new byte [(int) messageSize]; - System.Runtime.InteropServices.Marshal.Copy(messagePtr, messageData, 0, (int) messageSize); + var messageData = new byte[(int)messageSize]; + System.Runtime.InteropServices.Marshal.Copy(messagePtr, messageData, 0, (int)messageSize); var message = ConvertMessage(messageData); var midiEventArgs = new MidiMessageReceivedEventArgs(message, TimeSpan.FromSeconds(timestamp)); OnMessageReceived?.Invoke(this, midiEventArgs); @@ -93,7 +93,7 @@ public async Task<(MidiMessage, TimeSpan)> GetMessageAsync(CancellationToken can { Stopwatch stopwatch = new(); byte[] messageData; - + stopwatch.Start(); do { @@ -113,10 +113,10 @@ private static MidiMessage ConvertMessage(IReadOnlyList message) { MidiMessageType type; - if (message[0] is >= (byte) MidiMessageType.NoteOff and < (byte) MidiMessageType.SystemExclusive) + if (message[0] is >= (byte)MidiMessageType.NoteOff and < (byte)MidiMessageType.SystemExclusive) { - var channel = (MidiChannel) (0b_0000_1111 & message[0]); - type = (MidiMessageType) (0b_1111_0000 & message[0]); + var channel = (MidiChannel)(0b_0000_1111 & message[0]); + type = (MidiMessageType)(0b_1111_0000 & message[0]); switch (type) { @@ -143,7 +143,7 @@ private static MidiMessage ConvertMessage(IReadOnlyList message) return new MidiMessageUnknown(message.ToArray()); } - type = (MidiMessageType) message[0]; + type = (MidiMessageType)message[0]; switch (type) { case MidiMessageType.SystemExclusive: diff --git a/RtMidi.Net/Clients/MidiOutputClient.cs b/RtMidi.Net/Clients/MidiOutputClient.cs index b231b9f..2abbe81 100644 --- a/RtMidi.Net/Clients/MidiOutputClient.cs +++ b/RtMidi.Net/Clients/MidiOutputClient.cs @@ -9,7 +9,7 @@ public class MidiOutputClient : MidiClient public MidiOutputClient(MidiDeviceInfo deviceInfo) : base(deviceInfo, new RtMidiOut()) { - _rtMidiOutClient = (RtMidiOut) RtMidiClient; + _rtMidiOutClient = (RtMidiOut)RtMidiClient; } public void SendMessage(byte[] message) @@ -64,7 +64,7 @@ private static byte[] ConvertMessage(MidiMessage message) }, MidiMessageType.SystemExclusive when message is MidiMessageSystemExclusive(var data, _) => data, //TODO Create Message for TimeCodeQuarterFrame - MidiMessageType.TimeCodeQuarterFrame when message is MidiMessageUnknown (var data, _) => data, + MidiMessageType.TimeCodeQuarterFrame when message is MidiMessageUnknown(var data, _) => data, MidiMessageType.SongPositionPointer when message is MidiMessageSongPositionPointer songPosPointer => new[] { (byte) songPosPointer.Type, @@ -97,12 +97,12 @@ private static byte[] ConvertMessage(MidiMessage message) byte ByteFrom(MidiMessageType messageType, MidiChannel channel) { - return (byte) ((byte) messageType | (byte) channel); + return (byte)((byte)messageType | (byte)channel); } byte[] DefaultMessage(MidiMessage midiMessage) { - return new[] {(byte) midiMessage.Type}; + return new[] { (byte)midiMessage.Type }; } } } \ No newline at end of file diff --git a/RtMidi.Net/Enums/MidiMessageType.cs b/RtMidi.Net/Enums/MidiMessageType.cs index 2b26c9f..1bdde86 100644 --- a/RtMidi.Net/Enums/MidiMessageType.cs +++ b/RtMidi.Net/Enums/MidiMessageType.cs @@ -9,7 +9,7 @@ namespace RtMidi.Net.Enums; public enum MidiMessageType : byte { Unknown = 0, - + NoteOff = 0b_1000_0000, NoteOn = 0b_1001_0000, PolyphonicKeyPressure = 0b_1010_0000, diff --git a/RtMidi.Net/Enums/MusicNote.cs b/RtMidi.Net/Enums/MusicNote.cs index 217be87..e7f73d3 100644 --- a/RtMidi.Net/Enums/MusicNote.cs +++ b/RtMidi.Net/Enums/MusicNote.cs @@ -14,7 +14,7 @@ public enum MusicNote : byte A = 9, ASharp = 10, B = 11, - + Do = C, DoSharp = CSharp, Re = D, diff --git a/RtMidi.Net/InteropServices/RtMidiBase.cs b/RtMidi.Net/InteropServices/RtMidiBase.cs index 75fe21c..7bfa88a 100644 --- a/RtMidi.Net/InteropServices/RtMidiBase.cs +++ b/RtMidi.Net/InteropServices/RtMidiBase.cs @@ -1,5 +1,5 @@ -using System.Runtime.InteropServices; using RtMidi.Net.Enums; +using System.Runtime.InteropServices; namespace RtMidi.Net.InteropServices; @@ -19,7 +19,7 @@ internal abstract class RtMidiBase : IDisposable /// /// Returns true if a port is open and false if not. public bool IsPortOpen { get; private set; } - + protected RtMidiBase(IntPtr rtMidiPtr) { RtMidiPtr = rtMidiPtr; @@ -97,7 +97,7 @@ public string GetPortName(uint portNumber, uint? nameSize = null) bufferNameSize = nameSize.Value; } - messagePtr = Marshal.AllocHGlobal((int) bufferNameSize); + messagePtr = Marshal.AllocHGlobal((int)bufferNameSize); try { resultInterop = RtMidiInterop.rtmidi_get_port_name(RtMidiPtr, portNumber, messagePtr, ref bufferNameSize); @@ -159,7 +159,7 @@ public static IReadOnlyCollection GetCompiledApi() var unmanagedPointer = Marshal.AllocHGlobal(apis.Length); Marshal.Copy(apis, 0, unmanagedPointer, apis.Length); var result = RtMidiInterop.rtmidi_get_compiled_api(unmanagedPointer, sizeof(MidiApi)); - apis = new byte [result]; + apis = new byte[result]; Marshal.Copy(unmanagedPointer, apis, 0, result); var apisResult = apis.Cast().ToList(); Marshal.FreeHGlobal(unmanagedPointer); diff --git a/RtMidi.Net/InteropServices/RtMidiCallback.cs b/RtMidi.Net/InteropServices/RtMidiCallback.cs index 305add1..ef32c7e 100644 --- a/RtMidi.Net/InteropServices/RtMidiCallback.cs +++ b/RtMidi.Net/InteropServices/RtMidiCallback.cs @@ -3,4 +3,4 @@ namespace RtMidi.Net.InteropServices; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] -internal delegate void RtMidiCallback (double timestamp, IntPtr message, UIntPtr size, IntPtr userData); \ No newline at end of file +internal delegate void RtMidiCallback(double timestamp, IntPtr message, UIntPtr size, IntPtr userData); \ No newline at end of file diff --git a/RtMidi.Net/InteropServices/RtMidiIn.cs b/RtMidi.Net/InteropServices/RtMidiIn.cs index da30a16..f482b66 100644 --- a/RtMidi.Net/InteropServices/RtMidiIn.cs +++ b/RtMidi.Net/InteropServices/RtMidiIn.cs @@ -1,5 +1,5 @@ -using System.Runtime.InteropServices; using RtMidi.Net.Enums; +using System.Runtime.InteropServices; namespace RtMidi.Net.InteropServices; @@ -121,12 +121,12 @@ public void IgnoreTypes(bool midiSysex = true, bool midiTime = true, bool midiSe { var size = 1024; var messagePtr = Marshal.AllocHGlobal(size); - + var timestamp = RtMidiInterop.rtmidi_in_get_message(RtMidiPtr, messagePtr, ref size); var message = new byte[size]; Marshal.Copy(messagePtr, message, 0, size); Marshal.FreeHGlobal(messagePtr); - + return (message, timestamp); } diff --git a/RtMidi.Net/InteropServices/RtMidiOut.cs b/RtMidi.Net/InteropServices/RtMidiOut.cs index 7eabd10..9e8297f 100644 --- a/RtMidi.Net/InteropServices/RtMidiOut.cs +++ b/RtMidi.Net/InteropServices/RtMidiOut.cs @@ -19,7 +19,7 @@ internal class RtMidiOut : RtMidiBase public RtMidiOut() : base(RtMidiInterop.rtmidi_out_create_default()) { } - + /// /// Default constructor that allows an optional client name. /// @@ -36,7 +36,7 @@ public RtMidiOut(MidiApi api, string clientName) : base(RtMidiInterop.rtmidi_out_create(api, clientName)) { } - + /// public override MidiApi GetCurrentApi() { diff --git a/RtMidi.Net/MidiNote.cs b/RtMidi.Net/MidiNote.cs index 1cbe6c1..e0b787d 100644 --- a/RtMidi.Net/MidiNote.cs +++ b/RtMidi.Net/MidiNote.cs @@ -21,8 +21,8 @@ namespace RtMidi.Net; public MidiNote(byte note) { if (note > 127) throw new ArgumentOutOfRangeException(nameof(note), "The note must be 0 to 127"); - Note = (MusicNote) (note % 12); - Octave = (MusicOctave) (note / 12); + Note = (MusicNote)(note % 12); + Octave = (MusicOctave)(note / 12); } /// @@ -42,7 +42,7 @@ public MidiNote(MusicNote note, MusicOctave octave) /// The MIDI byte representation public byte GetByteRepresentation() { - return (byte) ((byte) Note + (byte) ((byte) Octave * 12)); + return (byte)((byte)Note + (byte)((byte)Octave * 12)); } /// @@ -67,13 +67,13 @@ public string GetName(bool useLatinName = false) if (useLatinName) { var latinName = notesNames.Except(angloSaxonNames).ToList(); - noteName = latinName[(int) Note]; + noteName = latinName[(int)Note]; } else { - noteName = angloSaxonNames[(int) Note]; + noteName = angloSaxonNames[(int)Note]; } - return $"{noteName.Replace("Sharp", "#")}{(int) Octave}"; + return $"{noteName.Replace("Sharp", "#")}{(int)Octave}"; } } \ No newline at end of file diff --git a/WorkerTest/Worker.cs b/WorkerTest/Worker.cs index ba19229..3fbe77d 100644 --- a/WorkerTest/Worker.cs +++ b/WorkerTest/Worker.cs @@ -3,95 +3,94 @@ using RtMidi.Net.Enums; using RtMidi.Net.Events; -namespace WorkerTest +namespace WorkerTest; + +public class Worker : BackgroundService { - public class Worker : BackgroundService - { - private readonly ILogger _logger; - private MidiInputClient? _midiInputClient; - private const bool UseEventHandler = true; //Change to test + private readonly ILogger _logger; + private MidiInputClient? _midiInputClient; + private const bool UseEventHandler = true; //Change to test - /// - /// Constructor - /// - /// - public Worker(ILogger logger) - { - _logger = logger; - } + /// + /// Constructor + /// + /// + public Worker(ILogger logger) + { + _logger = logger; + } - public override async Task StartAsync(CancellationToken cancellationToken) + public override async Task StartAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Starting"); + var rtMidiVersion = MidiManager.GetRtMidiVersion(); + _logger.LogInformation("RtMidi version: {rtMidiVersion}", rtMidiVersion); + var devices = MidiManager.GetAvailableDevices(); + if (devices.Any()) { - _logger.LogInformation("Starting"); - var rtMidiVersion = MidiManager.GetRtMidiVersion(); - _logger.LogInformation("RtMidi version: {rtMidiVersion}", rtMidiVersion); - var devices = MidiManager.GetAvailableDevices(); - if (devices.Any()) + _logger.LogInformation("Available devices:"); + foreach (var d in devices.OrderBy(info => info.Port)) { - _logger.LogInformation("Available devices:"); - foreach (var d in devices.OrderBy(info => info.Port)) - { - _logger.LogInformation("{port}) {name} - {type}", d.Port, d.Name, d.Type); - } - - var devicePort = 1u; //Change device to test - var device = MidiManager.GetDeviceInfo(devicePort, MidiDeviceType.Input); - _midiInputClient = new MidiInputClient(device); - if (UseEventHandler) - { - _midiInputClient.OnMessageReceived += MidiClient_OnMessageReceived; - _midiInputClient.ActivateMessageReceivedEvent(); - } - _midiInputClient.Open(); + _logger.LogInformation("{port}) {name} - {type}", d.Port, d.Name, d.Type); } - else + + var devicePort = 1u; //Change device to test + var device = MidiManager.GetDeviceInfo(devicePort, MidiDeviceType.Input); + _midiInputClient = new MidiInputClient(device); + if (UseEventHandler) { - var exception = new Exception("No Midi devices found"); - _logger.LogError(exception, "No Midi devices found"); - throw exception; + _midiInputClient.OnMessageReceived += MidiClient_OnMessageReceived; + _midiInputClient.ActivateMessageReceivedEvent(); } - - await base.StartAsync(cancellationToken); + _midiInputClient.Open(); + } + else + { + var exception = new Exception("No Midi devices found"); + _logger.LogError(exception, "No Midi devices found"); + throw exception; } - protected override async Task ExecuteAsync(CancellationToken stoppingToken) + await base.StartAsync(cancellationToken); + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + _logger.LogInformation("Executing"); + if (!UseEventHandler) { - _logger.LogInformation("Executing"); - if (!UseEventHandler) + while (!stoppingToken.IsCancellationRequested) { - while (!stoppingToken.IsCancellationRequested) - { - var (message, _) = await _midiInputClient!.GetMessageAsync(stoppingToken); - OnMessageReceived(message); - } + var (message, _) = await _midiInputClient!.GetMessageAsync(stoppingToken); + OnMessageReceived(message); } } + } - public override async Task StopAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Stopping"); - _midiInputClient?.Close(); - _midiInputClient?.Dispose(); - await base.StopAsync(cancellationToken); - } + public override async Task StopAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Stopping"); + _midiInputClient?.Close(); + _midiInputClient?.Dispose(); + await base.StopAsync(cancellationToken); + } + + private void MidiClient_OnMessageReceived(object? sender, MidiMessageReceivedEventArgs args) + { + OnMessageReceived(args.Message); + } - private void MidiClient_OnMessageReceived(object? sender, MidiMessageReceivedEventArgs args) + private void OnMessageReceived(MidiMessage midiMessage) + { + if (midiMessage is MidiMessageNote { Type: MidiMessageType.NoteOn or MidiMessageType.NoteOff } message) { - OnMessageReceived(args.Message); + const int offset = 21; + var note = message.Note.GetByteRepresentation() - offset; + _logger.LogInformation("{noteName} - {messageType}, Note number: {noteNumber}", message.Note.GetName(), message.Type, note); } - - private void OnMessageReceived(MidiMessage midiMessage) + else { - if (midiMessage is MidiMessageNote { Type: MidiMessageType.NoteOn or MidiMessageType.NoteOff } message) - { - const int offset = 21; - var note = message.Note.GetByteRepresentation() - offset; - _logger.LogInformation("{noteName} - {messageType}, Note number: {noteNumber}", message.Note.GetName(), message.Type, note); - } - else - { - _logger.LogInformation("{messageType}", midiMessage.Type); - } + _logger.LogInformation("{messageType}", midiMessage.Type); } } } \ No newline at end of file