/// <summary> /// Creates and initializes a <see cref="LongMessage"/>, for use inside the <see cref="MidiInputDevice.Callback"/> method. /// </summary> /// <param name="messageParameterA">An <see cref="IntPtr"/> to store a reference to the first message parameter.</param> /// <param name="messageParameterB">An <see cref="IntPtr"/> to store a reference to the second message parameter.</param> internal LongMessage(IntPtr messageParameterA, IntPtr messageParameterB) { // Set the pointer to the MIDI header structure (Converted from UIntPtr to IntPtr) _MidiHeaderPointer = unchecked ((IntPtr)(long)(ulong)messageParameterA); // Create a managed copy of the MIDI header _MidiHeader = (API.MidiHeader)Marshal.PtrToStructure(_MidiHeaderPointer, typeof(API.MidiHeader)); // Create the data array with the size of the long message this.Data = new byte[_MidiHeader.BytesRecorded]; // Fill the data array by looping through the MIDI header data for (int i = 0; i < _MidiHeader.BytesRecorded; i++) { this.Data[i] = Marshal.ReadByte(_MidiHeader.Data, i); } // Extract the ID byte this.ID = this.Data[1]; // Extract message parameter B this.TimeStamp = (int)messageParameterB; // Set the parameter references this.ParameterA = messageParameterA; this.ParameterB = messageParameterB; }
private void Dispose(bool disposing) { if (!_IsDisposed) { if (disposing) { // TODO: dispose managed state (managed objects) } if (_Buffer.Count > 0) { API.ResetMidiInputDevice(_Handle); foreach (var headerPointer in _Buffer) { API.MidiHeader header = (API.MidiHeader)Marshal.PtrToStructure(headerPointer, typeof(API.MidiHeader)); API.UnprepareMidiInputHeader(_Handle, headerPointer, Marshal.SizeOf(typeof(API.MidiHeader))); Marshal.FreeHGlobal(header.Data); Marshal.FreeHGlobal(headerPointer); } } API.CloseMidiInputDevice(_Handle); // TODO: free unmanaged resources (unmanaged objects) and override finalizer // TODO: set large fields to null _IsDisposed = true; } }
/// <summary> /// Callback function to be called by the system. /// </summary> /// <param name="handle">An <see cref="API.MidiDeviceHandle"/> to the MIDI input device to associate with the callback function.</param> /// <param name="message">An <see cref="API.MidiInputMessage"/> containing the message.</param> /// <param name="instance">An <see cref="IntPtr"/> to the instance data supplied by the <see cref="API.OpenMidiInputDevice"/> function.</param> /// <param name="messageParameterA">An <see cref="IntPtr"/> to the first message parameter.</param> /// <param name="messageParameterB">An <see cref="IntPtr"/> to the second message parameter.</param> private void Callback(API.MidiDeviceHandle handle, API.MidiInputMessage message, IntPtr instance, IntPtr messageParameterA, IntPtr messageParameterB) { switch (message) { case API.MidiInputMessage.MIDI_INPUT_MESSAGE_DATA: // A = Packed MIDI message, B = Time in milliseconds since Start ProcessShortMessage(new ShortMessage(messageParameterA, messageParameterB)); break; case API.MidiInputMessage.MIDI_INPUT_MESSAGE_LONG_DATA: // Extracts the MIDI header for message validation API.MidiHeader midiHeader = (API.MidiHeader)Marshal.PtrToStructure(messageParameterA, typeof(API.MidiHeader)); // Prevents creation of long messages when the MIDI header buffer is empty if (midiHeader.BytesRecorded == 0) { ReleaseBuffer(messageParameterA); return; } // A = Pointer to MIDI header, B = Time in milliseconds since Start ProcessLongMessage(new LongMessage(messageParameterA, messageParameterB)); break; case API.MidiInputMessage.MIDI_INPUT_MESSAGE_MORE_DATA: Console.WriteLine("MIDI IN MORE DATA"); // A = Packed MIDI message, B = Time in milliseconds since Start break; case API.MidiInputMessage.MIDI_INPUT_MESSAGE_ERROR: // A = Invalid MIDI message, B = Time in milliseconds since Start break; case API.MidiInputMessage.MIDI_INPUT_MESSAGE_LONG_ERROR: // A = Pointer to MIDI header, B = Time in milliseconds since Start break; case API.MidiInputMessage.MIDI_INPUT_MESSAGE_OPEN: this.IsOpen = true; break; case API.MidiInputMessage.MIDI_INPUT_MESSAGE_CLOSE: this.IsOpen = false; break; } }
/// <summary> /// Releases an existing buffer and associated memory. /// </summary> /// <param name="buffer">An <see cref="IntPtr"/> referencing the buffer to release.</param> /// <exception cref="MidiInputDeviceException">Raises <see cref="API.Result.MULTIMEDIA_SYSTEM_ERROR_INVALID_HANDLE"/>.</exception> /// <exception cref="MidiInputDeviceException">Raises <see cref="API.Result.MULTIMEDIA_SYSTEM_ERROR_INVALID_PARAMETER"/>.</exception> /// <exception cref="MidiInputDeviceException">Raises <see cref="API.Result.MIDI_ERROR_STILL_PLAYING"/>.</exception> private void ReleaseBuffer(IntPtr buffer) { IntPtr headerPointer = unchecked ((IntPtr)(long)(ulong)buffer); int headerSize = Marshal.SizeOf(typeof(API.MidiHeader)); InvalidateResult(API.UnprepareMidiInputHeader(_Handle, headerPointer, headerSize)); API.MidiHeader midiHeader = (API.MidiHeader)Marshal.PtrToStructure(headerPointer, typeof(API.MidiHeader)); Marshal.FreeHGlobal(midiHeader.Data); Marshal.FreeHGlobal(headerPointer); _Buffer.Remove(headerPointer); }
/// <summary> /// Sends a long MIDI message. /// </summary> /// <param name="message">The long MIDI message to send.</param> /// <exception cref="MidiOutputDeviceException">Raises <see cref="API.Result.MULTIMEDIA_SYSTEM_ERROR_INVALID_HANDLE"/>.</exception> /// <exception cref="MidiOutputDeviceException">Raises <see cref="API.Result.MULTIMEDIA_SYSTEM_ERROR_NO_MEM"/>.</exception> /// <exception cref="MidiOutputDeviceException">Raises <see cref="API.Result.MULTIMEDIA_SYSTEM_ERROR_INVALID_PARAMETER"/>.</exception> /// <exception cref="MidiOutputDeviceException">Raises <see cref="API.Result.MIDI_ERROR_UNPREPARED"/>.</exception> /// <exception cref="MidiOutputDeviceException">Raises <see cref="API.Result.MIDI_ERROR_STILL_PLAYING"/>.</exception> /// <exception cref="MidiOutputDeviceException">Raises <see cref="API.Result.MIDI_ERROR_NOT_READY"/>.</exception> public void Send(LongMessage message) { IntPtr midiHeaderPointer; int midiHeaderSize = Marshal.SizeOf(typeof(API.MidiHeader)); API.MidiHeader midiHeader = new API.MidiHeader(); midiHeader.Data = Marshal.AllocHGlobal(message.Data.Length); for (int i = 0; i < message.Data.Length; i++) { Marshal.WriteByte(midiHeader.Data, i, message.Data[i]); } midiHeader.BufferSize = message.Data.Length; midiHeader.BytesRecorded = message.Data.Length; midiHeader.Flags = 0; try { midiHeaderPointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(API.MidiHeader))); } catch (Exception) { Marshal.FreeHGlobal(midiHeader.Data); throw; } try { Marshal.StructureToPtr(midiHeader, midiHeaderPointer, false); } catch (Exception) { Marshal.FreeHGlobal(midiHeader.Data); Marshal.FreeHGlobal(midiHeaderPointer); throw; } InvalidateResult(API.PrepareMidiOutputHeader(_Handle, midiHeaderPointer, midiHeaderSize)); InvalidateResult(API.SendLongMessage(_Handle, midiHeaderPointer, midiHeaderSize)); InvalidateResult(API.UnprepareMidiOutputHeader(_Handle, midiHeaderPointer, midiHeaderSize)); Marshal.FreeHGlobal(midiHeader.Data); Marshal.FreeHGlobal(midiHeaderPointer); }
/// <summary> /// Creates a buffer for receiving <see cref="LongMessage"/>s. /// </summary> /// <returns>An <see cref="IntPtr"/> referencing the created buffer.</returns> /// <exception cref="MidiInputDeviceException">Raises <see cref="API.Result.MULTIMEDIA_SYSTEM_ERROR_INVALID_HANDLE"/>.</exception> /// <exception cref="MidiInputDeviceException">Raises <see cref="API.Result.MULTIMEDIA_SYSTEM_ERROR_NO_MEM"/>.</exception> /// <exception cref="MidiInputDeviceException">Raises <see cref="API.Result.MULTIMEDIA_SYSTEM_ERROR_INVALID_PARAMETER"/>.</exception> /// <exception cref="MidiInputDeviceException">Raises <see cref="API.Result.MIDI_ERROR_UNPREPARED"/>.</exception> /// <exception cref="MidiInputDeviceException">Raises <see cref="API.Result.MIDI_ERROR_STILL_PLAYING"/>.</exception> private IntPtr CreateBuffer() { IntPtr midiHeaderPointer; int headerSize = Marshal.SizeOf(typeof(API.MidiHeader)); API.MidiHeader midiHeader = new API.MidiHeader(); // TODO: Optimize buffer size midiHeader.Data = Marshal.AllocHGlobal(256); midiHeader.BufferSize = 256; midiHeader.Flags = 0; try { midiHeaderPointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(API.MidiHeader))); } catch (Exception) { Marshal.FreeHGlobal(midiHeader.Data); throw; } try { Marshal.StructureToPtr(midiHeader, midiHeaderPointer, false); } catch (Exception) { Marshal.FreeHGlobal(midiHeader.Data); Marshal.FreeHGlobal(midiHeaderPointer); throw; } InvalidateResult(API.PrepareMidiInputHeader(_Handle, midiHeaderPointer, headerSize)); InvalidateResult(API.AddMidiInputBuffer(_Handle, midiHeaderPointer, headerSize)); return(midiHeaderPointer); }