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