Confirm demoplugin works in Windows/Linux
It seems that the following command is enough to produce working plugin for Windows/Linux:
go build --buildmode c-shared --tags plugin
Confirmation is required.
Can confirm that this compiles on Windows, but the plugin is not detectable by VST hosts.
As a sidenote, I'm also not seeing any VSTPluginMain or equivalent type exported symbols in the generated dll:
λ go build --buildmode=c-shared --tags plugin -o plugin.dll .
λ dumpbin /exports plugin.dll
<snip>
Dump of file plugin.dll
File Type: DLL
Section contains the following exports for plugin.dll
<snip>
ordinal hint RVA name
1 0 00189EF0 _cgo_dummy_export
2 1 0008ECB0 dispatchPluginBridge
3 2 0008EE00 getParameterPluginBridge
4 3 0008EC60 newGoPlugin
5 4 0008ED40 processDoublePluginBridge
6 5 0008EDA0 processFloatPluginBridge
7 6 0008EE60 setParameterPluginBridge
<snip>
AFAIK a VST2.x plugin requires a VSTPluginMain or equivalent exported symbol. Am I missing something here?
You are absolutely right @lsegal!
As you already discovered in your PR, this entry point exists in include/plugin.c and for Darwin architecture it's exported automatically. I guess that for DLL it behaves differently.
Tried this, too. But plugin crashes in different hosts. Tried Unify x64 and Renoise x64, it just freeze. VSTPluginMain export is there, so it must be something else.
;
; Definition file of plugin.dll
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "plugin.dll"
EXPORTS
VSTPluginMain
_cgo_dummy_export DATA
dispatchPluginBridge
getParameterPluginBridge
newGoPlugin
processDoublePluginBridge
processFloatPluginBridge
setParameterPluginBridge
I used:
- go version go1.16.4 windows/amd64
- gcc (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0
- GNU ld (GNU Binutils) 2.30
Thanks for looking into this @ryrun ! Can you clarify one thing - do those hosts crash when they scan plugins or when you try to instantiate plug-in instance?
@dudk When i try to instantiate plug-in instance. Renoise and Unify simply freeze, need to force close it. Crash was the wrong term, sorry :) Can also test it in FL and Bitwig, if needed.
Thanks for clarification @ryrun. It would be great if you can check there as well. I can see this behaviour with Renoise on Mac, but only when the second plugin instance is created. That is - the first instance opens fine and works as expected, but when I create the second instance of the very same plugin - Renoise hangs up. Seems like it's the same problem.
Maybe i'm missing something, but how can i specify the uniqueID and version via go? Its missing in the demo.go example. Maybe thats' the reason why these Hosts cant load it.
In FL it is freezing, too.
Edit: Ok, it looks the memory gets corrupted. You can see this in the preset count parameter. This could be the reason why:

Thanks for checking it! That's an interesting find. Unique ID and versions are defined in CPlugin, but currently there is no way to actually set them. I'll put up a PR with it soon.
In the current implementation those members are not set to any value. I'm not sure if that can cause such issue because many vst2 plugin manuals don't provide those values either.
EDIT: read your edit, that's an even better catch. Is that happening with time or immediately?
Immediately. VSTHost seems to be good for quick testing. Loaded the plugin 3 times, always different informations about:

@dudk I played around abit with your code. It seems malloc is one issue. It allocates memory, but doesn't zero it and its needed to be zero as far as i can see. I've changed all mem allocations to calloc and i can finally load the plugin in Renoise. But it will also freeze, when i create a second instance. So this seems to be another problem.

I tend to think that it's due to vendor string. I'll do a PoC to confirm that.
@dudk It seems malloc is an issue, too. I've edited my post, again sorry :D. Maybe not a good idea, so you will miss this.
No worries @ryrun 😉 yes, I tend to think that I allocate CPlugin struct wrongfully - it should be 'malloc(sizeof *p)'. I tested this, but it still crashes on the second instance.
To conclude next steps for debugging it:
- [x] Provide initial values for all fields of the plug-in;
- [ ] Provide unique and version;
- [ ] Provide vendor string dispatch call;
Seems pretty interesting now👀
@dudk I did a pull request for malloc to calloc #47 This fixes my loading issues. I'm not sure how i can embed this here. I'm a github noob :D
It still crashes Renoise and FL, when i remove the plugin. But loading seems to be fine now. Was able to playing around with the demo plugin, trying sidechain input.
@dudk Does Renoise also crash on you when you remove the last instance of the plugin? It also happens in FLStudio. Unfortunately there is no information about the crash in the logs.
@ryrun no, it works fine on Mac. Probably some mach-o bundle magic that handles resource management differently. I assume that it crashes because plugin currently doesn't handle plugClose opcode.
@dudk I tried to debug this crash with gdb and i got this. Not sure how we can fix this:
Thread 66 received signal SIGSEGV, Segmentation fault.
[Switching to Thread 18800.0x29c8]
runtime.usleep2HighRes () at D:/Program Files/go1.16.4/src/runtime/sys_windows_amd64.s:487
487 MOVQ 64(SP), SP
(gdb) where
#0 runtime.usleep2HighRes () at D:/Program Files/go1.16.4/src/runtime/sys_windows_amd64.s:487
#1 0x00000000542c6d9a in runtime.onosstack () at D:/Program Files/go1.16.4/src/runtime/sys_windows_amd64.s:422
#2 0x00000000542a3719 in runtime.usleep (us=86298276) at D:/Program Files/go1.16.4/src/runtime/proc.go:5166
#3 runtime.sysmon () at D:/Program Files/go1.16.4/src/runtime/proc.go:5166
#4 0x000000005429b31a in runtime.mstart1 () at D:/Program Files/go1.16.4/src/runtime/proc.go:1306
#5 0x000000005429b20d in runtime.mstart () at D:/Program Files/go1.16.4/src/runtime/proc.go:1272
#6 0x00000000542ef28c in crosscall_amd64 () at gcc_amd64.S:33
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) list
482 MOVQ $0, DX // alertable
483 MOVQ $0, R8 // ptime
484 MOVQ runtime·_NtWaitForSingleObject(SB), AX
485 CALL AX
486
487 MOVQ 64(SP), SP
488 RET
489
490 gisnotset:
491 // TLS is not configured. Call usleep2 instead.
Edit: Did some research. Maybe i'm wrong, but it seems that unloading a go c-shared dll causing this crash. Its a known problem: https://github.com/golang/go/issues/11100
Edit2: Maybe this could be a workaround: https://blogs.msmvps.com/vandooren/2006/10/09/preventing-a-dll-from-being-unloaded-by-the-app-that-uses-it/ was mentioned here: https://github.com/golang/go/issues/32497#issuecomment-549055487
Now it comes to my mind - I saw the issue you've mentioned before.
It's a pretty interesting workaround. It definitely comes with some price - go runtime would be always running if you. But on another hand, host won't crush 🤷♂️ seems like a fair trade off, but needs to be explicitly documented once there.
If you want to play around with it - look into vst_windows.go
@dudk Found a cleaner solution.
Call GetModuleHandleEx with the GET_MODULE_HANDLE_EX_FLAG_PIN flag. The module stays loaded until the process is terminated, no matter how many times FreeLibrary is called.
See https://stackoverflow.com/a/14436845
I think this would be a better solution for this issue.
@dudk I created a pull request. Not sure if this code is "clean enough". :) With this last fix, all crashes are fixed for me. I can load multiple instance of the demo plugin, remove them one by one. And when the last one was removed, no crash. Gain parameter is working fine. Tested this plugin in Renoise 3.3 and FLStudio 20.8 on a Windows 10 64bit machine.
plugGetParamDisplay is currently not working, returns an empty string. In VSTHost it shows no values.
@ryrun I think that's because I didn't set any value to Parameter.ValueLabel field. Actually this feature doesn't really work, because it should have the following logic: since all params in VST2 use values of [0;1] interval, plugGetParamDisplay should call a function that will return display value based on current parameter value.
I've created #54 to track it.
Confirmed demoplugin works on Linux (recognised and functional in Carla host)