Creating plugins for a juce app - mac osx, windows, linux


#1

Hello!

I am working at a vst-plugin. However, I’d like to have a possibility to add new functionality without recompiling the complete vst. So i though about a possibility to create “plugins” for my vst plugin. The biggest problem here: I want all of this to run on mac, linux and windows.
How can I achieve this?

I found the DynamicLibrary class, but it seems like this is only for windows.

Thanks for help,
StrangeMan


#2

Hello again,

I found DynObj (http://www.codeproject.com/Articles/20648/DynObj-C-Cross-Platform-Plugin-Objects) and tried to include that into my existing project. I’ve tried so much now, and finally i think it’s broken… I get hundrets of errors regarding internal macros and defines, and i really don’t want to make my fingers dirty tweaking the DynObj-Code.

Does anyone have another hint what I can do to realise plugins for my project?

Thanks a lot,
StrangeMan


#3

Seriously, don’t do it. If your reason for trying to use dynamic libraries is “to do less compiling”, then you’re just entering a world of pain for no reason at all.

The only reason why it’d ever make sense to go through the hell of creating and maintaining a plugin system is if you need to load and unload modules while your app is running. Otherwise, do everything statically and preserve your sanity.


#4

The thing is, I want my application to be expandable by others. Just like a vst host is “expandable” becourse it can load vst plugins.

That is the case I guess.


#5

Ah, well in that case, you need the DynamicLibrary class and plenty of patience!

I can’t see how other 3rd-party libraries would be any help at all, it’s up to you to define and implement your own plugin’s API.


#6

I found this series of tutorials helpful when I was working on the same problem:


#7

Have a look at the “Extension API” and “Extension Example” in OneGuyGroup / Public:

https://github.com/oneguygroup/Public


#8

What kind of new functionality are you trying to add? Embedding a scripting language like lua might be more suitable if your extensions are not too CPU hungry.


#9

@billythekid:
No, the plugins are meant to handle audio processing, so scripting would be unsatisfying. Nice hint anyway, for other purposes it could do well.
@TheVinn:
Nice, thanks for the link. I’ll take a look at it.
@symfonysid:
I found that one, too. Unfortunately I have not found the time to fully understand it yet, though it looks good.

@all:
I found this one here http://wanderinghorse.net/computing/papers/classloading_cpp.pdf and read through it. The idea is quite simple, though I wonder if it’s still up-to-date (written in 2005). From what I read so far, it is about defining a static classloader-class and registering new classes and appropriate factory functions there at runtime. The classloader can then be called to produce a specific class.
When loading a dll library this technique is supposed to make the dlls classes register themselfes with the static (and therefor global) classloader (via simple macros).
(I hope that was understandable - sorry for my bad english)
This is exactly what I need, and hopefully it works. I’ll try to implement this next weekend.

If this is platform independent and robust, it could be a nice addition to juce


#10

That’s exactly what the interface in ExtensionAPI that I linked to you implements. External shared libraries which provide factories for producing classes.


#11

Hi there again,

Thanks again for all your suggestions and hints. I read through a lot of stuff and finally managed to load a simple class from a dll on windows using the POCO Library. However, things start to get weird, once I call “delete” to destroy an object from that dll or when I try to unload the dll.
I searched the web and found lots of hints that it is undefined, what happens when you load a libraray from DllMain. I’m afraid that this might be the case for me. Let me explain:
When the user clicks a button in the GUI of my vst-plugin, the dll is loaded and a class from it is instantiated. A method of that object is called. It runs and returns without trouble. Afterwards the object is deleted with “delete”. And on that “delete” my plugin crashes.

So the question is: What happens internally in JUCE, when the user clicks a button on the GUI? Is that part of DllMain?
And: How can I avoid these problems and still load classes from a dll? Spawn a new thread for it?

Thank you sooo much for your help!
StrangeMan


#12

[quote=“StrangeMan”]Hi there again,

Thanks again for all your suggestions and hints. I read through a lot of stuff and finally managed to load a simple class from a dll on windows using the POCO Library. However, things start to get weird, once I call “delete” to destroy an object from that dll or when I try to unload the dll.
I searched the web and found lots of hints that it is undefined, what happens when you load a libraray from DllMain. I’m afraid that this might be the case for me. Let me explain:
When the user clicks a button in the GUI of my vst-plugin, the dll is loaded and a class from it is instantiated. A method of that object is called. It runs and returns without trouble. Afterwards the object is deleted with “delete”. And on that “delete” my plugin crashes.

So the question is: What happens internally in JUCE, when the user clicks a button on the GUI? Is that part of DllMain?
And: How can I avoid these problems and still load classes from a dll? Spawn a new thread for it?

Thank you sooo much for your help!
StrangeMan[/quote]

I haven’t time to explain it properly, but the problem is that your DLL will use a different heap allocator to your exe - you need to think about which allocator is called when you call delete. It’s a basic DLL problem that everyone hits, and there are tricks involving overloaded new and delete operators that you can use - a bit of googling should get you plenty more info about this.


#13

Thanks jules, that’s a good hint for me. I’ll ask google about it and come back later.

[size=85][quote]I haven’t time to explain it properly[/quote] It would be inappropriate to expect a complete explaination from you - a push in the right direction is all I need :)[/size]


#14

Hello community!

My problem is solved now - thanks jules and all the others!

Now that I finally managed to create my plugin system, I’d like to share some basic thoughts and hints for those, who stumble upon this thread and try to do the same. I will try to use simple words and “pictures” to make it easy to understand. It might not be the best approach, but it works and might help other beginners to get started. Pros will not read anything new…

First of all: Never delete stuff in the library that was allocated in the main application and the other way round. See jules posts above for details. If you need to get data from “the other side”, allocate an array and pass it over. Let the other side fill this array with the data. Then you can safely read the content and then delete it where you created it.

Second: Do not try to pass objects between the library and the main application.
It is possible and it works for some special cases, but sooner or later the problems begin. One big thing is that static classes are not shared between the library and the main application. Thus, everything that relies on anything static will not work. (e.g. any “Component”-derived class will not be repainted - it relies on a static list of top-level components, that is not shared between library and main application).
Overall it is much safer to create a plain and simple C API. Functions that are exported by a dynamic library are well supported and easy to understand. All you need is some kind of abstraction layer that translates calls from C++ objects to simple C function calls and the other way round.

If you’re new to programming concepts, maybe this will help you a bit:
Think of that API as a long pipe that you can shout through. On both ends, you have a crowd of people that want to talk to each other (these are the C++ classes inside the application and inside the library). They can all only shout through this one single pipe. When a sound reaches one end of the pipe, how can you know where it came from an who’s supposed to receive it? Its best to give each person on each side a unique number. So now, when someone from one end wants to talk to someone on the other end of the pipe, he only needs to say his number and the number of the person he would like to talk to. That would work.
But it is not a good solution: Every single person would need to listen to the sound coming out of the pipe - that’s inefficient. It’s much better to have a manager sitting at each end. When someone wants to make a “call”, he lets the manager deliver the message. On the other end, the other manager receives the message and passes it on to its final destination. Thats exactly what you need for a plugin system.

On the application-side:
Write a singleton/static-class for calls to the library and callbacks from the library
[list][]provides static functions that can be passed over to the library as function pointers (done during initialization of the library). These will be used for callbacks from the library to the main application.[/]
[]All C++ objects inside the main application that need to communicate with the library register themselves at this class and a unique ID number is assigned to them[/]
[]C++ objects do calls to this singleton class. It passes these calls on to the library, adding the sender’s ID as well as the ID of the target object as a reference.[/]
[]incoming calls to the callback functions are passed on to their targets, by addressing them via their ID number (which was assigned to them when they registered themselves)[/][/list]
On the library-side:
Export all the functions you need and also provide an init function that takes pointers to all the callbacks. Through these pointers you can call the main application.
Write a singleton-class for calls to the main application and for delivering incoming calls from the application to their target objects
[list][]All C++ objects inside the library, that need to communicate with the main application register there and a unique ID number is assigned to them[/]
[]C++ objects do calls to this singleton class. It passes these calls on to the main application via the callback functions, adding the sender’s ID as well as the ID of the target object as a reference.[/][/list]
In the exported functions of your library, just do a call to this singleton and let it deliver the message to their registered targets.

I hope thats a bit of a help for beginners. Feel free to correct me if anything about that is wrong.
StrangeMan