3 #include <jack/thread.h>
7 #include <wine/exception.h>
24 static pthread_mutex_t plugin_mutex
;
25 static FST
* fst_first
= NULL
;
26 const char magic
[] = "FST Plugin State v002";
28 DWORD gui_thread_id
= 0;
29 static int gui_quit
= 0;
31 #define DELAYED_WINDOW 1
35 my_window_proc (HWND w
, UINT msg
, WPARAM wp
, LPARAM lp
)
38 if (msg
!= WM_TIMER
) {
39 fst_error ("window callback handler, msg = 0x%x win=%p\n", msg
, w
);
49 /* we don't care about windows closing ... */
55 /* we don't care about windows being destroyed ... */
63 return DefWindowProcA (w
, msg
, wp
, lp
);
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;
81 FSTHandle
* fst
= (FSTHandle
*) calloc (1, sizeof (FSTHandle
));
85 DWORD WINAPI
gui_event_loop (LPVOID param
)
92 gui_thread_id
= GetCurrentThreadId ();
94 /* create a dummy window for timer events */
96 if ((hInst
= GetModuleHandleA (NULL
)) == NULL
) {
97 fst_error ("can't get module handle");
101 if ((window
= CreateWindowExA (0, "FST", "dummy",
102 WS_OVERLAPPEDWINDOW
& ~WS_THICKFRAME
& ~WS_MAXIMIZEBOX
,
108 fst_error ("cannot create dummy timer window");
111 if (!SetTimer (window
, 1000, 20, NULL
)) {
112 fst_error ("cannot set timer on dummy window");
117 if (!GetMessageA (&msg
, NULL
, 0,0)) {
119 fprintf (stderr
, "QUIT message received by Windows GUI thread - ignored\n");
126 TranslateMessage( &msg
);
127 DispatchMessageA (&msg
);
129 /* handle window creation requests, destroy requests,
130 and run idle callbacks
133 if (msg
.message
== WM_TIMER
) {
134 pthread_mutex_lock (&plugin_mutex
);
137 for (fst
= fst_first
; fst
; fst
= fst
->next
) {
139 pthread_mutex_lock (&fst
->lock
);
142 fprintf (stderr
, "%s scheduled for destroy\n", fst
->handle
->name
);
144 fst
->plugin
->dispatcher( fst
->plugin
, effEditClose
, 0, 0, NULL
, 0.0 );
145 CloseWindow (fst
->window
);
147 fst
->destroy
= FALSE
;
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
);
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
);
164 /* condition/unlock: it was signalled & unlocked in fst_create_editor() */
168 if (fst
->want_program
!= -1 ) {
169 if (fst
->vst_version
>= 2) {
170 fst
->plugin
->dispatcher (fst
->plugin
, 67 /* effBeginSetProgram */, 0, 0, NULL
, 0);
173 fst
->plugin
->dispatcher (fst
->plugin
, effSetProgram
, 0, fst
->want_program
, NULL
, 0);
175 if (fst
->vst_version
>= 2) {
176 fst
->plugin
->dispatcher (fst
->plugin
, 68 /* effEndSetProgram */, 0, 0, NULL
, 0);
179 fst
->current_program
= fst
->plugin
->dispatcher (fst
->plugin
, 3, /* effGetProgram */ 0, 0, NULL
, 0);
180 fst
->want_program
= -1;
183 if(fst
->dispatcher_wantcall
) {
184 fst
->dispatcher_retval
= fst
->plugin
->dispatcher( fst
->plugin
,
185 fst
->dispatcher_opcode
,
186 fst
->dispatcher_index
,
189 fst
->dispatcher_opt
);
190 fst
->dispatcher_wantcall
= 0;
191 pthread_cond_signal (&fst
->plugin_dispatcher_called
);
194 fst
->plugin
->dispatcher (fst
->plugin
, effEditIdle
, 0, 0, NULL
, 0);
196 if( fst
->wantIdle
) {
197 fst
->plugin
->dispatcher (fst
->plugin
, 53, 0, 0, NULL
, 0);
200 pthread_mutex_unlock (&fst
->lock
);
202 pthread_mutex_unlock (&plugin_mutex
);
211 fst_init (void* possible_hmodule
)
216 if (possible_hmodule
) {
217 hInst
= (HMODULE
) possible_hmodule
;
218 } else if ((hInst
= GetModuleHandleA (NULL
)) == NULL
) {
219 fst_error ("can't get module handle");
223 wclass
.cbSize
= sizeof(WNDCLASSEX
);
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";
237 if (!RegisterClassExA(&wclass
)){
238 printf( "Class register failed :(\n" );
242 fst_error ("Startup win32 GUI thread\n");
244 if (CreateThread (NULL
, 0, gui_event_loop
, NULL
, 0, NULL
) == NULL
) {
245 fst_error ("could not create new thread proxy");
249 #ifdef HAVE_JACK_SET_THREAD_CREATOR
250 jack_set_thread_creator (wine_pthread_create
);
264 fst_run_editor (FST
* fst
)
266 pthread_mutex_lock (&plugin_mutex
);
268 if (fst_first
== NULL
) {
278 pthread_mutex_unlock (&plugin_mutex
);
280 /* wait for the plugin editor window to be created (or not) */
282 pthread_mutex_lock (&fst
->lock
);
284 pthread_cond_wait (&fst
->window_status_change
, &fst
->lock
);
286 pthread_mutex_unlock (&fst
->lock
);
296 fst_call_dispatcher (FST
*fst
, int opcode
, int index
, int val
, void *ptr
, float opt
)
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;
306 pthread_cond_wait (&fst
->plugin_dispatcher_called
, &fst
->lock
);
307 pthread_mutex_unlock (&fst
->lock
);
309 return fst
->dispatcher_retval
;
313 fst_create_editor (FST
* fst
)
319 /* "guard point" to trap errors that occur during plugin loading */
321 /* Note: fst->lock is held while this function is called */
323 if (!(fst
->plugin
->flags
& effFlagsHasEditor
)) {
324 fst_error ("Plugin \"%s\" has no editor", fst
->handle
->name
);
328 if ((hInst
= GetModuleHandleA (NULL
)) == NULL
) {
329 fst_error ("can't get module handle");
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),
338 // CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
342 fst_error ("cannot create editor window");
346 if (!SetPropA (window
, "fst_ptr", fst
)) {
347 fst_error ("cannot set fst_ptr on window");
350 fst
->window
= window
;
351 // fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
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 );
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 );
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);
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
);
376 fst_move_window_into_view (FST
* fst
)
379 SetWindowPos (fst
->window
, 0, 0, 0, fst
->width
, fst
->height
+24, 0);
380 ShowWindow (fst
->window
, SW_SHOWNA
);
385 fst_destroy_editor (FST
* fst
)
387 pthread_mutex_lock (&fst
->lock
);
389 fprintf (stderr
, "mark %s for destroy\n", fst
->handle
->name
);
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");
395 pthread_cond_wait (&fst
->window_status_change
, &fst
->lock
);
396 fprintf (stderr
, "%s editor destroyed\n", fst
->handle
->name
);
399 pthread_mutex_unlock (&fst
->lock
);
403 fst_event_loop_remove_plugin (FST
* fst
)
408 for (p
= fst_first
, prev
= NULL
; p
->next
; prev
= p
, p
= p
->next
) {
411 prev
->next
= p
->next
;
416 if (fst_first
== fst
) {
417 fst_first
= fst_first
->next
;
423 fst_load_vst_library(const char * path
)
432 if ((dll
= LoadLibraryA (path
)) != NULL
) {
436 envdup
= getenv ("VST_PATH");
437 if (envdup
== NULL
) {
441 envdup
= strdup (envdup
);
442 if (envdup
== NULL
) {
443 fst_error ("strdup failed");
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';
459 if ((dll
= LoadLibraryA (full_path
)) != NULL
) {
463 vst_path
= strtok (NULL
, ":");
472 fst_load (const char *path
)
478 fhandle
= fst_handle_new ();
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 :(
483 if (strstr (path
, ".dll") == NULL
) {
485 buf
= (char *) malloc (strlen (path
) + 7);
487 if( path
[0] == '/' ) {
488 sprintf (buf
, "Z:%s.dll", path
);
490 sprintf (buf
, "%s.dll", path
);
493 fhandle
->nameptr
= strdup (path
);
497 buf
= (char *) malloc (strlen (path
) + 3);
499 if( path
[0] == '/' ) {
500 sprintf (buf
, "Z:%s", path
);
502 sprintf (buf
, "%s", path
);
505 fhandle
->nameptr
= strdup (path
);
508 fhandle
->name
= basename (fhandle
->nameptr
);
512 if ((period
= strrchr (fhandle
->name
, '.')) != NULL
) {
516 if ((fhandle
->dll
= fst_load_vst_library (buf
)) == NULL
) {
517 fst_unload (fhandle
);
521 if ((fhandle
->main_entry
= (main_entry_t
) GetProcAddress (fhandle
->dll
, "main")) == NULL
) {
522 fst_unload (fhandle
);
530 fst_unload (FSTHandle
* fhandle
)
532 if (fhandle
->plugincnt
) {
537 FreeLibrary (fhandle
->dll
);
541 if (fhandle
->nameptr
) {
542 free (fhandle
->nameptr
);
543 fhandle
->name
= NULL
;
551 fst_instantiate (FSTHandle
* fhandle
, audioMasterCallback amc
, void* userptr
)
553 FST
* fst
= fst_new ();
555 if( fhandle
== NULL
) {
556 fst_error( "the handle was NULL\n" );
560 if ((fst
->plugin
= fhandle
->main_entry (amc
)) == NULL
) {
561 fst_error ("%s could not be instantiated\n", fhandle
->name
);
566 fst
->handle
= fhandle
;
567 fst
->plugin
->user
= userptr
;
569 if (fst
->plugin
->magic
!= kEffectMagic
) {
570 fst_error ("%s is not a VST plugin\n", fhandle
->name
);
575 fst
->plugin
->dispatcher (fst
->plugin
, effOpen
, 0, 0, 0, 0);
576 //fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
578 fst
->vst_version
= fst
->plugin
->dispatcher (fst
->plugin
, effGetVstVersion
, 0, 0, 0, 0);
580 fst
->handle
->plugincnt
++;
589 fst_destroy_editor (fst
);
591 fst
->plugin
->dispatcher (fst
->plugin
, effMainsChanged
, 0, 0, NULL
, 0);
592 fst
->plugin
->dispatcher (fst
->plugin
, effClose
, 0, 0, 0, 0);
594 if (fst
->handle
->plugincnt
) {
595 --fst
->handle
->plugincnt
;
600 fst_get_XID (FST
* fst
)
605 float htonf (float v
)
608 char * fin
= (char*)&v
;
609 char * fout
= (char*)&result
;
618 int fst_load_state (FST
* fst
, char * filename
)
620 FILE * f
= fopen (filename
, "rb");
622 char testMagic
[sizeof (magic
)];
623 fread (&testMagic
, sizeof (magic
), 1, f
);
624 if (strcmp (testMagic
, magic
)) {
625 printf ("File corrupt\n");
629 char productString
[64];
630 char vendorString
[64];
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
);
642 success
= fst_call_dispatcher( fst
, effGetProductString
, 0, 0, testString
, 0 );
644 if (strcmp (testString
, productString
) != 0) {
645 printf ("Product string mismatch! Plugin has: %s\n", testString
);
649 } else if (length
!= 0) {
650 printf ("Product string mismatch! Plugin has none.\n", testString
);
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
);
661 success
= fst_call_dispatcher( fst
, effGetEffectName
, 0, 0, testString
, 0 );
663 if (strcmp (testString
, effectName
) != 0) {
664 printf ("Effect name mismatch! Plugin has: %s\n", testString
);
668 } else if (length
!= 0) {
669 printf ("Effect name mismatch! Plugin has none.\n", testString
);
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
);
680 success
= fst_call_dispatcher( fst
, effGetVendorString
, 0, 0, testString
, 0 );
682 if (strcmp (testString
, vendorString
) != 0) {
683 printf ("Vendor string mismatch! Plugin has: %s\n", testString
);
687 } else if (length
!= 0) {
688 printf ("Vendor string mismatch! Plugin has none.\n", testString
);
695 fread (&numParam
, sizeof (int), 1, f
);
696 numParam
= htonl (numParam
);
697 for (i
= 0; i
< numParam
; ++i
) {
699 fread (&val
, sizeof (float), 1, f
);
702 pthread_mutex_lock( &fst
->lock
);
703 fst
->plugin
->setParameter( fst
->plugin
, i
, val
);
704 pthread_mutex_unlock( &fst
->lock
);
708 fread (&bytelen
, sizeof (int), 1, f
);
709 bytelen
= htonl (bytelen
);
711 char * buf
= malloc (bytelen
);
712 fread (buf
, bytelen
, 1, f
);
714 fst_call_dispatcher( fst
, 24, 0, bytelen
, buf
, 0 );
718 printf ("Could not open state file\n");
726 int fst_save_state (FST
* fst
, char * filename
)
728 FILE * f
= fopen (filename
, "wb");
731 int numParams
= fst
->plugin
->numParams
;
733 char productString
[64];
735 char vendorString
[64];
739 fprintf( f
, "<plugin_state>\n" );
741 success
= fst_call_dispatcher( fst
, effGetProductString
, 0, 0, productString
, 0 );
743 fprintf (f
, " <check field=\"productString\" value=\"%s\"/>\n", productString
);
745 printf ("No product string\n");
748 success
= fst_call_dispatcher( fst
, effGetEffectName
, 0, 0, effectName
, 0 );
750 fprintf (f
, " <check field=\"effectName\" value=\"%s\"/>\n", effectName
);
751 printf ("Effect name: %s\n", effectName
);
753 printf ("No effect name\n");
756 success
= fst_call_dispatcher( fst
, effGetVendorString
, 0, 0, vendorString
, 0 );
758 fprintf (f
, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString
);
759 printf ("Vendor string: %s\n", vendorString
);
761 printf ("No vendor string\n");
765 if( fst
->plugin
->flags
& 32 ) {
769 for( i
=0; i
<numParams
; i
++ ) {
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
);
778 if( fst
->plugin
->flags
& 32 ) {
779 printf( "getting chunk...\n" );
781 bytelen
= fst_call_dispatcher( fst
, 23, 0, 0, &chunk
, 0 );
782 printf( "got tha chunk..\n" );
785 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
787 char *encoded
= g_base64_encode( chunk
, bytelen
);
788 fprintf( f
, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen
, encoded
);
794 fprintf( f
, "</plugin_state>\n" );
797 printf ("Could not open state file\n");