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;
23 extern char * strdup (const char *);
34 static pthread_mutex_t plugin_mutex;
35 static VSTState* fst_first = NULL; /**< Head of linked list of all FSTs */
36 static int host_initialized = 0;
37 static const char magic[] = "FST Plugin State v002";
41 vstedit_wndproc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
49 /* we don't care about windows closing ...
50 * WM_CLOSE is used for minimizing the window.
51 * Our window has no frame so it shouldn't ever
52 * get sent - but if it does, we don't want our
53 * window to get minimized!
60 /* we don't care about windows being destroyed ... */
68 return DefWindowProcA (w, msg, wp, lp );
73 maybe_set_program (VSTState* fst)
75 if (fst->want_program != -1) {
76 if (fst->vst_version >= 2) {
77 fst->plugin->dispatcher (fst->plugin, effBeginSetProgram, 0, 0, NULL, 0);
80 fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
82 if (fst->vst_version >= 2) {
83 fst->plugin->dispatcher (fst->plugin, effEndSetProgram, 0, 0, NULL, 0);
85 fst->want_program = -1;
88 if (fst->want_chunk == 1) {
90 // 24 == audioMasterGetAutomationState,
91 // 48 == audioMasterGetChunkFile
92 fst->plugin->dispatcher (fst->plugin, 24 /* effSetChunk */, 1, fst->wanted_chunk_size, fst->wanted_chunk, 0);
99 HWND hwnd, // handle to window for timer messages
100 UINT message, // WM_TIMER message
101 UINT idTimer, // timer identifier
102 DWORD dwTime) // current system time
106 pthread_mutex_lock (&plugin_mutex);
108 for (fst = fst_first; fst; fst = fst->next) {
109 if (fst->gui_shown) {
110 // this seems insane, but some plugins will not draw their meters if you don't
111 // call this every time. Example Ambience by Magnus @ Smartelectron:x
112 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
115 fst->wantIdle = fst->plugin->dispatcher (fst->plugin, effIdle, 0, 0, NULL, 0);
119 pthread_mutex_lock (&fst->lock);
120 #ifndef PLATFORM_WINDOWS /* linux + wine */
121 /* Dispatch messages to send keypresses to the plugin */
124 for (i = 0; i < fst->n_pending_keys; ++i) {
126 /* I'm not quite sure what is going on here; it seems
127 * `special' keys must be delivered with WM_KEYDOWN,
128 * but that alphanumerics etc. must use WM_CHAR or
129 * they will be ignored. Ours is not to reason why ...
131 if (fst->pending_keys[i].special != 0) {
132 msg.message = WM_KEYDOWN;
133 msg.wParam = fst->pending_keys[i].special;
135 msg.message = WM_CHAR;
136 msg.wParam = fst->pending_keys[i].character;
138 msg.hwnd = GetFocus ();
140 DispatchMessageA (&msg);
143 fst->n_pending_keys = 0;
146 /* See comment for maybe_set_program call below */
147 maybe_set_program (fst);
148 fst->want_program = -1;
150 /* If we don't have an editor window yet, we still need to
151 * set up the program, otherwise when we load a plugin without
152 * opening its window it will sound wrong. However, it seems
153 * that if you don't also load the program after opening the GUI,
154 * the GUI does not reflect the program properly. So we'll not
155 * mark that we've done this (ie we won't set want_program to -1)
156 * and so it will be done again if and when the GUI arrives.
158 if (fst->program_set_without_editor == 0) {
159 maybe_set_program (fst);
160 fst->program_set_without_editor = 1;
163 pthread_mutex_unlock (&fst->lock);
166 pthread_mutex_unlock (&plugin_mutex);
170 fst_idle_timer_add_plugin (VSTState* fst)
172 pthread_mutex_lock (&plugin_mutex);
174 if (fst_first == NULL) {
177 VSTState* p = fst_first;
184 pthread_mutex_unlock (&plugin_mutex);
188 fst_idle_timer_remove_plugin (VSTState* fst)
193 pthread_mutex_lock (&plugin_mutex);
195 for (p = fst_first, prev = NULL; p; prev = p, p = p->next) {
198 prev->next = p->next;
207 if (fst_first == fst) {
208 fst_first = fst_first->next;
211 pthread_mutex_unlock (&plugin_mutex);
217 VSTState* fst = (VSTState*) calloc (1, sizeof (VSTState));
218 pthread_mutex_init (&fst->lock, NULL);
219 pthread_cond_init (&fst->window_status_change, NULL); // unused ?? -> TODO check gtk2ardour
220 pthread_cond_init (&fst->plugin_dispatcher_called, NULL); // unused ??
221 fst->want_program = -1;
223 fst->n_pending_keys = 0;
225 #ifdef PLATFORM_WINDOWS
228 #else /* linux + wine */
232 fst->program_set_without_editor = 0;
237 fst_delete (VSTState* fst)
246 fst_handle_new (void)
248 VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
252 #ifndef PLATFORM_WINDOWS /* linux + wine */
254 g_idle_call (gpointer ignored) {
255 if (gui_quit) return FALSE;
257 if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
258 TranslateMessage (&msg);
259 DispatchMessageA (&msg);
261 idle_hands(NULL, 0, 0, 0);
262 g_main_context_iteration(NULL, FALSE);
263 return gui_quit ? FALSE : TRUE;
269 fst_init (void* possible_hmodule)
271 if (host_initialized) return 0;
274 if (possible_hmodule) {
275 #ifdef PLATFORM_WINDOWS
276 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
278 #else /* linux + wine */
279 hInst = (HMODULE) possible_hmodule;
281 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
282 fst_error ("can't get module handle");
287 fst_error ("Cannot initialise VST host");
293 wclass.cbSize = sizeof(WNDCLASSEX);
294 #ifdef PLATFORM_WINDOWS
295 wclass.style = (CS_HREDRAW | CS_VREDRAW);
297 wclass.hCursor = LoadCursor(0, IDC_ARROW);
298 #else /* linux + wine */
300 wclass.hIcon = LoadIcon(hInst, "FST");
301 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
303 wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
304 wclass.lpfnWndProc = vstedit_wndproc;
305 wclass.cbClsExtra = 0;
306 wclass.cbWndExtra = 0;
307 wclass.hInstance = hInst;
308 wclass.lpszMenuName = "MENU_FST";
309 wclass.lpszClassName = "FST";
312 pthread_mutex_init (&plugin_mutex, NULL);
313 host_initialized = -1;
315 if (!RegisterClassExA(&wclass)){
316 fst_error ("Error in fst_init(): (class registration failed");
323 fst_start_threading(void)
325 #ifndef PLATFORM_WINDOWS /* linux + wine */
328 idle_id = g_idle_add (g_idle_call, NULL);
334 fst_stop_threading(void) {
335 #ifndef PLATFORM_WINDOWS /* linux + wine */
339 g_main_context_iteration(NULL, FALSE);
340 //g_source_remove(idle_id);
349 if (!host_initialized) return;
351 // If any plugins are still open at this point, close them!
352 while ((fst = fst_first))
355 #ifdef PLATFORM_WINDOWS
356 if (idle_timer_id != 0) {
357 KillTimer(NULL, idle_timer_id);
359 #else /* linux + wine */
366 host_initialized = FALSE;
367 pthread_mutex_destroy (&plugin_mutex);
372 fst_run_editor (VSTState* fst, void* window_parent)
374 if (fst->windows_window == NULL) {
379 if (!(fst->plugin->flags & effFlagsHasEditor)) {
380 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
384 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
385 fst_error ("fst_create_editor() can't get module handle");
389 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
390 window_parent ? WS_CHILD : (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
391 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
392 (HWND)window_parent, NULL,
395 fst_error ("fst_create_editor() cannot create editor window");
399 if (!SetPropA (window, "fst_ptr", fst)) {
400 fst_error ("fst_create_editor() cannot set fst_ptr on window");
403 fst->windows_window = window;
406 // This is requiredv for some reason. Note the parent is set above when the window
407 // is created. Without this extra call the actual plugin window will draw outside
408 // of our plugin window.
409 SetParent((HWND)fst->windows_window, (HWND)window_parent);
411 #ifndef PLATFORM_WINDOWS /* linux + wine */
413 SetWindowPos (fst->windows_window, 0, 9999, 9999, 2, 2, 0);
414 ShowWindow (fst->windows_window, SW_SHOWNA);
415 fst->xid = (int) GetPropA (fst->windows_window, "__wine_x11_whole_window");
419 // This is the suggested order of calls.
420 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
421 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->windows_window, 0 );
422 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
424 fst->width = er->right-er->left;
425 fst->height = er->bottom-er->top;
428 fst->been_activated = TRUE;
432 if (fst->windows_window) {
433 #ifdef PLATFORM_WINDOWS
434 if (idle_timer_id == 0) {
435 // Init the idle timer if needed, so that the main window calls us.
436 idle_timer_id = SetTimer(NULL, idle_timer_id, 50, (TIMERPROC) idle_hands);
440 fst_idle_timer_add_plugin (fst);
443 return fst->windows_window == NULL ? -1 : 0;
447 fst_destroy_editor (VSTState* fst)
449 if (fst->windows_window) {
450 fprintf (stderr, "%s destroying edit window\n", fst->handle->name);
452 fst_idle_timer_remove_plugin (fst);
453 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
455 DestroyWindow ((HWND)(fst->windows_window));
457 fst->windows_window = NULL;
460 fst->been_activated = FALSE;
464 fst_move_window_into_view (VSTState* fst)
466 if (fst->windows_window) {
467 #ifdef PLATFORM_WINDOWS
468 SetWindowPos ((HWND)(fst->windows_window), 0, fst->hoffset, fst->voffset, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
469 #else /* linux + wine */
470 SetWindowPos ((HWND)(fst->windows_window), 0, 0, 0, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
472 ShowWindow ((HWND)(fst->windows_window), SW_SHOWNA);
477 fst_load_vst_library(const char * path)
479 char legalized_path[PATH_MAX];
480 strcpy (legalized_path, g_locale_from_utf8(path, -1, NULL, NULL, NULL));
481 return ( LoadLibraryA (legalized_path) );
485 fst_load (const char *path)
487 VSTHandle* fhandle = NULL;
489 if ((strlen(path)) && (NULL != (fhandle = fst_handle_new ())))
492 fhandle->path = strdup (path);
493 fhandle->name = g_path_get_basename(path);
494 if ((period = strrchr (fhandle->name, '.'))) {
498 // See if we can load the plugin DLL
499 if ((fhandle->dll = (HMODULE)fst_load_vst_library (path)) == NULL) {
500 fst_unload (&fhandle);
504 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "main");
506 if (fhandle->main_entry == 0) {
507 if ((fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "VSTPluginMain"))) {
508 fprintf(stderr, "VST >= 2.4 plugin '%s'\n", path);
509 //PBD::warning << path << _(": is a VST >= 2.4 - this plugin may or may not function correctly with this version of Ardour.") << endmsg;
513 if (fhandle->main_entry == 0) {
514 fst_unload (&fhandle);
522 fst_unload (VSTHandle** fhandle)
528 if ((*fhandle)->plugincnt) {
532 if ((*fhandle)->dll) {
533 FreeLibrary ((HMODULE)(*fhandle)->dll);
534 (*fhandle)->dll = NULL;
537 if ((*fhandle)->path) {
538 free ((*fhandle)->path);
539 (*fhandle)->path = NULL;
542 if ((*fhandle)->name) {
543 free ((*fhandle)->name);
544 (*fhandle)->name = NULL;
554 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
556 VSTState* fst = NULL;
558 if( fhandle == NULL ) {
559 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);
580 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
581 fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
583 fst->handle->plugincnt++;
589 void fst_audio_master_idle(void) {
590 while(g_main_context_iteration(NULL, FALSE)) ;
594 fst_close (VSTState* fst)
597 fst_destroy_editor (fst);
600 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
601 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
606 if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
608 fst->handle->main_entry = NULL;
609 fst_unload (&fst->handle); // XXX
613 /* It might be good for this to be in it's own cleanup function
614 since it will free the memory for the fst leaving the caller
615 with an invalid pointer. Caller beware */
620 #if 0 // ?? who needs this, where?
621 float htonf (float v)
624 char * fin = (char*)&v;
625 char * fout = (char*)&result;