1 /******************************************************************/
2 /** VSTFX - An engine based on FST for handling linuxVST plugins **/
3 /******************************************************************/
5 /*This is derived from the original FST (C code) with some tweaks*/
8 /** EDITOR tab stops at 4 **/
12 #include <jack/jack.h>
13 #include <jack/thread.h>
20 #include <ardour/vstfx.h>
37 static pthread_mutex_t plugin_mutex;
39 static VSTFX* vstfx_first = NULL;
41 const char magic[] = "VSTFX Plugin State v002";
43 int gui_thread_id = 0;
44 static int gui_quit = 0;
46 /*This will be our connection to X*/
48 Display* LXVST_XDisplay = NULL;
50 /*The thread handle for the GUI event loop*/
52 pthread_t LXVST_gui_event_thread;
54 #define DELAYED_WINDOW 1
56 /*Util functions to get the value of a property attached to an XWindow*/
60 int TempErrorHandler(Display *display, XErrorEvent *e)
69 int getXWindowProperty(Window window, Atom atom)
74 unsigned long userCount;
79 /*Use our own Xerror handler while we're in here - in an
80 attempt to stop the brain dead default Xerror behaviour of
81 qutting the entire application because of e.g. an invalid
84 XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
86 XGetWindowProperty( LXVST_XDisplay, //The display
89 0, //Offset into the data
90 1, //Number of 32Bit chunks of data
91 false, //false = don't delete the property
92 AnyPropertyType, //Required property type mask
93 &userType, //Actual type returned
94 &userSize, //Actual format returned
95 &userCount, //Actual number of items stored in the returned data
96 &bytes, //Number of bytes remaining if a partial read
97 &data); //The actual data read
99 if(LXVST_xerror == false && userCount == 1)
100 result = *(int*)data;
102 XSetErrorHandler(olderrorhandler);
104 /*Hopefully this will return zero if the property is not set*/
113 /********************************************************************/
114 /* This is untested - have no 64Bit plugins which use this */
115 /* system of passing an eventProc address */
116 /********************************************************************/
118 long getXWindowProperty(Window window, Atom atom)
123 unsigned long userCount;
126 LXVST_xerror = false;
128 /*Use our own Xerror handler while we're in here - in an
129 attempt to stop the brain dead default Xerror behaviour of
130 qutting the entire application because of e.g. an invalid
133 XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
135 XGetWindowProperty( LXVST_XDisplay,
148 if(LXVST_xerror == false && userCount == 1)
149 result = *(long*)data;
151 XSetErrorHandler(olderrorhandler);
153 /*Hopefully this will return zero if the property is not set*/
160 /*The event handler - called from within the main GUI thread to
161 dispatch events to any VST UIs which have callbacks stuck to them*/
163 static void dispatch_x_events(XEvent* event, VSTFX* vstfx)
165 /*Handle some of the Events we might be interested in*/
169 /*Configure event - when the window is resized or first drawn*/
171 case ConfigureNotify:
173 Window window = event->xconfigure.event;
175 int width = event->xconfigure.width;
176 int height = event->xconfigure.height;
178 /*If we get a config notify on the parent window XID then we need to see
179 if the size has been changed - some plugins re-size their UI window e.g.
180 when opening a preset manager (you might think that should be spawned as a new window...) */
182 /*if the size has changed, we flag this so that in lxvst_pluginui.cc we can make the
183 change to the GTK parent window in ardour, from its UI thread*/
185 if(window == (Window)(vstfx->window))
187 if((width!=vstfx->width) || (height!=vstfx->height))
189 vstfx->width = width;
190 vstfx->height = height;
191 vstfx->want_resize = 1;
193 /*QUIRK : Loomer plugins not only resize the UI but throw it into some random
194 position at the same time. We need to re-position the window at the origin of
197 if(vstfx->plugin_ui_window)
198 XMoveWindow(LXVST_XDisplay, vstfx->plugin_ui_window, 0, 0);
206 /*Reparent Notify - when the plugin UI is reparented into
207 our Host Window we will get an event here... probably... */
211 Window ParentWindow = event->xreparent.parent;
213 /*If the ParentWindow matches the window for the vstfx instance then
214 the Child window must be the XID of the pluginUI window created by the
215 plugin, so we need to see if it has a callback stuck to it, and if so
216 set that up in the vstfx */
218 /***********************************************************/
219 /* 64Bit --- This mechanism is not 64Bit compatible at the */
221 /***********************************************************/
223 if(ParentWindow == (Window)(vstfx->window))
225 Window PluginUIWindowID = event->xreparent.window;
227 vstfx->plugin_ui_window = PluginUIWindowID;
229 int result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
232 vstfx->eventProc = NULL;
234 vstfx->eventProc = (void (*) (void* event))result;
237 long result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
240 vstfx->eventProc = NULL;
242 vstfx->eventProc = (void (*) (void* event))result;
250 Window window = event->xany.window;
251 Atom message_type = event->xclient.message_type;
253 /*The only client message we are interested in is to signal
254 that the plugin parent window is now valid and can be passed
255 to effEditOpen when the editor is launched*/
257 if(window == (Window)(vstfx->window))
259 char* message = XGetAtomName(LXVST_XDisplay, message_type);
261 if(strcmp(message,"LaunchEditor") == 0)
264 if(event->xclient.data.l[0] == 0x0FEEDBAC)
265 vstfx_launch_editor(vstfx);
277 /* Some VSTs built with toolkits e.g. JUCE will manager their own UI
278 autonomously in the plugin, running the UI in its own thread, so once
279 we have created a parent window for the plugin, its UI takes care of
282 /*Other types register a callback as an Xwindow property on the plugin
283 UI window after they create it. If that is the case, we need to call it
284 here, passing the XEvent into it*/
286 if(vstfx->eventProc == NULL)
289 vstfx->eventProc((void*)event);
293 /*Create and return a pointer to a new vstfx instance*/
295 static VSTFX* vstfx_new ()
297 VSTFX* vstfx = (VSTFX*) calloc (1, sizeof (VSTFX));
301 pthread_mutex_init (&vstfx->lock, NULL);
302 pthread_cond_init (&vstfx->window_status_change, NULL);
303 pthread_cond_init (&vstfx->plugin_dispatcher_called, NULL);
304 pthread_cond_init (&vstfx->window_created, NULL);
308 vstfx->want_program = -1;
309 vstfx->want_chunk = 0;
310 vstfx->current_program = -1;
311 vstfx->n_pending_keys = 0;
312 vstfx->has_editor = 0;
313 vstfx->program_set_without_editor = 0;
315 vstfx->plugin_ui_window = 0;
316 vstfx->eventProc = NULL;
317 vstfx->extra_data = NULL;
318 vstfx->want_resize = 0;
323 /*Create and return a pointer to a new VSTFX handle*/
325 static VSTFXHandle* vstfx_handle_new()
327 VSTFXHandle* vstfx = (VSTFXHandle*)calloc(1, sizeof (VSTFXHandle));
331 /** This is the main gui event loop for the plugin, we also need to pass
332 any Xevents to all the UI callbacks plugins 'may' have registered on their
333 windows, that is if they don't manage their own UIs **/
335 void* gui_event_loop (void* ptr)
339 int LXVST_sched_event_timer = 0;
340 int LXVST_sched_timer_interval = 50; //ms
343 /*The 'Forever' loop - runs the plugin UIs etc - based on the FST gui event loop*/
347 /* handle window creation requests, destroy requests,
348 and run idle callbacks */
350 /*Look at the XEvent queue - if there are any XEvents we need to handle them,
351 including passing them to all the plugin (eventProcs) we are currently managing*/
355 /*See if there are any events in the queue*/
357 int num_events = XPending(LXVST_XDisplay);
359 /*process them if there are any*/
363 XNextEvent(LXVST_XDisplay, &event);
365 /*Call dispatch events, with the event, for each plugin in the linked list*/
367 for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
369 pthread_mutex_lock(&vstfx->lock);
371 dispatch_x_events(&event, vstfx);
373 pthread_mutex_unlock(&vstfx->lock);
380 /*We don't want to use all the CPU.. */
384 LXVST_sched_event_timer++;
386 LXVST_sched_event_timer = LXVST_sched_event_timer & 0x00FFFFFF;
388 /*See if its time for us to do a scheduled event pass on all the plugins*/
390 if((LXVST_sched_timer_interval!=0) && (!(LXVST_sched_event_timer% LXVST_sched_timer_interval)))
392 pthread_mutex_lock (&plugin_mutex);
395 /*Parse through the linked list of plugins*/
397 for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
399 pthread_mutex_lock (&vstfx->lock);
401 /*Window scheduled for destruction*/
407 vstfx->plugin->dispatcher( vstfx->plugin, effEditClose, 0, 0, NULL, 0.0 );
409 XDestroyWindow (LXVST_XDisplay, vstfx->window);
410 vstfx->window = 0; //FIXME - probably safe to assume we never have an XID of 0 but not explicitly true
411 vstfx->destroy = FALSE;
414 vstfx_event_loop_remove_plugin (vstfx);
415 vstfx->been_activated = FALSE;
416 pthread_cond_signal (&vstfx->window_status_change);
417 pthread_mutex_unlock (&vstfx->lock);
422 /*Window does not yet exist - scheduled for creation*/
424 if (vstfx->window == 0) //FIXME - probably safe to assume 0 is not a valid XID but not explicitly true
426 if (vstfx_create_editor (vstfx))
428 vstfx_error ("** ERROR ** VSTFX : Cannot create editor for plugin %s", vstfx->handle->name);
429 vstfx_event_loop_remove_plugin (vstfx);
430 pthread_cond_signal (&vstfx->window_status_change);
431 pthread_mutex_unlock (&vstfx->lock);
436 /* condition/unlock: it was signalled & unlocked in fst_create_editor() */
440 /*Scheduled for setting a new program*/
442 if (vstfx->want_program != -1 )
444 if (vstfx->vst_version >= 2)
446 vstfx->plugin->dispatcher (vstfx->plugin, 67 /* effBeginSetProgram */, 0, 0, NULL, 0);
449 vstfx->plugin->dispatcher (vstfx->plugin, effSetProgram, 0, vstfx->want_program, NULL, 0);
451 if (vstfx->vst_version >= 2)
453 vstfx->plugin->dispatcher (vstfx->plugin, 68 /* effEndSetProgram */, 0, 0, NULL, 0);
458 vstfx->current_program = vstfx->plugin->dispatcher (vstfx->plugin, 3, /* effGetProgram */ 0, 0, NULL, 0);
459 vstfx->want_program = -1;
462 /*scheduled call to dispatcher*/
464 if (vstfx->dispatcher_wantcall) {
465 vstfx->dispatcher_retval = vstfx->plugin->dispatcher (
467 vstfx->dispatcher_opcode,
468 vstfx->dispatcher_index,
469 vstfx->dispatcher_val,
470 vstfx->dispatcher_ptr,
471 vstfx->dispatcher_opt
474 vstfx->dispatcher_wantcall = 0;
475 pthread_cond_signal (&vstfx->plugin_dispatcher_called);
478 /*Call the editor Idle function in the plugin*/
480 vstfx->plugin->dispatcher (vstfx->plugin, effEditIdle, 0, 0, NULL, 0);
483 vstfx->plugin->dispatcher (vstfx->plugin, 53, 0, 0, NULL, 0);
485 pthread_mutex_unlock (&vstfx->lock);
487 pthread_mutex_unlock (&plugin_mutex);
491 /*Drop out to here if we set gui_quit to 1 */
496 /*The VSTFX Init function - this needs to be called before the VSTFX engine
497 can be accessed, it gets the UI thread running, opens a connection to X etc
498 normally started in globals.cc*/
500 int vstfx_init (void* ptr)
503 int thread_create_result;
505 pthread_attr_t thread_attributes;
507 /*Init the attribs to defaults*/
509 pthread_attr_init(&thread_attributes);
511 /*Make sure the thread is joinable - this should be the default anyway -
512 so we can join to it on vstfx_exit*/
514 pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
517 /*This is where we need to open a connection to X, and start the GUI thread*/
519 /*Open our connection to X - all linuxVST plugin UIs handled by the LXVST engine
520 will talk to X down this connection - X cannot handle multi-threaded access via
523 if(LXVST_XDisplay==NULL)
524 LXVST_XDisplay = XOpenDisplay(NULL); //We might be able to make this open a specific screen etc
526 /*Drop out and report the error if we fail to connect to X */
528 if(LXVST_XDisplay==NULL)
530 vstfx_error ("** ERROR ** VSTFX: Failed opening connection to X");
535 /*We have a connection to X - so start the gui event loop*/
537 /*Create the thread - use default attrs for now, don't think we need anything special*/
539 thread_create_result = pthread_create(&LXVST_gui_event_thread, NULL, gui_event_loop, NULL);
541 if(thread_create_result!=0)
543 /*There was a problem starting the GUI event thread*/
545 vstfx_error ("** ERROR ** VSTFX: Failed starting GUI event thread");
547 XCloseDisplay(LXVST_XDisplay);
555 /*The vstfx Quit function*/
561 /*We need to pthread_join the gui_thread here so
562 we know when it has stopped*/
564 pthread_join(LXVST_gui_event_thread, NULL);
567 /*Adds a new plugin (VSTFX) instance to the linked list*/
569 int vstfx_run_editor (VSTFX* vstfx)
571 pthread_mutex_lock (&plugin_mutex);
573 /*Add the new VSTFX instance to the linked list*/
575 if (vstfx_first == NULL)
581 VSTFX* p = vstfx_first;
589 /*Mark the new end of the list*/
594 pthread_mutex_unlock (&plugin_mutex);
596 /* wait for the plugin editor window to be created (or not) */
598 pthread_mutex_lock (&vstfx->lock);
602 pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
605 pthread_mutex_unlock (&vstfx->lock);
615 /*Set up a call to the plugins 'dispatcher' function*/
617 int vstfx_call_dispatcher (VSTFX *vstfx, int opcode, int index, int val, void *ptr, float opt)
619 pthread_mutex_lock (&vstfx->lock);
621 /*Set up the opcode and parameters*/
623 vstfx->dispatcher_opcode = opcode;
624 vstfx->dispatcher_index = index;
625 vstfx->dispatcher_val = val;
626 vstfx->dispatcher_ptr = ptr;
627 vstfx->dispatcher_opt = opt;
629 /*Signal that we want the call to happen*/
631 vstfx->dispatcher_wantcall = 1;
633 /*Wait for the call to happen*/
635 pthread_cond_wait (&vstfx->plugin_dispatcher_called, &vstfx->lock);
636 pthread_mutex_unlock (&vstfx->lock);
638 /*Return the result*/
640 return vstfx->dispatcher_retval;
643 /*Creates an editor for the plugin - normally called from within the gui event loop
644 after run_editor has added the plugin (editor) to the linked list*/
646 int vstfx_create_editor (VSTFX* vstfx)
648 Window parent_window;
653 /* Note: vstfx->lock is held while this function is called */
655 if (!(vstfx->plugin->flags & effFlagsHasEditor))
657 vstfx_error ("** ERROR ** VSTFX: Plugin \"%s\" has no editor", vstfx->handle->name);
662 /*Create an XWindow for the plugin to inhabit*/
664 parent_window = XCreateSimpleWindow (
666 DefaultRootWindow(LXVST_XDisplay),
676 /*Select the events we are interested in receiving - we need Substructure notify so that
677 if the plugin resizes its window - e.g. Loomer Manifold then we get a message*/
679 XSelectInput(LXVST_XDisplay,
681 SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask);
683 vstfx->window = parent_window;
685 vstfx->xid = parent_window; //vstfx->xid will be referenced to connect to GTK UI in ardour later
687 /*Because the plugin may be operating on a different Display* to us, and therefore
688 the two event queues can be asynchronous, although we have created the window on
689 our display, we can't guarantee it exists in the server yet, which will
690 cause BadWindow crashes if the plugin tries to use it.
692 It would be nice to use CreateNotify events here, but they don't get
693 through on all window managers, so instead we pass a client message
694 into out queue, after the XCreateWindow. When this message pops out
695 in our event handler, it will trigger the second stage of plugin
696 Editor instantiation, and by then the Window should be valid...*/
698 XClientMessageEvent event;
700 /*Create an atom to identify our message (only if it doesn't already exist)*/
702 Atom WindowActiveAtom = XInternAtom(LXVST_XDisplay, "LaunchEditor", false);
704 event.type = ClientMessage;
705 event.send_event = true;
706 event.window = parent_window;
707 event.message_type = WindowActiveAtom;
709 event.format = 32; //Data format
710 event.data.l[0] = 0x0FEEDBAC; //Something we can recognize later
712 /*Push the event into the queue on our Display*/
714 XSendEvent(LXVST_XDisplay, parent_window, FALSE, NoEventMask, (XEvent*)&event);
716 /*Unlock - and we are done for the first part of staring the Editor...*/
718 pthread_mutex_unlock (&vstfx->lock);
723 int vstfx_launch_editor(VSTFX* vstfx)
725 /*This is the second stage of launching the editor (see vstfx_create editor)
726 we get called here in response to receiving the ClientMessage on our Window,
727 therefore it's about as safe (as can be) to assume that the Window we created
728 is now valid in the XServer and can be passed to the plugin in effEditOpen
729 without generating BadWindow errors when the plugin reparents itself into our
732 if(vstfx->been_activated)
735 Window parent_window;
741 parent_window = vstfx->window;
743 /*Open the editor - Bah! we have to pass the int windowID as a void pointer - yuck
744 it gets cast back to an int as the parent window XID in the plugin - and we have to pass the
745 Display* as a long */
747 /**************************************************************/
748 /* 64Bit --- parent window is an int passed as a void* so */
749 /* that should be ok for 64Bit machines */
751 /* Display is passed in as a long - ok on arch's where sizeof */
754 /* Most linux VST plugins open a connection to X on their own */
755 /* Display anyway so it may not matter */
757 /* linuxDSP VSTs don't use the host Display* at all */
758 /**************************************************************/
760 vstfx->plugin->dispatcher (vstfx->plugin, effEditOpen, 0, (long)LXVST_XDisplay, (void*)(parent_window), 0 );
762 /*QUIRK - some plugins need a slight delay after opening the editor before you can
763 ask the window size or they might return zero - specifically discoDSP */
767 /*Now we can find out how big the parent window should be (and try) to resize it*/
769 vstfx->plugin->dispatcher (vstfx->plugin, effEditGetRect, 0, 0, &er, 0 );
771 x_size = er->right - er->left;
772 y_size = er->bottom - er->top;
774 vstfx->width = x_size;
775 vstfx->height = y_size;
777 XResizeWindow(LXVST_XDisplay, parent_window, x_size, y_size);
779 XFlush (LXVST_XDisplay);
781 /*Not sure if we need to map the window or if the plugin will do it for us
782 it should be ok because XReparentWindow generates a Map event*/
784 /*mark the editor as activated - mainly so that vstfx_get_XID
785 will know it is valid*/
787 vstfx->been_activated = TRUE;
789 pthread_cond_signal (&vstfx->window_status_change);
793 /*May not be needed in the XLib version*/
795 void vstfx_move_window_into_view (VSTFX* vstfx)
798 /*This is probably the equivalent of Mapping an XWindow
799 but we most likely don't need it because the window
800 will be Mapped by XReparentWindow*/
804 /*Destroy the editor window*/
806 void vstfx_destroy_editor (VSTFX* vstfx)
808 pthread_mutex_lock (&vstfx->lock);
811 vstfx->destroy = TRUE;
812 pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
814 pthread_mutex_unlock (&vstfx->lock);
817 /*Remove a vstfx instance from the linked list parsed by the
820 void vstfx_event_loop_remove_plugin (VSTFX* vstfx)
822 /*This only ever gets called from within our GUI thread
823 so we don't need to lock here - if we did there would be
829 for(p = vstfx_first, prev = NULL; p; prev = p, p = p->next)
835 prev->next = p->next;
841 if (vstfx_first == vstfx)
842 vstfx_first = vstfx_first->next;
845 /*This loads the plugin shared library*/
847 void* vstfx_load_vst_library(const char* path)
856 /*Try and load the shared library pointed to by the path -
857 NOTE: You have to give RTLD_LAZY or RTLD_NOW to dlopen or
858 you get some occasional failures to load - dlerror reports
861 if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
864 /*We didn't find the library so try and get the path specified in the
865 env variable LXVST_PATH*/
867 envdup = getenv ("LXVST_PATH");
869 /*Path not specified - not much more we can do*/
874 /*Copy the path into envdup*/
876 envdup = strdup (envdup);
883 /*Try all the possibilities in the path - deliminated by : */
885 lxvst_path = strtok (envdup, ":");
887 while (lxvst_path != NULL)
889 vstfx_error ("\"%s\"", lxvst_path);
890 len1 = strlen(lxvst_path);
892 full_path = (char*)malloc(len1 + 1 + len2 + 1);
893 memcpy(full_path, lxvst_path, len1);
894 full_path[len1] = '/';
895 memcpy(full_path + len1 + 1, path, len2);
896 full_path[len1 + 1 + len2] = '\0';
898 /*Try and load the library*/
900 if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
908 lxvst_path = strtok (NULL, ":");
918 /*This loads up a plugin, given the path to its .so file and
919 finds its main entry point etc*/
921 VSTFXHandle* vstfx_load (const char *path)
924 VSTFXHandle* fhandle;
927 /*Create a new handle we can use to reference the plugin*/
929 fhandle = vstfx_handle_new();
931 /*See if we have .so appended to the path - if not we need to make sure it is added*/
933 if (strstr (path, ".so") == NULL)
936 /*Append the .so to the path - Make sure the path has enough space*/
938 buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
940 sprintf (buf, "%s.so", path);
942 fhandle->nameptr = strdup (path);
947 /*We already have .so appened to the filename*/
951 fhandle->nameptr = strdup (path);
954 /*Use basename to shorten the path and then strip off the .so - the old VST problem,
955 we don't know anything about its name until we load and instantiate the plugin
956 which we don't want to do at this point*/
958 for(i=0; i < (int)strlen(fhandle->nameptr); i++)
960 if(fhandle->nameptr[i] == '.')
961 fhandle->nameptr[i] = 0;
965 fhandle->name = basename (fhandle->nameptr);
967 /*call load_vstfx_library to actually load the .so into memory*/
969 if ((fhandle->dll = vstfx_load_vst_library (buf)) == NULL)
971 vstfx_unload (fhandle);
978 /*Find the main entry point into the plugin*/
980 if ((fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main")) == NULL)
982 /*If it can't be found, unload the plugin and return a NULL handle*/
984 vstfx_unload (fhandle);
993 /*return the handle of the plugin*/
998 /*This unloads a plugin*/
1000 int vstfx_unload (VSTFXHandle* fhandle)
1002 if (fhandle->plugincnt)
1004 /*Still have plugin instances - can't unload the library
1005 - actually dlclose keeps an instance count anyway*/
1010 /*Valid plugin loaded?*/
1014 dlclose(fhandle->dll);
1015 fhandle->dll = NULL;
1018 if (fhandle->nameptr)
1020 free (fhandle->nameptr);
1021 fhandle->name = NULL;
1024 /*Don't need the plugin handle any more*/
1030 /*This instantiates a plugin*/
1032 VSTFX* vstfx_instantiate (VSTFXHandle* fhandle, audioMasterCallback amc, void* userptr)
1034 VSTFX* vstfx = vstfx_new ();
1038 vstfx_error( "** ERROR ** VSTFX : The handle was NULL\n" );
1042 if ((vstfx->plugin = fhandle->main_entry (amc)) == NULL)
1044 vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
1049 vstfx->handle = fhandle;
1050 vstfx->plugin->user = userptr;
1052 if (vstfx->plugin->magic != kEffectMagic)
1054 vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
1059 vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
1061 /*May or May not need to 'switch the plugin on' here - unlikely
1062 since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
1064 //vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 1, NULL, 0);
1066 vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
1068 vstfx->handle->plugincnt++;
1069 vstfx->wantIdle = 0;
1074 /*Close a vstfx instance*/
1076 void vstfx_close (VSTFX* vstfx)
1078 vstfx_destroy_editor(vstfx);
1082 vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, NULL, 0);
1084 /*Calling dispatcher with effClose will cause the plugin's destructor to
1085 be called, which will also remove the editor if it exists*/
1087 vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
1090 if (vstfx->handle->plugincnt)
1091 vstfx->handle->plugincnt--;
1093 /*vstfx_unload will unload the dll if the instance count allows -
1094 we need to do this because some plugins keep their own instance count
1095 and (JUCE) manages the plugin UI in its own thread. When the plugins
1096 internal instance count reaches zero, JUCE stops the UI thread and won't
1097 restart it until the next time the library is loaded. If we don't unload
1098 the lib JUCE will never restart*/
1101 if (vstfx->handle->plugincnt)
1106 /*Valid plugin loaded - so we can unload it and NULL the pointer
1107 to it. We can't free the handle here because we don't know what else
1108 might need it. It should be / is freed when the plugin is deleted*/
1110 if (vstfx->handle->dll)
1112 dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
1113 vstfx->handle->dll = NULL;
1118 /*Get the XID of the plugin editor window*/
1120 int vstfx_get_XID (VSTFX* vstfx)
1124 /*Wait for the lock to become free - otherwise
1125 the window might be in the process of being
1126 created and we get bad Window errors when trying
1127 to embed it in the GTK UI*/
1129 pthread_mutex_lock(&vstfx->lock);
1131 /*The Window may be scheduled for creation
1132 but not actually created by the gui_event_loop yet -
1134 spin here until it has been activated. Possible
1135 deadlock if the window never gets activated but
1136 should not be called here if the window doesn't
1137 exist or will never exist*/
1139 while(!(vstfx->been_activated))
1144 pthread_mutex_unlock(&vstfx->lock);
1146 /*Finally it might be safe to return the ID -
1147 problems will arise if we return either a zero ID
1148 and GTK tries to socket it or if we return an ID
1149 which hasn't yet become real to the server*/
1154 float htonf (float v)
1157 char * fin = (char*)&v;
1158 char * fout = (char*)&result;
1167 /*load_state and save_state do not appear to be needed (yet) in ardour
1168 - untested at the moment, these are just replicas of the fst code*/
1172 int vstfx_load_state (VSTFX* vstfx, char * filename)
1174 FILE* f = fopen (filename, "rb");
1177 char testMagic[sizeof (magic)];
1178 fread (&testMagic, sizeof (magic), 1, f);
1179 if (strcmp (testMagic, magic))
1181 printf ("File corrupt\n");
1185 char productString[64];
1186 char vendorString[64];
1187 char effectName[64];
1188 char testString[64];
1192 fread (&length, sizeof (unsigned), 1, f);
1193 length = htonl (length);
1194 fread (productString, length, 1, f);
1195 productString[length] = 0;
1196 printf ("Product string: %s\n", productString);
1198 success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, testString, 0);
1202 if (strcmp (testString, productString) != 0)
1204 printf ("Product string mismatch! Plugin has: %s\n", testString);
1209 else if (length != 0)
1211 printf ("Product string mismatch! Plugin has none.\n", testString);
1216 fread (&length, sizeof (unsigned), 1, f);
1217 length = htonl (length);
1218 fread (effectName, length, 1, f);
1219 effectName[length] = 0;
1220 printf ("Effect name: %s\n", effectName);
1222 success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, testString, 0);
1226 if(strcmp(testString, effectName)!= 0)
1228 printf ("Effect name mismatch! Plugin has: %s\n", testString);
1233 else if(length != 0)
1235 printf ("Effect name mismatch! Plugin has none.\n", testString);
1240 fread (&length, sizeof (unsigned), 1, f);
1241 length = htonl (length);
1242 fread (vendorString, length, 1, f);
1243 vendorString[length] = 0;
1245 printf ("Vendor string: %s\n", vendorString);
1247 success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, testString, 0);
1250 if (strcmp(testString, vendorString)!= 0)
1252 printf ("Vendor string mismatch! Plugin has: %s\n", testString);
1257 else if(length != 0)
1259 printf ("Vendor string mismatch! Plugin has none.\n", testString);
1266 fread (&numParam, sizeof (int), 1, f);
1267 numParam = htonl (numParam);
1269 for (i = 0; i < numParam; ++i)
1272 fread (&val, sizeof (float), 1, f);
1275 pthread_mutex_lock(&vstfx->lock );
1276 vstfx->plugin->setParameter(vstfx->plugin, i, val);
1277 pthread_mutex_unlock(&vstfx->lock );
1282 fread (&bytelen, sizeof (int), 1, f);
1283 bytelen = htonl (bytelen);
1287 char * buf = malloc (bytelen);
1288 fread (buf, bytelen, 1, f);
1290 vstfx_call_dispatcher(vstfx, 24, 0, bytelen, buf, 0);
1296 printf ("Could not open state file\n");
1304 int vstfx_save_state (VSTFX* vstfx, char * filename)
1306 FILE* f = fopen (filename, "wb");
1310 int numParams = vstfx->plugin->numParams;
1312 char productString[64];
1313 char effectName[64];
1314 char vendorString[64];
1319 fprintf(f, "<plugin_state>\n");
1321 success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, productString, 0);
1325 fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
1329 printf ("No product string\n");
1332 success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, effectName, 0);
1336 fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
1337 printf ("Effect name: %s\n", effectName);
1341 printf ("No effect name\n");
1344 success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, vendorString, 0);
1348 fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
1349 printf ("Vendor string: %s\n", vendorString);
1353 printf ("No vendor string\n");
1357 if(vstfx->plugin->flags & 32 )
1362 for(i=0; i < numParams; i++)
1366 pthread_mutex_lock( &vstfx->lock );
1367 val = vstfx->plugin->getParameter(vstfx->plugin, i );
1368 pthread_mutex_unlock( &vstfx->lock );
1369 fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", i, val );
1372 if(vstfx->plugin->flags & 32 )
1374 printf( "getting chunk...\n" );
1376 bytelen = vstfx_call_dispatcher(vstfx, 23, 0, 0, &chunk, 0 );
1377 printf( "got tha chunk..\n" );
1382 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
1386 //char *encoded = g_base64_encode( chunk, bytelen );
1387 //fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
1388 //g_free( encoded );
1393 fprintf( f, "</plugin_state>\n" );
1398 printf ("Could not open state file\n");