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