Share main VSTFX / FST struct between windows / linux VSTs.
[ardour.git] / libs / fst / vstwin.c
1 #include <stdio.h>
2 #include <jack/jack.h>
3 #include <jack/thread.h>
4 #include <libgen.h>
5 #include <windows.h>
6 #include <winnt.h>
7 #include <wine/exception.h>
8 #include <pthread.h>
9 #include <signal.h>
10 #include <glib.h>
11
12 #include "fst.h"
13
14 #include <X11/X.h>
15 #include <X11/Xlib.h>
16
17 extern char * strdup (const char *);
18
19 struct ERect{
20     short top;
21     short left;
22     short bottom;
23     short right;
24 };
25
26 static pthread_mutex_t plugin_mutex;
27
28 /** Head of linked list of all FSTs */
29 static VSTState* fst_first = NULL;
30
31 const char magic[] = "FST Plugin State v002";
32
33 DWORD  gui_thread_id = 0;
34 static int gui_quit = 0;
35
36 #define DELAYED_WINDOW 1
37
38
39 static LRESULT WINAPI 
40 my_window_proc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
41 {
42 #if 0   
43         if (msg != WM_TIMER) {
44                 fst_error ("window callback handler, msg = 0x%x win=%p\n", msg, w);
45         }
46 #endif  
47
48         switch (msg) {
49         case WM_KEYUP:
50         case WM_KEYDOWN:
51                 break;
52
53         case WM_CLOSE:
54                 /* we don't care about windows closing ... */
55                 return 0;
56                 break;
57
58         case WM_DESTROY:
59         case WM_NCDESTROY:
60                 /* we don't care about windows being destroyed ... */
61                 return 0;
62                 break;
63
64         default:
65                 break;
66         }
67
68         return DefWindowProcA (w, msg, wp, lp );
69 }
70
71 static VSTState * 
72 fst_new ()
73 {
74         VSTState* fst = (VSTState *) calloc (1, sizeof (VSTState));
75         pthread_mutex_init (&fst->lock, NULL);
76         pthread_cond_init (&fst->window_status_change, NULL);
77         pthread_cond_init (&fst->plugin_dispatcher_called, NULL);
78         fst->want_program = -1;
79         fst->want_chunk = 0;
80         fst->current_program = -1;
81         fst->n_pending_keys = 0;
82         fst->has_editor = 0;
83         fst->program_set_without_editor = 0;
84         return fst;
85 }
86
87 static VSTHandle* 
88 fst_handle_new ()
89 {
90         VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
91         return fst;
92 }
93
94 void
95 maybe_set_program (VSTState* fst)
96 {
97         if (fst->want_program != -1) {
98                 if (fst->vst_version >= 2) {
99                         fst->plugin->dispatcher (fst->plugin, 67 /* effBeginSetProgram */, 0, 0, NULL, 0);
100                 }
101                 
102                 fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
103                 
104                 if (fst->vst_version >= 2) {
105                         fst->plugin->dispatcher (fst->plugin, 68 /* effEndSetProgram */, 0, 0, NULL, 0);
106                 }
107                 /* did it work? */
108                 fst->current_program = fst->plugin->dispatcher (fst->plugin, 3, /* effGetProgram */ 0, 0, NULL, 0);
109                 fst->want_program = -1; 
110         }
111         
112         if (fst->want_chunk == 1) {
113                 fst->plugin->dispatcher (fst->plugin, 24 /* effSetChunk */, 1, fst->wanted_chunk_size, fst->wanted_chunk, 0);
114                 fst->want_chunk = 0;
115         }
116 }
117
118 DWORD WINAPI gui_event_loop (LPVOID param)
119 {
120         MSG msg;
121         VSTState* fst;
122         HMODULE hInst;
123         HWND window;
124         int i;
125
126         gui_thread_id = GetCurrentThreadId ();
127
128         /* create a dummy window for timer events */
129
130         if ((hInst = GetModuleHandleA (NULL)) == NULL) {
131                 fst_error ("can't get module handle");
132                 return 1;
133         }
134         
135         if ((window = CreateWindowExA (0, "FST", "dummy",
136                                        WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
137                                        9999, 9999,
138                                        1, 1,
139                                        NULL, NULL,
140                                        hInst,
141                                        NULL )) == NULL) {
142                 fst_error ("cannot create dummy timer window");
143         }
144
145         if (!SetTimer (window, 1000, 20, NULL)) {
146                 fst_error ("cannot set timer on dummy window");
147         }
148
149         while (!gui_quit) {
150
151                 if (!GetMessageA (&msg, NULL, 0,0)) {
152                         if (!gui_quit) {
153                                 fprintf (stderr, "QUIT message received by Windows GUI thread - ignored\n");
154                                 continue;
155                         } else {
156                                 break;
157                         }
158                 }
159
160                 TranslateMessage( &msg );
161                 DispatchMessageA (&msg);
162
163                 if (msg.message != WM_TIMER) {
164                         continue;
165                 }
166
167                 pthread_mutex_lock (&plugin_mutex);
168
169                 /* Do things that are appropriate for plugins which have open editor windows:
170                    handle window creation requests, destroy requests, 
171                    and run idle callbacks 
172                 */
173                 
174 again:
175                 for (fst = fst_first; fst; fst = fst->next) {
176                         
177                         pthread_mutex_lock (&fst->lock);
178                         
179                         if (fst->has_editor == 1) {
180                                 
181                                 if (fst->destroy) {
182                                         fprintf (stderr, "%s scheduled for destroy\n", fst->handle->name);
183                                         if (fst->windows_window) {
184                                                 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
185                                                 CloseWindow (fst->windows_window);
186                                                 fst->windows_window = NULL;
187                                                 fst->destroy = FALSE;
188                                         }
189                                         fst_event_loop_remove_plugin (fst);
190                                         fst->been_activated = FALSE;
191                                         pthread_cond_signal (&fst->window_status_change);
192                                         pthread_mutex_unlock (&fst->lock);
193                                         goto again;
194                                 } 
195                                 
196                                 if (fst->windows_window == NULL) {
197                                         if (fst_create_editor (fst)) {
198                                                 fst_error ("cannot create editor for plugin %s", fst->handle->name);
199                                                 fst_event_loop_remove_plugin (fst);
200                                                 pthread_cond_signal (&fst->window_status_change);
201                                                 pthread_mutex_unlock (&fst->lock);
202                                                 goto again;
203                                         } else {
204                                                 /* condition/unlock: it was signalled & unlocked in fst_create_editor()   */
205                                         }
206                                 }
207                                 
208                                 if (fst->dispatcher_wantcall) {
209                                         fst->dispatcher_retval = fst->plugin->dispatcher( fst->plugin, 
210                                                                                           fst->dispatcher_opcode,
211                                                                                           fst->dispatcher_index,
212                                                                                           fst->dispatcher_val,
213                                                                                           fst->dispatcher_ptr,
214                                                                                           fst->dispatcher_opt );
215                                         fst->dispatcher_wantcall = 0;
216                                         pthread_cond_signal (&fst->plugin_dispatcher_called);
217                                 }
218                                 
219                                 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
220                                 
221                                 if (fst->wantIdle) {
222                                         fst->plugin->dispatcher (fst->plugin, 53, 0, 0, NULL, 0);
223                                 }
224                                 
225                                 /* Dispatch messages to send keypresses to the plugin */
226                                 
227                                 for (i = 0; i < fst->n_pending_keys; ++i) {
228                                         /* I'm not quite sure what is going on here; it seems
229                                            `special' keys must be delivered with WM_KEYDOWN,
230                                            but that alphanumerics etc. must use WM_CHAR or
231                                            they will be ignored.  Ours is not to reason why ...
232                                         */
233                                         if (fst->pending_keys[i].special != 0) {
234                                                 msg.message = WM_KEYDOWN;
235                                                 msg.wParam = fst->pending_keys[i].special;
236                                         } else {
237                                                 msg.message = WM_CHAR;
238                                                 msg.wParam = fst->pending_keys[i].character;
239                                         }
240                                         msg.hwnd = GetFocus ();
241                                         msg.lParam = 0;
242                                         DispatchMessageA (&msg);
243                                 }
244                                 
245                                 fst->n_pending_keys = 0;
246
247                                 /* See comment for maybe_set_program call below */
248                                 maybe_set_program (fst);
249                                 fst->want_program = -1;
250                                 fst->want_chunk = 0;
251                         }
252
253                         /* If we don't have an editor window yet, we still need to
254                          * set up the program, otherwise when we load a plugin without
255                          * opening its window it will sound wrong.  However, it seems
256                          * that if you don't also load the program after opening the GUI,
257                          * the GUI does not reflect the program properly.  So we'll not
258                          * mark that we've done this (ie we won't set want_program to -1)
259                          * and so it will be done again if and when the GUI arrives.
260                          */
261                         if (fst->program_set_without_editor == 0) {
262                                 maybe_set_program (fst);
263                                 fst->program_set_without_editor = 1;
264                         }
265
266                         pthread_mutex_unlock (&fst->lock);
267                 }
268
269                 pthread_mutex_unlock (&plugin_mutex);
270         }
271
272         return 0;
273 }
274
275 int
276 fst_init (void* possible_hmodule)
277 {
278         WNDCLASSEX wclass;
279         HMODULE hInst;
280         
281         if (possible_hmodule) {
282                 hInst = (HMODULE) possible_hmodule;
283         } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
284                 fst_error ("can't get module handle");
285                 return -1;
286         }
287
288         wclass.cbSize = sizeof(WNDCLASSEX);
289         wclass.style = 0;
290         wclass.lpfnWndProc = my_window_proc;
291         wclass.cbClsExtra = 0;
292         wclass.cbWndExtra = 0;
293         wclass.hInstance = hInst;
294         wclass.hIcon = LoadIcon(hInst, "FST");
295         wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
296 //    wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
297         wclass.lpszMenuName = "MENU_FST";
298         wclass.lpszClassName = "FST";
299         wclass.hIconSm = 0;
300
301
302         if (!RegisterClassExA(&wclass)){
303                 printf( "Class register failed :(\n" );
304                 return -1;
305         }
306
307         fst_error ("Startup win32 GUI thread\n");
308
309         if (CreateThread (NULL, 0, gui_event_loop, NULL, 0, NULL) == NULL) {
310                 fst_error ("could not create new thread proxy");
311                 return -1;
312         }
313
314 #ifdef HAVE_JACK_SET_THREAD_CREATOR
315         jack_set_thread_creator (wine_pthread_create);
316 #endif
317
318         return 0;
319 }
320
321 void
322 fst_exit ()
323 {
324         gui_quit = 1;
325         PostQuitMessage (0);
326 }
327
328 int
329 fst_run_editor (VSTState* fst)
330 {
331         /* wait for the plugin editor window to be created (or not) */
332
333         pthread_mutex_lock (&fst->lock);
334
335         fst->has_editor = 1;
336         
337         if (!fst->windows_window) {
338                 pthread_cond_wait (&fst->window_status_change, &fst->lock);
339         }
340         pthread_mutex_unlock (&fst->lock);
341
342         if (!fst->windows_window) {
343                 return -1;
344         }
345
346         return 0;
347 }
348
349 int
350 fst_call_dispatcher (VSTState* fst, int opcode, int index, int val, void *ptr, float opt) 
351 {
352         pthread_mutex_lock (&fst->lock);
353         fst->dispatcher_opcode = opcode;
354         fst->dispatcher_index = index;
355         fst->dispatcher_val = val;
356         fst->dispatcher_ptr = ptr;
357         fst->dispatcher_opt = opt;
358         fst->dispatcher_wantcall = 1;
359
360         pthread_cond_wait (&fst->plugin_dispatcher_called, &fst->lock);
361         pthread_mutex_unlock (&fst->lock);
362
363         return fst->dispatcher_retval;
364 }
365
366 int
367 fst_create_editor (VSTState * fst)
368 {
369         HMODULE hInst;
370         HWND window;
371         struct ERect* er;
372
373         /* "guard point" to trap errors that occur during plugin loading */
374
375         /* Note: fst->lock is held while this function is called */
376
377         if (!(fst->plugin->flags & effFlagsHasEditor)) {
378                 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
379                 return -1;
380         }
381
382         if ((hInst = GetModuleHandleA (NULL)) == NULL) {
383                 fst_error ("can't get module handle");
384                 return 1;
385         }
386         
387 //      if ((window = CreateWindowExA (WS_EX_TOOLWINDOW | WS_EX_TRAYWINDOW, "FST", fst->handle->name,
388         if ((window = CreateWindowExA (0, "FST", fst->handle->name,
389                                        (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
390 //                                     (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
391                                        9999,9999,1,1,
392 //                                     CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
393                                        NULL, NULL,
394                                        hInst,
395                                        NULL)) == NULL) {
396                 fst_error ("cannot create editor window");
397                 return 1;
398         }
399
400         if (!SetPropA (window, "fst_ptr", fst)) {
401                 fst_error ("cannot set fst_ptr on window");
402         }
403
404         fst->windows_window = window;
405 //      fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
406
407
408         //printf( "effEditOpen......\n" );
409         fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->windows_window, 0);
410         fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
411
412         fst->width =  er->right-er->left;
413         fst->height =  er->bottom-er->top;
414         //printf( "get rect ses... %d,%d\n", fst->width, fst->height );
415
416         //SetWindowPos (fst->window, 0, 9999, 9999, er->right-er->left+8, er->bottom-er->top+26, 0);
417         SetWindowPos (fst->windows_window, 0, 9999, 9999, 2, 2, 0);
418         ShowWindow (fst->windows_window, SW_SHOWNA);
419         //SetWindowPos (fst->window, 0, 0, 0, er->right-er->left+8, er->bottom-er->top+26, SWP_NOMOVE|SWP_NOZORDER);
420         
421         fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
422         fst->been_activated = TRUE;
423         pthread_cond_signal (&fst->window_status_change);
424         pthread_mutex_unlock (&fst->lock);
425
426         return 0;
427 }
428
429 void
430 fst_move_window_into_view (VSTState* fst)
431 {
432         if (fst->windows_window) {
433                 SetWindowPos (fst->windows_window, 0, 0, 0, fst->width, fst->height + 24, 0);
434                 ShowWindow (fst->windows_window, SW_SHOWNA);
435         }
436 }
437
438 void
439 fst_destroy_editor (VSTState* fst)
440 {
441         pthread_mutex_lock (&fst->lock);
442         if (fst->windows_window) {
443                 fprintf (stderr, "mark %s for destroy\n", fst->handle->name);
444                 fst->destroy = TRUE;
445                 //if (!PostThreadMessageA (gui_thread_id, WM_USER, 0, 0)) {
446                 //if (!PostThreadMessageA (gui_thread_id, WM_QUIT, 0, 0)) {
447                 //      fst_error ("could not post message to gui thread");
448                 //}
449                 pthread_cond_wait (&fst->window_status_change, &fst->lock);
450                 fprintf (stderr, "%s editor destroyed\n", fst->handle->name);
451                 fst->has_editor = 0;
452         }
453         pthread_mutex_unlock (&fst->lock);
454 }
455
456 void
457 fst_event_loop_remove_plugin (VSTState* fst)
458 {
459         VSTState* p;
460         VSTState* prev;
461
462         for (p = fst_first, prev = NULL; p->next; prev = p, p = p->next) {
463                 if (p == fst) {
464                         if (prev) {
465                                 prev->next = p->next;
466                         }
467                 }
468         }
469
470         if (fst_first == fst) {
471                 fst_first = fst_first->next;
472         }
473
474 }
475
476 HMODULE
477 fst_load_vst_library(const char * path)
478 {
479         HMODULE dll;
480         char * full_path;
481         char * envdup;
482         char * vst_path;
483         size_t len1;
484         size_t len2;
485
486         if ((dll = LoadLibraryA (path)) != NULL) {
487                 return dll;
488         }
489
490         envdup = getenv ("VST_PATH");
491         if (envdup == NULL) {
492                 return NULL;
493         }
494
495         envdup = strdup (envdup);
496         if (envdup == NULL) {
497                 fst_error ("strdup failed");
498                 return NULL;
499         }
500
501         len2 = strlen(path);
502
503         vst_path = strtok (envdup, ":");
504         while (vst_path != NULL) {
505                 fst_error ("\"%s\"", vst_path);
506                 len1 = strlen(vst_path);
507                 full_path = malloc (len1 + 1 + len2 + 1);
508                 memcpy(full_path, vst_path, len1);
509                 full_path[len1] = '/';
510                 memcpy(full_path + len1 + 1, path, len2);
511                 full_path[len1 + 1 + len2] = '\0';
512
513                 if ((dll = LoadLibraryA (full_path)) != NULL) {
514                         break;
515                 }
516
517                 vst_path = strtok (NULL, ":");
518         }
519
520         free(envdup);
521
522         return dll;
523 }
524
525 VSTHandle *
526 fst_load (const char *path)
527 {
528         char* buf;
529         VSTHandle* fhandle;
530         char* period;
531
532         fhandle = fst_handle_new ();
533         
534         // XXX: Would be nice to find the correct call for this.
535         //      if the user does not configure Z: to be / we are doomed :(
536
537         if (strstr (path, ".dll") == NULL) {
538
539                 buf = (char *) malloc (strlen (path) + 7);
540
541                 if( path[0] == '/' ) {
542                     sprintf (buf, "Z:%s.dll", path);
543                 } else {
544                     sprintf (buf, "%s.dll", path);
545                 }
546
547                 fhandle->nameptr = strdup (path);
548
549         } else {
550
551                 buf = (char *) malloc (strlen (path) + 3);
552
553                 if( path[0] == '/' ) {
554                     sprintf (buf, "Z:%s", path);
555                 } else {
556                     sprintf (buf, "%s", path);
557                 }
558
559                 fhandle->nameptr = strdup (path);
560         }
561         
562         fhandle->name = basename (fhandle->nameptr);
563
564         /* strip off .dll */
565
566         if ((period = strrchr (fhandle->name, '.')) != NULL) {
567                 *period = '\0';
568         }
569
570         if ((fhandle->dll = fst_load_vst_library (buf)) == NULL) {
571                 fst_unload (fhandle);
572                 return NULL;
573         }
574
575         if ((fhandle->main_entry = (main_entry_t) GetProcAddress (fhandle->dll, "main")) == NULL) {
576                 fst_unload (fhandle);
577                 return NULL;
578         }
579
580         return fhandle;
581 }
582
583 int
584 fst_unload (VSTHandle* fhandle)
585 {
586         if (fhandle->plugincnt) {
587                 return -1;
588         }
589
590         if (fhandle->dll) {
591                 FreeLibrary (fhandle->dll);
592                 fhandle->dll = NULL;
593         }
594
595         if (fhandle->nameptr) {
596                 free (fhandle->nameptr);
597                 fhandle->name = NULL;
598         }
599         
600         free (fhandle);
601         return 0;
602 }
603
604 VSTState*
605 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
606 {
607         VSTState* fst = fst_new ();
608
609         pthread_mutex_lock (&plugin_mutex);
610
611         if (fst_first == NULL) {
612                 fst_first = fst;
613         } else {
614                 VSTState* p = fst_first;
615                 while (p->next) {
616                         p = p->next;
617                 }
618                 p->next = fst;
619         }
620
621         pthread_mutex_unlock (&plugin_mutex);
622         
623         if( fhandle == NULL ) {
624             fst_error( "the handle was NULL\n" );
625             return NULL;
626         }
627
628         if ((fst->plugin = fhandle->main_entry (amc)) == NULL)  {
629                 fst_error ("%s could not be instantiated\n", fhandle->name);
630                 free (fst);
631                 return NULL;
632         }
633         
634         fst->handle = fhandle;
635         fst->plugin->user = userptr;
636                 
637         if (fst->plugin->magic != kEffectMagic) {
638                 fst_error ("%s is not a VST plugin\n", fhandle->name);
639                 free (fst);
640                 return NULL;
641         }
642         
643         fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
644         //fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
645
646         fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
647         
648         fst->handle->plugincnt++;
649         fst->wantIdle = 0;
650
651         return fst;
652 }
653
654 void
655 fst_close (VSTState* fst)
656 {
657         fst_destroy_editor (fst);
658
659         fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
660         fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
661
662         if (fst->handle->plugincnt) {
663                 --fst->handle->plugincnt;
664         }
665 }
666
667 int
668 fst_get_XID (VSTState* fst)
669 {
670         return fst->xid;
671 }
672
673 float htonf (float v)
674 {
675       float result;
676       char * fin = (char*)&v;
677       char * fout = (char*)&result;
678       fout[0] = fin[3];
679       fout[1] = fin[2];
680       fout[2] = fin[1];
681       fout[3] = fin[0];
682       return result;
683 }
684
685 #if 0
686 int fst_load_state (FST * fst, char * filename)
687 {
688         FILE * f = fopen (filename, "rb");
689         if (f) {
690                 char testMagic[sizeof (magic)];
691                 fread (&testMagic, sizeof (magic), 1, f);
692                 if (strcmp (testMagic, magic)) {
693                         printf ("File corrupt\n");
694                         return FALSE;
695                 }
696
697                 char productString[64];
698                 char vendorString[64];
699                 char effectName[64];
700                 char testString[64];
701                 unsigned length;
702                 int success;
703
704                 fread (&length, sizeof (unsigned), 1, f);
705                 length = htonl (length);
706                 fread (productString, length, 1, f);
707                 productString[length] = 0;
708                 printf ("Product string: %s\n", productString);
709
710                 success = fst_call_dispatcher( fst, effGetProductString, 0, 0, testString, 0 );
711                 if (success == 1) {
712                         if (strcmp (testString, productString) != 0) {
713                                 printf ("Product string mismatch! Plugin has: %s\n", testString);
714                                 fclose (f);
715                                 return FALSE;
716                         }
717                 } else if (length != 0) {
718                         printf ("Product string mismatch! Plugin has none.\n", testString);
719                         fclose (f);
720                         return FALSE;
721                 }
722
723                 fread (&length, sizeof (unsigned), 1, f);
724                 length = htonl (length);
725                 fread (effectName, length, 1, f);
726                 effectName[length] = 0;
727                 printf ("Effect name: %s\n", effectName);
728
729                 success = fst_call_dispatcher( fst, effGetEffectName, 0, 0, testString, 0 );
730                 if (success == 1) {
731                         if (strcmp (testString, effectName) != 0) {
732                                 printf ("Effect name mismatch! Plugin has: %s\n", testString);
733                                 fclose (f);
734                                 return FALSE;
735                         }
736                 } else if (length != 0) {
737                         printf ("Effect name mismatch! Plugin has none.\n", testString);
738                         fclose (f);
739                         return FALSE;
740                 }
741
742                 fread (&length, sizeof (unsigned), 1, f);
743                 length = htonl (length);
744                 fread (vendorString, length, 1, f);
745                 vendorString[length] = 0;
746                 printf ("Vendor string: %s\n", vendorString);
747
748                 success = fst_call_dispatcher( fst, effGetVendorString, 0, 0, testString, 0 );
749                 if (success == 1) {
750                         if (strcmp (testString, vendorString) != 0) {
751                                 printf ("Vendor string mismatch! Plugin has: %s\n", testString);
752                                 fclose (f);
753                                 return FALSE;
754                         }
755                 } else if (length != 0) {
756                         printf ("Vendor string mismatch! Plugin has none.\n", testString);
757                         fclose (f);
758                         return FALSE;
759                 }
760
761                 int numParam;
762                 unsigned i;
763                 fread (&numParam, sizeof (int), 1, f);
764                 numParam = htonl (numParam);
765                 for (i = 0; i < numParam; ++i) {
766                         float val;
767                         fread (&val, sizeof (float), 1, f);
768                         val = htonf (val);
769
770                         pthread_mutex_lock( &fst->lock );
771                         fst->plugin->setParameter( fst->plugin, i, val );
772                         pthread_mutex_unlock( &fst->lock );
773                 }
774
775                 int bytelen;
776                 fread (&bytelen, sizeof (int), 1, f);
777                 bytelen = htonl (bytelen);
778                 if (bytelen) {
779                         char * buf = malloc (bytelen);
780                         fread (buf, bytelen, 1, f);
781
782                         fst_call_dispatcher( fst, 24, 0, bytelen, buf, 0 );
783                         free (buf);
784                 }
785         } else {
786                 printf ("Could not open state file\n");
787                 return FALSE;
788         }
789         return TRUE;
790
791 }
792 #endif
793
794 int
795 fst_save_state (VSTState * fst, char * filename)
796 {
797         FILE * f = fopen (filename, "wb");
798         int j;
799
800         if (f) {
801                 int bytelen;
802                 int numParams = fst->plugin->numParams;
803                 char productString[64];
804                 char effectName[64];
805                 char vendorString[64];
806                 int success;
807
808                 // write header
809                 fprintf( f, "<plugin_state>\n" );
810
811                 success = fst_call_dispatcher( fst, effGetProductString, 0, 0, productString, 0 );
812                 if( success == 1 ) {
813                         fprintf (f, "  <check field=\"productString\" value=\"%s\"/>\n", productString);
814                 } else {
815                         printf ("No product string\n");
816                 }
817
818                 success = fst_call_dispatcher( fst, effGetEffectName, 0, 0, effectName, 0 );
819                 if( success == 1 ) {
820                         fprintf (f, "  <check field=\"effectName\" value=\"%s\"/>\n", effectName);
821                         printf ("Effect name: %s\n", effectName);
822                 } else {
823                         printf ("No effect name\n");
824                 }
825
826                 success = fst_call_dispatcher( fst, effGetVendorString, 0, 0, vendorString, 0 );
827                 if( success == 1 ) {
828                         fprintf (f, "  <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
829                         printf ("Vendor string: %s\n", vendorString);
830                 } else {
831                         printf ("No vendor string\n");
832                 }
833
834
835                 if( fst->plugin->flags & 32 ) {
836                         numParams = 0;
837                 }
838
839                 for (j = 0; j < numParams; ++j) {
840                         float val;
841                         
842                         pthread_mutex_lock( &fst->lock );
843                         val = fst->plugin->getParameter (fst->plugin, j);
844                         pthread_mutex_unlock( &fst->lock );
845                         fprintf( f, "  <param index=\"%d\" value=\"%f\"/>\n", j, val );
846                 }
847
848                 if( fst->plugin->flags & 32 ) {
849                         printf( "getting chunk...\n" );
850                         void * chunk;
851                         bytelen = fst_call_dispatcher( fst, 23, 0, 0, &chunk, 0 );
852                         printf( "got tha chunk..\n" );
853                         if( bytelen ) {
854                                 if( bytelen < 0 ) {
855                                         printf( "Chunke len < 0 !!! Not saving chunk.\n" );
856                                 } else {
857                                         char *encoded = g_base64_encode( chunk, bytelen );
858                                         fprintf( f, "  <chunk size=\"%d\">\n    %s\n  </chunk>\n", bytelen, encoded );
859                                         g_free( encoded );
860                                 }
861                         }
862                 } 
863
864                 fprintf( f, "</plugin_state>\n" );
865                 fclose( f );
866         } else {
867                 printf ("Could not open state file\n");
868                 return FALSE;
869         }
870         return TRUE;
871 }
872