Running the audio processing and midi dispatcher loops in a regular
`std::thread` causes weird memory corruption issues (likely because of
calling conventions are not being respected). Luckily this does not
cause any issues here, so we can get rid of a lot of ugly glue code and
manual memory management.
This makes the individual plugin host slightly more complex, but now
both individually hosted plugins and plugin groups handle both
dispatcher events and GUI events in the exact same way.
Should not matter that much, but a potential situation where you would
want to have handled the X11 events first is when the editor enters a
blocking message loop while it is waiting on a GUI component just as the
window gets moved by an external program or window manager.
At a 30 fps rate with a limit on the number of window messages per
frame. This is somehow needed for Melda plugins, as they otherwise
dispatch tiemr messages indefinitely after opening a second editor with
seemingly no way around it.
With this and some refactoring #15 should be almost done.
This is a bit more restrictive than the old approach that only skipped
when `effEditOpen()` got called after `effEditGetRect()`. Not sure why
the Melda plugins block indefinitely on the message loop without this
now.
Based on a function. This is needed because the message loop should be
skipped while any of the plugins is opening their GUI, similar to how
`EditorOpening` worked for individually hosted plugins.
With this the plugin groups functionality is feature complete, although
I still want to do a few rounds of refactoring and the readme has not
yet been updated.
Handles for things like timers should be unique on a per-thread basis in
the Win32 API, but apparently window classes have to be unique for the
entire application.
This allows for a significant speedup in plugin scanning time for plugin
groups, since starting Wine processes takes up pretty much the entirety
of the time spent scanning plugins.
This was not a problem with individually hosted plugins because the
entire process got terminated at once, but here we all threads to shut
down gracefully when a plugin's sockets get closed. I wish this wouldn't
need all these try-catches, but we're not writing Haskell here.
The only issue remaining is that for some reason only the first
instance's editor works, at least for Serum. This might be because of
the message loop.
In case two yabridge instances start at the same time and both try to
launch a group host for the same group and the second plugin connects to
the first group host, then we should of course be using that process'es
PID to check if the group host is still running.