5 #define fst_error(...) fprintf(stderr, __VA_ARGS__)
7 #ifdef PLATFORM_WINDOWS
10 static UINT_PTR idle_timer_id = 0;
12 #else /* linux + wine */
14 #include <linux/limits.h> // PATH_MAX
16 #include <wine/exception.h>
18 static int gui_quit = 0;
19 static unsigned int idle_id = 0;
24 extern char * strdup (const char *);
37 static pthread_mutex_t plugin_mutex;
38 static VSTState* fst_first = NULL; /**< Head of linked list of all FSTs */
39 static int host_initialized = 0;
40 static const char magic[] = "FST Plugin State v002";
44 vstedit_wndproc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
52 #ifdef PLATFORM_WINDOWS
54 LRESULT rv = DefWindowProcA (w, msg, wp, lp);
56 GetClientRect(w, &rect);
58 printf("VST WM_SIZE.. %ld %ld %ld %ld\n", rect.top, rect.left, (rect.right - rect.left), (rect.bottom - rect.top));
60 VSTState* fst = (VSTState*) GetProp (w, "fst_ptr");
62 int32_t width = (rect.right - rect.left);
63 int32_t height = (rect.bottom - rect.top);
64 if (width > 0 && height > 0) {
65 fst->amc (fst->plugin, 15 /*audioMasterSizeWindow */, width, height, NULL, 0);
73 /* we don't care about windows closing ...
74 * WM_CLOSE is used for minimizing the window.
75 * Our window has no frame so it shouldn't ever
76 * get sent - but if it does, we don't want our
77 * window to get minimized!
84 /* we don't care about windows being destroyed ... */
92 return DefWindowProcA (w, msg, wp, lp);
98 HWND hwnd, // handle to window for timer messages
99 UINT message, // WM_TIMER message
100 UINT idTimer, // timer identifier
101 DWORD dwTime) // current system time
105 pthread_mutex_lock (&plugin_mutex);
107 for (fst = fst_first; fst; fst = fst->next) {
108 if (fst->gui_shown) {
109 // this seems insane, but some plugins will not draw their meters if you don't
110 // call this every time. Example Ambience by Magnus @ Smartelectron:x
111 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
114 fst->wantIdle = fst->plugin->dispatcher (fst->plugin, effIdle, 0, 0, NULL, 0);
118 pthread_mutex_lock (&fst->lock);
119 #ifndef PLATFORM_WINDOWS /* linux + wine */
120 /* Dispatch messages to send keypresses to the plugin */
123 for (i = 0; i < fst->n_pending_keys; ++i) {
125 /* I'm not quite sure what is going on here; it seems
126 * `special' keys must be delivered with WM_KEYDOWN,
127 * but that alphanumerics etc. must use WM_CHAR or
128 * they will be ignored. Ours is not to reason why ...
130 if (fst->pending_keys[i].special != 0) {
131 msg.message = WM_KEYDOWN;
132 msg.wParam = fst->pending_keys[i].special;
134 msg.message = WM_CHAR;
135 msg.wParam = fst->pending_keys[i].character;
137 msg.hwnd = GetFocus ();
139 DispatchMessageA (&msg);
142 fst->n_pending_keys = 0;
145 /* See comment for call below */
146 vststate_maybe_set_program (fst);
147 fst->want_program = -1;
149 /* If we don't have an editor window yet, we still need to
150 * set up the program, otherwise when we load a plugin without
151 * opening its window it will sound wrong. However, it seems
152 * that if you don't also load the program after opening the GUI,
153 * the GUI does not reflect the program properly. So we'll not
154 * mark that we've done this (ie we won't set want_program to -1)
155 * and so it will be done again if and when the GUI arrives.
157 if (fst->program_set_without_editor == 0) {
158 vststate_maybe_set_program (fst);
159 fst->program_set_without_editor = 1;
162 pthread_mutex_unlock (&fst->lock);
165 pthread_mutex_unlock (&plugin_mutex);
169 fst_idle_timer_add_plugin (VSTState* fst)
171 pthread_mutex_lock (&plugin_mutex);
173 if (fst_first == NULL) {
176 VSTState* p = fst_first;
183 pthread_mutex_unlock (&plugin_mutex);
187 fst_idle_timer_remove_plugin (VSTState* fst)
192 pthread_mutex_lock (&plugin_mutex);
194 for (p = fst_first, prev = NULL; p; prev = p, p = p->next) {
197 prev->next = p->next;
206 if (fst_first == fst) {
207 fst_first = fst_first->next;
210 pthread_mutex_unlock (&plugin_mutex);
216 VSTState* fst = (VSTState*) calloc (1, sizeof (VSTState));
219 #ifdef PLATFORM_WINDOWS
222 #else /* linux + wine */
230 fst_delete (VSTState* fst)
239 fst_handle_new (void)
241 VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
245 #ifndef PLATFORM_WINDOWS /* linux + wine */
247 g_idle_call (gpointer ignored) {
248 if (gui_quit) return FALSE;
250 if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
251 TranslateMessage (&msg);
252 DispatchMessageA (&msg);
254 idle_hands(NULL, 0, 0, 0);
255 g_main_context_iteration(NULL, FALSE);
256 return gui_quit ? FALSE : TRUE;
262 fst_init (void* possible_hmodule)
264 if (host_initialized) return 0;
267 if (possible_hmodule) {
268 #ifdef PLATFORM_WINDOWS
269 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
271 #else /* linux + wine */
272 hInst = (HMODULE) possible_hmodule;
274 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
275 fst_error ("can't get module handle");
280 fst_error ("Cannot initialise VST host");
286 wclass.cbSize = sizeof(WNDCLASSEX);
287 #ifdef PLATFORM_WINDOWS
288 wclass.style = (CS_HREDRAW | CS_VREDRAW);
290 wclass.hCursor = LoadCursor(0, IDC_ARROW);
291 #else /* linux + wine */
293 wclass.hIcon = LoadIcon(hInst, "FST");
294 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
296 wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
297 wclass.lpfnWndProc = vstedit_wndproc;
298 wclass.cbClsExtra = 0;
299 wclass.cbWndExtra = 0;
300 wclass.hInstance = hInst;
301 wclass.lpszMenuName = "MENU_FST";
302 wclass.lpszClassName = "FST";
305 pthread_mutex_init (&plugin_mutex, NULL);
306 host_initialized = -1;
308 if (!RegisterClassExA(&wclass)){
309 fst_error ("Error in fst_init(): (class registration failed");
316 fst_start_threading(void)
318 #ifndef PLATFORM_WINDOWS /* linux + wine */
321 idle_id = g_idle_add (g_idle_call, NULL);
327 fst_stop_threading(void) {
328 #ifndef PLATFORM_WINDOWS /* linux + wine */
332 g_main_context_iteration(NULL, FALSE);
333 //g_source_remove(idle_id);
342 if (!host_initialized) return;
344 // If any plugins are still open at this point, close them!
345 while ((fst = fst_first))
348 #ifdef PLATFORM_WINDOWS
349 if (idle_timer_id != 0) {
350 KillTimer(NULL, idle_timer_id);
352 #else /* linux + wine */
359 host_initialized = FALSE;
360 pthread_mutex_destroy (&plugin_mutex);
365 fst_run_editor (VSTState* fst, void* window_parent)
367 /* For safety, remove any pre-existing editor window */
368 fst_destroy_editor (fst);
370 if (fst->windows_window == NULL) {
373 struct ERect* er = NULL;
375 if (!(fst->plugin->flags & effFlagsHasEditor)) {
376 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
380 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
381 fst_error ("fst_create_editor() can't get module handle");
385 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
386 window_parent ? WS_CHILD : (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
387 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
388 (HWND)window_parent, NULL,
391 fst_error ("fst_create_editor() cannot create editor window");
395 if (!SetPropA (window, "fst_ptr", fst)) {
396 fst_error ("fst_create_editor() cannot set fst_ptr on window");
399 fst->windows_window = window;
402 // This is requiredv for some reason. Note the parent is set above when the window
403 // is created. Without this extra call the actual plugin window will draw outside
404 // of our plugin window.
405 SetParent((HWND)fst->windows_window, (HWND)window_parent);
407 #ifndef PLATFORM_WINDOWS /* linux + wine */
409 SetWindowPos (fst->windows_window, 0, 9999, 9999, 2, 2, 0);
410 ShowWindow (fst->windows_window, SW_SHOWNA);
411 fst->xid = (int) GetPropA (fst->windows_window, "__wine_x11_whole_window");
415 // This is the suggested order of calls.
416 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
417 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->windows_window, 0 );
418 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
421 fst->width = er->right - er->left;
422 fst->height = er->bottom - er->top;
425 fst->been_activated = TRUE;
429 if (fst->windows_window) {
430 #ifdef PLATFORM_WINDOWS
431 if (idle_timer_id == 0) {
432 // Init the idle timer if needed, so that the main window calls us.
433 idle_timer_id = SetTimer(NULL, idle_timer_id, 50, (TIMERPROC) idle_hands);
437 fst_idle_timer_add_plugin (fst);
440 return fst->windows_window == NULL ? -1 : 0;
444 fst_destroy_editor (VSTState* fst)
446 if (fst->windows_window) {
447 fprintf (stderr, "%s destroying edit window\n", fst->handle->name);
449 fst_idle_timer_remove_plugin (fst);
450 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
452 DestroyWindow ((HWND)(fst->windows_window));
454 fst->windows_window = NULL;
457 fst->been_activated = FALSE;
461 fst_move_window_into_view (VSTState* fst)
463 if (fst->windows_window) {
464 #ifdef PLATFORM_WINDOWS
465 SetWindowPos ((HWND)(fst->windows_window),
467 fst->hoffset, fst->voffset,
468 fst->width, fst->height,
469 SWP_NOACTIVATE|SWP_NOOWNERZORDER);
470 #else /* linux + wine */
471 SetWindowPos ((HWND)(fst->windows_window), 0, 0, 0, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
473 ShowWindow ((HWND)(fst->windows_window), SW_SHOWNA);
474 UpdateWindow ((HWND)(fst->windows_window));
479 fst_load_vst_library(const char * path)
481 char legalized_path[PATH_MAX];
482 strcpy (legalized_path, g_locale_from_utf8(path, -1, NULL, NULL, NULL));
483 return ( LoadLibraryA (legalized_path) );
487 fst_load (const char *path)
489 VSTHandle* fhandle = NULL;
491 if ((strlen(path)) && (NULL != (fhandle = fst_handle_new ())))
494 fhandle->path = strdup (path);
495 fhandle->name = g_path_get_basename(path);
496 if ((period = strrchr (fhandle->name, '.'))) {
500 // See if we can load the plugin DLL
501 if ((fhandle->dll = (HMODULE)fst_load_vst_library (path)) == NULL) {
502 fst_unload (&fhandle);
506 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "VSTPluginMain");
508 if (fhandle->main_entry == 0) {
509 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "main");
512 if (fhandle->main_entry == 0) {
513 fst_unload (&fhandle);
521 fst_unload (VSTHandle** fhandle)
527 if ((*fhandle)->plugincnt) {
531 if ((*fhandle)->dll) {
532 FreeLibrary ((HMODULE)(*fhandle)->dll);
533 (*fhandle)->dll = NULL;
536 if ((*fhandle)->path) {
537 free ((*fhandle)->path);
538 (*fhandle)->path = NULL;
541 if ((*fhandle)->name) {
542 free ((*fhandle)->name);
543 (*fhandle)->name = NULL;
553 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
555 VSTState* fst = NULL;
557 if( fhandle == NULL ) {
558 fst_error( "fst_instantiate(): (the handle was NULL)\n" );
565 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
566 fst_error ("fst_instantiate: %s could not be instantiated\n", fhandle->name);
571 fst->handle = fhandle;
572 fst->plugin->user = userptr;
574 if (fst->plugin->magic != kEffectMagic) {
575 fst_error ("fst_instantiate: %s is not a vst plugin\n", fhandle->name);
581 /* scanning.. or w/o master-callback userptr == 0, open now.
583 * Session::vst_callback needs a pointer to the AEffect
584 * ((VSTPlugin*)userptr)->_plugin = vstfx->plugin
585 * before calling effOpen, because effOpen may call back
587 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
588 fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
591 fst->handle->plugincnt++;
597 void fst_audio_master_idle(void) {
598 while(g_main_context_iteration(NULL, FALSE)) ;
602 fst_close (VSTState* fst)
605 fst_destroy_editor (fst);
608 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
609 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
614 if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
616 fst->handle->main_entry = NULL;
617 fst_unload (&fst->handle); // XXX
621 /* It might be good for this to be in it's own cleanup function
622 since it will free the memory for the fst leaving the caller
623 with an invalid pointer. Caller beware */
628 #if 0 // ?? who needs this, where?
629 float htonf (float v)
632 char * fin = (char*)&v;
633 char * fout = (char*)&result;