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
152 if( msg.message == WM_TIMER ) {
153 pthread_mutex_lock (&plugin_mutex);
155 for (fst = fst_first; fst; fst = fst->next) {
159 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
160 CloseWindow (fst->window);
162 fst->destroy = FALSE;
164 fst_event_loop_remove_plugin (fst);
165 fst->been_activated = FALSE;
166 pthread_mutex_lock (&fst->lock);
167 pthread_cond_signal (&fst->window_status_change);
168 pthread_mutex_unlock (&fst->lock);
172 if (fst->window == NULL) {
173 pthread_mutex_lock (&fst->lock);
174 fst_error ("Creating window for FST plugin %s", fst->handle->name);
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: it was signalled & unlocked in fst_create_editor() */
184 if(fst->want_program != -1 ) {
185 fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
186 fst->want_program = -1;
189 if(fst->dispatcher_wantcall) {
191 pthread_mutex_lock (&fst->lock);
192 fst->dispatcher_retval = fst->plugin->dispatcher( fst->plugin, fst->dispatcher_opcode,
193 fst->dispatcher_index,
196 fst->dispatcher_opt );
197 fst->dispatcher_wantcall = 0;
198 pthread_cond_signal (&fst->plugin_dispatcher_called);
199 pthread_mutex_unlock (&fst->lock);
202 pthread_mutex_lock (&fst->lock);
203 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
204 if( fst->wantIdle ) {
205 fst->plugin->dispatcher (fst->plugin, 53, 0, 0, NULL, 0);
207 pthread_mutex_unlock (&fst->lock);
209 pthread_mutex_unlock (&plugin_mutex);
212 fprintf (stderr, "VST GUI EVENT LOOP THREAD EXIT\n");
217 fst_init (void* possible_hmodule)
222 if (possible_hmodule) {
223 hInst = (HMODULE) possible_hmodule;
224 } else 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 fst_error ("Startup win32 GUI thread\n");
262 if (CreateThread (NULL, 0, gui_event_loop, NULL, 0, NULL) == NULL) {
263 fst_error ("could not create new thread proxy");
270 fst_run_editor (FST* fst)
272 pthread_mutex_lock (&plugin_mutex);
274 if (fst_first == NULL) {
284 pthread_mutex_unlock (&plugin_mutex);
286 /* wait for the plugin editor window to be created (or not) */
288 pthread_mutex_lock (&fst->lock);
290 pthread_cond_wait (&fst->window_status_change, &fst->lock);
292 pthread_mutex_unlock (&fst->lock);
302 fst_call_dispatcher (FST *fst, int opcode, int index, int val, void *ptr, float opt)
304 pthread_mutex_lock (&fst->lock);
305 fst->dispatcher_opcode = opcode;
306 fst->dispatcher_index = index;
307 fst->dispatcher_val = val;
308 fst->dispatcher_ptr = ptr;
309 fst->dispatcher_opt = opt;
310 fst->dispatcher_wantcall = 1;
312 pthread_cond_wait (&fst->plugin_dispatcher_called, &fst->lock);
313 pthread_mutex_unlock (&fst->lock);
315 return fst->dispatcher_retval;
319 fst_create_editor (FST* fst)
326 /* "guard point" to trap errors that occur during plugin loading */
328 /* Note: fst->lock is held while this function is called */
330 if (!(fst->plugin->flags & effFlagsHasEditor)) {
331 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
335 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
336 fst_error ("can't get module handle");
340 // if ((window = CreateWindowExA (WS_EX_TOOLWINDOW | WS_EX_TRAYWINDOW, "FST", fst->handle->name,
341 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
342 (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
343 // (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
345 // CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
349 fst_error ("cannot create editor window");
353 if (!SetPropA (window, "fst_ptr", fst)) {
354 fst_error ("cannot set fst_ptr on window");
357 fst->window = window;
358 // fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
361 //printf( "effEditOpen......\n" );
362 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->window, 0 );
363 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
365 fst->width = er->right-er->left;
366 fst->height = er->bottom-er->top;
367 //printf( "get rect ses... %d,%d\n", fst->width, fst->height );
369 //SetWindowPos (fst->window, 0, 9999, 9999, er->right-er->left+8, er->bottom-er->top+26, 0);
370 SetWindowPos (fst->window, 0, 9999, 9999, 2, 2, 0);
371 ShowWindow (fst->window, SW_SHOWNA);
372 //SetWindowPos (fst->window, 0, 0, 0, er->right-er->left+8, er->bottom-er->top+26, SWP_NOMOVE|SWP_NOZORDER);
374 fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
375 printf( "And xid = %x\n", fst->xid );
376 fst->been_activated = TRUE;
377 printf ("Signalling window ready\n");
378 pthread_cond_signal (&fst->window_status_change);
379 pthread_mutex_unlock (&fst->lock);
385 fst_move_window_into_view (FST* fst)
388 SetWindowPos (fst->window, 0, 0, 0, fst->width, fst->height+24, 0);
389 ShowWindow (fst->window, SW_SHOWNA);
394 fst_destroy_editor (FST* fst)
399 pthread_mutex_lock (&fst->lock);
402 //if (!PostThreadMessageA (gui_thread_id, WM_USER, 0, 0)) {
403 //if (!PostThreadMessageA (gui_thread_id, WM_QUIT, 0, 0)) {
404 // fst_error ("could not post message to gui thread");
406 pthread_cond_wait (&fst->window_status_change, &fst->lock);
409 pthread_mutex_unlock (&fst->lock);
413 fst_event_loop_remove_plugin (FST* fst)
418 for (p = fst_first, prev = NULL; p->next; prev = p, p = p->next) {
421 prev->next = p->next;
426 if (fst_first == fst) {
427 fst_first = fst_first->next;
433 fst_load_vst_library(const char * path)
442 if ((dll = LoadLibraryA (path)) != NULL) {
446 envdup = getenv ("VST_PATH");
447 if (envdup == NULL) {
451 envdup = strdup (envdup);
452 if (envdup == NULL) {
453 fst_error ("strdup failed");
459 vst_path = strtok (envdup, ":");
460 while (vst_path != NULL) {
461 fst_error ("\"%s\"", vst_path);
462 len1 = strlen(vst_path);
463 full_path = malloc (len1 + 1 + len2 + 1);
464 memcpy(full_path, vst_path, len1);
465 full_path[len1] = '/';
466 memcpy(full_path + len1 + 1, path, len2);
467 full_path[len1 + 1 + len2] = '\0';
469 if ((dll = LoadLibraryA (full_path)) != NULL) {
473 vst_path = strtok (NULL, ":");
482 fst_load (const char *path)
488 fhandle = fst_handle_new ();
490 // XXX: Would be nice to find the correct call for this.
491 // if the user does not configure Z: to be / we are doomed :(
493 if (strstr (path, ".dll") == NULL) {
495 buf = (char *) malloc (strlen (path) + 7);
497 if( path[0] == '/' ) {
498 sprintf (buf, "Z:%s.dll", path);
500 sprintf (buf, "%s.dll", path);
503 fhandle->nameptr = strdup (path);
507 buf = (char *) malloc (strlen (path) + 3);
509 if( path[0] == '/' ) {
510 sprintf (buf, "Z:%s", path);
512 sprintf (buf, "%s", path);
515 fhandle->nameptr = strdup (path);
518 fhandle->name = basename (fhandle->nameptr);
522 if ((period = strrchr (fhandle->name, '.')) != NULL) {
526 if ((fhandle->dll = fst_load_vst_library (buf)) == NULL) {
527 fst_unload (fhandle);
531 if ((fhandle->main_entry = (main_entry_t) GetProcAddress (fhandle->dll, "main")) == NULL) {
532 fst_unload (fhandle);
540 fst_unload (FSTHandle* fhandle)
542 if (fhandle->plugincnt) {
547 FreeLibrary (fhandle->dll);
551 if (fhandle->nameptr) {
552 free (fhandle->nameptr);
553 fhandle->name = NULL;
561 fst_instantiate (FSTHandle* fhandle, audioMasterCallback amc, void* userptr)
563 FST* fst = fst_new ();
565 if( fhandle == NULL ) {
566 fst_error( "the handle was NULL\n" );
570 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
571 fst_error ("%s could not be instantiated\n", fhandle->name);
576 fst->handle = fhandle;
577 fst->plugin->user = userptr;
579 if (fst->plugin->magic != kEffectMagic) {
580 fst_error ("%s is not a VST plugin\n", fhandle->name);
585 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
586 //fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
588 fst->handle->plugincnt++;
597 fst_destroy_editor (fst);
599 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
600 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
602 if (fst->handle->plugincnt) {
603 --fst->handle->plugincnt;
608 fst_get_XID (FST* fst)
613 float htonf (float v)
616 char * fin = (char*)&v;
617 char * fout = (char*)&result;
626 int fst_load_state (FST * fst, char * filename)
628 FILE * f = fopen (filename, "rb");
630 char testMagic[sizeof (magic)];
631 fread (&testMagic, sizeof (magic), 1, f);
632 if (strcmp (testMagic, magic)) {
633 printf ("File corrupt\n");
637 char productString[64];
638 char vendorString[64];
644 fread (&length, sizeof (unsigned), 1, f);
645 length = htonl (length);
646 fread (productString, length, 1, f);
647 productString[length] = 0;
648 printf ("Product string: %s\n", productString);
650 success = fst_call_dispatcher( fst, effGetProductString, 0, 0, testString, 0 );
652 if (strcmp (testString, productString) != 0) {
653 printf ("Product string mismatch! Plugin has: %s\n", testString);
657 } else if (length != 0) {
658 printf ("Product string mismatch! Plugin has none.\n", testString);
663 fread (&length, sizeof (unsigned), 1, f);
664 length = htonl (length);
665 fread (effectName, length, 1, f);
666 effectName[length] = 0;
667 printf ("Effect name: %s\n", effectName);
669 success = fst_call_dispatcher( fst, effGetEffectName, 0, 0, testString, 0 );
671 if (strcmp (testString, effectName) != 0) {
672 printf ("Effect name mismatch! Plugin has: %s\n", testString);
676 } else if (length != 0) {
677 printf ("Effect name mismatch! Plugin has none.\n", testString);
682 fread (&length, sizeof (unsigned), 1, f);
683 length = htonl (length);
684 fread (vendorString, length, 1, f);
685 vendorString[length] = 0;
686 printf ("Vendor string: %s\n", vendorString);
688 success = fst_call_dispatcher( fst, effGetVendorString, 0, 0, testString, 0 );
690 if (strcmp (testString, vendorString) != 0) {
691 printf ("Vendor string mismatch! Plugin has: %s\n", testString);
695 } else if (length != 0) {
696 printf ("Vendor string mismatch! Plugin has none.\n", testString);
703 fread (&numParam, sizeof (int), 1, f);
704 numParam = htonl (numParam);
705 for (i = 0; i < numParam; ++i) {
707 fread (&val, sizeof (float), 1, f);
710 pthread_mutex_lock( &fst->lock );
711 fst->plugin->setParameter( fst->plugin, i, val );
712 pthread_mutex_unlock( &fst->lock );
716 fread (&bytelen, sizeof (int), 1, f);
717 bytelen = htonl (bytelen);
719 char * buf = malloc (bytelen);
720 fread (buf, bytelen, 1, f);
722 fst_call_dispatcher( fst, 24, 0, bytelen, buf, 0 );
726 printf ("Could not open state file\n");
734 int fst_save_state (FST * fst, char * filename)
736 FILE * f = fopen (filename, "wb");
739 int numParams = fst->plugin->numParams;
741 char productString[64];
743 char vendorString[64];
748 fprintf( f, "<plugin_state>\n" );
750 success = fst_call_dispatcher( fst, effGetProductString, 0, 0, productString, 0 );
752 fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
754 printf ("No product string\n");
757 success = fst_call_dispatcher( fst, effGetEffectName, 0, 0, effectName, 0 );
759 fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
760 printf ("Effect name: %s\n", effectName);
762 printf ("No effect name\n");
765 success = fst_call_dispatcher( fst, effGetVendorString, 0, 0, vendorString, 0 );
767 fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
768 printf ("Vendor string: %s\n", vendorString);
770 printf ("No vendor string\n");
774 if( fst->plugin->flags & 32 ) {
778 for( i=0; i<numParams; i++ ) {
781 pthread_mutex_lock( &fst->lock );
782 val = fst->plugin->getParameter( fst->plugin, i );
783 pthread_mutex_unlock( &fst->lock );
784 fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", i, val );
787 if( fst->plugin->flags & 32 ) {
788 printf( "getting chunk...\n" );
790 bytelen = fst_call_dispatcher( fst, 23, 0, 0, &chunk, 0 );
791 printf( "got tha chunk..\n" );
794 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
796 char *encoded = g_base64_encode( chunk, bytelen );
797 fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
803 fprintf( f, "</plugin_state>\n" );
806 printf ("Could not open state file\n");