JUCE LV2 Plugin Wrapper

Discuss issues relating to audio plugins

Re: JUCE LV2 Plugin Wrapper

Postby jpo » Tue May 22, 2012 5:51 pm

With your latest change, the presets are now working correctly in jalv ! My issue with parameter names was solved by replacing the "if (trimmedName.isEmpty())" in nameToSymbol by a simple "if (true)" -- that way my lv2 parameter ports have are identified by a generic symbol with is independent of the actual name.
jpo
JUCE UberWeenie
 
Posts: 336
Joined: Thu Mar 20, 2008 2:45 pm

Re: JUCE LV2 Plugin Wrapper

Postby falkTX » Tue May 22, 2012 6:00 pm

jpo wrote:With your latest change, the presets are now working correctly in jalv ! .

Awesome!
I look forward to test one of your plugins! :twisted:
falkTX
JUCE UberWeenie
 
Posts: 117
Joined: Sat Jun 04, 2011 4:15 pm

Re: JUCE LV2 Plugin Wrapper

Postby jpo » Tue May 22, 2012 6:01 pm

Btw here is what I'm using on linux when the plugin wants to find out what is the full pathname of its .so file (could be a replacement for getBinaryName, but that's not very important):

Code: Select all
void dummyFunction() {}
...
   Dl_info inf; memset(&inf, 0, sizeof inf);
    int er=dladdr((void*)&dummyFonction, &inf);
    if (er != 0) {
      strncpy(path, inf.dli_fname, 512); path[511] = 0;
    } else strcpy(path, JucePlugin_Name);
jpo
JUCE UberWeenie
 
Posts: 336
Joined: Thu Mar 20, 2008 2:45 pm

Re: JUCE LV2 Plugin Wrapper

Postby jpo » Tue May 22, 2012 6:04 pm

I look forward to test one of your plugins! :twisted:


Sure ! I'll send you a copy as soon as I have packaged it in a usable way
jpo
JUCE UberWeenie
 
Posts: 336
Joined: Thu Mar 20, 2008 2:45 pm

Re: JUCE LV2 Plugin Wrapper

Postby jpo » Tue May 22, 2012 7:01 pm

Btw the presets.ttl generation is a bit slow with my plugin, it takes ~30 seconds to generate it. replacing

Code: Select all
    for (int i = 0; i < numPrograms; i++)
    {
        presets += "<" JucePlugin_LV2URI "#preset" + String(i+1) + "> a pset:Preset ;\n";
        presets += "    rdfs:label \"" + filter->getProgramName(i) + "\" ;\n";
        presets += ....etc;
}


with
Code: Select all
    for (int i = 0; i < numPrograms; i++)
    {
        String preset;
        preset += "<" JucePlugin_LV2URI "#preset" + String(i+1) + "> a pset:Preset ;\n";
        preset += "    rdfs:label \"" + filter->getProgramName(i) + "\" ;\n";
        preset += ....etc;

        presets += preset;
}


brings it back to ~1 second.
jpo
JUCE UberWeenie
 
Posts: 336
Joined: Thu Mar 20, 2008 2:45 pm

Re: JUCE LV2 Plugin Wrapper

Postby jules » Tue May 22, 2012 7:42 pm

FYI: if you want to do a lot of string concatenations, it's *much* faster to use << into a MemoryOutputStream and then get the string from it afterwards using toString().
User avatar
jules
Fearless Leader
 
Posts: 17209
Joined: Mon Sep 06, 2004 9:03 am
Location: London, UK

Re: JUCE LV2 Plugin Wrapper

Postby jpo » Wed May 23, 2012 11:34 am

Here is my local patch for now. The hostPrograms variable is not initialized in the constructor, it caused some random crashes when changing preset. I also had to add a few MessageManagerLock in the constructor / destructor / setStateBinary / setStateString to avoid assertions in juce component code.

Code: Select all
--- distrho/libs/juce-lv2/juce_LV2_Wrapper.cpp   2012-05-22 17:49:27.000000000 +0200
+++ lv2/juce_LV2_Wrapper.cpp   2012-05-23 12:27:42.000000000 +0200
@@ -100,10 +100,12 @@
  #define PLUGIN_EXT ".dll"
#endif

+namespace juceLV2 {
+
/** Returns the name of the plugin binary file */
String getBinaryName()
{
-    return String(JucePlugin_Name).replace(" ", "_");
+   return String(JucePlugin_Name); //.replace(" ", "_");
}

/** Returns plugin type, defined in AppConfig.h or JucePluginCharacteristics.h */
@@ -125,7 +127,8 @@
{
     String symbol, trimmedName = name.trimStart().trimEnd().toLowerCase();

-    if (trimmedName.isEmpty())
+    // always use generic symbols because my names are dynamic
+    if (true || trimmedName.isEmpty())
     {
         symbol += "lv2_port_";
         symbol += String(portIndex+1);
@@ -519,33 +522,35 @@
         std::cout << "\nSaving preset " << i+1 << "/" << numPrograms+1 << "...";
         std::cout.flush();

+        String preset;
+
         // Label
         filter->setCurrentProgram(i);
-        presets += "<" JucePlugin_LV2URI "#preset" + String(i+1) + "> a pset:Preset ;\n";
-        presets += "    rdfs:label \"" + filter->getProgramName(i) + "\" ;\n";
+        preset += "<" JucePlugin_LV2URI "#preset" + String(i+1) + "> a pset:Preset ;\n";
+        preset += "    rdfs:label \"" + filter->getProgramName(i) + "\" ;\n";

         // State
#if JucePlugin_WantsLV2State
-        presets += "    state:state [\n";
+        preset += "    state:state [\n";
  #if JucePlugin_WantsLV2StateString
-        presets += "        <" JUCE_LV2_STATE_STRING_URI ">\n";
-        presets += "\"\"\"\n";
-        presets += filter->getStateInformationString().replace("\r\n","\n");
-        presets += "\"\"\"\n";
+        preset += "        <" JUCE_LV2_STATE_STRING_URI ">\n";
+        preset += "\"\"\"\n";
+        preset += filter->getStateInformationString().replace("\r\n","\n");
+        preset += "\"\"\"\n";
  #else
         MemoryBlock chunkMemory;
         filter->getCurrentProgramStateInformation(chunkMemory);
         const String chunkString = Base64Encode(chunkMemory);

-        presets += "        <" JUCE_LV2_STATE_BINARY_URI "> [\n";
-        presets += "            a atom:Chunk ;\n";
-        presets += "            rdf:value\"\"\"" + chunkString + "\"\"\"^^xsd:base64Binary\n";
-        presets += "        ]\n";
+        preset += "        <" JUCE_LV2_STATE_BINARY_URI "> [\n";
+        preset += "            a atom:Chunk ;\n";
+        preset += "            rdf:value\"\"\"" + chunkString + "\"\"\"^^xsd:base64Binary\n";
+        preset += "        ]\n";
  #endif
         if (filter->getNumParameters() > 0)
-            presets += "    ] ;\n\n";
+            preset += "    ] ;\n\n";
         else
-            presets += "    ] .\n\n";
+            preset += "    ] .\n\n";
#endif

         // Port values
@@ -554,19 +559,21 @@
         for (int j=0; j < filter->getNumParameters(); j++)
         {
               if (j == 0)
-                presets += "    lv2:port [\n";
+                preset += "    lv2:port [\n";
             else
-                presets += "    [\n";
+                preset += "    [\n";

-            presets += "        lv2:symbol \"" + nameToSymbol(filter->getParameterName(j), j) + "\" ;\n";
-            presets += "        pset:value " + String(safeParamValue(filter->getParameter(j)), 8) + " ;\n";
+            preset += "        lv2:symbol \"" + nameToSymbol(filter->getParameterName(j), j) + "\" ;\n";
+            preset += "        pset:value " + String(safeParamValue(filter->getParameter(j)), 8) + " ;\n";

             if (j+1 == filter->getNumParameters())
-                presets += "    ] ";
+                preset += "    ] ";
             else
-                presets += "    ] ,\n";
+                preset += "    ] ,\n";
         }
-        presets += ".\n\n";
+        preset += ".\n\n";
+
+        presets += preset;
     }

     return presets;
@@ -895,7 +902,8 @@
             externalUI (nullptr),
             externalUIHost (nullptr),
             externalUIPos (100, 100),
-            uiTouch (nullptr)
+            uiTouch (nullptr),
+            hostPrograms (nullptr)
     {
         filter->addListener(this);

@@ -1231,6 +1239,9 @@
#endif
             uridMap (nullptr)
     {
+#if JUCE_LINUX
+        MessageManagerLock mmLock;
+#endif
         filter = createPluginFilter();
         jassert(filter != nullptr);

@@ -1283,6 +1294,9 @@

     ~JuceLV2Wrapper()
     {
+#if JUCE_LINUX
+        MessageManagerLock mmLock;
+#endif
         filter = nullptr;

         channels.free();
@@ -1719,8 +1733,12 @@
         if (filter)
             filter->setCurrentProgramStateInformation (data, sizeInBytes);

-        if (ui)
+        if (ui) {
+#if JUCE_LINUX
+            MessageManagerLock mmLock;
+#endif
             ui->repaint();
+        }
     }

#if JucePlugin_WantsLV2StateString
@@ -1739,8 +1757,12 @@

         filter->setStateInformationString(data);

-        if (ui)
+        if (ui) {
+#if JUCE_LINUX
+            MessageManagerLock mmLock;
+#endif
             ui->repaint();
+        }
     }
#endif

@@ -2141,6 +2163,9 @@
     juceLV2UI_ExtensionData
};

+} // namespace juceLV2
+using namespace juceLV2;
+
//==============================================================================
// Mac startup code..
#if JUCE_MAC
@@ -2203,10 +2228,6 @@
         }
     }

-    // don't put initialiseJuce_GUI or shutdownJuce_GUI in these... it will crash!
-    __attribute__((constructor)) void myPluginInit() {}
-    __attribute__((destructor))  void myPluginFini() {}
-
//==============================================================================
// Windows startup code..
#else
jpo
JUCE UberWeenie
 
Posts: 336
Joined: Thu Mar 20, 2008 2:45 pm

Re: JUCE LV2 Plugin Wrapper

Postby falkTX » Wed May 23, 2012 2:41 pm

I applied your fixes on the distrho git code, thanks!
(not the namespace though, afaik the VST code doesn't use it either)
falkTX
JUCE UberWeenie
 
Posts: 117
Joined: Sat Jun 04, 2011 4:15 pm

Re: JUCE LV2 Plugin Wrapper

Postby jpo » Wed May 23, 2012 3:22 pm

Just to explain why I'm using a different namespace (in could be also in the vst wrapper , or in both) : it allows me to build an "all-in-one" plugin binary, that is at the same time a vst plugin, and an lv2 plugin

Btw I'm testing a bit with ardour 3 svn right now, it seems to work fine (except for the presets , but I think you already know that). The only issue is that it crashes when closing the plugin ui. Happens also with, for example, drumsynth.lv2. The backtrace seems to only involve ardour/suil/gtk code , though
jpo
JUCE UberWeenie
 
Posts: 336
Joined: Thu Mar 20, 2008 2:45 pm

Re: JUCE LV2 Plugin Wrapper

Postby falkTX » Wed May 23, 2012 3:27 pm

jpo wrote:Just to explain why I'm using a different namespace (in could be also in the vst wrapper , or in both) : it allows me to build an "all-in-one" plugin binary, that is at the same time a vst plugin, and an lv2 plugin

Btw I'm testing a bit with ardour 3 svn right now, it seems to work fine (except for the presets , but I think you already know that). The only issue is that it crashes when closing the plugin ui. Happens also with, for example, drumsynth.lv2. he backtrace seems to only involve ardour/gtk code , though

Use the latest suil from SVN, it's a known bug and has been fixed, from changelog:
* Fix crashes when wrapper widget is destroyed by toolkit before
suil cleanup function is called


I don't really see the point on making an "all-in-one" binary for lv2, since it has to be inside a *.lv2 folder to work. unless you symlink it from another location.. ?
falkTX
JUCE UberWeenie
 
Posts: 117
Joined: Sat Jun 04, 2011 4:15 pm

Re: JUCE LV2 Plugin Wrapper

Postby falkTX » Mon Mar 18, 2013 8:10 pm

Just a heads-up to interested parties.
I'm doing a code cleanup and update during this week (LV2 now has more useful features).
By the end of it I should have a fully working implementation of the Juce LV2 wrapper.
This will require the very latest host versions to work, but I consider that a good thing.


Jules, can we please try to merge this wrapper next week then?
I know you don't want the new 2 StateString calls to AudioProcessor just for LV2, so that will be optional (I will still use it internally). LV2 can work with binary chunks just as fine.
If you could start by adding the new LV2 wrapper type to the juce source code, that would be nice.
Thanks!
falkTX
JUCE UberWeenie
 
Posts: 117
Joined: Sat Jun 04, 2011 4:15 pm

Re: JUCE LV2 Plugin Wrapper

Postby jules » Mon Mar 18, 2013 8:23 pm

falkTX wrote:Jules, can we please try to merge this wrapper next week then?
I know you don't want the new 2 StateString calls to AudioProcessor just for LV2, so that will be optional (I will still use it internally). LV2 can work with binary chunks just as fine.
If you could start by adding the new LV2 wrapper type to the juce source code, that would be nice.
Thanks!


Sure, would be happy to have a look!
User avatar
jules
Fearless Leader
 
Posts: 17209
Joined: Mon Sep 06, 2004 9:03 am
Location: London, UK

Re: JUCE LV2 Plugin Wrapper

Postby falkTX » Tue Mar 26, 2013 3:49 am

ok, I've made some big changes to the code, overall fixing and cleanup, etc etc.

Latest code is here:
https://github.com/falkTX/DISTRHO/tree/ ... client/LV2

Notes:
- LV2 wrapper requires JucePlugin_LV2URI macro to be set. It's used as the ID of the plugin and must be a valid URI and unique across the system.

- Some macros have been added: (all optional)
JucePlugin_LV2Category -> Set it as string to a valid LV2 plugin category. See http://lv2plug.in/ns/lv2core/ for valid values.
Example: "InstrumentPlugin". If this macro is not set and plugin is marked as synth, the wrapper will automatically add "InstrumentPlugin" class.
JucePlugin_WantsLV2State -> If 1, the wrapper will export stateInformation to the host, otherwise it just uses parameter values.
JucePlugin_WantsLV2Presets -> If 1, the wrapper will create a presets.ttl file with the default preset data.
JucePlugin_WantsLV2TimePos -> If 1, the wrapper will report timePosition support.
There's also JucePlugin_WantsLV2StateString, but it's an internal thing for me and Juce will probably not use it.

- The Juce plugin type is set as 'VST'.
Jules, please add LV2 in AudioProcessor::WrapperType.

- The final binary needs to be ran with a minor tool that generates its *.ttl data, see:
https://github.com/falkTX/DISTRHO/tree/ ... -generator


I'm still doing some testing, but please try the wrapper and let me know what you think.
It's supposed to work on Windows, Mac and Linux, but I only tested it so far in Linux.
Last edited by falkTX on Sun Apr 28, 2013 1:48 am, edited 1 time in total.
falkTX
JUCE UberWeenie
 
Posts: 117
Joined: Sat Jun 04, 2011 4:15 pm

Re: JUCE LV2 Plugin Wrapper

Postby jules » Tue Mar 26, 2013 1:00 pm

Very cool stuff.

If only there was an LV2 hosting class to go with it, I could probably find a use for that... ;)
User avatar
jules
Fearless Leader
 
Posts: 17209
Joined: Mon Sep 06, 2004 9:03 am
Location: London, UK

Re: JUCE LV2 Plugin Wrapper

Postby falkTX » Sun Apr 28, 2013 1:45 am

I've finished the missing LV2 timePos code so now the wrapper is pretty much complete afaik.
The only thing needed now is testing and bugfixing. :D

I want to code a juce class for hosting LV2s as well, but it will take some time as I'm still working on LV2 for my own host.
falkTX
JUCE UberWeenie
 
Posts: 117
Joined: Sat Jun 04, 2011 4:15 pm

PreviousNext

Return to Audio Plugins

Who is online

Users browsing this forum: No registered users and 1 guest

cron