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)
466 vstfx->dispatcher_retval = vstfx->plugin->dispatcher( vstfx->plugin,
467 vstfx->dispatcher_opcode,
468 vstfx->dispatcher_index,
469 vstfx->dispatcher_val,
470 vstfx->dispatcher_ptr,
471 vstfx->dispatcher_opt );
472 vstfx->dispatcher_wantcall = 0;
473 pthread_cond_signal (&vstfx->plugin_dispatcher_called);
476 /*Call the editor Idle function in the plugin*/
478 vstfx->plugin->dispatcher (vstfx->plugin, effEditIdle, 0, 0, NULL, 0);
481 vstfx->plugin->dispatcher (vstfx->plugin, 53, 0, 0, NULL, 0);
483 pthread_mutex_unlock (&vstfx->lock);
485 pthread_mutex_unlock (&plugin_mutex);
489 /*Drop out to here if we set gui_quit to 1 */
494 /*The VSTFX Init function - this needs to be called before the VSTFX engine
495 can be accessed, it gets the UI thread running, opens a connection to X etc
496 normally started in globals.cc*/
498 int vstfx_init (void* ptr)
501 int thread_create_result;
503 pthread_attr_t thread_attributes;
505 /*Init the attribs to defaults*/
507 pthread_attr_init(&thread_attributes);
509 /*Make sure the thread is joinable - this should be the default anyway -
510 so we can join to it on vstfx_exit*/
512 pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
515 /*This is where we need to open a connection to X, and start the GUI thread*/
517 /*Open our connection to X - all linuxVST plugin UIs handled by the LXVST engine
518 will talk to X down this connection - X cannot handle multi-threaded access via
521 if(LXVST_XDisplay==NULL)
522 LXVST_XDisplay = XOpenDisplay(NULL); //We might be able to make this open a specific screen etc
524 /*Drop out and report the error if we fail to connect to X */
526 if(LXVST_XDisplay==NULL)
528 vstfx_error ("** ERROR ** VSTFX: Failed opening connection to X");
533 /*We have a connection to X - so start the gui event loop*/
535 /*Create the thread - use default attrs for now, don't think we need anything special*/
537 thread_create_result = pthread_create(&LXVST_gui_event_thread, NULL, gui_event_loop, NULL);
539 if(thread_create_result!=0)
541 /*There was a problem starting the GUI event thread*/
543 vstfx_error ("** ERROR ** VSTFX: Failed starting GUI event thread");
545 XCloseDisplay(LXVST_XDisplay);
553 /*The vstfx Quit function*/
559 /*We need to pthread_join the gui_thread here so
560 we know when it has stopped*/
562 pthread_join(LXVST_gui_event_thread, NULL);
565 /*Adds a new plugin (VSTFX) instance to the linked list*/
567 int vstfx_run_editor (VSTFX* vstfx)
569 pthread_mutex_lock (&plugin_mutex);
571 /*Add the new VSTFX instance to the linked list*/
573 if (vstfx_first == NULL)
579 VSTFX* p = vstfx_first;
587 /*Mark the new end of the list*/
592 pthread_mutex_unlock (&plugin_mutex);
594 /* wait for the plugin editor window to be created (or not) */
596 pthread_mutex_lock (&vstfx->lock);
600 pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
603 pthread_mutex_unlock (&vstfx->lock);
613 /*Set up a call to the plugins 'dispatcher' function*/
615 int vstfx_call_dispatcher (VSTFX *vstfx, int opcode, int index, int val, void *ptr, float opt)
617 pthread_mutex_lock (&vstfx->lock);
619 /*Set up the opcode and parameters*/
621 vstfx->dispatcher_opcode = opcode;
622 vstfx->dispatcher_index = index;
623 vstfx->dispatcher_val = val;
624 vstfx->dispatcher_ptr = ptr;
625 vstfx->dispatcher_opt = opt;
627 /*Signal that we want the call to happen*/
629 vstfx->dispatcher_wantcall = 1;
631 /*Wait for the call to happen*/
633 pthread_cond_wait (&vstfx->plugin_dispatcher_called, &vstfx->lock);
634 pthread_mutex_unlock (&vstfx->lock);
636 /*Return the result*/
638 return vstfx->dispatcher_retval;
641 /*Creates an editor for the plugin - normally called from within the gui event loop
642 after run_editor has added the plugin (editor) to the linked list*/
644 int vstfx_create_editor (VSTFX* vstfx)
646 Window parent_window;
651 /* Note: vstfx->lock is held while this function is called */
653 if (!(vstfx->plugin->flags & effFlagsHasEditor))
655 vstfx_error ("** ERROR ** VSTFX: Plugin \"%s\" has no editor", vstfx->handle->name);
660 /*Create an XWindow for the plugin to inhabit*/
662 parent_window = XCreateSimpleWindow(LXVST_XDisplay,
663 DefaultRootWindow(LXVST_XDisplay),
672 /*Select the events we are interested in receiving - we need Substructure notify so that
673 if the plugin resizes its window - e.g. Loomer Manifold then we get a message*/
675 XSelectInput(LXVST_XDisplay,
677 SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask);
679 vstfx->window = parent_window;
681 vstfx->xid = parent_window; //vstfx->xid will be referenced to connect to GTK UI in ardour later
683 /*Because the plugin may be operating on a different Display* to us, and therefore
684 the two event queues can be asynchronous, although we have created the window on
685 our display, we can't guarantee it exists in the server yet, which will
686 cause BadWindow crashes if the plugin tries to use it.
688 It would be nice to use CreateNotify events here, but they don't get
689 through on all window managers, so instead we pass a client message
690 into out queue, after the XCreateWindow. When this message pops out
691 in our event handler, it will trigger the second stage of plugin
692 Editor instantiation, and by then the Window should be valid...*/
694 XClientMessageEvent event;
696 /*Create an atom to identify our message (only if it doesn't already exist)*/
698 Atom WindowActiveAtom = XInternAtom(LXVST_XDisplay, "LaunchEditor", false);
700 event.type = ClientMessage;
701 event.send_event = true;
702 event.window = parent_window;
703 event.message_type = WindowActiveAtom;
705 event.format = 32; //Data format
706 event.data.l[0] = 0x0FEEDBAC; //Something we can recognize later
708 /*Push the event into the queue on our Display*/
710 XSendEvent(LXVST_XDisplay, parent_window, FALSE, NoEventMask, (XEvent*)&event);
712 /*Unlock - and we are done for the first part of staring the Editor...*/
714 pthread_mutex_unlock (&vstfx->lock);
719 int vstfx_launch_editor(VSTFX* vstfx)
721 /*This is the second stage of launching the editor (see vstfx_create editor)
722 we get called here in response to receiving the ClientMessage on our Window,
723 therefore it's about as safe (as can be) to assume that the Window we created
724 is now valid in the XServer and can be passed to the plugin in effEditOpen
725 without generating BadWindow errors when the plugin reparents itself into our
728 if(vstfx->been_activated)
731 Window parent_window;
737 parent_window = vstfx->window;
739 /*Open the editor - Bah! we have to pass the int windowID as a void pointer - yuck
740 it gets cast back to an int as the parent window XID in the plugin - and we have to pass the
741 Display* as a long */
743 /**************************************************************/
744 /* 64Bit --- parent window is an int passed as a void* so */
745 /* that should be ok for 64Bit machines */
747 /* Display is passed in as a long - ok on arch's where sizeof */
750 /* Most linux VST plugins open a connection to X on their own */
751 /* Display anyway so it may not matter */
753 /* linuxDSP VSTs don't use the host Display* at all */
754 /**************************************************************/
756 vstfx->plugin->dispatcher (vstfx->plugin, effEditOpen, 0, (long)LXVST_XDisplay, (void*)(parent_window), 0 );
758 /*QUIRK - some plugins need a slight delay after opening the editor before you can
759 ask the window size or they might return zero - specifically discoDSP */
763 /*Now we can find out how big the parent window should be (and try) to resize it*/
765 vstfx->plugin->dispatcher (vstfx->plugin, effEditGetRect, 0, 0, &er, 0 );
767 x_size = er->right - er->left;
768 y_size = er->bottom - er->top;
770 vstfx->width = x_size;
771 vstfx->height = y_size;
773 XResizeWindow(LXVST_XDisplay, parent_window, x_size, y_size);
775 XFlush (LXVST_XDisplay);
777 /*Not sure if we need to map the window or if the plugin will do it for us
778 it should be ok because XReparentWindow generates a Map event*/
780 /*mark the editor as activated - mainly so that vstfx_get_XID
781 will know it is valid*/
783 vstfx->been_activated = TRUE;
785 pthread_cond_signal (&vstfx->window_status_change);
789 /*May not be needed in the XLib version*/
791 void vstfx_move_window_into_view (VSTFX* vstfx)
794 /*This is probably the equivalent of Mapping an XWindow
795 but we most likely don't need it because the window
796 will be Mapped by XReparentWindow*/
800 /*Destroy the editor window*/
802 void vstfx_destroy_editor (VSTFX* vstfx)
804 pthread_mutex_lock (&vstfx->lock);
807 vstfx->destroy = TRUE;
808 pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
810 pthread_mutex_unlock (&vstfx->lock);
813 /*Remove a vstfx instance from the linked list parsed by the
816 void vstfx_event_loop_remove_plugin (VSTFX* vstfx)
818 /*This only ever gets called from within our GUI thread
819 so we don't need to lock here - if we did there would be
825 for(p = vstfx_first, prev = NULL; p; prev = p, p = p->next)
831 prev->next = p->next;
837 if (vstfx_first == vstfx)
838 vstfx_first = vstfx_first->next;
841 /*This loads the plugin shared library*/
843 void* vstfx_load_vst_library(const char* path)
852 /*Try and load the shared library pointed to by the path -
853 NOTE: You have to give RTLD_LAZY or RTLD_NOW to dlopen or
854 you get some occasional failures to load - dlerror reports
857 if ((dll = dlopen (path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
860 /*We didn't find the library so try and get the path specified in the
861 env variable LXVST_PATH*/
863 envdup = getenv ("LXVST_PATH");
865 /*Path not specified - not much more we can do*/
870 /*Copy the path into envdup*/
872 envdup = strdup (envdup);
879 /*Try all the possibilities in the path - deliminated by : */
881 lxvst_path = strtok (envdup, ":");
883 while (lxvst_path != NULL)
885 vstfx_error ("\"%s\"", lxvst_path);
886 len1 = strlen(lxvst_path);
888 full_path = (char*)malloc(len1 + 1 + len2 + 1);
889 memcpy(full_path, lxvst_path, len1);
890 full_path[len1] = '/';
891 memcpy(full_path + len1 + 1, path, len2);
892 full_path[len1 + 1 + len2] = '\0';
894 /*Try and load the library*/
896 if ((dll = dlopen(full_path, RTLD_LOCAL | RTLD_LAZY)) != NULL)
904 lxvst_path = strtok (NULL, ":");
914 /*This loads up a plugin, given the path to its .so file and
915 finds its main entry point etc*/
917 VSTFXHandle* vstfx_load (const char *path)
920 VSTFXHandle* fhandle;
923 /*Create a new handle we can use to reference the plugin*/
925 fhandle = vstfx_handle_new();
927 /*See if we have .so appended to the path - if not we need to make sure it is added*/
929 if (strstr (path, ".so") == NULL)
932 /*Append the .so to the path - Make sure the path has enough space*/
934 buf = (char *)malloc(strlen(path) + 4); //The .so and a terminating zero
936 sprintf (buf, "%s.so", path);
938 fhandle->nameptr = strdup (path);
943 /*We already have .so appened to the filename*/
947 fhandle->nameptr = strdup (path);
950 /*Use basename to shorten the path and then strip off the .so - the old VST problem,
951 we don't know anything about its name until we load and instantiate the plugin
952 which we don't want to do at this point*/
954 for(i=0; i < (int)strlen(fhandle->nameptr); i++)
956 if(fhandle->nameptr[i] == '.')
957 fhandle->nameptr[i] = 0;
961 fhandle->name = basename (fhandle->nameptr);
963 /*call load_vstfx_library to actually load the .so into memory*/
965 if ((fhandle->dll = vstfx_load_vst_library (buf)) == NULL)
967 vstfx_unload (fhandle);
974 /*Find the main entry point into the plugin*/
976 if ((fhandle->main_entry = (main_entry_t) dlsym(fhandle->dll, "main")) == NULL)
978 /*If it can't be found, unload the plugin and return a NULL handle*/
980 vstfx_unload (fhandle);
989 /*return the handle of the plugin*/
994 /*This unloads a plugin*/
996 int vstfx_unload (VSTFXHandle* fhandle)
998 if (fhandle->plugincnt)
1000 /*Still have plugin instances - can't unload the library
1001 - actually dlclose keeps an instance count anyway*/
1006 /*Valid plugin loaded?*/
1010 dlclose(fhandle->dll);
1011 fhandle->dll = NULL;
1014 if (fhandle->nameptr)
1016 free (fhandle->nameptr);
1017 fhandle->name = NULL;
1020 /*Don't need the plugin handle any more*/
1026 /*This instantiates a plugin*/
1028 VSTFX* vstfx_instantiate (VSTFXHandle* fhandle, audioMasterCallback amc, void* userptr)
1030 VSTFX* vstfx = vstfx_new ();
1034 vstfx_error( "** ERROR ** VSTFX : The handle was NULL\n" );
1038 if ((vstfx->plugin = fhandle->main_entry (amc)) == NULL)
1040 vstfx_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
1045 vstfx->handle = fhandle;
1046 vstfx->plugin->user = userptr;
1048 if (vstfx->plugin->magic != kEffectMagic)
1050 vstfx_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
1055 vstfx->plugin->dispatcher (vstfx->plugin, effOpen, 0, 0, 0, 0);
1057 /*May or May not need to 'switch the plugin on' here - unlikely
1058 since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
1060 //vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 1, NULL, 0);
1062 vstfx->vst_version = vstfx->plugin->dispatcher (vstfx->plugin, effGetVstVersion, 0, 0, 0, 0);
1064 vstfx->handle->plugincnt++;
1065 vstfx->wantIdle = 0;
1070 /*Close a vstfx instance*/
1072 void vstfx_close (VSTFX* vstfx)
1074 vstfx_destroy_editor(vstfx);
1078 vstfx->plugin->dispatcher (vstfx->plugin, effMainsChanged, 0, 0, NULL, 0);
1080 /*Calling dispatcher with effClose will cause the plugin's destructor to
1081 be called, which will also remove the editor if it exists*/
1083 vstfx->plugin->dispatcher (vstfx->plugin, effClose, 0, 0, 0, 0);
1086 if (vstfx->handle->plugincnt)
1087 vstfx->handle->plugincnt--;
1089 /*vstfx_unload will unload the dll if the instance count allows -
1090 we need to do this because some plugins keep their own instance count
1091 and (JUCE) manages the plugin UI in its own thread. When the plugins
1092 internal instance count reaches zero, JUCE stops the UI thread and won't
1093 restart it until the next time the library is loaded. If we don't unload
1094 the lib JUCE will never restart*/
1097 if (vstfx->handle->plugincnt)
1102 /*Valid plugin loaded - so we can unload it and NULL the pointer
1103 to it. We can't free the handle here because we don't know what else
1104 might need it. It should be / is freed when the plugin is deleted*/
1106 if (vstfx->handle->dll)
1108 dlclose(vstfx->handle->dll); //dlclose keeps its own reference count
1109 vstfx->handle->dll = NULL;
1114 /*Get the XID of the plugin editor window*/
1116 int vstfx_get_XID (VSTFX* vstfx)
1120 /*Wait for the lock to become free - otherwise
1121 the window might be in the process of being
1122 created and we get bad Window errors when trying
1123 to embed it in the GTK UI*/
1125 pthread_mutex_lock(&vstfx->lock);
1127 /*The Window may be scheduled for creation
1128 but not actually created by the gui_event_loop yet -
1130 spin here until it has been activated. Possible
1131 deadlock if the window never gets activated but
1132 should not be called here if the window doesn't
1133 exist or will never exist*/
1135 while(!(vstfx->been_activated))
1140 pthread_mutex_unlock(&vstfx->lock);
1142 /*Finally it might be safe to return the ID -
1143 problems will arise if we return either a zero ID
1144 and GTK tries to socket it or if we return an ID
1145 which hasn't yet become real to the server*/
1150 float htonf (float v)
1153 char * fin = (char*)&v;
1154 char * fout = (char*)&result;
1163 /*load_state and save_state do not appear to be needed (yet) in ardour
1164 - untested at the moment, these are just replicas of the fst code*/
1168 int vstfx_load_state (VSTFX* vstfx, char * filename)
1170 FILE* f = fopen (filename, "rb");
1173 char testMagic[sizeof (magic)];
1174 fread (&testMagic, sizeof (magic), 1, f);
1175 if (strcmp (testMagic, magic))
1177 printf ("File corrupt\n");
1181 char productString[64];
1182 char vendorString[64];
1183 char effectName[64];
1184 char testString[64];
1188 fread (&length, sizeof (unsigned), 1, f);
1189 length = htonl (length);
1190 fread (productString, length, 1, f);
1191 productString[length] = 0;
1192 printf ("Product string: %s\n", productString);
1194 success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, testString, 0);
1198 if (strcmp (testString, productString) != 0)
1200 printf ("Product string mismatch! Plugin has: %s\n", testString);
1205 else if (length != 0)
1207 printf ("Product string mismatch! Plugin has none.\n", testString);
1212 fread (&length, sizeof (unsigned), 1, f);
1213 length = htonl (length);
1214 fread (effectName, length, 1, f);
1215 effectName[length] = 0;
1216 printf ("Effect name: %s\n", effectName);
1218 success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, testString, 0);
1222 if(strcmp(testString, effectName)!= 0)
1224 printf ("Effect name mismatch! Plugin has: %s\n", testString);
1229 else if(length != 0)
1231 printf ("Effect name mismatch! Plugin has none.\n", testString);
1236 fread (&length, sizeof (unsigned), 1, f);
1237 length = htonl (length);
1238 fread (vendorString, length, 1, f);
1239 vendorString[length] = 0;
1241 printf ("Vendor string: %s\n", vendorString);
1243 success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, testString, 0);
1246 if (strcmp(testString, vendorString)!= 0)
1248 printf ("Vendor string mismatch! Plugin has: %s\n", testString);
1253 else if(length != 0)
1255 printf ("Vendor string mismatch! Plugin has none.\n", testString);
1262 fread (&numParam, sizeof (int), 1, f);
1263 numParam = htonl (numParam);
1265 for (i = 0; i < numParam; ++i)
1268 fread (&val, sizeof (float), 1, f);
1271 pthread_mutex_lock(&vstfx->lock );
1272 vstfx->plugin->setParameter(vstfx->plugin, i, val);
1273 pthread_mutex_unlock(&vstfx->lock );
1278 fread (&bytelen, sizeof (int), 1, f);
1279 bytelen = htonl (bytelen);
1283 char * buf = malloc (bytelen);
1284 fread (buf, bytelen, 1, f);
1286 vstfx_call_dispatcher(vstfx, 24, 0, bytelen, buf, 0);
1292 printf ("Could not open state file\n");
1300 int vstfx_save_state (VSTFX* vstfx, char * filename)
1302 FILE* f = fopen (filename, "wb");
1306 int numParams = vstfx->plugin->numParams;
1308 char productString[64];
1309 char effectName[64];
1310 char vendorString[64];
1315 fprintf(f, "<plugin_state>\n");
1317 success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, productString, 0);
1321 fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
1325 printf ("No product string\n");
1328 success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, effectName, 0);
1332 fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
1333 printf ("Effect name: %s\n", effectName);
1337 printf ("No effect name\n");
1340 success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, vendorString, 0);
1344 fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
1345 printf ("Vendor string: %s\n", vendorString);
1349 printf ("No vendor string\n");
1353 if(vstfx->plugin->flags & 32 )
1358 for(i=0; i < numParams; i++)
1362 pthread_mutex_lock( &vstfx->lock );
1363 val = vstfx->plugin->getParameter(vstfx->plugin, i );
1364 pthread_mutex_unlock( &vstfx->lock );
1365 fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", i, val );
1368 if(vstfx->plugin->flags & 32 )
1370 printf( "getting chunk...\n" );
1372 bytelen = vstfx_call_dispatcher(vstfx, 23, 0, 0, &chunk, 0 );
1373 printf( "got tha chunk..\n" );
1378 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
1382 //char *encoded = g_base64_encode( chunk, bytelen );
1383 //fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
1384 //g_free( encoded );
1389 fprintf( f, "</plugin_state>\n" );
1394 printf ("Could not open state file\n");