osxmidi / LinVst

Linux Windows vst wrapper/bridge
GNU General Public License v3.0
683 stars 41 forks source link

LinVst in Bitwig #70

Closed fonkle closed 5 years ago

fonkle commented 5 years ago

I have been using LinVst with Bitwig Studio and have run into 2 issues:

The first issue relates to the plugin-name returned by any LinVst plugins in Bitwig. Instead of the expected name, LinVst returns the first 32 characters (kVstMaxEffectNameLen) of the path to the plugin .so or .dll file. For example, if I have Harmor in this location:

/home/user/vstplugins/synthesizer/plugin/plugin.dll

the device will be called

/home/user/vstplugins/synthesize

in Bitwig Studio. Any other plugins in this synthesize folder will get the exact same name, resulting in both plugins writing their presets to the same folder called /home/user/vstplugins/synthesize. Since this interferes with the wonderful browser-workflow in Bitwig Studio, I have patched LinVst to return the name of the plugins as returned by "effGetEffectName", which works great. Why does LinVst return the truncated path instead of the plugin name? Is this by design?

The second issue regards the returned VendorString. Since Bitwig requests this string before the plugin is opened, LinVst returns an empty string initially. If a preset is then saved, the 'device_creator' in that preset will be missing, rendering it unrelated to the device which created it and therefore invisible in the browser. I modified the getName() and getMaker() functions to get the respective strings via the "effGetEffectName" and "effGetVendorString" operators if these are empty. Works great, raising the same question: was this left out by design or do these changes interfere with some other DAW's workflow?

Anyway, I would like to incorporate these changes in LinVst for use by me or anyone using Bitwig Studio in the future. Are you interested in a patch for LinVst (I am a noob in GitHub) or should I fork this repository for my own personal use? Advice will be appreciated.

Thank you for LinVst and greetings!

osxmidi commented 5 years ago

Yes that would be great.

How large are the changes?

You could post them in this topic and then I'll edit the main code to reflect them.

I'm pretty sure that I'll know where they need to go but some line numbers might help as well.

The other way is to fork and do a pull request but being a GitHub noob that requires some learning about it.

fonkle commented 5 years ago

The changes are very small. Only lin-vst-server.cpp is modified in 3 locations:

--- patch 1/3 (RemoteVSTServer class definition)

77    virtual std::string getName(); 
78    virtual std::string getMaker();

--- patch 2/3 (RemoteVSTServer functions)

353   std::string RemoteVSTServer::getName()
354   {
355       if ((m_name == "") && (m_plugin))
356       {
357           char buffer[512];
358           memset(buffer, 0, sizeof(buffer));
359           m_plugin->dispatcher(m_plugin, effGetEffectName, 0, 0, buffer, 0);
360           if (buffer[0])
361           m_name = buffer;
362       }
363       return m_name;
364   }
365
366   std::string RemoteVSTServer::getMaker()
367   {
368       if ((m_maker == "") && (m_plugin))
369       {
370           char buffer[512];
371           memset(buffer, 0, sizeof(buffer));
372           m_plugin->dispatcher(m_plugin, effGetVendorString, 0, 0, buffer, 0);
373           if (buffer[0])
374           m_maker = buffer;
375       }
376       return m_maker;
377   }

--- patch 3/3 in WinMain()

2087   // remoteVSTServerInstance = new RemoteVSTServer(fileInfo, libname);
2088
2089   string deviceName = fileName;
2090   size_t foundext = deviceName.find_last_of(".");
2091   deviceName = deviceName.substr(0, foundext);
2092   remoteVSTServerInstance = new RemoteVSTServer(fileInfo, deviceName);

--- end

The line numbers are based on the original file. The code tests for m_plugin to exist an only runs them if m_name or m_maker are empty. It removes the filename extension from the last found '.' (or nothing if not present). I have only tested this with Bitwig 2.5 beta 7 on Kubuntu 18.10 lowlatency but -as far as I can tell- it should be pretty unobtrusive in other situations?

p.s. a plugin instance (along with all its modulators and effects) is called a 'device' in Bitwig. Please feel free to change that name to something else (e.g. effName or pluginName).

I hope you can incorporate this into LinVst; I think Bitwig users will appreciate it. If I can do anything to improve the solution please let me know. In the meantime I will try to improve my GitHub skills :).

osxmidi commented 5 years ago

Thanks for that.

I'll try to get them in by tomorrow and then build new binaries as well.

fonkle commented 5 years ago

Awesome! I'm looking forward to trying it out.

osxmidi commented 5 years ago

The filepath should not have been in libname, thanks for picking up on it.

The 32 character limit is standard vst2 for plugin names, unfortunately the filepath put it well past the 32 char limit.

I've entered that fix into the code.

Bitwig calls EffectOpen at startup (but not getName/getMaker) but it seems to be before the default name (made from the dll filename) is set into m_name, so Bitwig gets the default m_name (which had the filepath bug in it) which it would use when saving presets (as you mentioned).

So, I've made getName and getMaker into functions following your changes and when the presets are saved the correct internal plugin name/maker should be picked up via Bitwig calling getName and getMaker (effGetEffectName and effGetVendorString) (and not the default name made from the dll filename).

Reaper calls EffectOpen and then getName and then getMaker at startup and so all the names are set ok.

If you could try it out then that would be very helpful.

fonkle commented 5 years ago

I tested the new code:

-The plugin name, and therefore the location of the preset file are now working in Bitwig Studio. -The 'device_creator' is still empty when I save a preset after creating a plugin device, preventing presets to show up for the device they belong to.

I think this has to do with the test for 'effectrun': I am not sure when this flag gets set but it seems that Bitwig queries for the VendorString before effectrun becomes true? This makes sense, because the browser in Bitwig is already showing the 'device_creator' of the plugin even before an instance of the plugin is created, so it must have already called getMaker() or effectOpen() before that. So testing for an empty m_maker will be true, yet effectrun is still false...?

I will try to attach a debugger to the running process to confirm the exact order in which Bitwig calls the entry points of the plugin.

osxmidi commented 5 years ago

I think I might have it ok now, or at least I can now see the plugin's category and vendor in the browser.

fonkle commented 5 years ago

I have tested the 64 bit version and it works like a charm. Presets include the 'device_creator' now and get saved to the right folder.

I did notice that Toxic Biohazard no longer has a space in its folder name (ToxicBiohazard), while Harmor still does (IL Harmor). However since they both work as intended, I reckon that is by design and all is good.

Will there be a new release for this version?

osxmidi commented 5 years ago

Yes, LinVst 2.4.3

Thanks for the help.