atsushieno / managed-midi

[Past project] Cross-platform MIDI processing library for mono and .NET (ALSA, CoreMIDI, Android, WinMM and UWP).
MIT License
195 stars 26 forks source link

"start_index + length > array length" with sample code #76

Open jamesdlow opened 1 year ago

jamesdlow commented 1 year ago

I'm getting an error when I try to execute the sample code on macOS. I've tried running on iOS and it errors too. I've debugged and the output exists and I have its name/id. Any idea what the issue is?

Message:

start_index + length > array length
Parameter name: length

The exception is a System.ArgumentException

Stacktrace:

Parameter name: length
  at (wrapper managed-to-native) System.Runtime.InteropServices.Marshal.copy_to_unmanaged_fixed(System.Array,int,intptr,int,void*)
  at System.Runtime.InteropServices.Marshal.copy_to_unmanaged (System.Byte[] source, System.Int32 startIndex, System.IntPtr destination, System.Int32 length) [0x00009] in <a6df87efff2943d29ff8026b1ac9d2b4>:0 
  at System.Runtime.InteropServices.Marshal.Copy (System.Byte[] source, System.Int32 startIndex, System.IntPtr destination, System.Int32 length) [0x00009] in <a6df87efff2943d29ff8026b1ac9d2b4>:0 
  at CoreMidi.MidiPacket.CreatePacketList (CoreMidi.MidiPacket[] packets) [0x000c3] in <2735c8d44acc4ce5b6bc41d44dbdcd65>:0 
  at CoreMidi.MidiPort.Send (CoreMidi.MidiEndpoint endpoint, CoreMidi.MidiPacket[] packets) [0x00027] in <2735c8d44acc4ce5b6bc41d44dbdcd65>:0 
  at Commons.Music.Midi.CoreMidiApi.CoreMidiOutput.Send (System.Byte[] mevent, System.Int32 offset, System.Int32 length, System.Int64 timestamp) [0x00045] in <01d9a7dce4614f6abd73f7ca4c00c2ae>:0 
  at PadMIDI.App.Down_Clicked (System.Object sender, System.EventArgs e) [0x0006c] in <44638a4d7b7f4c21a78010334ae19de6>:0 

Code:

var access = MidiAccessManager.Default;
if (access.Outputs.Count() > 0) {
    var output = access.OpenOutputAsync(access.Outputs.Last().Id).Result;
    output.Send(new byte[] { MidiEvent.NoteOn, 0x40, 0x70 }, 0, 3, 0);
    output.CloseAsync();
}
jamesdlow commented 1 year ago

I've tried wrapping in a Device.BeginInvokeOnMainThread incase that helped, but it didn't.

jamesdlow commented 1 year ago

I've also double-checked, I can receive MIDI from my device.

jamesdlow commented 1 year ago

Ok, so if I set length to 0, i.e. output.Send(new byte[] { MidiEvent.NoteOn, 0x40, 0x70 }, 0, 0, 0); there is no error, but this sends no MIDI data. But may help in debugging the exception, since it may be that for whatever reason the length of an array further down is 0. Is it when it's being copied in System.Runtime.InteropServices.Marshal.Copy?

jamesdlow commented 1 year ago

I think I've tracked it down to an issue with xamarin/xamarin-macios https://github.com/xamarin/xamarin-macios/pull/18981

jamesdlow commented 1 year ago

A workaround would be to switch: new MidiPacket(timestamp, (ushort)length, (IntPtr)(ptr + offset)); to new MidiPacket(timestamp, mevent, offset, length) in CoreMidiAccess.cs

        public void Send (byte[] mevent, int offset, int length, long timestamp)
        {
            unsafe {
                fixed (byte* ptr = mevent) {
                    arr [0] = new MidiPacket(timestamp, (ushort)length, (IntPtr)(ptr + offset));
                    port.Send (details.Endpoint, arr);
                }
            }
        }

There are other constructors for MidiPacket that don't use pointers: https://learn.microsoft.com/en-us/dotnet/api/coremidi.midipacket.-ctor?view=xamarin-ios-sdk-12