managed-midi icon indicating copy to clipboard operation
managed-midi copied to clipboard

"start_index + length > array length" with sample code

Open jamesdlow opened this issue 2 years ago • 5 comments

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 avatar Sep 09 '23 04:09 jamesdlow

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

jamesdlow avatar Sep 09 '23 05:09 jamesdlow

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

jamesdlow avatar Sep 09 '23 06:09 jamesdlow

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 avatar Sep 09 '23 08:09 jamesdlow

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

jamesdlow avatar Sep 09 '23 11:09 jamesdlow

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

jamesdlow avatar Sep 09 '23 11:09 jamesdlow