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 //vststate_init (fst);
225 pthread_mutex_init (&fst->lock, 0);
226 pthread_mutex_init (&fst->state_lock, 0);
227 pthread_cond_init (&fst->window_status_change, 0);
228 pthread_cond_init (&fst->plugin_dispatcher_called, 0);
229 pthread_cond_init (&fst->window_created, 0);
230 fst->want_program = -1;
233 #ifdef PLATFORM_WINDOWS
236 #else /* linux + wine */
244 fst_delete (VSTState* fst)
253 fst_handle_new (void)
255 VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
259 #ifndef PLATFORM_WINDOWS /* linux + wine */
261 g_idle_call (gpointer ignored) {
262 if (gui_quit) return FALSE;
264 if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
265 TranslateMessage (&msg);
266 DispatchMessageA (&msg);
268 idle_hands(NULL, 0, 0, 0);
269 g_main_context_iteration(NULL, FALSE);
270 return gui_quit ? FALSE : TRUE;
276 fst_init (void* possible_hmodule)
278 if (host_initialized) return 0;
281 if (possible_hmodule) {
282 #ifdef PLATFORM_WINDOWS
283 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
285 #else /* linux + wine */
286 hInst = (HMODULE) possible_hmodule;
288 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
289 fst_error ("can't get module handle");
294 fst_error ("Cannot initialise VST host");
300 wclass.cbSize = sizeof(WNDCLASSEX);
301 #ifdef PLATFORM_WINDOWS
302 wclass.style = (CS_HREDRAW | CS_VREDRAW);
304 wclass.hCursor = LoadCursor(0, IDC_ARROW);
305 #else /* linux + wine */
307 wclass.hIcon = LoadIcon(hInst, "FST");
308 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
310 wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
311 wclass.lpfnWndProc = vstedit_wndproc;
312 wclass.cbClsExtra = 0;
313 wclass.cbWndExtra = 0;
314 wclass.hInstance = hInst;
315 wclass.lpszMenuName = "MENU_FST";
316 wclass.lpszClassName = "FST";
319 pthread_mutex_init (&plugin_mutex, NULL);
320 host_initialized = -1;
322 if (!RegisterClassExA(&wclass)){
323 fst_error ("Error in fst_init(): (class registration failed");
330 fst_start_threading(void)
332 #ifndef PLATFORM_WINDOWS /* linux + wine */
335 idle_id = g_idle_add (g_idle_call, NULL);
341 fst_stop_threading(void) {
342 #ifndef PLATFORM_WINDOWS /* linux + wine */
346 g_main_context_iteration(NULL, FALSE);
347 //g_source_remove(idle_id);
356 if (!host_initialized) return;
358 // If any plugins are still open at this point, close them!
359 while ((fst = fst_first))
362 #ifdef PLATFORM_WINDOWS
363 if (idle_timer_id != 0) {
364 KillTimer(NULL, idle_timer_id);
366 #else /* linux + wine */
373 host_initialized = FALSE;
374 pthread_mutex_destroy (&plugin_mutex);
379 fst_run_editor (VSTState* fst, void* window_parent)
381 /* For safety, remove any pre-existing editor window */
382 fst_destroy_editor (fst);
384 if (fst->windows_window == NULL) {
387 struct ERect* er = NULL;
389 if (!(fst->plugin->flags & effFlagsHasEditor)) {
390 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
394 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
395 fst_error ("fst_create_editor() can't get module handle");
399 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
400 window_parent ? WS_CHILD : (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
401 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
402 (HWND)window_parent, NULL,
405 fst_error ("fst_create_editor() cannot create editor window");
409 if (!SetPropA (window, "fst_ptr", fst)) {
410 fst_error ("fst_create_editor() cannot set fst_ptr on window");
413 fst->windows_window = window;
416 // This is requiredv for some reason. Note the parent is set above when the window
417 // is created. Without this extra call the actual plugin window will draw outside
418 // of our plugin window.
419 SetParent((HWND)fst->windows_window, (HWND)window_parent);
421 #ifndef PLATFORM_WINDOWS /* linux + wine */
423 SetWindowPos (fst->windows_window, 0, 9999, 9999, 2, 2, 0);
424 ShowWindow (fst->windows_window, SW_SHOWNA);
425 fst->xid = (int) GetPropA (fst->windows_window, "__wine_x11_whole_window");
429 // This is the suggested order of calls.
430 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
431 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->windows_window, 0 );
432 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
435 fst->width = er->right - er->left;
436 fst->height = er->bottom - er->top;
439 fst->been_activated = TRUE;
443 if (fst->windows_window) {
444 #ifdef PLATFORM_WINDOWS
445 if (idle_timer_id == 0) {
446 // Init the idle timer if needed, so that the main window calls us.
447 idle_timer_id = SetTimer(NULL, idle_timer_id, 50, (TIMERPROC) idle_hands);
451 fst_idle_timer_add_plugin (fst);
454 return fst->windows_window == NULL ? -1 : 0;
458 fst_destroy_editor (VSTState* fst)
460 if (fst->windows_window) {
461 fprintf (stderr, "%s destroying edit window\n", fst->handle->name);
463 fst_idle_timer_remove_plugin (fst);
464 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
466 DestroyWindow ((HWND)(fst->windows_window));
468 fst->windows_window = NULL;
471 fst->been_activated = FALSE;
475 fst_move_window_into_view (VSTState* fst)
477 if (fst->windows_window) {
478 #ifdef PLATFORM_WINDOWS
479 SetWindowPos ((HWND)(fst->windows_window), 0, fst->hoffset, fst->voffset, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
480 #else /* linux + wine */
481 SetWindowPos ((HWND)(fst->windows_window), 0, 0, 0, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
483 ShowWindow ((HWND)(fst->windows_window), SW_SHOWNA);
488 fst_load_vst_library(const char * path)
490 char legalized_path[PATH_MAX];
491 strcpy (legalized_path, g_locale_from_utf8(path, -1, NULL, NULL, NULL));
492 return ( LoadLibraryA (legalized_path) );
496 fst_load (const char *path)
498 VSTHandle* fhandle = NULL;
500 if ((strlen(path)) && (NULL != (fhandle = fst_handle_new ())))
503 fhandle->path = strdup (path);
504 fhandle->name = g_path_get_basename(path);
505 if ((period = strrchr (fhandle->name, '.'))) {
509 // See if we can load the plugin DLL
510 if ((fhandle->dll = (HMODULE)fst_load_vst_library (path)) == NULL) {
511 fst_unload (&fhandle);
515 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "main");
517 if (fhandle->main_entry == 0) {
518 if ((fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "VSTPluginMain"))) {
519 fprintf(stderr, "VST >= 2.4 plugin '%s'\n", path);
520 //PBD::warning << path << _(": is a VST >= 2.4 - this plugin may or may not function correctly with this version of Ardour.") << endmsg;
524 if (fhandle->main_entry == 0) {
525 fst_unload (&fhandle);
533 fst_unload (VSTHandle** fhandle)
539 if ((*fhandle)->plugincnt) {
543 if ((*fhandle)->dll) {
544 FreeLibrary ((HMODULE)(*fhandle)->dll);
545 (*fhandle)->dll = NULL;
548 if ((*fhandle)->path) {
549 free ((*fhandle)->path);
550 (*fhandle)->path = NULL;
553 if ((*fhandle)->name) {
554 free ((*fhandle)->name);
555 (*fhandle)->name = NULL;
565 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
567 VSTState* fst = NULL;
569 if( fhandle == NULL ) {
570 fst_error( "fst_instantiate(): (the handle was NULL)\n" );
576 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
577 fst_error ("fst_instantiate: %s could not be instantiated\n", fhandle->name);
582 fst->handle = fhandle;
583 fst->plugin->user = userptr;
585 if (fst->plugin->magic != kEffectMagic) {
586 fst_error ("fst_instantiate: %s is not a vst plugin\n", fhandle->name);
591 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
592 fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
594 fst->handle->plugincnt++;
600 void fst_audio_master_idle(void) {
601 while(g_main_context_iteration(NULL, FALSE)) ;
605 fst_close (VSTState* fst)
608 fst_destroy_editor (fst);
611 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
612 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
617 if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
619 fst->handle->main_entry = NULL;
620 fst_unload (&fst->handle); // XXX
624 /* It might be good for this to be in it's own cleanup function
625 since it will free the memory for the fst leaving the caller
626 with an invalid pointer. Caller beware */
631 #if 0 // ?? who needs this, where?
632 float htonf (float v)
635 char * fin = (char*)&v;
636 char * fout = (char*)&result;