3 #include <jack/thread.h>
7 #include <wine/exception.h>
17 extern char * strdup (const char *);
26 static pthread_mutex_t plugin_mutex
;
28 /** Head of linked list of all FSTs */
29 static FST
* fst_first
= NULL
;
31 const char magic
[] = "FST Plugin State v002";
33 DWORD gui_thread_id
= 0;
34 static int gui_quit
= 0;
36 #define DELAYED_WINDOW 1
40 my_window_proc (HWND w
, UINT msg
, WPARAM wp
, LPARAM lp
)
43 if (msg
!= WM_TIMER
) {
44 fst_error ("window callback handler, msg = 0x%x win=%p\n", msg
, w
);
54 /* we don't care about windows closing ... */
60 /* we don't care about windows being destroyed ... */
68 return DefWindowProcA (w
, msg
, wp
, lp
);
74 FST
* fst
= (FST
*) calloc (1, sizeof (FST
));
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;
80 fst
->current_program
= -1;
81 fst
->n_pending_keys
= 0;
83 fst
->program_set_without_editor
= 0;
90 FSTHandle
* fst
= (FSTHandle
*) calloc (1, sizeof (FSTHandle
));
95 maybe_set_program (FST
* fst
)
97 if (fst
->want_program
!= -1) {
98 if (fst
->vst_version
>= 2) {
99 fst
->plugin
->dispatcher (fst
->plugin
, 67 /* effBeginSetProgram */, 0, 0, NULL
, 0);
102 fst
->plugin
->dispatcher (fst
->plugin
, effSetProgram
, 0, fst
->want_program
, NULL
, 0);
104 if (fst
->vst_version
>= 2) {
105 fst
->plugin
->dispatcher (fst
->plugin
, 68 /* effEndSetProgram */, 0, 0, NULL
, 0);
108 fst
->current_program
= fst
->plugin
->dispatcher (fst
->plugin
, 3, /* effGetProgram */ 0, 0, NULL
, 0);
109 fst
->want_program
= -1;
112 if (fst
->want_chunk
== 1) {
113 fst
->plugin
->dispatcher (fst
->plugin
, 24 /* effSetChunk */, 1, fst
->wanted_chunk_size
, fst
->wanted_chunk
, 0);
118 DWORD WINAPI
gui_event_loop (LPVOID param
)
126 gui_thread_id
= GetCurrentThreadId ();
128 /* create a dummy window for timer events */
130 if ((hInst
= GetModuleHandleA (NULL
)) == NULL
) {
131 fst_error ("can't get module handle");
135 if ((window
= CreateWindowExA (0, "FST", "dummy",
136 WS_OVERLAPPEDWINDOW
& ~WS_THICKFRAME
& ~WS_MAXIMIZEBOX
,
142 fst_error ("cannot create dummy timer window");
145 if (!SetTimer (window
, 1000, 20, NULL
)) {
146 fst_error ("cannot set timer on dummy window");
151 if (!GetMessageA (&msg
, NULL
, 0,0)) {
153 fprintf (stderr
, "QUIT message received by Windows GUI thread - ignored\n");
160 TranslateMessage( &msg
);
161 DispatchMessageA (&msg
);
163 if (msg
.message
!= WM_TIMER
) {
167 pthread_mutex_lock (&plugin_mutex
);
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
175 for (fst
= fst_first
; fst
; fst
= fst
->next
) {
177 pthread_mutex_lock (&fst
->lock
);
179 if (fst
->has_editor
== 1) {
182 fprintf (stderr
, "%s scheduled for destroy\n", fst
->handle
->name
);
184 fst
->plugin
->dispatcher( fst
->plugin
, effEditClose
, 0, 0, NULL
, 0.0 );
185 CloseWindow (fst
->window
);
187 fst
->destroy
= FALSE
;
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
);
196 if (fst
->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
);
204 /* condition/unlock: it was signalled & unlocked in fst_create_editor() */
208 if (fst
->dispatcher_wantcall
) {
209 fst
->dispatcher_retval
= fst
->plugin
->dispatcher( fst
->plugin
,
210 fst
->dispatcher_opcode
,
211 fst
->dispatcher_index
,
214 fst
->dispatcher_opt
);
215 fst
->dispatcher_wantcall
= 0;
216 pthread_cond_signal (&fst
->plugin_dispatcher_called
);
219 fst
->plugin
->dispatcher (fst
->plugin
, effEditIdle
, 0, 0, NULL
, 0);
222 fst
->plugin
->dispatcher (fst
->plugin
, 53, 0, 0, NULL
, 0);
225 /* Dispatch messages to send keypresses to the plugin */
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 ...
233 if (fst
->pending_keys
[i
].special
!= 0) {
234 msg
.message
= WM_KEYDOWN
;
235 msg
.wParam
= fst
->pending_keys
[i
].special
;
237 msg
.message
= WM_CHAR
;
238 msg
.wParam
= fst
->pending_keys
[i
].character
;
240 msg
.hwnd
= GetFocus ();
242 DispatchMessageA (&msg
);
245 fst
->n_pending_keys
= 0;
247 /* See comment for maybe_set_program call below */
248 maybe_set_program (fst
);
249 fst
->want_program
= -1;
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.
261 if (fst
->program_set_without_editor
== 0) {
262 maybe_set_program (fst
);
263 fst
->program_set_without_editor
= 1;
266 pthread_mutex_unlock (&fst
->lock
);
269 pthread_mutex_unlock (&plugin_mutex
);
276 fst_init (void* possible_hmodule
)
281 if (possible_hmodule
) {
282 hInst
= (HMODULE
) possible_hmodule
;
283 } else if ((hInst
= GetModuleHandleA (NULL
)) == NULL
) {
284 fst_error ("can't get module handle");
288 wclass
.cbSize
= sizeof(WNDCLASSEX
);
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";
302 if (!RegisterClassExA(&wclass
)){
303 printf( "Class register failed :(\n" );
307 fst_error ("Startup win32 GUI thread\n");
309 if (CreateThread (NULL
, 0, gui_event_loop
, NULL
, 0, NULL
) == NULL
) {
310 fst_error ("could not create new thread proxy");
314 #ifdef HAVE_JACK_SET_THREAD_CREATOR
315 jack_set_thread_creator (wine_pthread_create
);
329 fst_run_editor (FST
* fst
)
331 /* wait for the plugin editor window to be created (or not) */
333 pthread_mutex_lock (&fst
->lock
);
338 pthread_cond_wait (&fst
->window_status_change
, &fst
->lock
);
340 pthread_mutex_unlock (&fst
->lock
);
350 fst_call_dispatcher (FST
*fst
, int opcode
, int index
, int val
, void *ptr
, float opt
)
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;
360 pthread_cond_wait (&fst
->plugin_dispatcher_called
, &fst
->lock
);
361 pthread_mutex_unlock (&fst
->lock
);
363 return fst
->dispatcher_retval
;
367 fst_create_editor (FST
* fst
)
373 /* "guard point" to trap errors that occur during plugin loading */
375 /* Note: fst->lock is held while this function is called */
377 if (!(fst
->plugin
->flags
& effFlagsHasEditor
)) {
378 fst_error ("Plugin \"%s\" has no editor", fst
->handle
->name
);
382 if ((hInst
= GetModuleHandleA (NULL
)) == NULL
) {
383 fst_error ("can't get module handle");
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),
392 // CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
396 fst_error ("cannot create editor window");
400 if (!SetPropA (window
, "fst_ptr", fst
)) {
401 fst_error ("cannot set fst_ptr on window");
404 fst
->window
= window
;
405 // fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
408 //printf( "effEditOpen......\n" );
409 fst
->plugin
->dispatcher (fst
->plugin
, effEditOpen
, 0, 0, fst
->window
, 0 );
410 fst
->plugin
->dispatcher (fst
->plugin
, effEditGetRect
, 0, 0, &er
, 0 );
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 );
416 //SetWindowPos (fst->window, 0, 9999, 9999, er->right-er->left+8, er->bottom-er->top+26, 0);
417 SetWindowPos (fst
->window
, 0, 9999, 9999, 2, 2, 0);
418 ShowWindow (fst
->window
, SW_SHOWNA
);
419 //SetWindowPos (fst->window, 0, 0, 0, er->right-er->left+8, er->bottom-er->top+26, SWP_NOMOVE|SWP_NOZORDER);
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
);
430 fst_move_window_into_view (FST
* fst
)
433 SetWindowPos (fst
->window
, 0, 0, 0, fst
->width
, fst
->height
+24, 0);
434 ShowWindow (fst
->window
, SW_SHOWNA
);
439 fst_destroy_editor (FST
* fst
)
441 pthread_mutex_lock (&fst
->lock
);
443 fprintf (stderr
, "mark %s for destroy\n", fst
->handle
->name
);
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");
449 pthread_cond_wait (&fst
->window_status_change
, &fst
->lock
);
450 fprintf (stderr
, "%s editor destroyed\n", fst
->handle
->name
);
453 pthread_mutex_unlock (&fst
->lock
);
457 fst_event_loop_remove_plugin (FST
* fst
)
462 for (p
= fst_first
, prev
= NULL
; p
->next
; prev
= p
, p
= p
->next
) {
465 prev
->next
= p
->next
;
470 if (fst_first
== fst
) {
471 fst_first
= fst_first
->next
;
477 fst_load_vst_library(const char * path
)
486 if ((dll
= LoadLibraryA (path
)) != NULL
) {
490 envdup
= getenv ("VST_PATH");
491 if (envdup
== NULL
) {
495 envdup
= strdup (envdup
);
496 if (envdup
== NULL
) {
497 fst_error ("strdup failed");
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';
513 if ((dll
= LoadLibraryA (full_path
)) != NULL
) {
517 vst_path
= strtok (NULL
, ":");
526 fst_load (const char *path
)
532 fhandle
= fst_handle_new ();
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 :(
537 if (strstr (path
, ".dll") == NULL
) {
539 buf
= (char *) malloc (strlen (path
) + 7);
541 if( path
[0] == '/' ) {
542 sprintf (buf
, "Z:%s.dll", path
);
544 sprintf (buf
, "%s.dll", path
);
547 fhandle
->nameptr
= strdup (path
);
551 buf
= (char *) malloc (strlen (path
) + 3);
553 if( path
[0] == '/' ) {
554 sprintf (buf
, "Z:%s", path
);
556 sprintf (buf
, "%s", path
);
559 fhandle
->nameptr
= strdup (path
);
562 fhandle
->name
= basename (fhandle
->nameptr
);
566 if ((period
= strrchr (fhandle
->name
, '.')) != NULL
) {
570 if ((fhandle
->dll
= fst_load_vst_library (buf
)) == NULL
) {
571 fst_unload (fhandle
);
575 if ((fhandle
->main_entry
= (main_entry_t
) GetProcAddress (fhandle
->dll
, "main")) == NULL
) {
576 fst_unload (fhandle
);
584 fst_unload (FSTHandle
* fhandle
)
586 if (fhandle
->plugincnt
) {
591 FreeLibrary (fhandle
->dll
);
595 if (fhandle
->nameptr
) {
596 free (fhandle
->nameptr
);
597 fhandle
->name
= NULL
;
605 fst_instantiate (FSTHandle
* fhandle
, audioMasterCallback amc
, void* userptr
)
607 FST
* fst
= fst_new ();
609 pthread_mutex_lock (&plugin_mutex
);
611 if (fst_first
== NULL
) {
621 pthread_mutex_unlock (&plugin_mutex
);
623 if( fhandle
== NULL
) {
624 fst_error( "the handle was NULL\n" );
628 if ((fst
->plugin
= fhandle
->main_entry (amc
)) == NULL
) {
629 fst_error ("%s could not be instantiated\n", fhandle
->name
);
634 fst
->handle
= fhandle
;
635 fst
->plugin
->user
= userptr
;
637 if (fst
->plugin
->magic
!= kEffectMagic
) {
638 fst_error ("%s is not a VST plugin\n", fhandle
->name
);
643 fst
->plugin
->dispatcher (fst
->plugin
, effOpen
, 0, 0, 0, 0);
644 //fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
646 fst
->vst_version
= fst
->plugin
->dispatcher (fst
->plugin
, effGetVstVersion
, 0, 0, 0, 0);
648 fst
->handle
->plugincnt
++;
657 fst_destroy_editor (fst
);
659 fst
->plugin
->dispatcher (fst
->plugin
, effMainsChanged
, 0, 0, NULL
, 0);
660 fst
->plugin
->dispatcher (fst
->plugin
, effClose
, 0, 0, 0, 0);
662 if (fst
->handle
->plugincnt
) {
663 --fst
->handle
->plugincnt
;
668 fst_get_XID (FST
* fst
)
673 float htonf (float v
)
676 char * fin
= (char*)&v
;
677 char * fout
= (char*)&result
;
686 int fst_load_state (FST
* fst
, char * filename
)
688 FILE * f
= fopen (filename
, "rb");
690 char testMagic
[sizeof (magic
)];
691 fread (&testMagic
, sizeof (magic
), 1, f
);
692 if (strcmp (testMagic
, magic
)) {
693 printf ("File corrupt\n");
697 char productString
[64];
698 char vendorString
[64];
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
);
710 success
= fst_call_dispatcher( fst
, effGetProductString
, 0, 0, testString
, 0 );
712 if (strcmp (testString
, productString
) != 0) {
713 printf ("Product string mismatch! Plugin has: %s\n", testString
);
717 } else if (length
!= 0) {
718 printf ("Product string mismatch! Plugin has none.\n", testString
);
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
);
729 success
= fst_call_dispatcher( fst
, effGetEffectName
, 0, 0, testString
, 0 );
731 if (strcmp (testString
, effectName
) != 0) {
732 printf ("Effect name mismatch! Plugin has: %s\n", testString
);
736 } else if (length
!= 0) {
737 printf ("Effect name mismatch! Plugin has none.\n", testString
);
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
);
748 success
= fst_call_dispatcher( fst
, effGetVendorString
, 0, 0, testString
, 0 );
750 if (strcmp (testString
, vendorString
) != 0) {
751 printf ("Vendor string mismatch! Plugin has: %s\n", testString
);
755 } else if (length
!= 0) {
756 printf ("Vendor string mismatch! Plugin has none.\n", testString
);
763 fread (&numParam
, sizeof (int), 1, f
);
764 numParam
= htonl (numParam
);
765 for (i
= 0; i
< numParam
; ++i
) {
767 fread (&val
, sizeof (float), 1, f
);
770 pthread_mutex_lock( &fst
->lock
);
771 fst
->plugin
->setParameter( fst
->plugin
, i
, val
);
772 pthread_mutex_unlock( &fst
->lock
);
776 fread (&bytelen
, sizeof (int), 1, f
);
777 bytelen
= htonl (bytelen
);
779 char * buf
= malloc (bytelen
);
780 fread (buf
, bytelen
, 1, f
);
782 fst_call_dispatcher( fst
, 24, 0, bytelen
, buf
, 0 );
786 printf ("Could not open state file\n");
794 int fst_save_state (FST
* fst
, char * filename
)
796 FILE * f
= fopen (filename
, "wb");
801 int numParams
= fst
->plugin
->numParams
;
802 char productString
[64];
804 char vendorString
[64];
808 fprintf( f
, "<plugin_state>\n" );
810 success
= fst_call_dispatcher( fst
, effGetProductString
, 0, 0, productString
, 0 );
812 fprintf (f
, " <check field=\"productString\" value=\"%s\"/>\n", productString
);
814 printf ("No product string\n");
817 success
= fst_call_dispatcher( fst
, effGetEffectName
, 0, 0, effectName
, 0 );
819 fprintf (f
, " <check field=\"effectName\" value=\"%s\"/>\n", effectName
);
820 printf ("Effect name: %s\n", effectName
);
822 printf ("No effect name\n");
825 success
= fst_call_dispatcher( fst
, effGetVendorString
, 0, 0, vendorString
, 0 );
827 fprintf (f
, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString
);
828 printf ("Vendor string: %s\n", vendorString
);
830 printf ("No vendor string\n");
834 if( fst
->plugin
->flags
& 32 ) {
838 for (j
= 0; j
< numParams
; ++j
) {
841 pthread_mutex_lock( &fst
->lock
);
842 val
= fst
->plugin
->getParameter (fst
->plugin
, j
);
843 pthread_mutex_unlock( &fst
->lock
);
844 fprintf( f
, " <param index=\"%d\" value=\"%f\"/>\n", j
, val
);
847 if( fst
->plugin
->flags
& 32 ) {
848 printf( "getting chunk...\n" );
850 bytelen
= fst_call_dispatcher( fst
, 23, 0, 0, &chunk
, 0 );
851 printf( "got tha chunk..\n" );
854 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
856 char *encoded
= g_base64_encode( chunk
, bytelen
);
857 fprintf( f
, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen
, encoded
);
863 fprintf( f
, "</plugin_state>\n" );
866 printf ("Could not open state file\n");