5 #define fst_error(...) fprintf(stderr, __VA_ARGS__)
7 #ifdef PLATFORM_WINDOWS
10 static UINT_PTR idle_timer_id = 0;
11 extern char *basename(char *path);
13 #else /* linux + wine */
15 #include <linux/limits.h> // PATH_MAX
16 #include <libgen.h> // basename
18 #include <wine/exception.h>
20 static int gui_quit = 0;
21 static unsigned int idle_id = 0;
25 extern char * strdup (const char *);
36 static pthread_mutex_t plugin_mutex;
37 static VSTState* fst_first = NULL; /**< Head of linked list of all FSTs */
38 static int host_initialized = 0;
39 static const char magic[] = "FST Plugin State v002";
43 vstedit_wndproc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
51 /* we don't care about windows closing ...
52 * WM_CLOSE is used for minimizing the window.
53 * Our window has no frame so it shouldn't ever
54 * get sent - but if it does, we don't want our
55 * window to get minimized!
62 /* we don't care about windows being destroyed ... */
70 return DefWindowProcA (w, msg, wp, lp );
75 maybe_set_program (VSTState* fst)
77 if (fst->want_program != -1) {
78 if (fst->vst_version >= 2) {
79 fst->plugin->dispatcher (fst->plugin, effBeginSetProgram, 0, 0, NULL, 0);
82 fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
84 if (fst->vst_version >= 2) {
85 fst->plugin->dispatcher (fst->plugin, effEndSetProgram, 0, 0, NULL, 0);
87 fst->want_program = -1;
90 if (fst->want_chunk == 1) {
92 // 24 == audioMasterGetAutomationState,
93 // 48 == audioMasterGetChunkFile
94 fst->plugin->dispatcher (fst->plugin, 24 /* effSetChunk */, 1, fst->wanted_chunk_size, fst->wanted_chunk, 0);
101 HWND hwnd, // handle to window for timer messages
102 UINT message, // WM_TIMER message
103 UINT idTimer, // timer identifier
104 DWORD dwTime) // current system time
108 pthread_mutex_lock (&plugin_mutex);
110 for (fst = fst_first; fst; fst = fst->next) {
111 if (fst->gui_shown) {
112 // this seems insane, but some plugins will not draw their meters if you don't
113 // call this every time. Example Ambience by Magnus @ Smartelectron:x
114 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
117 fst->wantIdle = fst->plugin->dispatcher (fst->plugin, effIdle, 0, 0, NULL, 0);
121 pthread_mutex_lock (&fst->lock);
122 #ifndef PLATFORM_WINDOWS /* linux + wine */
123 /* Dispatch messages to send keypresses to the plugin */
126 for (i = 0; i < fst->n_pending_keys; ++i) {
128 /* I'm not quite sure what is going on here; it seems
129 * `special' keys must be delivered with WM_KEYDOWN,
130 * but that alphanumerics etc. must use WM_CHAR or
131 * they will be ignored. Ours is not to reason why ...
133 if (fst->pending_keys[i].special != 0) {
134 msg.message = WM_KEYDOWN;
135 msg.wParam = fst->pending_keys[i].special;
137 msg.message = WM_CHAR;
138 msg.wParam = fst->pending_keys[i].character;
140 msg.hwnd = GetFocus ();
142 DispatchMessageA (&msg);
145 fst->n_pending_keys = 0;
148 /* See comment for maybe_set_program call below */
149 maybe_set_program (fst);
150 fst->want_program = -1;
152 /* If we don't have an editor window yet, we still need to
153 * set up the program, otherwise when we load a plugin without
154 * opening its window it will sound wrong. However, it seems
155 * that if you don't also load the program after opening the GUI,
156 * the GUI does not reflect the program properly. So we'll not
157 * mark that we've done this (ie we won't set want_program to -1)
158 * and so it will be done again if and when the GUI arrives.
160 if (fst->program_set_without_editor == 0) {
161 maybe_set_program (fst);
162 fst->program_set_without_editor = 1;
165 pthread_mutex_unlock (&fst->lock);
168 pthread_mutex_unlock (&plugin_mutex);
172 fst_idle_timer_add_plugin (VSTState* fst)
174 pthread_mutex_lock (&plugin_mutex);
176 if (fst_first == NULL) {
179 VSTState* p = fst_first;
186 pthread_mutex_unlock (&plugin_mutex);
190 fst_idle_timer_remove_plugin (VSTState* fst)
195 pthread_mutex_lock (&plugin_mutex);
197 for (p = fst_first, prev = NULL; p; prev = p, p = p->next) {
200 prev->next = p->next;
209 if (fst_first == fst) {
210 fst_first = fst_first->next;
213 pthread_mutex_unlock (&plugin_mutex);
219 VSTState* fst = (VSTState*) calloc (1, sizeof (VSTState));
220 pthread_mutex_init (&fst->lock, NULL);
221 pthread_cond_init (&fst->window_status_change, NULL); // unused ?? -> TODO check gtk2ardour
222 pthread_cond_init (&fst->plugin_dispatcher_called, NULL); // unused ??
223 fst->want_program = -1;
225 fst->n_pending_keys = 0;
227 #ifdef PLATFORM_WINDOWS
230 #else /* linux + wine */
234 fst->program_set_without_editor = 0;
239 fst_delete (VSTState* fst)
248 fst_handle_new (void)
250 VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
254 #ifndef PLATFORM_WINDOWS /* linux + wine */
256 g_idle_call (gpointer ignored) {
257 if (gui_quit) return FALSE;
259 if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
260 TranslateMessage (&msg);
261 DispatchMessageA (&msg);
263 idle_hands(NULL, 0, 0, 0);
264 g_main_context_iteration(NULL, FALSE);
265 return gui_quit ? FALSE : TRUE;
271 fst_init (void* possible_hmodule)
273 if (host_initialized) return 0;
276 if (possible_hmodule) {
277 #ifdef PLATFORM_WINDOWS
278 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
280 #else /* linux + wine */
281 hInst = (HMODULE) possible_hmodule;
283 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
284 fst_error ("can't get module handle");
289 fst_error ("Cannot initialise VST host");
295 wclass.cbSize = sizeof(WNDCLASSEX);
296 #ifdef PLATFORM_WINDOWS
297 wclass.style = (CS_HREDRAW | CS_VREDRAW);
299 wclass.hCursor = LoadCursor(0, IDC_ARROW);
300 #else /* linux + wine */
302 wclass.hIcon = LoadIcon(hInst, "FST");
303 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
305 wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
306 wclass.lpfnWndProc = vstedit_wndproc;
307 wclass.cbClsExtra = 0;
308 wclass.cbWndExtra = 0;
309 wclass.hInstance = hInst;
310 wclass.lpszMenuName = "MENU_FST";
311 wclass.lpszClassName = "FST";
314 pthread_mutex_init (&plugin_mutex, NULL);
315 host_initialized = -1;
317 if (!RegisterClassExA(&wclass)){
318 fst_error ("Error in fst_init(): (class registration failed");
325 fst_start_threading(void)
327 #ifndef PLATFORM_WINDOWS /* linux + wine */
330 idle_id = g_idle_add (g_idle_call, NULL);
336 fst_stop_threading(void) {
337 #ifndef PLATFORM_WINDOWS /* linux + wine */
341 g_main_context_iteration(NULL, FALSE);
342 //g_source_remove(idle_id);
351 if (!host_initialized) return;
353 // If any plugins are still open at this point, close them!
354 while ((fst = fst_first))
357 #ifdef PLATFORM_WINDOWS
358 if (idle_timer_id != 0) {
359 KillTimer(NULL, idle_timer_id);
361 #else /* linux + wine */
368 host_initialized = FALSE;
369 pthread_mutex_destroy (&plugin_mutex);
374 fst_run_editor (VSTState* fst, void* window_parent)
376 if (fst->windows_window == NULL) {
381 if (!(fst->plugin->flags & effFlagsHasEditor)) {
382 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
386 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
387 fst_error ("fst_create_editor() can't get module handle");
391 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
392 window_parent ? WS_CHILD : (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
393 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
394 (HWND)window_parent, NULL,
397 fst_error ("fst_create_editor() cannot create editor window");
401 if (!SetPropA (window, "fst_ptr", fst)) {
402 fst_error ("fst_create_editor() cannot set fst_ptr on window");
405 fst->windows_window = window;
408 // This is requiredv for some reason. Note the parent is set above when the window
409 // is created. Without this extra call the actual plugin window will draw outside
410 // of our plugin window.
411 SetParent((HWND)fst->windows_window, (HWND)window_parent);
413 #ifndef PLATFORM_WINDOWS /* linux + wine */
415 SetWindowPos (fst->windows_window, 0, 9999, 9999, 2, 2, 0);
416 ShowWindow (fst->windows_window, SW_SHOWNA);
417 fst->xid = (int) GetPropA (fst->windows_window, "__wine_x11_whole_window");
421 // This is the suggested order of calls.
422 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
423 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->windows_window, 0 );
424 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
426 fst->width = er->right-er->left;
427 fst->height = er->bottom-er->top;
430 fst->been_activated = TRUE;
434 if (fst->windows_window) {
435 #ifdef PLATFORM_WINDOWS
436 if (idle_timer_id == 0) {
437 // Init the idle timer if needed, so that the main window calls us.
438 idle_timer_id = SetTimer(NULL, idle_timer_id, 50, (TIMERPROC) idle_hands);
442 fst_idle_timer_add_plugin (fst);
445 return fst->windows_window == NULL ? -1 : 0;
449 fst_destroy_editor (VSTState* fst)
451 if (fst->windows_window) {
452 fprintf (stderr, "%s destroying edit window\n", fst->handle->name);
454 fst_idle_timer_remove_plugin (fst);
455 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
457 DestroyWindow ((HWND)(fst->windows_window));
459 fst->windows_window = NULL;
462 fst->been_activated = FALSE;
466 fst_move_window_into_view (VSTState* fst)
468 if (fst->windows_window) {
469 #ifdef PLATFORM_WINDOWS
470 SetWindowPos ((HWND)(fst->windows_window), 0, fst->hoffset, fst->voffset, fst->width, fst->height, 0);
471 #else /* linux + wine */
472 SetWindowPos ((HWND)(fst->windows_window), 0, 0, 0, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
474 ShowWindow ((HWND)(fst->windows_window), SW_SHOWNA);
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->nameptr = strdup (path);
495 fhandle->path = strdup (path);
496 fhandle->name = basename(fhandle->nameptr);
497 if ((period = strrchr (fhandle->name, '.'))) {
501 // See if we can load the plugin DLL
502 if ((fhandle->dll = (HMODULE)fst_load_vst_library (path)) == NULL) {
503 fst_unload (&fhandle);
507 fhandle->main_entry = (main_entry_t) GetProcAddress (fhandle->dll, "main");
509 if (fhandle->main_entry == 0) {
510 if ((fhandle->main_entry = (main_entry_t) GetProcAddress (fhandle->dll, "VSTPluginMain"))) {
511 fprintf(stderr, "VST >= 2.4 plugin '%s'\n", path);
512 //PBD::warning << path << _(": is a VST >= 2.4 - this plugin may or may not function correctly with this version of Ardour.") << endmsg;
516 if (fhandle->main_entry == 0) {
517 fst_unload (&fhandle);
525 fst_unload (VSTHandle** fhandle)
531 if ((*fhandle)->plugincnt) {
535 if ((*fhandle)->dll) {
536 FreeLibrary ((HMODULE)(*fhandle)->dll);
537 (*fhandle)->dll = NULL;
540 if ((*fhandle)->path) {
541 free ((*fhandle)->path);
542 (*fhandle)->path = NULL;
545 if ((*fhandle)->nameptr) {
546 free ((*fhandle)->nameptr);
547 (*fhandle)->nameptr = NULL;
548 (*fhandle)->name = NULL;
558 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
560 VSTState* fst = NULL;
562 if( fhandle == NULL ) {
563 fst_error( "fst_instantiate(): (the handle was NULL)\n" );
569 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
570 fst_error ("fst_instantiate: %s could not be instantiated\n", fhandle->name);
575 fst->handle = fhandle;
576 fst->plugin->user = userptr;
578 if (fst->plugin->magic != kEffectMagic) {
579 fst_error ("fst_instantiate: %s is not a vst plugin\n", fhandle->name);
584 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
585 fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
587 fst->handle->plugincnt++;
593 void fst_audio_master_idle(void) {
594 while(g_main_context_iteration(NULL, FALSE)) ;
598 fst_close (VSTState* fst)
601 fst_destroy_editor (fst);
604 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
605 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
610 if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
612 fst->handle->main_entry = NULL;
613 fst_unload (&fst->handle); // XXX
617 /* It might be good for this to be in it's own cleanup function
618 since it will free the memory for the fst leaving the caller
619 with an invalid pointer. Caller beware */
624 #if 0 // ?? who needs this, where?
625 float htonf (float v)
628 char * fin = (char*)&v;
629 char * fout = (char*)&result;