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 /* we don't care about windows closing ...
53 * WM_CLOSE is used for minimizing the window.
54 * Our window has no frame so it shouldn't ever
55 * get sent - but if it does, we don't want our
56 * window to get minimized!
63 /* we don't care about windows being destroyed ... */
71 return DefWindowProcA (w, msg, wp, lp );
76 maybe_set_program (VSTState* fst)
78 if (fst->want_program != -1) {
79 if (fst->vst_version >= 2) {
80 fst->plugin->dispatcher (fst->plugin, effBeginSetProgram, 0, 0, NULL, 0);
83 fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
85 if (fst->vst_version >= 2) {
86 fst->plugin->dispatcher (fst->plugin, effEndSetProgram, 0, 0, NULL, 0);
88 fst->want_program = -1;
91 if (fst->want_chunk == 1) {
93 // 24 == audioMasterGetAutomationState,
94 // 48 == audioMasterGetChunkFile
95 pthread_mutex_lock (&fst->state_lock);
96 fst->plugin->dispatcher (fst->plugin, 24 /* effSetChunk */, 1, fst->wanted_chunk_size, fst->wanted_chunk, 0);
98 pthread_mutex_unlock (&fst->state_lock);
104 HWND hwnd, // handle to window for timer messages
105 UINT message, // WM_TIMER message
106 UINT idTimer, // timer identifier
107 DWORD dwTime) // current system time
111 pthread_mutex_lock (&plugin_mutex);
113 for (fst = fst_first; fst; fst = fst->next) {
114 if (fst->gui_shown) {
115 // this seems insane, but some plugins will not draw their meters if you don't
116 // call this every time. Example Ambience by Magnus @ Smartelectron:x
117 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
120 fst->wantIdle = fst->plugin->dispatcher (fst->plugin, effIdle, 0, 0, NULL, 0);
124 pthread_mutex_lock (&fst->lock);
125 #ifndef PLATFORM_WINDOWS /* linux + wine */
126 /* Dispatch messages to send keypresses to the plugin */
129 for (i = 0; i < fst->n_pending_keys; ++i) {
131 /* I'm not quite sure what is going on here; it seems
132 * `special' keys must be delivered with WM_KEYDOWN,
133 * but that alphanumerics etc. must use WM_CHAR or
134 * they will be ignored. Ours is not to reason why ...
136 if (fst->pending_keys[i].special != 0) {
137 msg.message = WM_KEYDOWN;
138 msg.wParam = fst->pending_keys[i].special;
140 msg.message = WM_CHAR;
141 msg.wParam = fst->pending_keys[i].character;
143 msg.hwnd = GetFocus ();
145 DispatchMessageA (&msg);
148 fst->n_pending_keys = 0;
151 /* See comment for maybe_set_program call below */
152 maybe_set_program (fst);
153 fst->want_program = -1;
155 /* If we don't have an editor window yet, we still need to
156 * set up the program, otherwise when we load a plugin without
157 * opening its window it will sound wrong. However, it seems
158 * that if you don't also load the program after opening the GUI,
159 * the GUI does not reflect the program properly. So we'll not
160 * mark that we've done this (ie we won't set want_program to -1)
161 * and so it will be done again if and when the GUI arrives.
163 if (fst->program_set_without_editor == 0) {
164 maybe_set_program (fst);
165 fst->program_set_without_editor = 1;
168 pthread_mutex_unlock (&fst->lock);
171 pthread_mutex_unlock (&plugin_mutex);
175 fst_idle_timer_add_plugin (VSTState* fst)
177 pthread_mutex_lock (&plugin_mutex);
179 if (fst_first == NULL) {
182 VSTState* p = fst_first;
189 pthread_mutex_unlock (&plugin_mutex);
193 fst_idle_timer_remove_plugin (VSTState* fst)
198 pthread_mutex_lock (&plugin_mutex);
200 for (p = fst_first, prev = NULL; p; prev = p, p = p->next) {
203 prev->next = p->next;
212 if (fst_first == fst) {
213 fst_first = fst_first->next;
216 pthread_mutex_unlock (&plugin_mutex);
222 VSTState* fst = (VSTState*) calloc (1, sizeof (VSTState));
224 #ifdef PLATFORM_WINDOWS
227 #else /* linux + wine */
235 fst_delete (VSTState* fst)
244 fst_handle_new (void)
246 VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
250 #ifndef PLATFORM_WINDOWS /* linux + wine */
252 g_idle_call (gpointer ignored) {
253 if (gui_quit) return FALSE;
255 if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
256 TranslateMessage (&msg);
257 DispatchMessageA (&msg);
259 idle_hands(NULL, 0, 0, 0);
260 g_main_context_iteration(NULL, FALSE);
261 return gui_quit ? FALSE : TRUE;
267 fst_init (void* possible_hmodule)
269 if (host_initialized) return 0;
272 if (possible_hmodule) {
273 #ifdef PLATFORM_WINDOWS
274 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
276 #else /* linux + wine */
277 hInst = (HMODULE) possible_hmodule;
279 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
280 fst_error ("can't get module handle");
285 fst_error ("Cannot initialise VST host");
291 wclass.cbSize = sizeof(WNDCLASSEX);
292 #ifdef PLATFORM_WINDOWS
293 wclass.style = (CS_HREDRAW | CS_VREDRAW);
295 wclass.hCursor = LoadCursor(0, IDC_ARROW);
296 #else /* linux + wine */
298 wclass.hIcon = LoadIcon(hInst, "FST");
299 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
301 wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
302 wclass.lpfnWndProc = vstedit_wndproc;
303 wclass.cbClsExtra = 0;
304 wclass.cbWndExtra = 0;
305 wclass.hInstance = hInst;
306 wclass.lpszMenuName = "MENU_FST";
307 wclass.lpszClassName = "FST";
310 pthread_mutex_init (&plugin_mutex, NULL);
311 host_initialized = -1;
313 if (!RegisterClassExA(&wclass)){
314 fst_error ("Error in fst_init(): (class registration failed");
321 fst_start_threading(void)
323 #ifndef PLATFORM_WINDOWS /* linux + wine */
326 idle_id = g_idle_add (g_idle_call, NULL);
332 fst_stop_threading(void) {
333 #ifndef PLATFORM_WINDOWS /* linux + wine */
337 g_main_context_iteration(NULL, FALSE);
338 //g_source_remove(idle_id);
347 if (!host_initialized) return;
349 // If any plugins are still open at this point, close them!
350 while ((fst = fst_first))
353 #ifdef PLATFORM_WINDOWS
354 if (idle_timer_id != 0) {
355 KillTimer(NULL, idle_timer_id);
357 #else /* linux + wine */
364 host_initialized = FALSE;
365 pthread_mutex_destroy (&plugin_mutex);
370 fst_run_editor (VSTState* fst, void* window_parent)
372 /* For safety, remove any pre-existing editor window */
373 fst_destroy_editor (fst);
375 if (fst->windows_window == NULL) {
378 struct ERect* er = NULL;
380 if (!(fst->plugin->flags & effFlagsHasEditor)) {
381 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
385 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
386 fst_error ("fst_create_editor() can't get module handle");
390 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
391 window_parent ? WS_CHILD : (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
392 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
393 (HWND)window_parent, NULL,
396 fst_error ("fst_create_editor() cannot create editor window");
400 if (!SetPropA (window, "fst_ptr", fst)) {
401 fst_error ("fst_create_editor() cannot set fst_ptr on window");
404 fst->windows_window = window;
407 // This is requiredv for some reason. Note the parent is set above when the window
408 // is created. Without this extra call the actual plugin window will draw outside
409 // of our plugin window.
410 SetParent((HWND)fst->windows_window, (HWND)window_parent);
412 #ifndef PLATFORM_WINDOWS /* linux + wine */
414 SetWindowPos (fst->windows_window, 0, 9999, 9999, 2, 2, 0);
415 ShowWindow (fst->windows_window, SW_SHOWNA);
416 fst->xid = (int) GetPropA (fst->windows_window, "__wine_x11_whole_window");
420 // This is the suggested order of calls.
421 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
422 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->windows_window, 0 );
423 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->hoffset, fst->height + fst->voffset, 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->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, "main");
508 if (fhandle->main_entry == 0) {
509 if ((fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "VSTPluginMain"))) {
510 fprintf(stderr, "VST >= 2.4 plugin '%s'\n", path);
511 //PBD::warning << path << _(": is a VST >= 2.4 - this plugin may or may not function correctly with this version of Ardour.") << endmsg;
515 if (fhandle->main_entry == 0) {
516 fst_unload (&fhandle);
524 fst_unload (VSTHandle** fhandle)
530 if ((*fhandle)->plugincnt) {
534 if ((*fhandle)->dll) {
535 FreeLibrary ((HMODULE)(*fhandle)->dll);
536 (*fhandle)->dll = NULL;
539 if ((*fhandle)->path) {
540 free ((*fhandle)->path);
541 (*fhandle)->path = NULL;
544 if ((*fhandle)->name) {
545 free ((*fhandle)->name);
546 (*fhandle)->name = NULL;
556 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
558 VSTState* fst = NULL;
560 if( fhandle == NULL ) {
561 fst_error( "fst_instantiate(): (the handle was NULL)\n" );
567 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
568 fst_error ("fst_instantiate: %s could not be instantiated\n", fhandle->name);
573 fst->handle = fhandle;
574 fst->plugin->user = userptr;
576 if (fst->plugin->magic != kEffectMagic) {
577 fst_error ("fst_instantiate: %s is not a vst plugin\n", fhandle->name);
582 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
583 fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
585 fst->handle->plugincnt++;
591 void fst_audio_master_idle(void) {
592 while(g_main_context_iteration(NULL, FALSE)) ;
596 fst_close (VSTState* fst)
599 fst_destroy_editor (fst);
602 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
603 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
608 if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
610 fst->handle->main_entry = NULL;
611 fst_unload (&fst->handle); // XXX
615 /* It might be good for this to be in it's own cleanup function
616 since it will free the memory for the fst leaving the caller
617 with an invalid pointer. Caller beware */
622 #if 0 // ?? who needs this, where?
623 float htonf (float v)
626 char * fin = (char*)&v;
627 char * fout = (char*)&result;