implement relative clock editing (terminated by + or - keys, which adjust the clock...
[ardour.git] / gtk2_ardour / vstfxwin.cc
1 /******************************************************************/
2 /** VSTFX - An engine based on FST for handling linuxVST plugins **/
3 /******************************************************************/
4
5 /*This is derived from the original FST (C code) with some tweaks*/
6
7
8 /** EDITOR tab stops at 4 **/
9
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <jack/jack.h>
13 #include <jack/thread.h>
14 #include <libgen.h>
15
16 #include <pthread.h>
17 #include <signal.h>
18 #include <glib.h>
19
20 #include <ardour/vstfx.h>
21
22 #include <X11/X.h>
23 #include <X11/Xlib.h>
24 #include <dlfcn.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 #include <pthread.h>
29
30 struct ERect{
31     short top;
32     short left;
33     short bottom;
34     short right;
35 };
36
37 static pthread_mutex_t plugin_mutex;
38
39 static VSTFX* vstfx_first = NULL;
40
41 const char magic[] = "VSTFX Plugin State v002";
42
43 int  gui_thread_id = 0;
44 static int gui_quit = 0;
45
46 /*This will be our connection to X*/
47
48 Display* LXVST_XDisplay = NULL;
49
50 /*The thread handle for the GUI event loop*/
51
52 pthread_t LXVST_gui_event_thread;
53
54 #define DELAYED_WINDOW 1
55
56 /*Util functions to get the value of a property attached to an XWindow*/
57
58 bool LXVST_xerror;
59
60 int TempErrorHandler(Display *display, XErrorEvent *e)
61 {
62         LXVST_xerror = true;
63         
64         return 0;
65 }
66
67 #ifdef LXVST_32BIT
68
69 int getXWindowProperty(Window window, Atom atom)
70 {
71         int result = 0;
72         int userSize;
73         unsigned long bytes;
74         unsigned long userCount;
75         unsigned char *data;
76         Atom userType;
77         LXVST_xerror = false;
78         
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
82         window ID*/
83         
84         XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
85         
86         XGetWindowProperty(     LXVST_XDisplay,                 //The display
87                                                 window,                                 //The Window
88                                                 atom,                                   //The property
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
98                                                 
99         if(LXVST_xerror == false && userCount == 1)
100                 result = *(int*)data;
101                 
102         XSetErrorHandler(olderrorhandler);
103         
104         /*Hopefully this will return zero if the property is not set*/
105         
106         return result;
107 }
108
109 #endif
110
111 #ifdef LXVST_64BIT
112
113 /********************************************************************/
114 /* This is untested - have no 64Bit plugins which use this          */
115 /* system of passing an eventProc address                           */
116 /********************************************************************/
117
118 long getXWindowProperty(Window window, Atom atom)
119 {
120         long result = 0;
121         int userSize;
122         unsigned long bytes;
123         unsigned long userCount;
124         unsigned char *data;
125         Atom userType;
126         LXVST_xerror = false;
127         
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
131         window ID*/
132         
133         XErrorHandler olderrorhandler = XSetErrorHandler(TempErrorHandler);
134         
135         XGetWindowProperty(     LXVST_XDisplay, 
136                                                 window, 
137                                                 atom,
138                                                 0,
139                                                 2,
140                                                 false,
141                                                 AnyPropertyType, 
142                                                 &userType,
143                                                 &userSize,
144                                                 &userCount,
145                                                 &bytes,
146                                                 &data);
147                                                 
148         if(LXVST_xerror == false && userCount == 1)
149                 result = *(long*)data;
150                 
151         XSetErrorHandler(olderrorhandler);
152         
153         /*Hopefully this will return zero if the property is not set*/
154         
155         return result;
156 }
157
158 #endif
159
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*/
162
163 static void dispatch_x_events(XEvent* event, VSTFX* vstfx)
164 {
165         /*Handle some of the Events we might be interested in*/
166         
167         switch(event->type)
168         {
169                 /*Configure event - when the window is resized or first drawn*/
170                         
171                 case ConfigureNotify:
172                 {
173                         Window window = event->xconfigure.event;
174                         
175                         int width = event->xconfigure.width;
176                         int height = event->xconfigure.height;
177                         
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...) */
181                         
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*/ 
184                         
185                         if(window == (Window)(vstfx->window))
186                         {
187                                 if((width!=vstfx->width) || (height!=vstfx->height))
188                                 {
189                                         vstfx->width = width;
190                                         vstfx->height = height;
191                                         vstfx->want_resize = 1;
192                                         
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
195                                         the parent window*/
196                                         
197                                         if(vstfx->plugin_ui_window)
198                                                 XMoveWindow(LXVST_XDisplay, vstfx->plugin_ui_window, 0, 0);
199                                 }
200                         }
201                         
202                         break;
203                         
204                 }
205                 
206                 /*Reparent Notify - when the plugin UI is reparented into
207                 our Host Window we will get an event here... probably... */
208                 
209                 case ReparentNotify:
210                 {
211                         Window ParentWindow = event->xreparent.parent;
212                         
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 */
217                         
218                         /***********************************************************/
219                         /* 64Bit --- This mechanism is not 64Bit compatible at the */
220                         /* present time                                            */
221                         /***********************************************************/
222                         
223                         if(ParentWindow == (Window)(vstfx->window))
224                         {
225                                 Window PluginUIWindowID = event->xreparent.window;
226                                 
227                                 vstfx->plugin_ui_window = PluginUIWindowID;
228 #ifdef LXVST_32BIT
229                                 int result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
230         
231                                 if(result == 0)
232                                         vstfx->eventProc = NULL;
233                                 else
234                                         vstfx->eventProc = (void (*) (void* event))result;
235 #endif
236 #ifdef LXVST_64BIT
237                                 long result = getXWindowProperty(PluginUIWindowID, XInternAtom(LXVST_XDisplay, "_XEventProc", false));
238         
239                                 if(result == 0)
240                                         vstfx->eventProc = NULL;
241                                 else
242                                         vstfx->eventProc = (void (*) (void* event))result;
243 #endif
244                         }
245                         break;
246                 }
247                 
248                 case ClientMessage:
249                 {
250                         Window window = event->xany.window;
251                         Atom message_type = event->xclient.message_type;
252                         
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*/
256                         
257                         if(window == (Window)(vstfx->window))
258                         {
259                                 char* message = XGetAtomName(LXVST_XDisplay, message_type);
260                                 
261                                 if(strcmp(message,"LaunchEditor") == 0)
262                                 {
263                                 
264                                         if(event->xclient.data.l[0] == 0x0FEEDBAC)
265                                                 vstfx_launch_editor(vstfx);
266                                 }
267                                 
268                                 XFree(message);
269                         }
270                         break;
271                 }
272                 
273                 default:
274                         break;
275         }
276         
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
280         itself.*/
281         
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*/
285         
286         if(vstfx->eventProc == NULL)
287                 return;
288                                 
289         vstfx->eventProc((void*)event);
290 }
291
292 /** This is the main gui event loop for the plugin, we also need to pass
293 any Xevents to all the UI callbacks plugins 'may' have registered on their
294 windows, that is if they don't manage their own UIs **/
295
296 void* gui_event_loop (void* ptr)
297 {
298
299         VSTFX* vstfx;
300         int LXVST_sched_event_timer = 0;
301         int LXVST_sched_timer_interval = 50; //ms
302         XEvent event;
303         
304         /*The 'Forever' loop - runs the plugin UIs etc - based on the FST gui event loop*/
305         
306         while (!gui_quit)
307         {
308                 /* handle window creation requests, destroy requests, 
309                    and run idle callbacks */
310
311                 /*Look at the XEvent queue - if there are any XEvents we need to handle them,
312                 including passing them to all the plugin (eventProcs) we are currently managing*/
313                 
314                 if(LXVST_XDisplay)
315                 {
316                         /*See if there are any events in the queue*/
317                 
318                         int num_events = XPending(LXVST_XDisplay);
319                         
320                         /*process them if there are any*/
321                 
322                         while(num_events)
323                         {
324                                 XNextEvent(LXVST_XDisplay, &event);
325                                 
326                                 /*Call dispatch events, with the event, for each plugin in the linked list*/
327                                 
328                                 for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
329                                 {       
330                                         pthread_mutex_lock(&vstfx->lock);
331                                         
332                                         dispatch_x_events(&event, vstfx);
333                                         
334                                         pthread_mutex_unlock(&vstfx->lock);
335                                 }
336                                 
337                                 num_events--;
338                         }
339                 }
340
341                 /*We don't want to use all the CPU.. */
342
343                 usleep(1000);
344                 
345                 LXVST_sched_event_timer++;
346                 
347                 LXVST_sched_event_timer = LXVST_sched_event_timer & 0x00FFFFFF;
348
349                 /*See if its time for us to do a scheduled event pass on all the plugins*/
350
351                 if((LXVST_sched_timer_interval!=0) && (!(LXVST_sched_event_timer% LXVST_sched_timer_interval)))
352                 {
353                         pthread_mutex_lock (&plugin_mutex);
354                     
355 again:
356                         /*Parse through the linked list of plugins*/
357                         
358                         for (vstfx = vstfx_first; vstfx; vstfx = vstfx->next)
359                         {       
360                                 pthread_mutex_lock (&vstfx->lock);
361
362                                 /*Window scheduled for destruction*/
363                                 
364                                 if (vstfx->destroy)
365                                 {
366                                         if (vstfx->window)
367                                         {
368                                                 vstfx->plugin->dispatcher( vstfx->plugin, effEditClose, 0, 0, NULL, 0.0 );
369                                                         
370                                                 XDestroyWindow (LXVST_XDisplay, vstfx->window);
371                                                 vstfx->window = 0;                              //FIXME - probably safe to assume we never have an XID of 0 but not explicitly true
372                                                 vstfx->destroy = FALSE;
373                                         }
374                                         
375                                         vstfx_event_loop_remove_plugin (vstfx);
376                                         vstfx->been_activated = FALSE;
377                                         pthread_cond_signal (&vstfx->window_status_change);
378                                         pthread_mutex_unlock (&vstfx->lock);
379                                         
380                                         goto again;
381                                 } 
382                                 
383                                 /*Window does not yet exist - scheduled for creation*/
384                                 
385                                 if (vstfx->window == 0)         //FIXME - probably safe to assume 0 is not a valid XID but not explicitly true
386                                 {
387                                         if (vstfx_create_editor (vstfx))
388                                         {
389                                                 vstfx_error ("** ERROR ** VSTFX : Cannot create editor for plugin %s", vstfx->handle->name);
390                                                 vstfx_event_loop_remove_plugin (vstfx);
391                                                 pthread_cond_signal (&vstfx->window_status_change);
392                                                 pthread_mutex_unlock (&vstfx->lock);
393                                                 goto again;
394                                         }
395                                         else
396                                         {
397                                                 /* condition/unlock: it was signalled & unlocked in fst_create_editor()   */
398                                         }
399                                 }
400
401                                 /*Scheduled for setting a new program*/
402
403                                 if (vstfx->want_program != -1 )
404                                 {
405                                         if (vstfx->vst_version >= 2)
406                                         {
407                                                 vstfx->plugin->dispatcher (vstfx->plugin, 67 /* effBeginSetProgram */, 0, 0, NULL, 0);
408                                         }
409
410                                         vstfx->plugin->dispatcher (vstfx->plugin, effSetProgram, 0, vstfx->want_program, NULL, 0);
411
412                                         if (vstfx->vst_version >= 2)
413                                         {
414                                                 vstfx->plugin->dispatcher (vstfx->plugin, 68 /* effEndSetProgram */, 0, 0, NULL, 0);
415                                         }
416                                         
417                                         /* did it work? */
418                                         
419                                         vstfx->current_program = vstfx->plugin->dispatcher (vstfx->plugin, 3, /* effGetProgram */ 0, 0, NULL, 0);
420                                         vstfx->want_program = -1; 
421                                 }
422                                 
423                                 /*scheduled call to dispatcher*/
424                                 
425                                 if (vstfx->dispatcher_wantcall) {
426                                         vstfx->dispatcher_retval = vstfx->plugin->dispatcher (
427                                                 vstfx->plugin, 
428                                                 vstfx->dispatcher_opcode,
429                                                 vstfx->dispatcher_index,
430                                                 vstfx->dispatcher_val,
431                                                 vstfx->dispatcher_ptr,
432                                                 vstfx->dispatcher_opt
433                                                 );
434                                         
435                                         vstfx->dispatcher_wantcall = 0;
436                                         pthread_cond_signal (&vstfx->plugin_dispatcher_called);
437                                 }
438                                 
439                                 /*Call the editor Idle function in the plugin*/
440                                 
441                                 vstfx->plugin->dispatcher (vstfx->plugin, effEditIdle, 0, 0, NULL, 0);
442
443                                 if(vstfx->wantIdle)
444                                         vstfx->plugin->dispatcher (vstfx->plugin, 53, 0, 0, NULL, 0);
445                                         
446                                 pthread_mutex_unlock (&vstfx->lock);
447                         }
448                         pthread_mutex_unlock (&plugin_mutex);
449                 }
450         }
451
452         /*Drop out to here if we set gui_quit to 1 */
453
454         return NULL;
455 }
456
457 /*The VSTFX Init function - this needs to be called before the VSTFX engine
458 can be accessed, it gets the UI thread running, opens a connection to X etc
459 normally started in globals.cc*/
460
461 int vstfx_init (void* ptr)
462 {
463
464         int thread_create_result;
465         
466         pthread_attr_t thread_attributes;
467         
468         /*Init the attribs to defaults*/
469         
470         pthread_attr_init(&thread_attributes);
471         
472         /*Make sure the thread is joinable - this should be the default anyway - 
473         so we can join to it on vstfx_exit*/
474         
475         pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_JOINABLE);
476         
477
478         /*This is where we need to open a connection to X, and start the GUI thread*/
479         
480         /*Open our connection to X - all linuxVST plugin UIs handled by the LXVST engine
481         will talk to X down this connection - X cannot handle multi-threaded access via
482         the same Display* */
483         
484         if(LXVST_XDisplay==NULL)
485                 LXVST_XDisplay = XOpenDisplay(NULL);    //We might be able to make this open a specific screen etc
486
487         /*Drop out and report the error if we fail to connect to X */
488         
489         if(LXVST_XDisplay==NULL)
490         {
491                 vstfx_error ("** ERROR ** VSTFX: Failed opening connection to X");
492                 
493                 return -1;
494         }
495         
496         /*We have a connection to X - so start the gui event loop*/
497         
498         /*Create the thread - use default attrs for now, don't think we need anything special*/
499         
500         thread_create_result = pthread_create(&LXVST_gui_event_thread, NULL, gui_event_loop, NULL);
501         
502         if(thread_create_result!=0)
503         {
504                 /*There was a problem starting the GUI event thread*/
505                 
506                 vstfx_error ("** ERROR ** VSTFX: Failed starting GUI event thread");
507                 
508                 XCloseDisplay(LXVST_XDisplay);
509                 
510                 return -1;
511         }
512         
513         return 0;
514 }
515
516 /*The vstfx Quit function*/
517
518 void vstfx_exit()
519 {
520         gui_quit = 1;
521         
522         /*We need to pthread_join the gui_thread here so
523         we know when it has stopped*/
524         
525         pthread_join(LXVST_gui_event_thread, NULL);
526 }
527
528 /*Adds a new plugin (VSTFX) instance to the linked list*/
529
530 int vstfx_run_editor (VSTFX* vstfx)
531 {
532         pthread_mutex_lock (&plugin_mutex);
533
534         /*Add the new VSTFX instance to the linked list*/
535
536         if (vstfx_first == NULL)
537         {
538                 vstfx_first = vstfx;
539         }
540         else
541         {
542                 VSTFX* p = vstfx_first;
543                 
544                 while (p->next)
545                 {
546                         p = p->next;
547                 }
548                 p->next = vstfx;
549                 
550                 /*Mark the new end of the list*/
551                 
552                 vstfx->next = NULL;
553         }
554
555         pthread_mutex_unlock (&plugin_mutex);
556
557         /* wait for the plugin editor window to be created (or not) */
558
559         pthread_mutex_lock (&vstfx->lock);
560         
561         if (!vstfx->window)
562         {
563                 pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
564         }
565         
566         pthread_mutex_unlock (&vstfx->lock);
567
568         if (!vstfx->window)
569         {
570                 return -1;
571         }
572
573         return 0;
574 }
575
576
577 /*Creates an editor for the plugin - normally called from within the gui event loop
578 after run_editor has added the plugin (editor) to the linked list*/
579
580 int vstfx_create_editor (VSTFX* vstfx)
581 {
582         Window parent_window;
583         
584         int x_size = 1;
585         int y_size = 1;
586
587         /* Note: vstfx->lock is held while this function is called */
588
589         if (!(vstfx->plugin->flags & effFlagsHasEditor))
590         {
591                 vstfx_error ("** ERROR ** VSTFX: Plugin \"%s\" has no editor", vstfx->handle->name);
592                 return -1;
593         }
594         
595         
596         /*Create an XWindow for the plugin to inhabit*/
597         
598         parent_window = XCreateSimpleWindow (
599                 LXVST_XDisplay,
600                 DefaultRootWindow(LXVST_XDisplay),
601                 0,
602                 0,
603                 x_size,
604                 y_size,
605                 0,
606                 0,
607                 0
608                 );
609                                                                                 
610         /*Select the events we are interested in receiving - we need Substructure notify so that
611         if the plugin resizes its window - e.g. Loomer Manifold then we get a message*/
612         
613         XSelectInput(LXVST_XDisplay, 
614                                 parent_window,
615                                 SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ExposureMask);
616                                                                                 
617         vstfx->window = parent_window;
618                                                                                 
619         vstfx->xid = parent_window;  //vstfx->xid will be referenced to connect to GTK UI in ardour later
620         
621         /*Because the plugin may be operating on a different Display* to us, and therefore
622         the two event queues can be asynchronous, although we have created the window on
623         our display, we can't guarantee it exists in the server yet, which will
624         cause BadWindow crashes if the plugin tries to use it.
625         
626         It would be nice to use CreateNotify events here, but they don't get
627         through on all window managers, so instead we pass a client message
628         into out queue, after the XCreateWindow.  When this message pops out
629         in our event handler, it will trigger the second stage of plugin
630         Editor instantiation, and by then the Window should be valid...*/
631         
632         XClientMessageEvent event;
633         
634         /*Create an atom to identify our message (only if it doesn't already exist)*/
635         
636         Atom WindowActiveAtom = XInternAtom(LXVST_XDisplay, "LaunchEditor", false);
637         
638         event.type = ClientMessage;
639         event.send_event = true;
640         event.window = parent_window;
641         event.message_type = WindowActiveAtom;
642
643         event.format = 32;                                              //Data format
644         event.data.l[0] = 0x0FEEDBAC;                   //Something we can recognize later
645         
646         /*Push the event into the queue on our Display*/
647         
648         XSendEvent(LXVST_XDisplay, parent_window, FALSE, NoEventMask, (XEvent*)&event);
649
650         /*Unlock - and we are done for the first part of staring the Editor...*/
651         
652         pthread_mutex_unlock (&vstfx->lock);
653         
654         return 0;
655 }
656
657 int vstfx_launch_editor(VSTFX* vstfx)
658 {
659         /*This is the second stage of launching the editor (see vstfx_create editor)
660         we get called here in response to receiving the ClientMessage on our Window,
661         therefore it's about as safe (as can be) to assume that the Window we created
662         is now valid in the XServer and can be passed to the plugin in effEditOpen
663         without generating BadWindow errors when the plugin reparents itself into our
664         parent window*/
665         
666         if(vstfx->been_activated)
667                 return 0;
668         
669         Window parent_window;
670         struct ERect* er;
671         
672         int x_size = 1;
673         int y_size = 1;
674         
675         parent_window = vstfx->window;
676         
677         /*Open the editor - Bah! we have to pass the int windowID as a void pointer - yuck
678         it gets cast back to an int as the parent window XID in the plugin - and we have to pass the
679         Display* as a long */
680         
681         /**************************************************************/
682         /* 64Bit --- parent window is an int passed as a void* so     */
683         /* that should be ok for 64Bit machines                       */
684         /*                                                            */
685         /* Display is passed in as a long - ok on arch's where sizeof */
686         /* long = 8                                                   */
687         /*                                                            */
688         /* Most linux VST plugins open a connection to X on their own */
689         /* Display anyway so it may not matter                        */
690         /*                                                            */
691         /* linuxDSP VSTs don't use the host Display* at all           */
692         /**************************************************************/
693         
694         vstfx->plugin->dispatcher (vstfx->plugin, effEditOpen, 0, (long)LXVST_XDisplay, (void*)(parent_window), 0 );
695         
696         /*QUIRK - some plugins need a slight delay after opening the editor before you can
697         ask the window size or they might return zero - specifically discoDSP */
698         
699         usleep(100000);
700         
701         /*Now we can find out how big the parent window should be (and try) to resize it*/
702         
703         vstfx->plugin->dispatcher (vstfx->plugin, effEditGetRect, 0, 0, &er, 0 );
704
705         x_size = er->right - er->left;
706         y_size = er->bottom - er->top;
707         
708         vstfx->width =  x_size;
709         vstfx->height =  y_size;
710         
711         XResizeWindow(LXVST_XDisplay, parent_window, x_size, y_size);
712         
713         XFlush (LXVST_XDisplay);
714         
715         /*Not sure if we need to map the window or if the plugin will do it for us
716         it should be ok because XReparentWindow generates a Map event*/
717         
718         /*mark the editor as activated - mainly so that vstfx_get_XID
719         will know it is valid*/
720
721         vstfx->been_activated = TRUE;
722         
723         pthread_cond_signal (&vstfx->window_status_change);
724         return 0;
725 }
726
727 /*May not be needed in the XLib version*/
728
729 void vstfx_move_window_into_view (VSTFX* vstfx)
730 {
731
732         /*This is probably the equivalent of Mapping an XWindow
733         but we most likely don't need it because the window
734         will be Mapped by XReparentWindow*/
735
736 }
737
738 /*Destroy the editor window*/
739
740 void vstfx_destroy_editor (VSTFX* vstfx)
741 {
742         pthread_mutex_lock (&vstfx->lock);
743         if (vstfx->window)
744         {
745                 vstfx->destroy = TRUE;
746                 pthread_cond_wait (&vstfx->window_status_change, &vstfx->lock);
747         }
748         pthread_mutex_unlock (&vstfx->lock);
749 }
750
751 /*Remove a vstfx instance from the linked list parsed by the
752 event loop*/
753
754 void vstfx_event_loop_remove_plugin (VSTFX* vstfx)
755 {
756         /*This only ever gets called from within our GUI thread
757         so we don't need to lock here - if we did there would be
758         a deadlock anyway*/
759         
760         VSTFX* p;
761         VSTFX* prev;
762         
763         for(p = vstfx_first, prev = NULL; p; prev = p, p = p->next)
764         {
765                 if(p == vstfx)
766                 {
767                         if(prev)
768                         {
769                                 prev->next = p->next;
770                                 break;
771                         }
772                 }
773         }
774
775         if (vstfx_first == vstfx)
776                 vstfx_first = vstfx_first->next;
777 }
778
779 /*Get the XID of the plugin editor window*/
780
781 int vstfx_get_XID (VSTFX* vstfx)
782 {
783         int id;
784         
785         /*Wait for the lock to become free - otherwise
786         the window might be in the process of being
787         created and we get bad Window errors when trying
788         to embed it in the GTK UI*/
789         
790         pthread_mutex_lock(&vstfx->lock);
791         
792         /*The Window may be scheduled for creation
793         but not actually created by the gui_event_loop yet - 
794         
795         spin here until it has been activated.  Possible
796         deadlock if the window never gets activated but
797         should not be called here if the window doesn't
798         exist or will never exist*/
799         
800         while(!(vstfx->been_activated))
801                 usleep(1000);
802         
803         id = vstfx->xid;
804         
805         pthread_mutex_unlock(&vstfx->lock);
806         
807         /*Finally it might be safe to return the ID - 
808         problems will arise if we return either a zero ID
809         and GTK tries to socket it or if we return an ID
810         which hasn't yet become real to the server*/
811         
812         return id;
813 }
814
815 float htonf (float v)
816 {
817       float result;
818       char * fin = (char*)&v;
819       char * fout = (char*)&result;
820       fout[0] = fin[3];
821       fout[1] = fin[2];
822       fout[2] = fin[1];
823       fout[3] = fin[0];
824       return result;
825 }
826
827
828 /*load_state and save_state do not appear to be needed (yet) in ardour
829 - untested at the moment, these are just replicas of the fst code*/
830
831
832 #if 0
833 int vstfx_load_state (VSTFX* vstfx, char * filename)
834 {
835         FILE* f = fopen (filename, "rb");
836         if(f)
837         {
838                 char testMagic[sizeof (magic)];
839                 fread (&testMagic, sizeof (magic), 1, f);
840                 if (strcmp (testMagic, magic))
841                 {
842                         printf ("File corrupt\n");
843                         return FALSE;
844                 }
845
846                 char productString[64];
847                 char vendorString[64];
848                 char effectName[64];
849                 char testString[64];
850                 unsigned length;
851                 int success;
852
853                 fread (&length, sizeof (unsigned), 1, f);
854                 length = htonl (length);
855                 fread (productString, length, 1, f);
856                 productString[length] = 0;
857                 printf ("Product string: %s\n", productString);
858
859                 success = vstfx_call_dispatcher(vstfx, effGetProductString, 0, 0, testString, 0);
860                 
861                 if (success == 1)
862                 {
863                         if (strcmp (testString, productString) != 0)
864                         {
865                                 printf ("Product string mismatch! Plugin has: %s\n", testString);
866                                 fclose (f);
867                                 return FALSE;
868                         }
869                 }
870                 else if (length != 0)
871                 {
872                         printf ("Product string mismatch! Plugin has none.\n", testString);
873                         fclose (f);
874                         return FALSE;
875                 }
876
877                 fread (&length, sizeof (unsigned), 1, f);
878                 length = htonl (length);
879                 fread (effectName, length, 1, f);
880                 effectName[length] = 0;
881                 printf ("Effect name: %s\n", effectName);
882
883                 success = vstfx_call_dispatcher(vstfx, effGetEffectName, 0, 0, testString, 0);
884                 
885                 if(success == 1)
886                 {
887                         if(strcmp(testString, effectName)!= 0)
888                         {
889                                 printf ("Effect name mismatch! Plugin has: %s\n", testString);
890                                 fclose (f);
891                                 return FALSE;
892                         }
893                 }
894                 else if(length != 0)
895                 {
896                         printf ("Effect name mismatch! Plugin has none.\n", testString);
897                         fclose (f);
898                         return FALSE;
899                 }
900
901                 fread (&length, sizeof (unsigned), 1, f);
902                 length = htonl (length);
903                 fread (vendorString, length, 1, f);
904                 vendorString[length] = 0;
905                 
906                 printf ("Vendor string: %s\n", vendorString);
907
908                 success = vstfx_call_dispatcher(vstfx, effGetVendorString, 0, 0, testString, 0);
909                 if(success == 1)
910                 {
911                         if (strcmp(testString, vendorString)!= 0)
912                         {
913                                 printf ("Vendor string mismatch! Plugin has: %s\n", testString);
914                                 fclose (f);
915                                 return FALSE;
916                         }
917                 }
918                 else if(length != 0)
919                 {
920                         printf ("Vendor string mismatch! Plugin has none.\n", testString);
921                         fclose (f);
922                         return FALSE;
923                 }
924
925                 int numParam;
926                 unsigned i;
927                 fread (&numParam, sizeof (int), 1, f);
928                 numParam = htonl (numParam);
929                 
930                 for (i = 0; i < numParam; ++i)
931                 {
932                         float val;
933                         fread (&val, sizeof (float), 1, f);
934                         val = htonf (val);
935
936                         pthread_mutex_lock(&vstfx->lock );
937                         vstfx->plugin->setParameter(vstfx->plugin, i, val);
938                         pthread_mutex_unlock(&vstfx->lock );
939                 }
940
941                 int bytelen;
942                 
943                 fread (&bytelen, sizeof (int), 1, f);
944                 bytelen = htonl (bytelen);
945                 
946                 if (bytelen)
947                 {
948                         char * buf = malloc (bytelen);
949                         fread (buf, bytelen, 1, f);
950
951                         vstfx_call_dispatcher(vstfx, 24, 0, bytelen, buf, 0);
952                         free (buf);
953                 }
954         }
955         else
956         {
957                 printf ("Could not open state file\n");
958                 return FALSE;
959         }
960         return TRUE;
961
962 }
963 #endif
964