I'm trying to connect to my MIDI device to a Flutter app running on Windows. I'm using win32 and dart ffi. I have the following:
final Pointer<HMIDIIN> hMidiDevice = malloc();
Pointer<NativeFunction<MidiInProc>> callbackPointer =
Pointer.fromFunction(midiInCallback);
final result = midiInOpen(
hMidiDevice,
0,
callbackPointer.address,
0,
CALLBACK_FUNCTION,
);
midiInStart(hMidiDevice.value);
midiInOpen
takes a pointer to a function as 3rd argument. Here is my callback method:
static void midiInCallback(
int hMidiIn,
int wMsg,
int dwInstance,
int dwParam1,
int dwParam2,
) {
print('Message: $wMsg dwParam1: $dwParam1');
}
This compiles and works with a connected USB MIDI device. However, when I press a key on my MIDI device, then I get the following error:
../../third_party/dart/runtime/vm/runtime_entry.cc: 3657: error: Cannot invoke native callback outside an isolate.
pid=11004, thread=21860, isolate_group=(nil)(0000000000000000), isolate=(nil)(0000000000000000)
isolate_instructions=0, vm_instructions=7ffef50837c0
pc 0x00007ffef51a3732 fp 0x00000057468ff990 angle::PlatformMethods::operator=+0x322d8a
-- End of DumpStackTrace
What does it mean and what can I do so that my callback is called with MIDI data?
Dart 3.1 introduced NativeCallable.listener, which can be used to create callbacks that allow native code to call into Dart code from any thread. Only void
functions are supported.
Here's a revised version of your example, now incorporating the NativeCallable.listener
:
final Pointer<HMIDIIN> hMidiDevice = malloc();
final nativeCallable = NativeCallable<MidiInProc>.listener(midiInCallback);
final result = midiInOpen(
hMidiDevice,
0,
nativeCallable.nativeFunction.address,
0,
CALLBACK_FUNCTION,
);
midiInStart(hMidiDevice.value);
// Don't forget to close the callback when it is no longer needed.
// Otherwise, the Isolate will be kept alive indefinitely.
nativeCallable.close();