When many Midi Events are received, references outside the buffer range occur.
mkc1370
VRCSDK3-WORLD-2021.03.09.13.57_Public
Unity 2018.4.20f1
When many Midi Events are received, references outside the buffer range will occur.
Log
IndexOutOfRangeException: Index was outside the bounds of the array.
VRC.SDKBase.Midi.VRCPortMidiInput.Update () (at Assets/VRCSDK/SDK3/Runtime/Midi/VRCPortMidi.cs:71)
VRC.SDK3.Midi.VRCMidiHandler.Update () (at <5d3e9f7f72234587a2c25e98f82b4f27>:0)
Log In
ku6dra
I am having this problem as well.
VRCPortMidi.cs:line 39
_data = new byte[1024];
Currently, the size of
_data
(byte Array) that holds the incoming data is set to 1024 bytes.VRCPortMidi.cs:line 61
public void Update()
{
if (_input == null) return;
if (_input.HasData)
{
// Portmidi reports 4 bytes per event but the buffer has 8 bytes so we multiply count by 2
int count = (_input.Read(_data, 0, _data.Length)) * 2;
for (int i = 0; i < count; i+=8)
{
ConvertAndSend(_data[i], _data[i + 1], _data[i + 2]);
}
}
}
This exception occurs because the value that goes into the
count
(int) variable above exceeds the array length of _data
.MidiDeviceManager:line 11
private const int DefaultBufferSize = 1024;
In the above section,
DefaultBufferSize
is set to 1024, which I assume is the maximum number of buffers for incoming MIDI events.The return value of the
MidiInput.Read()
method is Number of MIDI events copied to _data * 4
, and then doubled when calculating count
, the maximum value of count
is 1024 * 4 * 2 = 8192
.In the current implementation, if more than 128 events are received in a single frame, an exception will be thrown and MIDI events beyond that will be dropped.
As a way to fix this problem...
- Change the _dataarray length from 1024 to 8192 and change the third argument of_input.Read()to 1024.
Allow up to 1024 events to be received per frame.
- Change the third argument of _input.Read()from 1024 to 128.
Events exceeding 128 will be processed in the next frame.
- If the value of countexceeds 1024, cap it to 1024.
Process up to 128 events per frame without exception, and drop events exceeding 128.
So far this is not a big problem (because it keeps working even if an exception is thrown), but there is another problem.
If MIDI events exceeding the
DefaultBufferSize
(1024) are received, all note-offs will be triggered and subsequent MIDI events will not be received, and a crash may occur at the following times.- (Both) Immediately
- (Client) During Scene transition (moving to another World)
- (Editor) When exit playmode
This problem can be reproduced by performing the following operations while playing a MIDI file to a Virtual MIDI IN Port created using loopMIDI, etc.
- (Both) Right-click on the window to open the context menu, and wait about 10 seconds
- (Both) Turn on the monitor (depends on the PC environment)
- (Client) Join/Leave the world
- (Editor) Focus the Editor window
- (Editor) Press Play or Pause button
- (Editor) Perform Asset import process
or...
- (Client) Load Avatar
- (Client) Open/Close in-game menu or SteamVR overlay
- (Client) Toggle Virtual Desktop Desktop/VR Mode
If you are developing a world that uses
VRCMidiListener
and are having this problem, you can make it less likely to crash in Editor by changing the DefaultBufferSize
in MidiDeviceManager.cs to a huge value like 65536.- Client: Build 1205
- com.vrchat.base: 3.0.8
- com.vrchat.worlds: 3.0.8
- com.vrchat.udonsharp: 1.0.1
DerpyEagle
In trying to pass data into VRChat via the MIDI interface, I have also just encountered this issue.
Unity 2019.4.29f1, using World SDK 2021.08.11.15.16 and UdonSharp 0.20.2.
I seem to only be able to receive around 100-300 MIDI events before the error occurs. The rate at which the MIDI note events are sent does not seem to affect the error.
That said, I have also noticed a strange behaviour related to the error: by "warming up" the MIDI handler by sending a few short bursts of events before finally sending larger chunks, the bug can be delayed. At this point, I've seen it work from anywhere between 12,000 MIDI events to around 70,000. The error will still eventually occur.
Here's a 7z containing the project folder for my test project, as well as the HTML file for the webpage I use to send MIDI events in. Load & play SampleScene, then send in data of varying length to replicate the bug.