5 #include <wine/exception.h>
22 static pthread_mutex_t plugin_mutex
;
23 static FST
* fst_first
= NULL
;
24 const char magic
[] = "FST Plugin State v002";
26 DWORD gui_thread_id
= 0;
28 extern boolean g_quit
;
33 #define DELAYED_WINDOW 1
37 my_window_proc (HWND w
, UINT msg
, WPARAM wp
, LPARAM lp
)
42 // if (msg != WM_TIMER) {
43 // fst_error ("window callback handler, msg = 0x%x win=%p\n", msg, w);
56 /* we should never get these */
61 if ((fst
= GetPropA (w
, "fst_ptr")) != NULL
) {
62 if (fst
->window
&& !fst
->been_activated
) {
63 fst
->been_activated
= TRUE
;
64 pthread_cond_signal (&fst
->window_status_change
);
65 pthread_mutex_unlock (&fst
->lock
);
73 fst
= GetPropA( w
, "fst_ptr" );
75 printf( "Timer without fst_ptr Prop :(\n" );
79 fst
->plugin
->dispatcher(fst
->plugin
, effEditIdle
, 0, 0, NULL
, 0.0f
);
81 fst
->plugin
->dispatcher(fst
->plugin
, 53, 0, 0, NULL
, 0.0f
);
91 return DefWindowProcA (w
, msg
, wp
, lp
);
98 FST
* fst
= (FST
*) calloc (1, sizeof (FST
));
99 pthread_mutex_init (&fst
->lock
, NULL
);
100 pthread_cond_init (&fst
->window_status_change
, NULL
);
101 pthread_cond_init (&fst
->plugin_dispatcher_called
, NULL
);
102 fst
->want_program
= -1;
109 FSTHandle
* fst
= (FSTHandle
*) calloc (1, sizeof (FSTHandle
));
113 DWORD WINAPI
gui_event_loop (LPVOID param
)
121 gui_thread_id
= GetCurrentThreadId ();
123 /* create a dummy window for timer events */
125 if ((hInst
= GetModuleHandleA (NULL
)) == NULL
) {
126 fst_error ("can't get module handle");
130 if ((window
= CreateWindowExA (0, "FST", "dummy",
131 WS_OVERLAPPEDWINDOW
& ~WS_THICKFRAME
& ~WS_MAXIMIZEBOX
,
137 fst_error ("cannot create dummy timer window");
140 if (!SetTimer (window
, 1000, 20, NULL
)) {
141 fst_error ("cannot set timer on dummy window");
144 while (GetMessageA (&msg
, NULL
, 0,0)) {
145 TranslateMessage( &msg
);
146 DispatchMessageA (&msg
);
148 /* handle window creation requests, destroy requests,
149 and run idle callbacks
153 if( msg
.message
== WM_TIMER
) {
154 pthread_mutex_lock (&plugin_mutex
);
156 for (fst
= fst_first
; fst
; fst
= fst
->next
) {
160 fst
->plugin
->dispatcher( fst
->plugin
, effEditClose
, 0, 0, NULL
, 0.0 );
161 CloseWindow (fst
->window
);
163 fst
->destroy
= FALSE
;
165 fst_event_loop_remove_plugin (fst
);
166 fst
->been_activated
= FALSE
;
167 pthread_mutex_lock (&fst
->lock
);
168 pthread_cond_signal (&fst
->window_status_change
);
169 pthread_mutex_unlock (&fst
->lock
);
173 if (fst
->window
== NULL
) {
174 pthread_mutex_lock (&fst
->lock
);
175 if (fst_create_editor (fst
)) {
176 fst_error ("cannot create editor for plugin %s", fst
->handle
->name
);
177 fst_event_loop_remove_plugin (fst
);
178 pthread_cond_signal (&fst
->window_status_change
);
179 pthread_mutex_unlock (&fst
->lock
);
182 /* condition/unlock handled when we receive WM_ACTIVATE */
183 /* XXX: not true. its unlocked in fst_create_editor() */
185 if(fst
->want_program
!= -1 ) {
186 fst
->plugin
->dispatcher (fst
->plugin
, effSetProgram
, 0, fst
->want_program
, NULL
, 0);
187 fst
->want_program
= -1;
190 if(fst
->dispatcher_wantcall
) {
192 pthread_mutex_lock (&fst
->lock
);
193 fst
->dispatcher_retval
= fst
->plugin
->dispatcher( fst
->plugin
, fst
->dispatcher_opcode
,
194 fst
->dispatcher_index
,
197 fst
->dispatcher_opt
);
198 fst
->dispatcher_wantcall
= 0;
199 pthread_cond_signal (&fst
->plugin_dispatcher_called
);
200 pthread_mutex_unlock (&fst
->lock
);
203 pthread_mutex_lock (&fst
->lock
);
204 fst
->plugin
->dispatcher (fst
->plugin
, effEditIdle
, 0, 0, NULL
, 0);
205 if( fst
->wantIdle
) {
206 fst
->plugin
->dispatcher (fst
->plugin
, 53, 0, 0, NULL
, 0);
208 pthread_mutex_unlock (&fst
->lock
);
210 pthread_mutex_unlock (&plugin_mutex
);
213 //printf( "quit........\n" );
219 fst_init (HMODULE hInst
)
224 //if ((hInst = GetModuleHandleA (NULL)) == NULL) {
225 // fst_error ("can't get module handle");
228 wclass
.cbSize
= sizeof(WNDCLASSEX
);
230 wclass
.lpfnWndProc
= my_window_proc
;
231 wclass
.cbClsExtra
= 0;
232 wclass
.cbWndExtra
= 0;
233 wclass
.hInstance
= hInst
;
234 wclass
.hIcon
= LoadIcon(hInst
, "FST");
235 wclass
.hCursor
= LoadCursor(0, IDI_APPLICATION
);
236 // wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
237 wclass
.lpszMenuName
= "MENU_FST";
238 wclass
.lpszClassName
= "FST";
243 wc
.lpfnWndProc
= my_window_proc
;
246 wc
.hInstance
= hInst
;
247 wc
.hIcon
= LoadIconA( hInst
, "FST");
248 wc
.hCursor
= LoadCursorA( NULL
, IDI_APPLICATION
);
249 wc
.hbrBackground
= GetStockObject( BLACK_BRUSH
);
250 wc
.lpszMenuName
= "FSTMENU";
251 wc
.lpszClassName
= "FST";
255 if (!RegisterClassExA(&wclass
)){
256 printf( "Class register failed :(\n" );
260 if (CreateThread (NULL
, 0, gui_event_loop
, NULL
, 0, NULL
) == NULL
) {
261 fst_error ("could not create new thread proxy");
268 fst_run_editor (FST
* fst
)
270 pthread_mutex_lock (&plugin_mutex
);
272 if (fst_first
== NULL
) {
282 //printf( "gui_thread_id = %d\n", gui_thread_id );
283 // if (!PostThreadMessageA (gui_thread_id, WM_USER, 0, 0)) {
284 // fst_error ("could not post message to gui thread");
288 pthread_mutex_unlock (&plugin_mutex
);
290 /* wait for the plugin editor window to be created (or not) */
292 pthread_mutex_lock (&fst
->lock
);
294 pthread_cond_wait (&fst
->window_status_change
, &fst
->lock
);
296 pthread_mutex_unlock (&fst
->lock
);
299 fst_error ("no window created for VST plugin editor");
307 fst_call_dispatcher(FST
*fst
, int opcode
, int index
, int val
, void *ptr
, float opt
) {
308 pthread_mutex_lock (&fst
->lock
);
309 fst
->dispatcher_opcode
= opcode
;
310 fst
->dispatcher_index
= index
;
311 fst
->dispatcher_val
= val
;
312 fst
->dispatcher_ptr
= ptr
;
313 fst
->dispatcher_opt
= opt
;
314 fst
->dispatcher_wantcall
= 1;
316 pthread_cond_wait (&fst
->plugin_dispatcher_called
, &fst
->lock
);
317 pthread_mutex_unlock (&fst
->lock
);
319 return fst
->dispatcher_retval
;
323 fst_create_editor (FST
* fst
)
330 /* "guard point" to trap errors that occur during plugin loading */
332 /* Note: fst->lock is held while this function is called */
334 if (!(fst
->plugin
->flags
& effFlagsHasEditor
)) {
335 fst_error ("Plugin \"%s\" has no editor", fst
->handle
->name
);
339 if ((hInst
= GetModuleHandleA (NULL
)) == NULL
) {
340 fst_error ("can't get module handle");
344 // if ((window = CreateWindowExA (WS_EX_TOOLWINDOW | WS_EX_TRAYWINDOW, "FST", fst->handle->name,
345 if ((window
= CreateWindowExA (0, "FST", fst
->handle
->name
,
346 (WS_OVERLAPPEDWINDOW
& ~WS_THICKFRAME
& ~WS_MAXIMIZEBOX
),
347 // (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
349 // CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
353 fst_error ("cannot create editor window");
357 if (!SetPropA (window
, "fst_ptr", fst
)) {
358 fst_error ("cannot set fst_ptr on window");
361 fst
->window
= window
;
362 // fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
368 //printf( "effEditOpen......\n" );
369 fst
->plugin
->dispatcher (fst
->plugin
, effEditOpen
, 0, 0, fst
->window
, 0 );
370 fst
->plugin
->dispatcher (fst
->plugin
, effEditGetRect
, 0, 0, &er
, 0 );
372 fst
->width
= er
->right
-er
->left
;
373 fst
->height
= er
->bottom
-er
->top
;
374 //printf( "get rect ses... %d,%d\n", fst->width, fst->height );
376 //SetWindowPos (fst->window, 0, 9999, 9999, er->right-er->left+8, er->bottom-er->top+26, 0);
377 SetWindowPos (fst
->window
, 0, 9999, 9999, 2, 2, 0);
378 ShowWindow (fst
->window
, SW_SHOWNA
);
379 //SetWindowPos (fst->window, 0, 0, 0, er->right-er->left+8, er->bottom-er->top+26, SWP_NOMOVE|SWP_NOZORDER);
381 fst
->xid
= (int) GetPropA (window
, "__wine_x11_whole_window");
382 printf( "And xid = %x\n", fst
->xid
);
383 fst
->been_activated
= TRUE
;
384 pthread_cond_signal (&fst
->window_status_change
);
385 pthread_mutex_unlock (&fst
->lock
);
391 fst_destroy_editor (FST
* fst
)
396 pthread_mutex_lock (&fst
->lock
);
399 //if (!PostThreadMessageA (gui_thread_id, WM_USER, 0, 0)) {
400 //if (!PostThreadMessageA (gui_thread_id, WM_QUIT, 0, 0)) {
401 // fst_error ("could not post message to gui thread");
403 pthread_cond_wait (&fst
->window_status_change
, &fst
->lock
);
406 pthread_mutex_unlock (&fst
->lock
);
410 fst_event_loop_remove_plugin (FST
* fst
)
415 for (p
= fst_first
, prev
= NULL
; p
->next
; prev
= p
, p
= p
->next
) {
418 prev
->next
= p
->next
;
423 if (fst_first
== fst
) {
424 fst_first
= fst_first
->next
;
430 int gui_event_loop (FST
*fst
)
432 printf( "in gui loop\n" );
438 if ((hInst
= GetModuleHandleA (NULL
)) == NULL
) {
439 fst_error ("can't get module handle");
443 while (GetMessageA (&msg
, NULL
, 0,0)) {
444 TranslateMessage( &msg
);
445 DispatchMessageA (&msg
);
447 printf( "in gui loop\n" );
453 fst_set_focus (FST
* fst
)
456 SetFocus (fst
->window
);
461 fst_run_editor (FST
* fst
, HMODULE hInst
)
469 if (!(fst
->plugin
->flags
& effFlagsHasEditor
)) {
470 fst_error ("Plugin \"%s\" has no editor", fst
->handle
->name
);
475 //if ((hInst = GetModuleHandleA (NULL)) == NULL) {
476 // fst_error ("can't get module handle");
482 fst
->plugin
->dispatcher (fst
->plugin
, effEditGetRect
, 0, 0, &er
, 0 );
484 fst
->width
= er
->right
-er
->left
;
485 fst
->height
= er
->bottom
-er
->top
;
486 printf( "get rect ses... %d,%d\n", fst
->width
, fst
->height
);
488 //SetWindowPos (fst->window, 0, 0, 0, er->right-er->left+8, er->bottom-er->top+26, SWP_SHOWWINDOW);
490 // if ((window = CreateWindowExA (WS_EX_TOOLWINDOW | WS_EX_TRAYWINDOW, "FST", fst->handle->name,
491 if ((window
= CreateWindowExA (0, "FST", fst
->handle
->name
,
492 (WS_OVERLAPPEDWINDOW
| WS_THICKFRAME
& ~WS_MAXIMIZEBOX
),
493 CW_USEDEFAULT
, CW_USEDEFAULT
,
494 fst
->width
+8, fst
->height
+26,
498 fst_error ("cannot create editor window");
503 if (!SetPropA (window
, "fst_ptr", fst
)) {
504 fst_error ("cannot set fst_ptr on window");
507 printf( "Trying to open Editor\n" );
508 fst
->plugin
->dispatcher (fst
->plugin
, effEditOpen
, 0, 0, window
, 0 );
509 printf( "effEditOpen returned\n" );
510 ShowWindow (window
, SW_SHOW
);
512 if (!SetTimer (window
, 1000, 100, NULL
)) {
513 fst_error ("cannot set timer on dummy window");
516 fst
->window
= window
;
517 fst
->xid
= (int) GetPropA (window
, "__wine_x11_whole_window");
519 // XChangeWindowAttributes( XOpenDisplay(NULL), fst->xid, CWOverrideRedirect, ~0 );
527 fst_destroy_editor (FST
* fst
)
530 if (!PostMessageA (fst
->window
, WM_QUIT
, 0, 0)) {
531 fst_error ("could not post message to gui thread");
538 fst_load_vst_library(const char * path
)
547 if ((dll
= LoadLibraryA (path
)) != NULL
) {
551 envdup
= getenv ("VST_PATH");
552 if (envdup
== NULL
) {
556 envdup
= strdup (envdup
);
557 if (envdup
== NULL
) {
558 fst_error ("strdup failed");
564 vst_path
= strtok (envdup
, ":");
565 while (vst_path
!= NULL
) {
566 fst_error ("\"%s\"", vst_path
);
567 len1
= strlen(vst_path
);
568 full_path
= malloc (len1
+ 1 + len2
+ 1);
569 memcpy(full_path
, vst_path
, len1
);
570 full_path
[len1
] = '/';
571 memcpy(full_path
+ len1
+ 1, path
, len2
);
572 full_path
[len1
+ 1 + len2
] = '\0';
574 if ((dll
= LoadLibraryA (full_path
)) != NULL
) {
578 vst_path
= strtok (NULL
, ":");
587 fst_load (const char *path
)
593 fhandle
= fst_handle_new ();
595 // XXX: Would be nice to find the correct call for this.
596 // if the user does not configure Z: to be / we are doomed :(
598 if (strstr (path
, ".dll") == NULL
) {
600 buf
= (char *) malloc (strlen (path
) + 7);
602 if( path
[0] == '/' ) {
603 sprintf (buf
, "Z:%s.dll", path
);
605 sprintf (buf
, "%s.dll", path
);
608 fhandle
->nameptr
= strdup (path
);
612 buf
= (char *) malloc (strlen (path
) + 3);
614 if( path
[0] == '/' ) {
615 sprintf (buf
, "Z:%s", path
);
617 sprintf (buf
, "%s", path
);
620 fhandle
->nameptr
= strdup (path
);
623 fhandle
->name
= basename (fhandle
->nameptr
);
627 if ((period
= strrchr (fhandle
->name
, '.')) != NULL
) {
631 if ((fhandle
->dll
= fst_load_vst_library (buf
)) == NULL
) {
632 fst_unload (fhandle
);
636 if ((fhandle
->main_entry
= (main_entry_t
) GetProcAddress (fhandle
->dll
, "main")) == NULL
) {
637 fst_unload (fhandle
);
645 fst_unload (FSTHandle
* fhandle
)
647 if (fhandle
->plugincnt
) {
652 FreeLibrary (fhandle
->dll
);
656 if (fhandle
->nameptr
) {
657 free (fhandle
->nameptr
);
658 fhandle
->name
= NULL
;
666 fst_instantiate (FSTHandle
* fhandle
, audioMasterCallback amc
, void* userptr
)
668 FST
* fst
= fst_new ();
670 if( fhandle
== NULL
) {
671 fst_error( "the handle was NULL\n" );
675 if ((fst
->plugin
= fhandle
->main_entry (amc
)) == NULL
) {
676 fst_error ("%s could not be instantiated\n", fhandle
->name
);
681 fst
->handle
= fhandle
;
682 fst
->plugin
->user
= userptr
;
684 if (fst
->plugin
->magic
!= kEffectMagic
) {
685 fst_error ("%s is not a VST plugin\n", fhandle
->name
);
690 fst
->plugin
->dispatcher (fst
->plugin
, effOpen
, 0, 0, 0, 0);
691 //fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
693 fst
->handle
->plugincnt
++;
702 fst_destroy_editor (fst
);
704 fst
->plugin
->dispatcher (fst
->plugin
, effMainsChanged
, 0, 0, NULL
, 0);
705 fst
->plugin
->dispatcher (fst
->plugin
, effClose
, 0, 0, 0, 0);
707 if (fst
->handle
->plugincnt
) {
708 --fst
->handle
->plugincnt
;
713 fst_get_XID (FST
* fst
)
718 float htonf (float v
)
721 char * fin
= (char*)&v
;
722 char * fout
= (char*)&result
;
731 int fst_load_state (FST
* fst
, char * filename
)
733 FILE * f
= fopen (filename
, "rb");
735 char testMagic
[sizeof (magic
)];
736 fread (&testMagic
, sizeof (magic
), 1, f
);
737 if (strcmp (testMagic
, magic
)) {
738 printf ("File corrupt\n");
742 char productString
[64];
743 char vendorString
[64];
749 fread (&length
, sizeof (unsigned), 1, f
);
750 length
= htonl (length
);
751 fread (productString
, length
, 1, f
);
752 productString
[length
] = 0;
753 printf ("Product string: %s\n", productString
);
755 success
= fst_call_dispatcher( fst
, effGetProductString
, 0, 0, testString
, 0 );
757 if (strcmp (testString
, productString
) != 0) {
758 printf ("Product string mismatch! Plugin has: %s\n", testString
);
762 } else if (length
!= 0) {
763 printf ("Product string mismatch! Plugin has none.\n", testString
);
768 fread (&length
, sizeof (unsigned), 1, f
);
769 length
= htonl (length
);
770 fread (effectName
, length
, 1, f
);
771 effectName
[length
] = 0;
772 printf ("Effect name: %s\n", effectName
);
774 success
= fst_call_dispatcher( fst
, effGetEffectName
, 0, 0, testString
, 0 );
776 if (strcmp (testString
, effectName
) != 0) {
777 printf ("Effect name mismatch! Plugin has: %s\n", testString
);
781 } else if (length
!= 0) {
782 printf ("Effect name mismatch! Plugin has none.\n", testString
);
787 fread (&length
, sizeof (unsigned), 1, f
);
788 length
= htonl (length
);
789 fread (vendorString
, length
, 1, f
);
790 vendorString
[length
] = 0;
791 printf ("Vendor string: %s\n", vendorString
);
793 success
= fst_call_dispatcher( fst
, effGetVendorString
, 0, 0, testString
, 0 );
795 if (strcmp (testString
, vendorString
) != 0) {
796 printf ("Vendor string mismatch! Plugin has: %s\n", testString
);
800 } else if (length
!= 0) {
801 printf ("Vendor string mismatch! Plugin has none.\n", testString
);
808 fread (&numParam
, sizeof (int), 1, f
);
809 numParam
= htonl (numParam
);
810 for (i
= 0; i
< numParam
; ++i
) {
812 fread (&val
, sizeof (float), 1, f
);
815 pthread_mutex_lock( &fst
->lock
);
816 fst
->plugin
->setParameter( fst
->plugin
, i
, val
);
817 pthread_mutex_unlock( &fst
->lock
);
821 fread (&bytelen
, sizeof (int), 1, f
);
822 bytelen
= htonl (bytelen
);
824 char * buf
= malloc (bytelen
);
825 fread (buf
, bytelen
, 1, f
);
827 fst_call_dispatcher( fst
, 24, 0, bytelen
, buf
, 0 );
831 printf ("Could not open state file\n");
839 int fst_save_state (FST
* fst
, char * filename
)
841 FILE * f
= fopen (filename
, "wb");
844 int numParams
= fst
->plugin
->numParams
;
846 char productString
[64];
848 char vendorString
[64];
853 fprintf( f
, "<plugin_state>\n" );
855 success
= fst_call_dispatcher( fst
, effGetProductString
, 0, 0, productString
, 0 );
857 fprintf (f
, " <check field=\"productString\" value=\"%s\"/>\n", productString
);
859 printf ("No product string\n");
862 success
= fst_call_dispatcher( fst
, effGetEffectName
, 0, 0, effectName
, 0 );
864 fprintf (f
, " <check field=\"effectName\" value=\"%s\"/>\n", effectName
);
865 printf ("Effect name: %s\n", effectName
);
867 printf ("No effect name\n");
870 success
= fst_call_dispatcher( fst
, effGetVendorString
, 0, 0, vendorString
, 0 );
872 fprintf (f
, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString
);
873 printf ("Vendor string: %s\n", vendorString
);
875 printf ("No vendor string\n");
879 if( fst
->plugin
->flags
& 32 ) {
883 for( i
=0; i
<numParams
; i
++ ) {
886 pthread_mutex_lock( &fst
->lock
);
887 val
= fst
->plugin
->getParameter( fst
->plugin
, i
);
888 pthread_mutex_unlock( &fst
->lock
);
889 fprintf( f
, " <param index=\"%d\" value=\"%f\"/>\n", i
, val
);
892 if( fst
->plugin
->flags
& 32 ) {
893 printf( "getting chunk...\n" );
895 bytelen
= fst_call_dispatcher( fst
, 23, 0, 0, &chunk
, 0 );
896 printf( "got tha chunk..\n" );
899 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
901 char *encoded
= g_base64_encode( chunk
, bytelen
);
902 fprintf( f
, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen
, encoded
);
908 fprintf( f
, "</plugin_state>\n" );
911 printf ("Could not open state file\n");