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;
80 FSTHandle* fst = (FSTHandle*) calloc (1, sizeof (FSTHandle));
84 DWORD WINAPI gui_event_loop (LPVOID param)
91 gui_thread_id = GetCurrentThreadId ();
93 /* create a dummy window for timer events */
95 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
96 fst_error ("can't get module handle");
100 if ((window = CreateWindowExA (0, "FST", "dummy",
101 WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
107 fst_error ("cannot create dummy timer window");
110 if (!SetTimer (window, 1000, 20, NULL)) {
111 fst_error ("cannot set timer on dummy window");
116 if (!GetMessageA (&msg, NULL, 0,0)) {
118 fprintf (stderr, "QUIT message received by Windows GUI thread - ignored\n");
125 TranslateMessage( &msg );
126 DispatchMessageA (&msg);
128 /* handle window creation requests, destroy requests,
129 and run idle callbacks
132 if (msg.message == WM_TIMER) {
133 pthread_mutex_lock (&plugin_mutex);
136 for (fst = fst_first; fst; fst = fst->next) {
138 pthread_mutex_lock (&fst->lock);
141 fprintf (stderr, "%s scheduled for destroy\n", fst->handle->name);
143 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
144 CloseWindow (fst->window);
146 fst->destroy = FALSE;
148 fst_event_loop_remove_plugin (fst);
149 fst->been_activated = FALSE;
150 pthread_cond_signal (&fst->window_status_change);
151 pthread_mutex_unlock (&fst->lock);
155 if (fst->window == NULL) {
156 if (fst_create_editor (fst)) {
157 fst_error ("cannot create editor for plugin %s", fst->handle->name);
158 fst_event_loop_remove_plugin (fst);
159 pthread_cond_signal (&fst->window_status_change);
160 pthread_mutex_unlock (&fst->lock);
163 /* condition/unlock: it was signalled & unlocked in fst_create_editor() */
167 if (fst->want_program != -1 ) {
168 fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
169 fst->want_program = -1;
172 if(fst->dispatcher_wantcall) {
173 fst->dispatcher_retval = fst->plugin->dispatcher( fst->plugin,
174 fst->dispatcher_opcode,
175 fst->dispatcher_index,
178 fst->dispatcher_opt );
179 fst->dispatcher_wantcall = 0;
180 pthread_cond_signal (&fst->plugin_dispatcher_called);
183 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
185 if( fst->wantIdle ) {
186 fst->plugin->dispatcher (fst->plugin, 53, 0, 0, NULL, 0);
189 pthread_mutex_unlock (&fst->lock);
191 pthread_mutex_unlock (&plugin_mutex);
200 fst_init (void* possible_hmodule)
205 if (possible_hmodule) {
206 hInst = (HMODULE) possible_hmodule;
207 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
208 fst_error ("can't get module handle");
212 wclass.cbSize = sizeof(WNDCLASSEX);
214 wclass.lpfnWndProc = my_window_proc;
215 wclass.cbClsExtra = 0;
216 wclass.cbWndExtra = 0;
217 wclass.hInstance = hInst;
218 wclass.hIcon = LoadIcon(hInst, "FST");
219 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
220 // wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
221 wclass.lpszMenuName = "MENU_FST";
222 wclass.lpszClassName = "FST";
226 if (!RegisterClassExA(&wclass)){
227 printf( "Class register failed :(\n" );
231 fst_error ("Startup win32 GUI thread\n");
233 if (CreateThread (NULL, 0, gui_event_loop, NULL, 0, NULL) == NULL) {
234 fst_error ("could not create new thread proxy");
238 #ifdef HAVE_JACK_SET_THREAD_CREATOR
239 jack_set_thread_creator (wine_pthread_create);
253 fst_run_editor (FST* fst)
255 pthread_mutex_lock (&plugin_mutex);
257 if (fst_first == NULL) {
267 pthread_mutex_unlock (&plugin_mutex);
269 /* wait for the plugin editor window to be created (or not) */
271 pthread_mutex_lock (&fst->lock);
273 pthread_cond_wait (&fst->window_status_change, &fst->lock);
275 pthread_mutex_unlock (&fst->lock);
285 fst_call_dispatcher (FST *fst, int opcode, int index, int val, void *ptr, float opt)
287 pthread_mutex_lock (&fst->lock);
288 fst->dispatcher_opcode = opcode;
289 fst->dispatcher_index = index;
290 fst->dispatcher_val = val;
291 fst->dispatcher_ptr = ptr;
292 fst->dispatcher_opt = opt;
293 fst->dispatcher_wantcall = 1;
295 pthread_cond_wait (&fst->plugin_dispatcher_called, &fst->lock);
296 pthread_mutex_unlock (&fst->lock);
298 return fst->dispatcher_retval;
302 fst_create_editor (FST* fst)
308 /* "guard point" to trap errors that occur during plugin loading */
310 /* Note: fst->lock is held while this function is called */
312 if (!(fst->plugin->flags & effFlagsHasEditor)) {
313 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
317 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
318 fst_error ("can't get module handle");
322 // if ((window = CreateWindowExA (WS_EX_TOOLWINDOW | WS_EX_TRAYWINDOW, "FST", fst->handle->name,
323 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
324 (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
325 // (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX),
327 // CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
331 fst_error ("cannot create editor window");
335 if (!SetPropA (window, "fst_ptr", fst)) {
336 fst_error ("cannot set fst_ptr on window");
339 fst->window = window;
340 // fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
343 //printf( "effEditOpen......\n" );
344 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->window, 0 );
345 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
347 fst->width = er->right-er->left;
348 fst->height = er->bottom-er->top;
349 //printf( "get rect ses... %d,%d\n", fst->width, fst->height );
351 //SetWindowPos (fst->window, 0, 9999, 9999, er->right-er->left+8, er->bottom-er->top+26, 0);
352 SetWindowPos (fst->window, 0, 9999, 9999, 2, 2, 0);
353 ShowWindow (fst->window, SW_SHOWNA);
354 //SetWindowPos (fst->window, 0, 0, 0, er->right-er->left+8, er->bottom-er->top+26, SWP_NOMOVE|SWP_NOZORDER);
356 fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
357 fst->been_activated = TRUE;
358 pthread_cond_signal (&fst->window_status_change);
359 pthread_mutex_unlock (&fst->lock);
365 fst_move_window_into_view (FST* fst)
368 SetWindowPos (fst->window, 0, 0, 0, fst->width, fst->height+24, 0);
369 ShowWindow (fst->window, SW_SHOWNA);
374 fst_destroy_editor (FST* fst)
376 pthread_mutex_lock (&fst->lock);
378 fprintf (stderr, "mark %s for destroy\n", fst->handle->name);
380 //if (!PostThreadMessageA (gui_thread_id, WM_USER, 0, 0)) {
381 //if (!PostThreadMessageA (gui_thread_id, WM_QUIT, 0, 0)) {
382 // fst_error ("could not post message to gui thread");
384 pthread_cond_wait (&fst->window_status_change, &fst->lock);
385 fprintf (stderr, "%s editor destroyed\n", fst->handle->name);
388 pthread_mutex_unlock (&fst->lock);
392 fst_event_loop_remove_plugin (FST* fst)
397 for (p = fst_first, prev = NULL; p->next; prev = p, p = p->next) {
400 prev->next = p->next;
405 if (fst_first == fst) {
406 fst_first = fst_first->next;
412 fst_load_vst_library(const char * path)
421 if ((dll = LoadLibraryA (path)) != NULL) {
425 envdup = getenv ("VST_PATH");
426 if (envdup == NULL) {
430 envdup = strdup (envdup);
431 if (envdup == NULL) {
432 fst_error ("strdup failed");
438 vst_path = strtok (envdup, ":");
439 while (vst_path != NULL) {
440 fst_error ("\"%s\"", vst_path);
441 len1 = strlen(vst_path);
442 full_path = malloc (len1 + 1 + len2 + 1);
443 memcpy(full_path, vst_path, len1);
444 full_path[len1] = '/';
445 memcpy(full_path + len1 + 1, path, len2);
446 full_path[len1 + 1 + len2] = '\0';
448 if ((dll = LoadLibraryA (full_path)) != NULL) {
452 vst_path = strtok (NULL, ":");
461 fst_load (const char *path)
467 fhandle = fst_handle_new ();
469 // XXX: Would be nice to find the correct call for this.
470 // if the user does not configure Z: to be / we are doomed :(
472 if (strstr (path, ".dll") == NULL) {
474 buf = (char *) malloc (strlen (path) + 7);
476 if( path[0] == '/' ) {
477 sprintf (buf, "Z:%s.dll", path);
479 sprintf (buf, "%s.dll", path);
482 fhandle->nameptr = strdup (path);
486 buf = (char *) malloc (strlen (path) + 3);
488 if( path[0] == '/' ) {
489 sprintf (buf, "Z:%s", path);
491 sprintf (buf, "%s", path);
494 fhandle->nameptr = strdup (path);
497 fhandle->name = basename (fhandle->nameptr);
501 if ((period = strrchr (fhandle->name, '.')) != NULL) {
505 if ((fhandle->dll = fst_load_vst_library (buf)) == NULL) {
506 fst_unload (fhandle);
510 if ((fhandle->main_entry = (main_entry_t) GetProcAddress (fhandle->dll, "main")) == NULL) {
511 fst_unload (fhandle);
519 fst_unload (FSTHandle* fhandle)
521 if (fhandle->plugincnt) {
526 FreeLibrary (fhandle->dll);
530 if (fhandle->nameptr) {
531 free (fhandle->nameptr);
532 fhandle->name = NULL;
540 fst_instantiate (FSTHandle* fhandle, audioMasterCallback amc, void* userptr)
542 FST* fst = fst_new ();
544 if( fhandle == NULL ) {
545 fst_error( "the handle was NULL\n" );
549 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
550 fst_error ("%s could not be instantiated\n", fhandle->name);
555 fst->handle = fhandle;
556 fst->plugin->user = userptr;
558 if (fst->plugin->magic != kEffectMagic) {
559 fst_error ("%s is not a VST plugin\n", fhandle->name);
564 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
565 //fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
567 fst->handle->plugincnt++;
576 fst_destroy_editor (fst);
578 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
579 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
581 if (fst->handle->plugincnt) {
582 --fst->handle->plugincnt;
587 fst_get_XID (FST* fst)
592 float htonf (float v)
595 char * fin = (char*)&v;
596 char * fout = (char*)&result;
605 int fst_load_state (FST * fst, char * filename)
607 FILE * f = fopen (filename, "rb");
609 char testMagic[sizeof (magic)];
610 fread (&testMagic, sizeof (magic), 1, f);
611 if (strcmp (testMagic, magic)) {
612 printf ("File corrupt\n");
616 char productString[64];
617 char vendorString[64];
623 fread (&length, sizeof (unsigned), 1, f);
624 length = htonl (length);
625 fread (productString, length, 1, f);
626 productString[length] = 0;
627 printf ("Product string: %s\n", productString);
629 success = fst_call_dispatcher( fst, effGetProductString, 0, 0, testString, 0 );
631 if (strcmp (testString, productString) != 0) {
632 printf ("Product string mismatch! Plugin has: %s\n", testString);
636 } else if (length != 0) {
637 printf ("Product string mismatch! Plugin has none.\n", testString);
642 fread (&length, sizeof (unsigned), 1, f);
643 length = htonl (length);
644 fread (effectName, length, 1, f);
645 effectName[length] = 0;
646 printf ("Effect name: %s\n", effectName);
648 success = fst_call_dispatcher( fst, effGetEffectName, 0, 0, testString, 0 );
650 if (strcmp (testString, effectName) != 0) {
651 printf ("Effect name mismatch! Plugin has: %s\n", testString);
655 } else if (length != 0) {
656 printf ("Effect name mismatch! Plugin has none.\n", testString);
661 fread (&length, sizeof (unsigned), 1, f);
662 length = htonl (length);
663 fread (vendorString, length, 1, f);
664 vendorString[length] = 0;
665 printf ("Vendor string: %s\n", vendorString);
667 success = fst_call_dispatcher( fst, effGetVendorString, 0, 0, testString, 0 );
669 if (strcmp (testString, vendorString) != 0) {
670 printf ("Vendor string mismatch! Plugin has: %s\n", testString);
674 } else if (length != 0) {
675 printf ("Vendor string mismatch! Plugin has none.\n", testString);
682 fread (&numParam, sizeof (int), 1, f);
683 numParam = htonl (numParam);
684 for (i = 0; i < numParam; ++i) {
686 fread (&val, sizeof (float), 1, f);
689 pthread_mutex_lock( &fst->lock );
690 fst->plugin->setParameter( fst->plugin, i, val );
691 pthread_mutex_unlock( &fst->lock );
695 fread (&bytelen, sizeof (int), 1, f);
696 bytelen = htonl (bytelen);
698 char * buf = malloc (bytelen);
699 fread (buf, bytelen, 1, f);
701 fst_call_dispatcher( fst, 24, 0, bytelen, buf, 0 );
705 printf ("Could not open state file\n");
713 int fst_save_state (FST * fst, char * filename)
715 FILE * f = fopen (filename, "wb");
718 int numParams = fst->plugin->numParams;
720 char productString[64];
722 char vendorString[64];
726 fprintf( f, "<plugin_state>\n" );
728 success = fst_call_dispatcher( fst, effGetProductString, 0, 0, productString, 0 );
730 fprintf (f, " <check field=\"productString\" value=\"%s\"/>\n", productString);
732 printf ("No product string\n");
735 success = fst_call_dispatcher( fst, effGetEffectName, 0, 0, effectName, 0 );
737 fprintf (f, " <check field=\"effectName\" value=\"%s\"/>\n", effectName);
738 printf ("Effect name: %s\n", effectName);
740 printf ("No effect name\n");
743 success = fst_call_dispatcher( fst, effGetVendorString, 0, 0, vendorString, 0 );
745 fprintf (f, " <check field=\"vendorString\" value=\"%s\"/>\n", vendorString);
746 printf ("Vendor string: %s\n", vendorString);
748 printf ("No vendor string\n");
752 if( fst->plugin->flags & 32 ) {
756 for( i=0; i<numParams; i++ ) {
759 pthread_mutex_lock( &fst->lock );
760 val = fst->plugin->getParameter( fst->plugin, i );
761 pthread_mutex_unlock( &fst->lock );
762 fprintf( f, " <param index=\"%d\" value=\"%f\"/>\n", i, val );
765 if( fst->plugin->flags & 32 ) {
766 printf( "getting chunk...\n" );
768 bytelen = fst_call_dispatcher( fst, 23, 0, 0, &chunk, 0 );
769 printf( "got tha chunk..\n" );
772 printf( "Chunke len < 0 !!! Not saving chunk.\n" );
774 char *encoded = g_base64_encode( chunk, bytelen );
775 fprintf( f, " <chunk size=\"%d\">\n %s\n </chunk>\n", bytelen, encoded );
781 fprintf( f, "</plugin_state>\n" );
784 printf ("Could not open state file\n");