Author Topic: Multi-threading loading VSTi channels  (Read 289 times)

Wayne McHugh

  • Posts: 91
Multi-threading loading VSTi channels
« on: 7 Jul '24 - 21:42 »
The upgrade to my C++ MIDI player to utilise VST instruments on some channels is finally nearly complete, however there is a speed issue in loading. The BASS_VST_ChannelCreate call takes up to a second to run, so in songs when (eg) 6 channels are utilising VSTi, the song can take 5-6 seconds to load which is uncomfortably long.  I thought to load them simultaneously in separate threads, using join() to wait for them all to complete. However there are tricky issues with some VSTi's (especially Addictive Keys), and I wonder if you have any advice on this multi-threading idea.

I expect the main issues relate to the three key lines:
   m_hVST_stream = BASS_VST_ChannelCreate(44100, 2, getVSTiPlugin()->getPluginFilePath(), BASS_SAMPLE_FLOAT | BASS_STREAM_DECODE);
   m_hGuitar_stream = BASS_MIDI_StreamGetChannel(m_hMIDI_chan, m_nChannel+16); // get a stream for the MIDI channel (0-15) to be handled by the VSTi
   BASS_ChannelSetDSP(m_hGuitar_stream, Guitar_DSP_Callback, (VOID*)this, 0); // set a DSP function on the guitar channel to feed-in the VSTi output

Soon after the above lines, I set initial chunk data and parameters on the VSTi.
   BASS_VST_SetChunk(m_hVST_stream, 1, lpszBuffer, nSize);
   Sleep(100);   // needed for execution of the VST_SetChunk()
   BASS_VST_SetParam(m_hVST_stream, pProgram->getVSTiCommand(i)->getCommand(), pProgram->getVSTiCommand(i)->getValue());
   BASS_VST_SetParam(m_hVST_stream, 0, 0.5);

These are all the BASS/BASSVST related calls that occur in the separate threads.

I learned through trial and error to mutex lock the top 3 lines per VSTi (eg Addictive Keys), because when I had 2 or more channels using Addictive Keys it was erroneously reporting wrong computer id.  The mutex resolved that issue, but not other issues.

I'm wondering if you have any general advice/experience on multi-threading the creation of VSTi channels.  Otherwise I seem to be stuck with the long song setup time.  Thanks, as always.

Wayne McHugh

  • Posts: 91
Re: Multi-threading loading VSTi channels
« Reply #1 on: 10 Jul '24 - 00:45 »
I've received a response from the Addictive Keys developers, which doesn't make enough sense to me to suggest an action.  They responded:

"Addictive Keys relies on an event loop running on its thread to initialize it. So I think it should be possible to load it entirely on a separate thread, but it would need to have access to some kind of event loop (either the main thread one, or another one). Similarly, instrument changes or other relies on the event-loop running too. This is most likely the only missing thing for having AK loading correctly without issue."

Changing instrument and bringing up the Addictive Keys console are the two things malfunctioning, so I suspect the advice is good. Any thoughts on what they mean as it intersects with BASS/BASSVST?

Ian @ un4seen

  • Administrator
  • Posts: 26015
Re: Multi-threading loading VSTi channels
« Reply #2 on: 10 Jul '24 - 13:39 »
By "event loop", I guess they mean a Windows message loop, something like this:

Code: [Select]
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

The main thread will already have one, and you can do the same in other threads. Did they say whether the initialization thread with its event/message loop needs to exist for the lifetime of the VSTi? Seems like it probably would, in which case, you wouldn't be able to "join" the created thread(s) already after inialization.

Are you creating multiple instances of the same VSTi and playing them together? If so, perhaps you could instead create just one instance and send events to it on multiple channels? Another tweak could be to reuse the VSTi on multiple MIDI files, so you only get the initialization delay once.

Wayne McHugh

  • Posts: 91
Re: Multi-threading loading VSTi channels
« Reply #3 on: 10 Jul '24 - 21:42 »
Thanks Ian. If they are referring to a windows message loop, I’m assuming it would have to be a stay-alive thread, since the main thread has a message loop and doesn’t work properly.

Sharing a thread per VSTi would be tricky since any instrument can be changed and cease to use the same (or any) VSTi, and visa versa.

Only the one VSTi in my list has this problem. All the others initialise and run fine being initialised in a different thread which ends after initialisation.

I’ll have a play, ask them further clarifying questions, and post back here what I learn.

Wayne McHugh

  • Posts: 91
Re: Multi-threading loading VSTi channels
« Reply #4 on: 17 Jul '24 - 01:19 »
I've made huge progress on this.

1. Yes, the threads have to stay alive for the lifetime of the VSTi instance.

2. The "event loop" is, in the first instance, a manually created loop watching for custom events that I invented. Setting a flag indicating the action to be performed, and fields for any supporting data, protected by mutexes, of course.

3. The VSTi console is the one that requires the most attention:
a) GetInfo has to be called to get the dimensions of the console, and later to load the console.
b) A modeless dialog has to be created on which the console will be embedded, and a message loop created to support it - loading some info in InitDialog and reading data from the VSTi in OnCancel/OnOK.

Sometimes it works perfectly. If music is playing it keeps playing, the console appears, and any changed get reflected back in my app, and the music changes accordingly.

Sometimes it dies in 3a above - in the GetInfo call. I can't discern any difference between the state of things when it succeeds or fails, though obviously I can't inquire on the internal state of the VSTi, which seems the most likely place for the issue to lie.  SO CLOSE!

Ian @ un4seen

  • Administrator
  • Posts: 26015
Re: Multi-threading loading VSTi channels
« Reply #5 on: 17 Jul '24 - 13:54 »
Sometimes it dies in 3a above - in the GetInfo call. I can't discern any difference between the state of things when it succeeds or fails, though obviously I can't inquire on the internal state of the VSTi, which seems the most likely place for the issue to lie.  SO CLOSE!

If you catch the crash in the debugger, the thread's call stack should reveal where it's happening (at least in what DLL).

Wayne McHugh

  • Posts: 91
Re: Multi-threading loading VSTi channels
« Reply #6 on: 4 Aug '24 - 21:41 »
It is a shame, but the final conclusion is that the particular VSTi that is faulting is not friendly when created in a separate thread, so it alone has to be created in the main thread. Unfortunate! Thanks for helping me give it the best shot.