--- /dev/null
+/******************************************************************/
+/** VSTFX - An engine based on FST for handling linuxVST plugins **/
+/******************************************************************/
+
+/*This is derived from the original FST (C code) with some tweaks*/
+
+
+/** EDITOR tab stops at 4 **/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <jack/jack.h>
+#include <jack/thread.h>
+#include <libgen.h>
+
+#include <pthread.h>
+#include <signal.h>
+#include <glib.h>
+
+#include "ardour/linux_vst_support.h"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <pthread.h>
+
+struct ERect{
+ short top;
+ short left;
+ short bottom;
+ short right;
+};
+
+static pthread_mutex_t plugin_mutex;
+
+static VSTState * vstfx_first = NULL;
+
+const char magic[] = "VSTFX Plugin State v002";
+
+int gui_thread_id = 0;
+static int gui_quit = 0;
+
+/*This will be our connection to X*/
+
+Display* LXVST_XDisplay = NULL;
+
+/*The thread handle for the GUI event loop*/
+
+pthread_t LXVST_gui_event_thread;
+
+/*Util functions to get the value of a property attached to an XWindow*/
+
+bool LXVST_xerror;
+
+int TempErrorHandler(Display *display, XErrorEvent *e)
+{
+ LXVST_xerror = true;
+
+ return 0;
+}
+
+#ifdef LXVST_32BIT
+
+int getXWindowProperty(Window window, Atom atom)
+{
+ int result = 0;
+ int userSize;
+ unsigned long bytes;
+ unsigned long userCount;
+ unsigned char *data;
+ Atom userType;
+ LXVST_xerror = false;
+
+ /*Use our own Xerror handler while we're in here - in an
+ attempt to stop the brain dead default Xerror behaviour of
+ qutting the entire application because of e.g. an invalid
+ window ID*/
+
+ XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
+
+ XGetWindowProperty( LXVST_XDisplay, //The display
+ window, //The Window
+ atom, //The property
+ 0, //Offset into the data
+ 1, //Number of 32Bit chunks of data
+ false, //false = don't delete the property
+ AnyPropertyType, //Required property type mask
+ &userType, //Actual type returned
+ &userSize, //Actual format returned
+ &userCount, //Actual number of items stored in the returned data
+ &bytes, //Number of bytes remaining if a partial read
+ &data); //The actual data read
+
+ if(LXVST_xerror == false && userCount == 1)
+ result = *(int*)data;
+
+ XSetErrorHandler(olderrorhandler);
+
+ /*Hopefully this will return zero if the property is not set*/
+
+ return result;
+}
+
+#endif
+
+#ifdef LXVST_64BIT
+
+/********************************************************************/
+/* This is untested - have no 64Bit plugins which use this */
+/* system of passing an eventProc address */
+/********************************************************************/
+
+long getXWindowProperty(Window window, Atom atom)
+{
+ long result = 0;
+ int userSize;
+ unsigned long bytes;
+ unsigned long userCount;
+ unsigned char *data;
+ Atom userType;
+ LXVST_xerror = false;
+
+ /*Use our own Xerror handler while we're in here - in an
+ attempt to stop the brain dead default Xerror behaviour of
+ qutting the entire application because of e.g. an invalid
+ window ID*/
+
+ XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
+
+ XGetWindowProperty( LXVST_XDisplay,
+ window,
+ atom,
+ 0,
+ 2,
+ false,
+ AnyPropertyType,
+ &userType,
+ &userSize,
+ &userCount,
+ &bytes,
+ &data);
+
+ if(LXVST_xerror == false && userCount == 1)
+ result = *(long*)data;
+
+ XSetErrorHandler(olderrorhandler);
+
+ /*Hopefully this will return zero if the property is not set*/
+
+ return result;
+}
+
+#endif
+
+/*The event handler - called from within the main GUI thread to
+dispatch events to any VST UIs which have callbacks stuck to them*/
+
+static void
+dispatch_x_events (XEvent* event, VSTState* vstfx)
+{
+ /*Handle some of the Events we might be interested in*/
+
+ switch(event->type)
+ {
+ /*Configure event - when the window is resized or first drawn*/
+
+ case ConfigureNotify:
+ {
+ Window window = event->xconfigure.event;
+
+ int width = event->xconfigure.width;
+ int height = event->xconfigure.height;
+
+ /*If we get a config notify on the parent window XID then we need to see
+ if the size has been changed - some plugins re-size their UI window e.g.
+ when opening a preset manager (you might think that should be spawned as a new window...) */
+
+ /*if the size has changed, we flag this so that in lxvst_pluginui.cc we can make the
+ change to the GTK parent window in ardour, from its UI thread*/
+
+ if (window == (Window) (vstfx->linux_window)) {
+ if (width != vstfx->width || height!=vstfx->height) {
+ vstfx->width = width;
+ vstfx->height = height;
+ vstfx->want_resize = 1;
+
+ /*QUIRK : Loomer plugins not only resize the UI but throw it into some random
+ position at the same time. We need to re-position the window at the origin of
+ the parent window*/
+
+ if (vstfx->linux_plugin_ui_window) {
+ XMoveWindow (LXVST_XDisplay, vstfx->linux_plugin_ui_window, 0, 0);
+ }
+ }
+ }
+
+ break;
+
+ }
+
+ /*Reparent Notify - when the plugin UI is reparented into
+ our Host Window we will get an event here... probably... */
+
+ case ReparentNotify:
+ {
+ Window ParentWindow = event->xreparent.parent;
+
+ /*If the ParentWindow matches the window for the vstfx instance then
+ the Child window must be the XID of the pluginUI window created by the
+ plugin, so we need to see if it has a callback stuck to it, and if so
+ set that up in the vstfx */
+
+ /***********************************************************/
+ /* 64Bit --- This mechanism is not 64Bit compatible at the */
+ /* present time */
+ /***********************************************************/
+
+ if (ParentWindow == (Window) (vstfx->linux_window)) {
+
+ Window PluginUIWindowID = event->xreparent.window;
+
+ vstfx->linux_plugin_ui_window = PluginUIWindowID;
+#ifdef LXVST_32BIT
+ int result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
+
+ if (result == 0) {
+ vstfx->eventProc = NULL;
+ } else {
+ vstfx->eventProc = (void (*) (void* event))result;
+ }
+#endif
+#ifdef LXVST_64BIT
+ long result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
+
+ if(result == 0)
+ vstfx->eventProc = NULL;
+ else
+ vstfx->eventProc = (void (*) (void* event))result;
+#endif
+ }
+ break;
+ }
+
+ case ClientMessage:
+ {
+ Window window = event->xany.window;
+ Atom message_type = event->xclient.message_type;
+
+ /*The only client message we are interested in is to signal
+ that the plugin parent window is now valid and can be passed
+ to effEditOpen when the editor is launched*/
+
+ if (window == (Window) (vstfx->linux_window)) {
+ char* message = XGetAtomName(LXVST_XDisplay, message_type);
+
+ if (strcmp(message,"LaunchEditor") == 0) {
+ if (event->xclient.data.l[0] == 0x0FEEDBAC) {
+ vstfx_launch_editor (vstfx);
+ }
+ }
+
+ XFree(message);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ /* Some VSTs built with toolkits e.g. JUCE will manager their own UI
+ autonomously in the plugin, running the UI in its own thread, so once
+ we have created a parent window for the plugin, its UI takes care of
+ itself.*/
+
+ /*Other types register a callback as an Xwindow property on the plugin
+ UI window after they create it. If that is the case, we need to call it
+ here, passing the XEvent into it*/
+
+ if (vstfx->eventProc == NULL) {
+ return;
+ }
+
+ vstfx->eventProc((void*)event);
+}
+
+static void
+maybe_set_program (VSTState* vstfx)
+{
+ if (vstfx->want_program != -1) {
+ if (vstfx->vst_version >= 2) {
+ vstfx->plugin->dispatcher (vstfx->plugin, 67 /* effBeginSetProgram */, 0, 0, NULL, 0);
+ }
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effSetProgram, 0, vstfx->want_program, NULL, 0);
+
+ if (vstfx->vst_version >= 2) {
+ vstfx->plugin->dispatcher (vstfx->plugin, 68 /* effEndSetProgram */, 0, 0, NULL, 0);
+ }
+
+ vstfx->want_program = -1;
+ }
+
+ if (vstfx->want_chunk == 1) {
+ vstfx->plugin->dispatcher (vstfx->plugin, 24 /* effSetChunk */, 1, vstfx->wanted_chunk_size, vstfx->wanted_chunk, 0);
+ vstfx->want_chunk = 0;
+ }
+}
+
+/** This is the main gui event loop for the plugin, we also need to pass
+any Xevents to all the UI callbacks plugins 'may' have registered on their
+windows, that is if they don't manage their own UIs **/
+
+void* gui_event_loop (void* ptr)
+{
+ VSTState* vstfx;
+ int LXVST_sched_event_timer = 0;
+ int LXVST_sched_timer_interval = 50; //ms
+ XEvent event;
+
+ /*The 'Forever' loop - runs the plugin UIs etc - based on the FST gui event loop*/
+
+ while (!gui_quit)
+ {
+ /* handle window creation requests, destroy requests,
+ and run idle callbacks */
+
+ /*Look at the XEvent queue - if there are any XEvents we need to handle them,
+ including passing them to all the plugin (eventProcs) we are currently managing*/
+
+ if(LXVST_XDisplay)
+ {
+ /*See if there are any events in the queue*/
+
+ int num_events = XPending(LXVST_XDisplay);
+
+ /*process them if there are any*/
+
+ while(num_events)
+ {
+ XNextEvent(LXVST_XDisplay, &event);
+
+ /*Call dispatch events, with the event, for each plugin in the linked list*/
+
+ for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
+ {
+ pthread_mutex_lock(&vstfx->lock);
+
+ dispatch_x_events(&event, vstfx);
+
+ pthread_mutex_unlock(&vstfx->lock);
+ }
+
+ num_events--;
+ }
+ }
+
+ /*We don't want to use all the CPU.. */
+
+ usleep(1000);
+
+ LXVST_sched_event_timer++;
+
+ LXVST_sched_event_timer = LXVST_sched_event_timer & 0x00FFFFFF;
+
+ /*See if its time for us to do a scheduled event pass on all the plugins*/
+
+ if((LXVST_sched_timer_interval!=0) && (!(LXVST_sched_event_timer% LXVST_sched_timer_interval)))
+ {
+ pthread_mutex_lock (&plugin_mutex);
+
+again:
+ /*Parse through the linked list of plugins*/
+
+ for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
+ {
+ pthread_mutex_lock (&vstfx->lock);
+
+ /*Window scheduled for destruction*/
+
+ if (vstfx->destroy) {
+ if (vstfx->linux_window) {
+ vstfx->plugin->dispatcher (vstfx->plugin, effEditClose, 0, 0, NULL, 0.0);
+
+ XDestroyWindow (LXVST_XDisplay, vstfx->linux_window);
+ /* FIXME - probably safe to assume we never have an XID of 0 but not explicitly true */
+ vstfx->linux_window = 0;
+ vstfx->destroy = FALSE;
+ }
+
+ vstfx_event_loop_remove_plugin (vstfx);
+ vstfx->been_activated = FALSE;
+ pthread_cond_signal (&vstfx->window_status_change);
+ pthread_mutex_unlock (&vstfx->lock);
+
+ goto again;
+ }
+
+ /*Window does not yet exist - scheduled for creation*/
+
+ /* FIXME - probably safe to assume 0 is not a valid XID but not explicitly true */
+ if (vstfx->linux_window == 0) {
+ if (vstfx_create_editor (vstfx)) {
+ vstfx_error ("** ERROR ** VSTFX : Cannot create editor for plugin %s", vstfx->handle->name);
+ vstfx_event_loop_remove_plugin (vstfx);
+ pthread_cond_signal (&vstfx->window_status_change);
+ pthread_mutex_unlock (&vstfx->lock);
+ goto again;
+ } else {
+ /* condition/unlock: it was signalled & unlocked in fst_create_editor() */
+ }
+ }
+
+ maybe_set_program (vstfx);
+ vstfx->want_program = -1;
+ vstfx->want_chunk = 0;
+
+ /*scheduled call to dispatcher*/
+
+ if (vstfx->dispatcher_wantcall) {
+ vstfx->dispatcher_retval = vstfx->plugin->dispatcher (
+ vstfx->plugin,
+ vstfx->dispatcher_opcode,
+ vstfx->dispatcher_index,
+ vstfx->dispatcher_val,
+ vstfx->dispatcher_ptr,
+ vstfx->dispatcher_opt
+ );
+
+ vstfx->dispatcher_wantcall = 0;
+ pthread_cond_signal (&vstfx->plugin_dispatcher_called);
+ }
+
+ /*Call the editor Idle function in the plugin*/
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effEditIdle, 0, 0, NULL, 0);
+
+ if(vstfx->wantIdle)
+ vstfx->plugin->dispatcher (vstfx->plugin, 53, 0, 0, NULL, 0);
+
+ pthread_mutex_unlock (&vstfx->lock);
+ }
+ pthread_mutex_unlock (&plugin_mutex);
+ }
+ }
+
+ /*Drop out to here if we set gui_quit to 1 */
+
+ return NULL;
+}
+
+/*The VSTFX Init function - this needs to be called before the VSTFX engine
+can be accessed, it gets the UI thread running, opens a connection to X etc
+normally started in globals.cc*/
+
+int vstfx_init (void* ptr)
+{
+
+ int thread_create_result;
+
+ pthread_attr_t thread_attributes;
+
+ /*Init the attribs to defaults*/
+
+ pthread_attr_init(&thread_attributes);
+
+ /*Make sure the thread is joinable - this should be the default anyway -
+ so we can join to it on vstfx_exit*/
+
+ pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
+
+
+ /*This is where we need to open a connection to X, and start the GUI thread*/
+
+ /*Open our connection to X - all linuxVST plugin UIs handled by the LXVST engine
+ will talk to X down this connection - X cannot handle multi-threaded access via
+ the same Display* */
+
+ if(LXVST_XDisplay==NULL)
+ LXVST_XDisplay = XOpenDisplay(NULL); //We might be able to make this open a specific screen etc
+
+ /*Drop out and report the error if we fail to connect to X */
+
+ if(LXVST_XDisplay==NULL)
+ {
+ vstfx_error ("** ERROR ** VSTFX: Failed opening connection to X");
+
+ return -1;
+ }
+
+ /*We have a connection to X - so start the gui event loop*/
+
+ /*Create the thread - use default attrs for now, don't think we need anything special*/
+
+ thread_create_result = pthread_create(&LXVST_gui_event_thread, NULL, gui_event_loop, NULL);
+
+ if(thread_create_result!=0)
+ {
+ /*There was a problem starting the GUI event thread*/
+
+ vstfx_error ("** ERROR ** VSTFX: Failed starting GUI event thread");
+
+ XCloseDisplay(LXVST_XDisplay);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/*The vstfx Quit function*/
+
+void vstfx_exit()
+{
+ gui_quit = 1;
+
+ /*We need to pthread_join the gui_thread here so
+ we know when it has stopped*/
+
+ pthread_join(LXVST_gui_event_thread, NULL);
+}
+
+/*Adds a new plugin (VSTFX) instance to the linked list*/
+
+int vstfx_run_editor (VSTState* vstfx)
+{
+ pthread_mutex_lock (&plugin_mutex);
+
+ /* Add the new VSTFX instance to the linked list */
+
+ if (vstfx_first == NULL) {
+ vstfx_first = vstfx;
+ } else {
+ VSTState* p = vstfx_first;
+
+ while (p->next) {
+ p = p->next;
+ }
+ p->next = vstfx;
+
+ /* Mark the new end of the list */
+
+ vstfx->next = NULL;
+ }
+
+ pthread_mutex_unlock (&plugin_mutex);
+
+ /* wait for the plugin editor window to be created (or not) */
+
+ pthread_mutex_lock (&vstfx->lock);
+
+ if (!vstfx->linux_window) {
+ pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
+ }
+
+ pthread_mutex_unlock (&vstfx->lock);
+
+ if (!vstfx->linux_window) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*Creates an editor for the plugin - normally called from within the gui event loop
+after run_editor has added the plugin (editor) to the linked list*/
+
+int vstfx_create_editor (VSTState* vstfx)
+{
+ Window parent_window;
+
+ int x_size = 1;
+ int y_size = 1;
+
+ /* Note: vstfx->lock is held while this function is called */
+
+ if (!(vstfx->plugin->flags & effFlagsHasEditor))
+ {
+ vstfx_error ("** ERROR ** VSTFX: Plugin \"%s\" has no editor", vstfx->handle->name);
+ return -1;
+ }
+
+
+ /*Create an XWindow for the plugin to inhabit*/
+
+ parent_window = XCreateSimpleWindow (
+ LXVST_XDisplay,
+ DefaultRootWindow(LXVST_XDisplay),
+ 0,
+ 0,
+ x_size,
+ y_size,
+ 0,
+ 0,
+ 0
+ );
+
+ /*Select the events we are interested in receiving - we need Substructure notify so that
+ if the plugin resizes its window - e.g. Loomer Manifold then we get a message*/
+
+ XSelectInput(LXVST_XDisplay,
+ parent_window,
+ SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask);
+
+ vstfx->linux_window = parent_window;
+
+ vstfx->xid = parent_window; //vstfx->xid will be referenced to connect to GTK UI in ardour later
+
+ /*Because the plugin may be operating on a different Display* to us, and therefore
+ the two event queues can be asynchronous, although we have created the window on
+ our display, we can't guarantee it exists in the server yet, which will
+ cause BadWindow crashes if the plugin tries to use it.
+
+ It would be nice to use CreateNotify events here, but they don't get
+ through on all window managers, so instead we pass a client message
+ into out queue, after the XCreateWindow. When this message pops out
+ in our event handler, it will trigger the second stage of plugin
+ Editor instantiation, and by then the Window should be valid...*/
+
+ XClientMessageEvent event;
+
+ /*Create an atom to identify our message (only if it doesn't already exist)*/
+
+ Atom WindowActiveAtom = XInternAtom(LXVST_XDisplay, "LaunchEditor", false);
+
+ event.type = ClientMessage;
+ event.send_event = true;
+ event.window = parent_window;
+ event.message_type = WindowActiveAtom;
+
+ event.format = 32; //Data format
+ event.data.l[0] = 0x0FEEDBAC; //Something we can recognize later
+
+ /*Push the event into the queue on our Display*/
+
+ XSendEvent(LXVST_XDisplay, parent_window, FALSE, NoEventMask, (XEvent*)&event);
+
+ /*Unlock - and we are done for the first part of staring the Editor...*/
+
+ pthread_mutex_unlock (&vstfx->lock);
+
+ return 0;
+}
+
+int
+vstfx_launch_editor (VSTState* vstfx)
+{
+ /*This is the second stage of launching the editor (see vstfx_create editor)
+ we get called here in response to receiving the ClientMessage on our Window,
+ therefore it's about as safe (as can be) to assume that the Window we created
+ is now valid in the XServer and can be passed to the plugin in effEditOpen
+ without generating BadWindow errors when the plugin reparents itself into our
+ parent window*/
+
+ if(vstfx->been_activated)
+ return 0;
+
+ Window parent_window;
+ struct ERect* er;
+
+ int x_size = 1;
+ int y_size = 1;
+
+ parent_window = vstfx->linux_window;
+
+ /*Open the editor - Bah! we have to pass the int windowID as a void pointer - yuck
+ it gets cast back to an int as the parent window XID in the plugin - and we have to pass the
+ Display* as a long */
+
+ /**************************************************************/
+ /* 64Bit --- parent window is an int passed as a void* so */
+ /* that should be ok for 64Bit machines */
+ /* */
+ /* Display is passed in as a long - ok on arch's where sizeof */
+ /* long = 8 */
+ /* */
+ /* Most linux VST plugins open a connection to X on their own */
+ /* Display anyway so it may not matter */
+ /* */
+ /* linuxDSP VSTs don't use the host Display* at all */
+ /**************************************************************/
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effEditOpen, 0, (long)LXVST_XDisplay, (void*)(parent_window), 0 );
+
+ /*QUIRK - some plugins need a slight delay after opening the editor before you can
+ ask the window size or they might return zero - specifically discoDSP */
+
+ usleep(100000);
+
+ /*Now we can find out how big the parent window should be (and try) to resize it*/
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effEditGetRect, 0, 0, &er, 0 );
+
+ x_size = er->right - er->left;
+ y_size = er->bottom - er->top;
+
+ vstfx->width = x_size;
+ vstfx->height = y_size;
+
+ XResizeWindow(LXVST_XDisplay, parent_window, x_size, y_size);
+
+ XFlush (LXVST_XDisplay);
+
+ /*Not sure if we need to map the window or if the plugin will do it for us
+ it should be ok because XReparentWindow generates a Map event*/
+
+ /*mark the editor as activated - mainly so that vstfx_get_XID
+ will know it is valid*/
+
+ vstfx->been_activated = TRUE;
+
+ pthread_cond_signal (&vstfx->window_status_change);
+ return 0;
+}
+
+/** Destroy the editor window */
+void
+vstfx_destroy_editor (VSTState* vstfx)
+{
+ pthread_mutex_lock (&vstfx->lock);
+ if (vstfx->linux_window) {
+ vstfx->destroy = TRUE;
+ pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
+ }
+ pthread_mutex_unlock (&vstfx->lock);
+}
+
+/** Remove a vstfx instance from the linked list parsed by the
+ event loop
+*/
+void
+vstfx_event_loop_remove_plugin (VSTState* vstfx)
+{
+ /* This only ever gets called from within our GUI thread
+ so we don't need to lock here - if we did there would be
+ a deadlock anyway
+ */
+
+ VSTState* p;
+ VSTState* prev;
+
+ for (p = vstfx_first, prev = NULL; p; prev = p, p = p->next) {
+ if (p == vstfx) {
+ if (prev) {
+ prev->next = p->next;
+ break;
+ }
+ }
+ }
+
+ if (vstfx_first == vstfx) {
+ vstfx_first = vstfx_first->next;
+ }
+}
+
*/
#include "ardour/lxvst_plugin.h"
-#include "ardour/vstfx.h"
+#include "ardour/linux_vst_support.h"
#include "lxvst_plugin_ui.h"
#include "ardour_ui.h"
#include <gdk/gdkx.h>
+++ /dev/null
-/******************************************************************/
-/** VSTFX - An engine based on FST for handling linuxVST plugins **/
-/******************************************************************/
-
-/*This is derived from the original FST (C code) with some tweaks*/
-
-
-/** EDITOR tab stops at 4 **/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <jack/jack.h>
-#include <jack/thread.h>
-#include <libgen.h>
-
-#include <pthread.h>
-#include <signal.h>
-#include <glib.h>
-
-#include "ardour/vstfx.h"
-
-#include <X11/X.h>
-#include <X11/Xlib.h>
-#include <dlfcn.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <pthread.h>
-
-struct ERect{
- short top;
- short left;
- short bottom;
- short right;
-};
-
-static pthread_mutex_t plugin_mutex;
-
-static VSTState * vstfx_first = NULL;
-
-const char magic[] = "VSTFX Plugin State v002";
-
-int gui_thread_id = 0;
-static int gui_quit = 0;
-
-/*This will be our connection to X*/
-
-Display* LXVST_XDisplay = NULL;
-
-/*The thread handle for the GUI event loop*/
-
-pthread_t LXVST_gui_event_thread;
-
-/*Util functions to get the value of a property attached to an XWindow*/
-
-bool LXVST_xerror;
-
-int TempErrorHandler(Display *display, XErrorEvent *e)
-{
- LXVST_xerror = true;
-
- return 0;
-}
-
-#ifdef LXVST_32BIT
-
-int getXWindowProperty(Window window, Atom atom)
-{
- int result = 0;
- int userSize;
- unsigned long bytes;
- unsigned long userCount;
- unsigned char *data;
- Atom userType;
- LXVST_xerror = false;
-
- /*Use our own Xerror handler while we're in here - in an
- attempt to stop the brain dead default Xerror behaviour of
- qutting the entire application because of e.g. an invalid
- window ID*/
-
- XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
-
- XGetWindowProperty( LXVST_XDisplay, //The display
- window, //The Window
- atom, //The property
- 0, //Offset into the data
- 1, //Number of 32Bit chunks of data
- false, //false = don't delete the property
- AnyPropertyType, //Required property type mask
- &userType, //Actual type returned
- &userSize, //Actual format returned
- &userCount, //Actual number of items stored in the returned data
- &bytes, //Number of bytes remaining if a partial read
- &data); //The actual data read
-
- if(LXVST_xerror == false && userCount == 1)
- result = *(int*)data;
-
- XSetErrorHandler(olderrorhandler);
-
- /*Hopefully this will return zero if the property is not set*/
-
- return result;
-}
-
-#endif
-
-#ifdef LXVST_64BIT
-
-/********************************************************************/
-/* This is untested - have no 64Bit plugins which use this */
-/* system of passing an eventProc address */
-/********************************************************************/
-
-long getXWindowProperty(Window window, Atom atom)
-{
- long result = 0;
- int userSize;
- unsigned long bytes;
- unsigned long userCount;
- unsigned char *data;
- Atom userType;
- LXVST_xerror = false;
-
- /*Use our own Xerror handler while we're in here - in an
- attempt to stop the brain dead default Xerror behaviour of
- qutting the entire application because of e.g. an invalid
- window ID*/
-
- XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
-
- XGetWindowProperty( LXVST_XDisplay,
- window,
- atom,
- 0,
- 2,
- false,
- AnyPropertyType,
- &userType,
- &userSize,
- &userCount,
- &bytes,
- &data);
-
- if(LXVST_xerror == false && userCount == 1)
- result = *(long*)data;
-
- XSetErrorHandler(olderrorhandler);
-
- /*Hopefully this will return zero if the property is not set*/
-
- return result;
-}
-
-#endif
-
-/*The event handler - called from within the main GUI thread to
-dispatch events to any VST UIs which have callbacks stuck to them*/
-
-static void
-dispatch_x_events (XEvent* event, VSTState* vstfx)
-{
- /*Handle some of the Events we might be interested in*/
-
- switch(event->type)
- {
- /*Configure event - when the window is resized or first drawn*/
-
- case ConfigureNotify:
- {
- Window window = event->xconfigure.event;
-
- int width = event->xconfigure.width;
- int height = event->xconfigure.height;
-
- /*If we get a config notify on the parent window XID then we need to see
- if the size has been changed - some plugins re-size their UI window e.g.
- when opening a preset manager (you might think that should be spawned as a new window...) */
-
- /*if the size has changed, we flag this so that in lxvst_pluginui.cc we can make the
- change to the GTK parent window in ardour, from its UI thread*/
-
- if (window == (Window) (vstfx->linux_window)) {
- if (width != vstfx->width || height!=vstfx->height) {
- vstfx->width = width;
- vstfx->height = height;
- vstfx->want_resize = 1;
-
- /*QUIRK : Loomer plugins not only resize the UI but throw it into some random
- position at the same time. We need to re-position the window at the origin of
- the parent window*/
-
- if (vstfx->linux_plugin_ui_window) {
- XMoveWindow (LXVST_XDisplay, vstfx->linux_plugin_ui_window, 0, 0);
- }
- }
- }
-
- break;
-
- }
-
- /*Reparent Notify - when the plugin UI is reparented into
- our Host Window we will get an event here... probably... */
-
- case ReparentNotify:
- {
- Window ParentWindow = event->xreparent.parent;
-
- /*If the ParentWindow matches the window for the vstfx instance then
- the Child window must be the XID of the pluginUI window created by the
- plugin, so we need to see if it has a callback stuck to it, and if so
- set that up in the vstfx */
-
- /***********************************************************/
- /* 64Bit --- This mechanism is not 64Bit compatible at the */
- /* present time */
- /***********************************************************/
-
- if (ParentWindow == (Window) (vstfx->linux_window)) {
-
- Window PluginUIWindowID = event->xreparent.window;
-
- vstfx->linux_plugin_ui_window = PluginUIWindowID;
-#ifdef LXVST_32BIT
- int result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
-
- if (result == 0) {
- vstfx->eventProc = NULL;
- } else {
- vstfx->eventProc = (void (*) (void* event))result;
- }
-#endif
-#ifdef LXVST_64BIT
- long result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
-
- if(result == 0)
- vstfx->eventProc = NULL;
- else
- vstfx->eventProc = (void (*) (void* event))result;
-#endif
- }
- break;
- }
-
- case ClientMessage:
- {
- Window window = event->xany.window;
- Atom message_type = event->xclient.message_type;
-
- /*The only client message we are interested in is to signal
- that the plugin parent window is now valid and can be passed
- to effEditOpen when the editor is launched*/
-
- if (window == (Window) (vstfx->linux_window)) {
- char* message = XGetAtomName(LXVST_XDisplay, message_type);
-
- if (strcmp(message,"LaunchEditor") == 0) {
- if (event->xclient.data.l[0] == 0x0FEEDBAC) {
- vstfx_launch_editor (vstfx);
- }
- }
-
- XFree(message);
- }
- break;
- }
-
- default:
- break;
- }
-
- /* Some VSTs built with toolkits e.g. JUCE will manager their own UI
- autonomously in the plugin, running the UI in its own thread, so once
- we have created a parent window for the plugin, its UI takes care of
- itself.*/
-
- /*Other types register a callback as an Xwindow property on the plugin
- UI window after they create it. If that is the case, we need to call it
- here, passing the XEvent into it*/
-
- if (vstfx->eventProc == NULL) {
- return;
- }
-
- vstfx->eventProc((void*)event);
-}
-
-static void
-maybe_set_program (VSTState* vstfx)
-{
- if (vstfx->want_program != -1) {
- if (vstfx->vst_version >= 2) {
- vstfx->plugin->dispatcher (vstfx->plugin, 67 /* effBeginSetProgram */, 0, 0, NULL, 0);
- }
-
- vstfx->plugin->dispatcher (vstfx->plugin, effSetProgram, 0, vstfx->want_program, NULL, 0);
-
- if (vstfx->vst_version >= 2) {
- vstfx->plugin->dispatcher (vstfx->plugin, 68 /* effEndSetProgram */, 0, 0, NULL, 0);
- }
-
- vstfx->want_program = -1;
- }
-
- if (vstfx->want_chunk == 1) {
- vstfx->plugin->dispatcher (vstfx->plugin, 24 /* effSetChunk */, 1, vstfx->wanted_chunk_size, vstfx->wanted_chunk, 0);
- vstfx->want_chunk = 0;
- }
-}
-
-/** This is the main gui event loop for the plugin, we also need to pass
-any Xevents to all the UI callbacks plugins 'may' have registered on their
-windows, that is if they don't manage their own UIs **/
-
-void* gui_event_loop (void* ptr)
-{
- VSTState* vstfx;
- int LXVST_sched_event_timer = 0;
- int LXVST_sched_timer_interval = 50; //ms
- XEvent event;
-
- /*The 'Forever' loop - runs the plugin UIs etc - based on the FST gui event loop*/
-
- while (!gui_quit)
- {
- /* handle window creation requests, destroy requests,
- and run idle callbacks */
-
- /*Look at the XEvent queue - if there are any XEvents we need to handle them,
- including passing them to all the plugin (eventProcs) we are currently managing*/
-
- if(LXVST_XDisplay)
- {
- /*See if there are any events in the queue*/
-
- int num_events = XPending(LXVST_XDisplay);
-
- /*process them if there are any*/
-
- while(num_events)
- {
- XNextEvent(LXVST_XDisplay, &event);
-
- /*Call dispatch events, with the event, for each plugin in the linked list*/
-
- for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
- {
- pthread_mutex_lock(&vstfx->lock);
-
- dispatch_x_events(&event, vstfx);
-
- pthread_mutex_unlock(&vstfx->lock);
- }
-
- num_events--;
- }
- }
-
- /*We don't want to use all the CPU.. */
-
- usleep(1000);
-
- LXVST_sched_event_timer++;
-
- LXVST_sched_event_timer = LXVST_sched_event_timer & 0x00FFFFFF;
-
- /*See if its time for us to do a scheduled event pass on all the plugins*/
-
- if((LXVST_sched_timer_interval!=0) && (!(LXVST_sched_event_timer% LXVST_sched_timer_interval)))
- {
- pthread_mutex_lock (&plugin_mutex);
-
-again:
- /*Parse through the linked list of plugins*/
-
- for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
- {
- pthread_mutex_lock (&vstfx->lock);
-
- /*Window scheduled for destruction*/
-
- if (vstfx->destroy) {
- if (vstfx->linux_window) {
- vstfx->plugin->dispatcher (vstfx->plugin, effEditClose, 0, 0, NULL, 0.0);
-
- XDestroyWindow (LXVST_XDisplay, vstfx->linux_window);
- /* FIXME - probably safe to assume we never have an XID of 0 but not explicitly true */
- vstfx->linux_window = 0;
- vstfx->destroy = FALSE;
- }
-
- vstfx_event_loop_remove_plugin (vstfx);
- vstfx->been_activated = FALSE;
- pthread_cond_signal (&vstfx->window_status_change);
- pthread_mutex_unlock (&vstfx->lock);
-
- goto again;
- }
-
- /*Window does not yet exist - scheduled for creation*/
-
- /* FIXME - probably safe to assume 0 is not a valid XID but not explicitly true */
- if (vstfx->linux_window == 0) {
- if (vstfx_create_editor (vstfx)) {
- vstfx_error ("** ERROR ** VSTFX : Cannot create editor for plugin %s", vstfx->handle->name);
- vstfx_event_loop_remove_plugin (vstfx);
- pthread_cond_signal (&vstfx->window_status_change);
- pthread_mutex_unlock (&vstfx->lock);
- goto again;
- } else {
- /* condition/unlock: it was signalled & unlocked in fst_create_editor() */
- }
- }
-
- maybe_set_program (vstfx);
- vstfx->want_program = -1;
- vstfx->want_chunk = 0;
-
- /*scheduled call to dispatcher*/
-
- if (vstfx->dispatcher_wantcall) {
- vstfx->dispatcher_retval = vstfx->plugin->dispatcher (
- vstfx->plugin,
- vstfx->dispatcher_opcode,
- vstfx->dispatcher_index,
- vstfx->dispatcher_val,
- vstfx->dispatcher_ptr,
- vstfx->dispatcher_opt
- );
-
- vstfx->dispatcher_wantcall = 0;
- pthread_cond_signal (&vstfx->plugin_dispatcher_called);
- }
-
- /*Call the editor Idle function in the plugin*/
-
- vstfx->plugin->dispatcher (vstfx->plugin, effEditIdle, 0, 0, NULL, 0);
-
- if(vstfx->wantIdle)
- vstfx->plugin->dispatcher (vstfx->plugin, 53, 0, 0, NULL, 0);
-
- pthread_mutex_unlock (&vstfx->lock);
- }
- pthread_mutex_unlock (&plugin_mutex);
- }
- }
-
- /*Drop out to here if we set gui_quit to 1 */
-
- return NULL;
-}
-
-/*The VSTFX Init function - this needs to be called before the VSTFX engine
-can be accessed, it gets the UI thread running, opens a connection to X etc
-normally started in globals.cc*/
-
-int vstfx_init (void* ptr)
-{
-
- int thread_create_result;
-
- pthread_attr_t thread_attributes;
-
- /*Init the attribs to defaults*/
-
- pthread_attr_init(&thread_attributes);
-
- /*Make sure the thread is joinable - this should be the default anyway -
- so we can join to it on vstfx_exit*/
-
- pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
-
-
- /*This is where we need to open a connection to X, and start the GUI thread*/
-
- /*Open our connection to X - all linuxVST plugin UIs handled by the LXVST engine
- will talk to X down this connection - X cannot handle multi-threaded access via
- the same Display* */
-
- if(LXVST_XDisplay==NULL)
- LXVST_XDisplay = XOpenDisplay(NULL); //We might be able to make this open a specific screen etc
-
- /*Drop out and report the error if we fail to connect to X */
-
- if(LXVST_XDisplay==NULL)
- {
- vstfx_error ("** ERROR ** VSTFX: Failed opening connection to X");
-
- return -1;
- }
-
- /*We have a connection to X - so start the gui event loop*/
-
- /*Create the thread - use default attrs for now, don't think we need anything special*/
-
- thread_create_result = pthread_create(&LXVST_gui_event_thread, NULL, gui_event_loop, NULL);
-
- if(thread_create_result!=0)
- {
- /*There was a problem starting the GUI event thread*/
-
- vstfx_error ("** ERROR ** VSTFX: Failed starting GUI event thread");
-
- XCloseDisplay(LXVST_XDisplay);
-
- return -1;
- }
-
- return 0;
-}
-
-/*The vstfx Quit function*/
-
-void vstfx_exit()
-{
- gui_quit = 1;
-
- /*We need to pthread_join the gui_thread here so
- we know when it has stopped*/
-
- pthread_join(LXVST_gui_event_thread, NULL);
-}
-
-/*Adds a new plugin (VSTFX) instance to the linked list*/
-
-int vstfx_run_editor (VSTState* vstfx)
-{
- pthread_mutex_lock (&plugin_mutex);
-
- /* Add the new VSTFX instance to the linked list */
-
- if (vstfx_first == NULL) {
- vstfx_first = vstfx;
- } else {
- VSTState* p = vstfx_first;
-
- while (p->next) {
- p = p->next;
- }
- p->next = vstfx;
-
- /* Mark the new end of the list */
-
- vstfx->next = NULL;
- }
-
- pthread_mutex_unlock (&plugin_mutex);
-
- /* wait for the plugin editor window to be created (or not) */
-
- pthread_mutex_lock (&vstfx->lock);
-
- if (!vstfx->linux_window) {
- pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
- }
-
- pthread_mutex_unlock (&vstfx->lock);
-
- if (!vstfx->linux_window) {
- return -1;
- }
-
- return 0;
-}
-
-
-/*Creates an editor for the plugin - normally called from within the gui event loop
-after run_editor has added the plugin (editor) to the linked list*/
-
-int vstfx_create_editor (VSTState* vstfx)
-{
- Window parent_window;
-
- int x_size = 1;
- int y_size = 1;
-
- /* Note: vstfx->lock is held while this function is called */
-
- if (!(vstfx->plugin->flags & effFlagsHasEditor))
- {
- vstfx_error ("** ERROR ** VSTFX: Plugin \"%s\" has no editor", vstfx->handle->name);
- return -1;
- }
-
-
- /*Create an XWindow for the plugin to inhabit*/
-
- parent_window = XCreateSimpleWindow (
- LXVST_XDisplay,
- DefaultRootWindow(LXVST_XDisplay),
- 0,
- 0,
- x_size,
- y_size,
- 0,
- 0,
- 0
- );
-
- /*Select the events we are interested in receiving - we need Substructure notify so that
- if the plugin resizes its window - e.g. Loomer Manifold then we get a message*/
-
- XSelectInput(LXVST_XDisplay,
- parent_window,
- SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask);
-
- vstfx->linux_window = parent_window;
-
- vstfx->xid = parent_window; //vstfx->xid will be referenced to connect to GTK UI in ardour later
-
- /*Because the plugin may be operating on a different Display* to us, and therefore
- the two event queues can be asynchronous, although we have created the window on
- our display, we can't guarantee it exists in the server yet, which will
- cause BadWindow crashes if the plugin tries to use it.
-
- It would be nice to use CreateNotify events here, but they don't get
- through on all window managers, so instead we pass a client message
- into out queue, after the XCreateWindow. When this message pops out
- in our event handler, it will trigger the second stage of plugin
- Editor instantiation, and by then the Window should be valid...*/
-
- XClientMessageEvent event;
-
- /*Create an atom to identify our message (only if it doesn't already exist)*/
-
- Atom WindowActiveAtom = XInternAtom(LXVST_XDisplay, "LaunchEditor", false);
-
- event.type = ClientMessage;
- event.send_event = true;
- event.window = parent_window;
- event.message_type = WindowActiveAtom;
-
- event.format = 32; //Data format
- event.data.l[0] = 0x0FEEDBAC; //Something we can recognize later
-
- /*Push the event into the queue on our Display*/
-
- XSendEvent(LXVST_XDisplay, parent_window, FALSE, NoEventMask, (XEvent*)&event);
-
- /*Unlock - and we are done for the first part of staring the Editor...*/
-
- pthread_mutex_unlock (&vstfx->lock);
-
- return 0;
-}
-
-int
-vstfx_launch_editor (VSTState* vstfx)
-{
- /*This is the second stage of launching the editor (see vstfx_create editor)
- we get called here in response to receiving the ClientMessage on our Window,
- therefore it's about as safe (as can be) to assume that the Window we created
- is now valid in the XServer and can be passed to the plugin in effEditOpen
- without generating BadWindow errors when the plugin reparents itself into our
- parent window*/
-
- if(vstfx->been_activated)
- return 0;
-
- Window parent_window;
- struct ERect* er;
-
- int x_size = 1;
- int y_size = 1;
-
- parent_window = vstfx->linux_window;
-
- /*Open the editor - Bah! we have to pass the int windowID as a void pointer - yuck
- it gets cast back to an int as the parent window XID in the plugin - and we have to pass the
- Display* as a long */
-
- /**************************************************************/
- /* 64Bit --- parent window is an int passed as a void* so */
- /* that should be ok for 64Bit machines */
- /* */
- /* Display is passed in as a long - ok on arch's where sizeof */
- /* long = 8 */
- /* */
- /* Most linux VST plugins open a connection to X on their own */
- /* Display anyway so it may not matter */
- /* */
- /* linuxDSP VSTs don't use the host Display* at all */
- /**************************************************************/
-
- vstfx->plugin->dispatcher (vstfx->plugin, effEditOpen, 0, (long)LXVST_XDisplay, (void*)(parent_window), 0 );
-
- /*QUIRK - some plugins need a slight delay after opening the editor before you can
- ask the window size or they might return zero - specifically discoDSP */
-
- usleep(100000);
-
- /*Now we can find out how big the parent window should be (and try) to resize it*/
-
- vstfx->plugin->dispatcher (vstfx->plugin, effEditGetRect, 0, 0, &er, 0 );
-
- x_size = er->right - er->left;
- y_size = er->bottom - er->top;
-
- vstfx->width = x_size;
- vstfx->height = y_size;
-
- XResizeWindow(LXVST_XDisplay, parent_window, x_size, y_size);
-
- XFlush (LXVST_XDisplay);
-
- /*Not sure if we need to map the window or if the plugin will do it for us
- it should be ok because XReparentWindow generates a Map event*/
-
- /*mark the editor as activated - mainly so that vstfx_get_XID
- will know it is valid*/
-
- vstfx->been_activated = TRUE;
-
- pthread_cond_signal (&vstfx->window_status_change);
- return 0;
-}
-
-/** Destroy the editor window */
-void
-vstfx_destroy_editor (VSTState* vstfx)
-{
- pthread_mutex_lock (&vstfx->lock);
- if (vstfx->linux_window) {
- vstfx->destroy = TRUE;
- pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
- }
- pthread_mutex_unlock (&vstfx->lock);
-}
-
-/** Remove a vstfx instance from the linked list parsed by the
- event loop
-*/
-void
-vstfx_event_loop_remove_plugin (VSTState* vstfx)
-{
- /* This only ever gets called from within our GUI thread
- so we don't need to lock here - if we did there would be
- a deadlock anyway
- */
-
- VSTState* p;
- VSTState* prev;
-
- for (p = vstfx_first, prev = NULL; p; prev = p, p = p->next) {
- if (p == vstfx) {
- if (prev) {
- prev->next = p->next;
- break;
- }
- }
- }
-
- if (vstfx_first == vstfx) {
- vstfx_first = vstfx_first->next;
- }
-}
-
obj.uselib += ' X11 '
if bld.is_defined('LXVST_SUPPORT'):
- obj.source += [ 'vstfxwin.cc', 'lxvst_plugin_ui.cc' ]
+ obj.source += [ 'linux_vst_gui_support.cc', 'lxvst_plugin_ui.cc' ]
obj.defines += [ 'LXVST_SUPPORT' ]
obj.uselib += ' X11 '
+++ /dev/null
-#ifndef __vstfx_h__
-#define __vstfx_h__
-
-#include <setjmp.h>
-#include <signal.h>
-#include <pthread.h>
-#include <stdio.h>
-
-#include "ardour/vst_types.h"
-
-/******************************************************************************************/
-/*VSTFX - an engine to manage native linux VST plugins - derived from FST for Windows VSTs*/
-/******************************************************************************************/
-
-extern void (*vstfx_error_callback)(const char *msg);
-
-void vstfx_set_error_function (void (*func)(const char *));
-
-void vstfx_error (const char *fmt, ...);
-
-/*API to vstfx*/
-
-extern int vstfx_launch_editor (VSTState *);
-extern int vstfx_init (void *);
-extern void vstfx_exit ();
-extern VSTHandle * vstfx_load (const char*);
-extern int vstfx_unload (VSTHandle *);
-extern VSTState * vstfx_instantiate (VSTHandle *, audioMasterCallback, void *);
-extern void vstfx_close (VSTState*);
-
-extern int vstfx_create_editor (VSTState *);
-extern int vstfx_run_editor (VSTState *);
-extern void vstfx_destroy_editor (VSTState *);
-
-extern VSTInfo * vstfx_get_info (char *);
-extern void vstfx_free_info (VSTInfo *);
-extern void vstfx_event_loop_remove_plugin (VSTState *);
-extern int vstfx_call_dispatcher (VSTState *, int, int, int, void *, float);
-
-/** Load a plugin state from a file.**/
-
-extern int vstfx_load_state (VSTState* vstfx, char * filename);
-
-/** Save a plugin state to a file.**/
-
-extern bool vstfx_save_state (VSTState* vstfx, char * filename);
-
-
-#endif /* __vstfx_h__ */
#endif
#ifdef LXVST_SUPPORT
-#include "ardour/vstfx.h"
+#include "ardour/linux_vst_support.h"
#endif
#ifdef AUDIOUNIT_SUPPORT
--- /dev/null
+/***********************************************************/
+/*vstfx infofile - module to manage info files */
+/*containing cached information about a plugin. e.g. its */
+/*name, creator etc etc */
+/***********************************************************/
+
+#include <iostream>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "ardour/linux_vst_support.h"
+
+#define MAX_STRING_LEN 256
+
+static char* read_string(FILE *fp)
+{
+ char buf[MAX_STRING_LEN];
+
+ if (!fgets( buf, MAX_STRING_LEN, fp )) {
+ return 0;
+ }
+
+ if(strlen(buf) < MAX_STRING_LEN) {
+ if (strlen(buf)) {
+ buf[strlen(buf)-1] = 0;
+ }
+ return strdup(buf);
+ } else {
+ return 0;
+ }
+}
+
+static VSTInfo *
+load_vstfx_info_file (FILE* fp)
+{
+ VSTInfo *info;
+ int i;
+
+ if ((info = (VSTInfo*) malloc (sizeof (VSTInfo))) == 0) {
+ return 0;
+ }
+
+ if((info->name = read_string(fp)) == 0) goto error;
+ if((info->creator = read_string(fp)) == 0) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->UniqueID)) goto error;
+ if((info->Category = read_string(fp)) == 0) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->numInputs)) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->numOutputs)) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->numParams)) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->wantMidi)) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->hasEditor)) goto error;
+ if(1 != fscanf(fp, "%d\n", &info->canProcessReplacing)) goto error;
+
+ if((info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams)) == 0) {
+ goto error;
+ }
+
+ for (i=0; i<info->numParams; i++) {
+ if((info->ParamNames[i] = read_string(fp)) == 0) goto error;
+ }
+
+ if ((info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams)) == 0) {
+ goto error;
+ }
+
+ for (i=0; i < info->numParams; i++) {
+ if((info->ParamLabels[i] = read_string(fp)) == 0) goto error;
+ }
+
+ return info;
+
+ error:
+ free( info );
+ return 0;
+}
+
+static int
+save_vstfx_info_file (VSTInfo *info, FILE* fp)
+{
+ int i;
+
+ if (info == 0) {
+ vstfx_error("** ERROR ** VSTFXinfofile : info ptr is 0\n");
+ return -1;
+ }
+
+ if (fp == 0) {
+ vstfx_error("** ERROR ** VSTFXinfofile : file ptr is 0\n");
+ return -1;
+ }
+
+ fprintf( fp, "%s\n", info->name );
+ fprintf( fp, "%s\n", info->creator );
+ fprintf( fp, "%d\n", info->UniqueID );
+ fprintf( fp, "%s\n", info->Category );
+ fprintf( fp, "%d\n", info->numInputs );
+ fprintf( fp, "%d\n", info->numOutputs );
+ fprintf( fp, "%d\n", info->numParams );
+ fprintf( fp, "%d\n", info->wantMidi );
+ fprintf( fp, "%d\n", info->hasEditor );
+ fprintf( fp, "%d\n", info->canProcessReplacing );
+
+ for (i=0; i < info->numParams; i++) {
+ fprintf(fp, "%s\n", info->ParamNames[i]);
+ }
+
+ for (i=0; i < info->numParams; i++) {
+ fprintf(fp, "%s\n", info->ParamLabels[i]);
+ }
+
+ return 0;
+}
+
+static char* vstfx_infofile_stat (char *dllpath, struct stat* statbuf, int personal)
+{
+ char* path;
+ char* dir_path;
+ char* basename;
+ char* base;
+ size_t blen;
+
+ if (strstr (dllpath, ".so" ) == 0) {
+ return 0;
+ }
+
+ if (personal) {
+ dir_path = g_build_filename (g_get_home_dir(), ".fst", NULL);
+ } else {
+ dir_path = g_path_get_dirname (dllpath);
+ }
+
+ base = g_path_get_basename (dllpath);
+ blen = strlen (base) + 2; // null char and '.'
+ basename = (char*) g_malloc (blen);
+ snprintf (basename, blen, ".%s.fsi", base);
+ g_free (base);
+
+ path = g_build_filename (dir_path, basename, NULL);
+
+ g_free (dir_path);
+ g_free (basename);
+
+
+ if (g_file_test (path, GFileTest (G_FILE_TEST_EXISTS|G_FILE_TEST_IS_REGULAR))) {
+
+ /* info file exists in same location as the shared object, so
+ check if its current and up to date
+ */
+
+
+ struct stat dllstat;
+
+ if (stat (dllpath, &dllstat) == 0) {
+ if (stat(path, statbuf) == 0) {
+ if (dllstat.st_mtime <= statbuf->st_mtime) {
+ /* plugin is older than info file */
+ return path;
+ }
+ }
+ }
+ }
+
+ g_free (path);
+
+ return 0;
+}
+
+
+static FILE* vstfx_infofile_for_read (char* dllpath)
+{
+ struct stat own_statbuf;
+ struct stat sys_statbuf;
+ char *own_info;
+ char *sys_info;
+
+ own_info = vstfx_infofile_stat (dllpath, &own_statbuf, 1);
+ sys_info = vstfx_infofile_stat (dllpath, &sys_statbuf, 0);
+
+ if (own_info) {
+ if (sys_info) {
+ if (own_statbuf.st_mtime <= sys_statbuf.st_mtime) {
+ /* system info file is newer, use it */
+ return fopen (sys_info, "r");
+ }
+ } else {
+ return fopen (own_info, "r");
+ }
+ }
+
+ return 0;
+}
+
+static FILE* vstfx_infofile_create (char* dllpath, int personal)
+{
+ char* path;
+ char* dir_path;
+ char* basename;
+ char* base;
+ size_t blen;
+
+ if (strstr (dllpath, ".so" ) == 0) {
+ return 0;
+ }
+
+ if (personal) {
+ dir_path = g_build_filename (g_get_home_dir(), ".fst", NULL);
+
+ /* if the directory doesn't yet exist, try to create it */
+
+ if (!g_file_test (dir_path, G_FILE_TEST_IS_DIR)) {
+ if (g_mkdir (dir_path, 0700)) {
+ return 0;
+ }
+ }
+
+ } else {
+ dir_path = g_path_get_dirname (dllpath);
+ }
+
+ base = g_path_get_basename (dllpath);
+ blen = strlen (base) + 2; // null char and '.'
+ basename = (char*) g_malloc (blen);
+ snprintf (basename, blen, ".%s.fsi", base);
+ g_free (base);
+
+ path = g_build_filename (dir_path, basename, NULL);
+
+ g_free (dir_path);
+ g_free (basename);
+
+ FILE* f = fopen (path, "w");
+ g_free (path);
+
+ return f;
+}
+
+static FILE* vstfx_infofile_for_write (char* dllpath)
+{
+ FILE* f;
+
+ if ((f = vstfx_infofile_create (dllpath, 0)) == 0) {
+ f = vstfx_infofile_create (dllpath, 1);
+ }
+
+ return f;
+}
+
+static
+int vstfx_can_midi (VSTState* vstfx)
+{
+ AEffect *plugin = vstfx->plugin;
+
+ int vst_version = plugin->dispatcher (plugin, effGetVstVersion, 0, 0, 0, 0.0f);
+
+ if (vst_version >= 2)
+ {
+ /* should we send it VST events (i.e. MIDI) */
+
+ if ((plugin->flags & effFlagsIsSynth) || (plugin->dispatcher (plugin, effCanDo, 0, 0,(void*) "receiveVstEvents", 0.0f) > 0))
+ return -1;
+ }
+ return false;
+}
+
+static VSTInfo *
+vstfx_info_from_plugin (VSTState* vstfx)
+{
+ VSTInfo* info = (VSTInfo*) malloc (sizeof (VSTInfo));
+
+ AEffect *plugin;
+ int i;
+
+ /*We need to init the creator because some plugins
+ fail to implement getVendorString, and so won't stuff the
+ string with any name*/
+
+ char creator[65] = "Unknown\0";
+
+ if(!vstfx)
+ {
+ vstfx_error( "** ERROR ** VSTFXinfofile : vstfx ptr is 0\n" );
+ return 0;
+ }
+
+ if(!info)
+ return 0;
+
+ plugin = vstfx->plugin;
+
+ info->name = strdup(vstfx->handle->name );
+
+ /*If the plugin doesn't bother to implement GetVendorString we will
+ have pre-stuffed the string with 'Unkown' */
+
+ plugin->dispatcher (plugin, effGetVendorString, 0, 0, creator, 0);
+
+ /*Some plugins DO implement GetVendorString, but DON'T put a name in it
+ so if its just a zero length string we replace it with 'Unknown' */
+
+ if (strlen(creator) == 0) {
+ info->creator = strdup("Unknown");
+ } else {
+ info->creator = strdup (creator);
+ }
+
+ info->UniqueID = plugin->uniqueID;
+
+ info->Category = strdup("None"); // FIXME:
+ info->numInputs = plugin->numInputs;
+ info->numOutputs = plugin->numOutputs;
+ info->numParams = plugin->numParams;
+ info->wantMidi = vstfx_can_midi(vstfx);
+ info->hasEditor = plugin->flags & effFlagsHasEditor ? true : false;
+ info->canProcessReplacing = plugin->flags & effFlagsCanReplacing ? true : false;
+ info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams);
+ info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams);
+
+ for(i=0; i < info->numParams; i++) {
+ char name[64];
+ char label[64];
+
+ /*Not all plugins give parameters labels as well as names*/
+
+ strcpy(name, "No Name");
+ strcpy(label, "No Label");
+
+ plugin->dispatcher (plugin, effGetParamName, i, 0, name, 0);
+ info->ParamNames[i] = strdup(name);
+
+ //NOTE: 'effGetParamLabel' is no longer defined in vestige headers
+ //plugin->dispatcher (plugin, effGetParamLabel, i, 0, label, 0);
+ info->ParamLabels[i] = strdup(label);
+ }
+ return info;
+}
+
+/* A simple 'dummy' audiomaster callback which should be ok,
+we will only be instantiating the plugin in order to get its info*/
+
+static intptr_t
+simple_master_callback (AEffect *, int32_t opcode, int32_t, intptr_t, void *, float)
+{
+ if (opcode == audioMasterVersion)
+ return 2;
+ else
+ return 0;
+}
+
+/*Try to get plugin info - first by looking for a .fsi cache of the
+data, and if that doesn't exist, load the plugin, get its data and
+then cache it for future ref*/
+
+VSTInfo *
+vstfx_get_info (char* dllpath)
+{
+ FILE* infofile;
+ VSTHandle* h;
+ VSTState* vstfx;
+ VSTInfo* info;
+
+ if ((infofile = vstfx_infofile_for_read (dllpath)) != 0) {
+ VSTInfo *info;
+ info = load_vstfx_info_file (infofile);
+ fclose (infofile);
+ return info;
+ }
+
+ if(!(h = vstfx_load(dllpath)))
+ return 0;
+
+ if(!(vstfx = vstfx_instantiate(h, simple_master_callback, 0))) {
+ vstfx_unload(h);
+ vstfx_error( "** ERROR ** VSTFXinfofile : Instantiate failed\n" );
+ return 0;
+ }
+
+ infofile = vstfx_infofile_for_write (dllpath);
+
+ if(!infofile) {
+ vstfx_close(vstfx);
+ vstfx_unload(h);
+ vstfx_error("cannot create new FST info file for plugin");
+ return 0;
+ }
+
+ info = vstfx_info_from_plugin(vstfx);
+
+ save_vstfx_info_file(info, infofile);
+ fclose (infofile);
+
+ vstfx_close(vstfx);
+ vstfx_unload(h);
+
+ return info;
+}
+
+void
+vstfx_free_info (VSTInfo *info)
+{
+ for (int i = 0; i < info->numParams; i++) {
+ free (info->ParamNames[i]);
+ free (info->ParamLabels[i]);
+ }
+
+ free (info->name);
+ free (info->creator);
+ free (info->Category);
+ free (info);
+}
+
+
--- /dev/null
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <libgen.h>
+#include <pthread.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "ardour/linux_vst_support.h"
+#include "pbd/error.h"
+
+/***********************************************************/
+/* VSTFX - A set of modules for managing linux VST plugins */
+/* vstfx.cc, vstfxwin.cc and vstfxinfofile.cc */
+/***********************************************************/
+
+/*Simple error handler stuff for VSTFX*/
+
+void vstfx_error (const char *fmt, ...)
+{
+ va_list ap;
+ char buffer[512];
+
+ va_start (ap, fmt);
+ vsnprintf (buffer, sizeof(buffer), fmt, ap);
+ vstfx_error_callback (buffer);
+ va_end (ap);
+}
+
+/*default error handler callback*/
+
+void default_vstfx_error_callback (const char *desc)
+{
+ PBD::error << desc << endmsg;
+}
+
+void (*vstfx_error_callback)(const char *desc) = &default_vstfx_error_callback;
+
+/* --- */
+
+/*Create and return a pointer to a new VSTFX handle*/
+
+VSTHandle *
+vstfx_handle_new ()
+{
+ VSTHandle* vstfx = (VSTHandle *) calloc (1, sizeof (VSTHandle));
+ return vstfx;
+}
+
+/*Create and return a pointer to a new vstfx instance*/
+
+VSTState *
+vstfx_new ()
+{
+ VSTState* vstfx = (VSTState *) calloc (1, sizeof (VSTState));
+
+ /*Mutexes*/
+
+ pthread_mutex_init (&vstfx->lock, NULL);
+ pthread_cond_init (&vstfx->window_status_change, NULL);
+ pthread_cond_init (&vstfx->plugin_dispatcher_called, NULL);
+ pthread_cond_init (&vstfx->window_created, NULL);
+
+ /*Safe values*/
+
+ vstfx->want_program = -1;
+ vstfx->want_chunk = 0;
+ vstfx->n_pending_keys = 0;
+ vstfx->has_editor = 0;
+ vstfx->program_set_without_editor = 0;
+ vstfx->linux_window = 0;
+ vstfx->linux_plugin_ui_window = 0;
+ vstfx->eventProc = NULL;
+ vstfx->extra_data = NULL;
+ vstfx->want_resize = 0;
+
+ return vstfx;
+}
+
+/*This loads the plugin shared library*/
+
+void* vstfx_load_vst_library(const char* path)
+{
+ void* dll;
+ char* full_path;
+ char* envdup;
+ char* lxvst_path;
+ size_t len1;
+ size_t len2;
+
+ /*Try and load the shared library pointed to by the path -
+ NOTE: You have to give RTLD_LAZY or RTLD_NOW to dlopen or
+ you get some occasional failures to load - dlerror reports
+ invalid arguments*/
+
+ if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
+ return dll;
+
+ /*We didn't find the library so try and get the path specified in the
+ env variable LXVST_PATH*/
+
+ envdup = getenv ("LXVST_PATH");
+
+ /*Path not specified - not much more we can do*/
+
+ if (envdup == NULL)
+ return NULL;
+
+ /*Copy the path into envdup*/
+
+ envdup = strdup (envdup);
+
+ if (envdup == NULL)
+ return NULL;
+
+ len2 = strlen(path);
+
+ /*Try all the possibilities in the path - deliminated by : */
+
+ lxvst_path = strtok (envdup, ":");
+
+ while (lxvst_path != NULL)
+ {
+ vstfx_error ("\"%s\"", lxvst_path);
+ len1 = strlen(lxvst_path);
+
+ full_path = (char*)malloc(len1 + 1 + len2 + 1);
+ memcpy(full_path, lxvst_path, len1);
+ full_path[len1] = '/';
+ memcpy(full_path + len1 + 1, path, len2);
+ full_path[len1 + 1 + len2] = '\0';
+
+ /*Try and load the library*/
+
+ if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
+ {
+ /*Succeeded */
+ break;
+ }
+
+ /*Try again*/
+
+ lxvst_path = strtok (NULL, ":");
+ }
+
+ /*Free the path*/
+
+ free(envdup);
+
+ return dll;
+}
+
+/*This loads up a plugin, given the path to its .so file and
+ finds its main entry point etc*/
+
+VSTHandle *
+vstfx_load (const char *path)
+{
+ char* buf = NULL;
+ VSTHandle* fhandle;
+ int i;
+
+ /*Create a new handle we can use to reference the plugin*/
+
+ fhandle = vstfx_handle_new();
+
+ /*See if we have .so appended to the path - if not we need to make sure it is added*/
+
+ if (strstr (path, ".so") == NULL)
+ {
+
+ /*Append the .so to the path - Make sure the path has enough space*/
+
+ buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
+
+ sprintf (buf, "%s.so", path);
+
+ fhandle->nameptr = strdup (path);
+
+ }
+ else
+ {
+ /*We already have .so appened to the filename*/
+
+ buf = strdup(path);
+
+ fhandle->nameptr = strdup (path);
+ }
+
+ /*Use basename to shorten the path and then strip off the .so - the old VST problem,
+ we don't know anything about its name until we load and instantiate the plugin
+ which we don't want to do at this point*/
+
+ for(i=0; i < (int)strlen(fhandle->nameptr); i++)
+ {
+ if(fhandle->nameptr[i] == '.')
+ fhandle->nameptr[i] = 0;
+ }
+
+
+ fhandle->name = basename (fhandle->nameptr);
+
+ /*call load_vstfx_library to actually load the .so into memory*/
+
+ if ((fhandle->dll = vstfx_load_vst_library (buf)) == NULL)
+ {
+ vstfx_unload (fhandle);
+
+ free(buf);
+
+ return NULL;
+ }
+
+ /*Find the main entry point into the plugin*/
+
+ if ((fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main")) == NULL)
+ {
+ /*If it can't be found, unload the plugin and return a NULL handle*/
+
+ vstfx_unload (fhandle);
+
+ free(buf);
+
+ return NULL;
+ }
+
+ free(buf);
+
+ /*return the handle of the plugin*/
+
+ return fhandle;
+}
+
+/*This unloads a plugin*/
+
+int
+vstfx_unload (VSTHandle* fhandle)
+{
+ if (fhandle->plugincnt)
+ {
+ /*Still have plugin instances - can't unload the library
+ - actually dlclose keeps an instance count anyway*/
+
+ return -1;
+ }
+
+ /*Valid plugin loaded?*/
+
+ if (fhandle->dll)
+ {
+ dlclose(fhandle->dll);
+ fhandle->dll = NULL;
+ }
+
+ if (fhandle->nameptr)
+ {
+ free (fhandle->nameptr);
+ fhandle->name = NULL;
+ }
+
+ /*Don't need the plugin handle any more*/
+
+ free (fhandle);
+ return 0;
+}
+
+/*This instantiates a plugin*/
+
+VSTState *
+vstfx_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
+{
+ VSTState* vstfx = vstfx_new ();
+
+ if(fhandle == NULL)
+ {
+ vstfx_error( "** ERROR ** VSTFX : The handle was NULL\n" );
+ return NULL;
+ }
+
+ if ((vstfx->plugin = fhandle->main_entry (amc)) == NULL)
+ {
+ vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
+ free (vstfx);
+ return NULL;
+ }
+
+ vstfx->handle = fhandle;
+ vstfx->plugin->user = userptr;
+
+ if (vstfx->plugin->magic != kEffectMagic)
+ {
+ vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
+ free (vstfx);
+ return NULL;
+ }
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
+
+ /*May or May not need to 'switch the plugin on' here - unlikely
+ since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
+
+ //vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 1, NULL, 0);
+
+ vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
+
+ vstfx->handle->plugincnt++;
+ vstfx->wantIdle = 0;
+
+ return vstfx;
+}
+
+/*Close a vstfx instance*/
+
+void vstfx_close (VSTState* vstfx)
+{
+ vstfx_destroy_editor(vstfx);
+
+ if(vstfx->plugin)
+ {
+ vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, NULL, 0);
+
+ /*Calling dispatcher with effClose will cause the plugin's destructor to
+ be called, which will also remove the editor if it exists*/
+
+ vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
+ }
+
+ if (vstfx->handle->plugincnt)
+ vstfx->handle->plugincnt--;
+
+ /*vstfx_unload will unload the dll if the instance count allows -
+ we need to do this because some plugins keep their own instance count
+ and (JUCE) manages the plugin UI in its own thread. When the plugins
+ internal instance count reaches zero, JUCE stops the UI thread and won't
+ restart it until the next time the library is loaded. If we don't unload
+ the lib JUCE will never restart*/
+
+
+ if (vstfx->handle->plugincnt)
+ {
+ return;
+ }
+
+ /*Valid plugin loaded - so we can unload it and NULL the pointer
+ to it. We can't free the handle here because we don't know what else
+ might need it. It should be / is freed when the plugin is deleted*/
+
+ if (vstfx->handle->dll)
+ {
+ dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
+ vstfx->handle->dll = NULL;
+ }
+}
+
+
+bool
+vstfx_save_state (VSTState* vstfx, char * filename)
+{
+ FILE* f = fopen (filename, "wb");
+ if (f)
+ {
+ int bytelen;
+ int numParams = vstfx->plugin->numParams;
+ int i;
+ char productString[64];
+ char effectName[64];
+ char vendorString[64];
+ int success;
+
+ /* write header */
+
+ fprintf(f, "<plugin_state>\n");
+
+ success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, productString, 0);
+
+ if(success == 1)
+ {
+ fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
+ }
+ else
+ {
+ printf ("No product string\n");
+ }
+
+ success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, effectName, 0);
+
+ if(success == 1)
+ {
+ fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
+ printf ("Effect name: %s\n", effectName);
+ }
+ else
+ {
+ printf ("No effect name\n");
+ }
+
+ success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, vendorString, 0);
+
+ if( success == 1 )
+ {
+ fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
+ printf ("Vendor string: %s\n", vendorString);
+ }
+ else
+ {
+ printf ("No vendor string\n");
+ }
+
+
+ if(vstfx->plugin->flags & 32 )
+ {
+ numParams = 0;
+ }
+
+ for(i=0; i < numParams; i++)
+ {
+ float val;
+
+ pthread_mutex_lock( &vstfx->lock );
+ val = vstfx->plugin->getParameter(vstfx->plugin, i );
+ pthread_mutex_unlock( &vstfx->lock );
+ fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", i, val );
+ }
+
+ if(vstfx->plugin->flags & 32 )
+ {
+ printf( "getting chunk...\n" );
+ void * chunk;
+ bytelen = vstfx_call_dispatcher(vstfx, 23, 0, 0, &chunk, 0 );
+ printf( "got tha chunk..\n" );
+ if( bytelen )
+ {
+ if( bytelen < 0 )
+ {
+ printf( "Chunke len < 0 !!! Not saving chunk.\n" );
+ }
+ else
+ {
+ //char *encoded = g_base64_encode( chunk, bytelen );
+ //fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
+ //g_free( encoded );
+ }
+ }
+ }
+
+ fprintf( f, "</plugin_state>\n" );
+ fclose( f );
+ }
+ else
+ {
+ printf ("Could not open state file\n");
+ return false;
+ }
+ return true;
+}
+
+/*Set up a call to the plugins 'dispatcher' function*/
+
+int vstfx_call_dispatcher (VSTState* vstfx, int opcode, int index, int val, void *ptr, float opt)
+{
+ pthread_mutex_lock (&vstfx->lock);
+
+ /*Set up the opcode and parameters*/
+
+ vstfx->dispatcher_opcode = opcode;
+ vstfx->dispatcher_index = index;
+ vstfx->dispatcher_val = val;
+ vstfx->dispatcher_ptr = ptr;
+ vstfx->dispatcher_opt = opt;
+
+ /*Signal that we want the call to happen*/
+
+ vstfx->dispatcher_wantcall = 1;
+
+ /*Wait for the call to happen*/
+
+ pthread_cond_wait (&vstfx->plugin_dispatcher_called, &vstfx->lock);
+ pthread_mutex_unlock (&vstfx->lock);
+
+ /*Return the result*/
+
+ return vstfx->dispatcher_retval;
+}
*/
-#include "ardour/vstfx.h"
+#include "ardour/linux_vst_support.h"
#include "ardour/session.h"
#include "ardour/lxvst_plugin.h"
#include <fstream>
#ifdef WINDOWS_VST_SUPPORT
-#include <fst.h>
+#include "fst.h"
#include "pbd/basename.h"
#include <cstring>
#endif // WINDOWS_VST_SUPPORT
#ifdef LXVST_SUPPORT
-#include <ardour/vstfx.h>
-#include <pbd/basename.h>
+#include "ardour/linux_vst_support.h"
+#include "pbd/basename.h"
#include <cstring>
#endif //LXVST_SUPPORT
/* Dummy LXVST methods so that libardour can be linked against the test code */
-#include "ardour/vstfx.h"
+#include "ardour/linux_vst_support.h"
int
vstfx_init (void* ptr)
+++ /dev/null
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <libgen.h>
-#include <pthread.h>
-#include <signal.h>
-#include <dlfcn.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <pthread.h>
-
-#include "ardour/vstfx.h"
-#include "pbd/error.h"
-
-/***********************************************************/
-/* VSTFX - A set of modules for managing linux VST plugins */
-/* vstfx.cc, vstfxwin.cc and vstfxinfofile.cc */
-/***********************************************************/
-
-/*Simple error handler stuff for VSTFX*/
-
-void vstfx_error (const char *fmt, ...)
-{
- va_list ap;
- char buffer[512];
-
- va_start (ap, fmt);
- vsnprintf (buffer, sizeof(buffer), fmt, ap);
- vstfx_error_callback (buffer);
- va_end (ap);
-}
-
-/*default error handler callback*/
-
-void default_vstfx_error_callback (const char *desc)
-{
- PBD::error << desc << endmsg;
-}
-
-void (*vstfx_error_callback)(const char *desc) = &default_vstfx_error_callback;
-
-/* --- */
-
-/*Create and return a pointer to a new VSTFX handle*/
-
-VSTHandle *
-vstfx_handle_new ()
-{
- VSTHandle* vstfx = (VSTHandle *) calloc (1, sizeof (VSTHandle));
- return vstfx;
-}
-
-/*Create and return a pointer to a new vstfx instance*/
-
-VSTState *
-vstfx_new ()
-{
- VSTState* vstfx = (VSTState *) calloc (1, sizeof (VSTState));
-
- /*Mutexes*/
-
- pthread_mutex_init (&vstfx->lock, NULL);
- pthread_cond_init (&vstfx->window_status_change, NULL);
- pthread_cond_init (&vstfx->plugin_dispatcher_called, NULL);
- pthread_cond_init (&vstfx->window_created, NULL);
-
- /*Safe values*/
-
- vstfx->want_program = -1;
- vstfx->want_chunk = 0;
- vstfx->n_pending_keys = 0;
- vstfx->has_editor = 0;
- vstfx->program_set_without_editor = 0;
- vstfx->linux_window = 0;
- vstfx->linux_plugin_ui_window = 0;
- vstfx->eventProc = NULL;
- vstfx->extra_data = NULL;
- vstfx->want_resize = 0;
-
- return vstfx;
-}
-
-/*This loads the plugin shared library*/
-
-void* vstfx_load_vst_library(const char* path)
-{
- void* dll;
- char* full_path;
- char* envdup;
- char* lxvst_path;
- size_t len1;
- size_t len2;
-
- /*Try and load the shared library pointed to by the path -
- NOTE: You have to give RTLD_LAZY or RTLD_NOW to dlopen or
- you get some occasional failures to load - dlerror reports
- invalid arguments*/
-
- if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
- return dll;
-
- /*We didn't find the library so try and get the path specified in the
- env variable LXVST_PATH*/
-
- envdup = getenv ("LXVST_PATH");
-
- /*Path not specified - not much more we can do*/
-
- if (envdup == NULL)
- return NULL;
-
- /*Copy the path into envdup*/
-
- envdup = strdup (envdup);
-
- if (envdup == NULL)
- return NULL;
-
- len2 = strlen(path);
-
- /*Try all the possibilities in the path - deliminated by : */
-
- lxvst_path = strtok (envdup, ":");
-
- while (lxvst_path != NULL)
- {
- vstfx_error ("\"%s\"", lxvst_path);
- len1 = strlen(lxvst_path);
-
- full_path = (char*)malloc(len1 + 1 + len2 + 1);
- memcpy(full_path, lxvst_path, len1);
- full_path[len1] = '/';
- memcpy(full_path + len1 + 1, path, len2);
- full_path[len1 + 1 + len2] = '\0';
-
- /*Try and load the library*/
-
- if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
- {
- /*Succeeded */
- break;
- }
-
- /*Try again*/
-
- lxvst_path = strtok (NULL, ":");
- }
-
- /*Free the path*/
-
- free(envdup);
-
- return dll;
-}
-
-/*This loads up a plugin, given the path to its .so file and
- finds its main entry point etc*/
-
-VSTHandle *
-vstfx_load (const char *path)
-{
- char* buf = NULL;
- VSTHandle* fhandle;
- int i;
-
- /*Create a new handle we can use to reference the plugin*/
-
- fhandle = vstfx_handle_new();
-
- /*See if we have .so appended to the path - if not we need to make sure it is added*/
-
- if (strstr (path, ".so") == NULL)
- {
-
- /*Append the .so to the path - Make sure the path has enough space*/
-
- buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
-
- sprintf (buf, "%s.so", path);
-
- fhandle->nameptr = strdup (path);
-
- }
- else
- {
- /*We already have .so appened to the filename*/
-
- buf = strdup(path);
-
- fhandle->nameptr = strdup (path);
- }
-
- /*Use basename to shorten the path and then strip off the .so - the old VST problem,
- we don't know anything about its name until we load and instantiate the plugin
- which we don't want to do at this point*/
-
- for(i=0; i < (int)strlen(fhandle->nameptr); i++)
- {
- if(fhandle->nameptr[i] == '.')
- fhandle->nameptr[i] = 0;
- }
-
-
- fhandle->name = basename (fhandle->nameptr);
-
- /*call load_vstfx_library to actually load the .so into memory*/
-
- if ((fhandle->dll = vstfx_load_vst_library (buf)) == NULL)
- {
- vstfx_unload (fhandle);
-
- free(buf);
-
- return NULL;
- }
-
- /*Find the main entry point into the plugin*/
-
- if ((fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main")) == NULL)
- {
- /*If it can't be found, unload the plugin and return a NULL handle*/
-
- vstfx_unload (fhandle);
-
- free(buf);
-
- return NULL;
- }
-
- free(buf);
-
- /*return the handle of the plugin*/
-
- return fhandle;
-}
-
-/*This unloads a plugin*/
-
-int
-vstfx_unload (VSTHandle* fhandle)
-{
- if (fhandle->plugincnt)
- {
- /*Still have plugin instances - can't unload the library
- - actually dlclose keeps an instance count anyway*/
-
- return -1;
- }
-
- /*Valid plugin loaded?*/
-
- if (fhandle->dll)
- {
- dlclose(fhandle->dll);
- fhandle->dll = NULL;
- }
-
- if (fhandle->nameptr)
- {
- free (fhandle->nameptr);
- fhandle->name = NULL;
- }
-
- /*Don't need the plugin handle any more*/
-
- free (fhandle);
- return 0;
-}
-
-/*This instantiates a plugin*/
-
-VSTState *
-vstfx_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
-{
- VSTState* vstfx = vstfx_new ();
-
- if(fhandle == NULL)
- {
- vstfx_error( "** ERROR ** VSTFX : The handle was NULL\n" );
- return NULL;
- }
-
- if ((vstfx->plugin = fhandle->main_entry (amc)) == NULL)
- {
- vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
- free (vstfx);
- return NULL;
- }
-
- vstfx->handle = fhandle;
- vstfx->plugin->user = userptr;
-
- if (vstfx->plugin->magic != kEffectMagic)
- {
- vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
- free (vstfx);
- return NULL;
- }
-
- vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
-
- /*May or May not need to 'switch the plugin on' here - unlikely
- since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
-
- //vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 1, NULL, 0);
-
- vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
-
- vstfx->handle->plugincnt++;
- vstfx->wantIdle = 0;
-
- return vstfx;
-}
-
-/*Close a vstfx instance*/
-
-void vstfx_close (VSTState* vstfx)
-{
- vstfx_destroy_editor(vstfx);
-
- if(vstfx->plugin)
- {
- vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, NULL, 0);
-
- /*Calling dispatcher with effClose will cause the plugin's destructor to
- be called, which will also remove the editor if it exists*/
-
- vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
- }
-
- if (vstfx->handle->plugincnt)
- vstfx->handle->plugincnt--;
-
- /*vstfx_unload will unload the dll if the instance count allows -
- we need to do this because some plugins keep their own instance count
- and (JUCE) manages the plugin UI in its own thread. When the plugins
- internal instance count reaches zero, JUCE stops the UI thread and won't
- restart it until the next time the library is loaded. If we don't unload
- the lib JUCE will never restart*/
-
-
- if (vstfx->handle->plugincnt)
- {
- return;
- }
-
- /*Valid plugin loaded - so we can unload it and NULL the pointer
- to it. We can't free the handle here because we don't know what else
- might need it. It should be / is freed when the plugin is deleted*/
-
- if (vstfx->handle->dll)
- {
- dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
- vstfx->handle->dll = NULL;
- }
-}
-
-
-bool
-vstfx_save_state (VSTState* vstfx, char * filename)
-{
- FILE* f = fopen (filename, "wb");
- if (f)
- {
- int bytelen;
- int numParams = vstfx->plugin->numParams;
- int i;
- char productString[64];
- char effectName[64];
- char vendorString[64];
- int success;
-
- /* write header */
-
- fprintf(f, "<plugin_state>\n");
-
- success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, productString, 0);
-
- if(success == 1)
- {
- fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
- }
- else
- {
- printf ("No product string\n");
- }
-
- success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, effectName, 0);
-
- if(success == 1)
- {
- fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
- printf ("Effect name: %s\n", effectName);
- }
- else
- {
- printf ("No effect name\n");
- }
-
- success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, vendorString, 0);
-
- if( success == 1 )
- {
- fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
- printf ("Vendor string: %s\n", vendorString);
- }
- else
- {
- printf ("No vendor string\n");
- }
-
-
- if(vstfx->plugin->flags & 32 )
- {
- numParams = 0;
- }
-
- for(i=0; i < numParams; i++)
- {
- float val;
-
- pthread_mutex_lock( &vstfx->lock );
- val = vstfx->plugin->getParameter(vstfx->plugin, i );
- pthread_mutex_unlock( &vstfx->lock );
- fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", i, val );
- }
-
- if(vstfx->plugin->flags & 32 )
- {
- printf( "getting chunk...\n" );
- void * chunk;
- bytelen = vstfx_call_dispatcher(vstfx, 23, 0, 0, &chunk, 0 );
- printf( "got tha chunk..\n" );
- if( bytelen )
- {
- if( bytelen < 0 )
- {
- printf( "Chunke len < 0 !!! Not saving chunk.\n" );
- }
- else
- {
- //char *encoded = g_base64_encode( chunk, bytelen );
- //fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
- //g_free( encoded );
- }
- }
- }
-
- fprintf( f, "</plugin_state>\n" );
- fclose( f );
- }
- else
- {
- printf ("Could not open state file\n");
- return false;
- }
- return true;
-}
-
-/*Set up a call to the plugins 'dispatcher' function*/
-
-int vstfx_call_dispatcher (VSTState* vstfx, int opcode, int index, int val, void *ptr, float opt)
-{
- pthread_mutex_lock (&vstfx->lock);
-
- /*Set up the opcode and parameters*/
-
- vstfx->dispatcher_opcode = opcode;
- vstfx->dispatcher_index = index;
- vstfx->dispatcher_val = val;
- vstfx->dispatcher_ptr = ptr;
- vstfx->dispatcher_opt = opt;
-
- /*Signal that we want the call to happen*/
-
- vstfx->dispatcher_wantcall = 1;
-
- /*Wait for the call to happen*/
-
- pthread_cond_wait (&vstfx->plugin_dispatcher_called, &vstfx->lock);
- pthread_mutex_unlock (&vstfx->lock);
-
- /*Return the result*/
-
- return vstfx->dispatcher_retval;
-}
+++ /dev/null
-/***********************************************************/
-/*vstfx infofile - module to manage info files */
-/*containing cached information about a plugin. e.g. its */
-/*name, creator etc etc */
-/***********************************************************/
-
-#include <iostream>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <libgen.h>
-
-#include <glib.h>
-#include <glib/gstdio.h>
-
-#include "ardour/vstfx.h"
-
-#define MAX_STRING_LEN 256
-
-static char* read_string(FILE *fp)
-{
- char buf[MAX_STRING_LEN];
-
- if (!fgets( buf, MAX_STRING_LEN, fp )) {
- return 0;
- }
-
- if(strlen(buf) < MAX_STRING_LEN) {
- if (strlen(buf)) {
- buf[strlen(buf)-1] = 0;
- }
- return strdup(buf);
- } else {
- return 0;
- }
-}
-
-static VSTInfo *
-load_vstfx_info_file (FILE* fp)
-{
- VSTInfo *info;
- int i;
-
- if ((info = (VSTInfo*) malloc (sizeof (VSTInfo))) == 0) {
- return 0;
- }
-
- if((info->name = read_string(fp)) == 0) goto error;
- if((info->creator = read_string(fp)) == 0) goto error;
- if(1 != fscanf(fp, "%d\n", &info->UniqueID)) goto error;
- if((info->Category = read_string(fp)) == 0) goto error;
- if(1 != fscanf(fp, "%d\n", &info->numInputs)) goto error;
- if(1 != fscanf(fp, "%d\n", &info->numOutputs)) goto error;
- if(1 != fscanf(fp, "%d\n", &info->numParams)) goto error;
- if(1 != fscanf(fp, "%d\n", &info->wantMidi)) goto error;
- if(1 != fscanf(fp, "%d\n", &info->hasEditor)) goto error;
- if(1 != fscanf(fp, "%d\n", &info->canProcessReplacing)) goto error;
-
- if((info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams)) == 0) {
- goto error;
- }
-
- for (i=0; i<info->numParams; i++) {
- if((info->ParamNames[i] = read_string(fp)) == 0) goto error;
- }
-
- if ((info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams)) == 0) {
- goto error;
- }
-
- for (i=0; i < info->numParams; i++) {
- if((info->ParamLabels[i] = read_string(fp)) == 0) goto error;
- }
-
- return info;
-
- error:
- free( info );
- return 0;
-}
-
-static int
-save_vstfx_info_file (VSTInfo *info, FILE* fp)
-{
- int i;
-
- if (info == 0) {
- vstfx_error("** ERROR ** VSTFXinfofile : info ptr is 0\n");
- return -1;
- }
-
- if (fp == 0) {
- vstfx_error("** ERROR ** VSTFXinfofile : file ptr is 0\n");
- return -1;
- }
-
- fprintf( fp, "%s\n", info->name );
- fprintf( fp, "%s\n", info->creator );
- fprintf( fp, "%d\n", info->UniqueID );
- fprintf( fp, "%s\n", info->Category );
- fprintf( fp, "%d\n", info->numInputs );
- fprintf( fp, "%d\n", info->numOutputs );
- fprintf( fp, "%d\n", info->numParams );
- fprintf( fp, "%d\n", info->wantMidi );
- fprintf( fp, "%d\n", info->hasEditor );
- fprintf( fp, "%d\n", info->canProcessReplacing );
-
- for (i=0; i < info->numParams; i++) {
- fprintf(fp, "%s\n", info->ParamNames[i]);
- }
-
- for (i=0; i < info->numParams; i++) {
- fprintf(fp, "%s\n", info->ParamLabels[i]);
- }
-
- return 0;
-}
-
-static char* vstfx_infofile_stat (char *dllpath, struct stat* statbuf, int personal)
-{
- char* path;
- char* dir_path;
- char* basename;
- char* base;
- size_t blen;
-
- if (strstr (dllpath, ".so" ) == 0) {
- return 0;
- }
-
- if (personal) {
- dir_path = g_build_filename (g_get_home_dir(), ".fst", NULL);
- } else {
- dir_path = g_path_get_dirname (dllpath);
- }
-
- base = g_path_get_basename (dllpath);
- blen = strlen (base) + 2; // null char and '.'
- basename = (char*) g_malloc (blen);
- snprintf (basename, blen, ".%s.fsi", base);
- g_free (base);
-
- path = g_build_filename (dir_path, basename, NULL);
-
- g_free (dir_path);
- g_free (basename);
-
-
- if (g_file_test (path, GFileTest (G_FILE_TEST_EXISTS|G_FILE_TEST_IS_REGULAR))) {
-
- /* info file exists in same location as the shared object, so
- check if its current and up to date
- */
-
-
- struct stat dllstat;
-
- if (stat (dllpath, &dllstat) == 0) {
- if (stat(path, statbuf) == 0) {
- if (dllstat.st_mtime <= statbuf->st_mtime) {
- /* plugin is older than info file */
- return path;
- }
- }
- }
- }
-
- g_free (path);
-
- return 0;
-}
-
-
-static FILE* vstfx_infofile_for_read (char* dllpath)
-{
- struct stat own_statbuf;
- struct stat sys_statbuf;
- char *own_info;
- char *sys_info;
-
- own_info = vstfx_infofile_stat (dllpath, &own_statbuf, 1);
- sys_info = vstfx_infofile_stat (dllpath, &sys_statbuf, 0);
-
- if (own_info) {
- if (sys_info) {
- if (own_statbuf.st_mtime <= sys_statbuf.st_mtime) {
- /* system info file is newer, use it */
- return fopen (sys_info, "r");
- }
- } else {
- return fopen (own_info, "r");
- }
- }
-
- return 0;
-}
-
-static FILE* vstfx_infofile_create (char* dllpath, int personal)
-{
- char* path;
- char* dir_path;
- char* basename;
- char* base;
- size_t blen;
-
- if (strstr (dllpath, ".so" ) == 0) {
- return 0;
- }
-
- if (personal) {
- dir_path = g_build_filename (g_get_home_dir(), ".fst", NULL);
-
- /* if the directory doesn't yet exist, try to create it */
-
- if (!g_file_test (dir_path, G_FILE_TEST_IS_DIR)) {
- if (g_mkdir (dir_path, 0700)) {
- return 0;
- }
- }
-
- } else {
- dir_path = g_path_get_dirname (dllpath);
- }
-
- base = g_path_get_basename (dllpath);
- blen = strlen (base) + 2; // null char and '.'
- basename = (char*) g_malloc (blen);
- snprintf (basename, blen, ".%s.fsi", base);
- g_free (base);
-
- path = g_build_filename (dir_path, basename, NULL);
-
- g_free (dir_path);
- g_free (basename);
-
- FILE* f = fopen (path, "w");
- g_free (path);
-
- return f;
-}
-
-static FILE* vstfx_infofile_for_write (char* dllpath)
-{
- FILE* f;
-
- if ((f = vstfx_infofile_create (dllpath, 0)) == 0) {
- f = vstfx_infofile_create (dllpath, 1);
- }
-
- return f;
-}
-
-static
-int vstfx_can_midi (VSTState* vstfx)
-{
- AEffect *plugin = vstfx->plugin;
-
- int vst_version = plugin->dispatcher (plugin, effGetVstVersion, 0, 0, 0, 0.0f);
-
- if (vst_version >= 2)
- {
- /* should we send it VST events (i.e. MIDI) */
-
- if ((plugin->flags & effFlagsIsSynth) || (plugin->dispatcher (plugin, effCanDo, 0, 0,(void*) "receiveVstEvents", 0.0f) > 0))
- return -1;
- }
- return false;
-}
-
-static VSTInfo *
-vstfx_info_from_plugin (VSTState* vstfx)
-{
- VSTInfo* info = (VSTInfo*) malloc (sizeof (VSTInfo));
-
- AEffect *plugin;
- int i;
-
- /*We need to init the creator because some plugins
- fail to implement getVendorString, and so won't stuff the
- string with any name*/
-
- char creator[65] = "Unknown\0";
-
- if(!vstfx)
- {
- vstfx_error( "** ERROR ** VSTFXinfofile : vstfx ptr is 0\n" );
- return 0;
- }
-
- if(!info)
- return 0;
-
- plugin = vstfx->plugin;
-
- info->name = strdup(vstfx->handle->name );
-
- /*If the plugin doesn't bother to implement GetVendorString we will
- have pre-stuffed the string with 'Unkown' */
-
- plugin->dispatcher (plugin, effGetVendorString, 0, 0, creator, 0);
-
- /*Some plugins DO implement GetVendorString, but DON'T put a name in it
- so if its just a zero length string we replace it with 'Unknown' */
-
- if (strlen(creator) == 0) {
- info->creator = strdup("Unknown");
- } else {
- info->creator = strdup (creator);
- }
-
- info->UniqueID = plugin->uniqueID;
-
- info->Category = strdup("None"); // FIXME:
- info->numInputs = plugin->numInputs;
- info->numOutputs = plugin->numOutputs;
- info->numParams = plugin->numParams;
- info->wantMidi = vstfx_can_midi(vstfx);
- info->hasEditor = plugin->flags & effFlagsHasEditor ? true : false;
- info->canProcessReplacing = plugin->flags & effFlagsCanReplacing ? true : false;
- info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams);
- info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams);
-
- for(i=0; i < info->numParams; i++) {
- char name[64];
- char label[64];
-
- /*Not all plugins give parameters labels as well as names*/
-
- strcpy(name, "No Name");
- strcpy(label, "No Label");
-
- plugin->dispatcher (plugin, effGetParamName, i, 0, name, 0);
- info->ParamNames[i] = strdup(name);
-
- //NOTE: 'effGetParamLabel' is no longer defined in vestige headers
- //plugin->dispatcher (plugin, effGetParamLabel, i, 0, label, 0);
- info->ParamLabels[i] = strdup(label);
- }
- return info;
-}
-
-/* A simple 'dummy' audiomaster callback which should be ok,
-we will only be instantiating the plugin in order to get its info*/
-
-static intptr_t
-simple_master_callback (AEffect *, int32_t opcode, int32_t, intptr_t, void *, float)
-{
- if (opcode == audioMasterVersion)
- return 2;
- else
- return 0;
-}
-
-/*Try to get plugin info - first by looking for a .fsi cache of the
-data, and if that doesn't exist, load the plugin, get its data and
-then cache it for future ref*/
-
-VSTInfo *
-vstfx_get_info (char* dllpath)
-{
- FILE* infofile;
- VSTHandle* h;
- VSTState* vstfx;
- VSTInfo* info;
-
- if ((infofile = vstfx_infofile_for_read (dllpath)) != 0) {
- VSTInfo *info;
- info = load_vstfx_info_file (infofile);
- fclose (infofile);
- return info;
- }
-
- if(!(h = vstfx_load(dllpath)))
- return 0;
-
- if(!(vstfx = vstfx_instantiate(h, simple_master_callback, 0))) {
- vstfx_unload(h);
- vstfx_error( "** ERROR ** VSTFXinfofile : Instantiate failed\n" );
- return 0;
- }
-
- infofile = vstfx_infofile_for_write (dllpath);
-
- if(!infofile) {
- vstfx_close(vstfx);
- vstfx_unload(h);
- vstfx_error("cannot create new FST info file for plugin");
- return 0;
- }
-
- info = vstfx_info_from_plugin(vstfx);
-
- save_vstfx_info_file(info, infofile);
- fclose (infofile);
-
- vstfx_close(vstfx);
- vstfx_unload(h);
-
- return info;
-}
-
-void
-vstfx_free_info (VSTInfo *info)
-{
- for (int i = 0; i < info->numParams; i++) {
- free (info->ParamNames[i]);
- free (info->ParamLabels[i]);
- }
-
- free (info->name);
- free (info->creator);
- free (info->Category);
- free (info);
-}
-
-
obj.defines += [ 'WINDOWS_VST_SUPPORT' ]
if bld.is_defined('LXVST_SUPPORT'):
- obj.source += [ 'lxvst_plugin.cc', 'vstfx.cc', 'vstfxinfofile.cc' ]
+ obj.source += [ 'lxvst_plugin.cc', 'linux_vst_support.cc', 'linux_vst_info_file.cc' ]
obj.defines += [ 'LXVST_SUPPORT' ]
if bld.is_defined('WINDOWS_VST_SUPPORT') or bld.is_defined('LXVST_SUPPORT'):