2 * Copyright (C) 2006-2010 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2010-2011 Carl Hetherington <carl@carlh.net>
4 * Copyright (C) 2014-2016 John Emmas <john@creativepost.co.uk>
5 * Copyright (C) 2014-2017 Robin Gareus <robin@gareus.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #define fst_error(...) fprintf(stderr, __VA_ARGS__)
28 #ifdef PLATFORM_WINDOWS
31 static UINT_PTR idle_timer_id = 0;
33 #else /* linux + wine */
35 #include <linux/limits.h> // PATH_MAX
37 #include <wine/exception.h>
39 static int gui_quit = 0;
40 static unsigned int idle_id = 0;
45 extern char * strdup (const char *);
58 static pthread_mutex_t plugin_mutex;
59 static VSTState* fst_first = NULL; /**< Head of linked list of all FSTs */
60 static int host_initialized = 0;
61 static const char magic[] = "FST Plugin State v002";
65 vstedit_wndproc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
73 #ifdef PLATFORM_WINDOWS
75 LRESULT rv = DefWindowProcA (w, msg, wp, lp);
77 GetClientRect(w, &rect);
79 printf("VST WM_SIZE.. %ld %ld %ld %ld\n", rect.top, rect.left, (rect.right - rect.left), (rect.bottom - rect.top));
81 VSTState* fst = (VSTState*) GetProp (w, "fst_ptr");
83 int32_t width = (rect.right - rect.left);
84 int32_t height = (rect.bottom - rect.top);
85 if (width > 0 && height > 0) {
86 fst->amc (fst->plugin, 15 /*audioMasterSizeWindow */, width, height, NULL, 0);
94 /* we don't care about windows closing ...
95 * WM_CLOSE is used for minimizing the window.
96 * Our window has no frame so it shouldn't ever
97 * get sent - but if it does, we don't want our
98 * window to get minimized!
105 /* we don't care about windows being destroyed ... */
113 return DefWindowProcA (w, msg, wp, lp);
119 HWND hwnd, // handle to window for timer messages
120 UINT message, // WM_TIMER message
121 UINT idTimer, // timer identifier
122 DWORD dwTime) // current system time
126 pthread_mutex_lock (&plugin_mutex);
128 for (fst = fst_first; fst; fst = fst->next) {
129 if (fst->gui_shown) {
130 // this seems insane, but some plugins will not draw their meters if you don't
131 // call this every time. Example Ambience by Magnus @ Smartelectron:x
132 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
135 fst->wantIdle = fst->plugin->dispatcher (fst->plugin, effIdle, 0, 0, NULL, 0);
139 pthread_mutex_lock (&fst->lock);
140 #ifndef PLATFORM_WINDOWS /* linux + wine */
141 /* Dispatch messages to send keypresses to the plugin */
144 for (i = 0; i < fst->n_pending_keys; ++i) {
146 /* I'm not quite sure what is going on here; it seems
147 * `special' keys must be delivered with WM_KEYDOWN,
148 * but that alphanumerics etc. must use WM_CHAR or
149 * they will be ignored. Ours is not to reason why ...
151 if (fst->pending_keys[i].special != 0) {
152 msg.message = WM_KEYDOWN;
153 msg.wParam = fst->pending_keys[i].special;
155 msg.message = WM_CHAR;
156 msg.wParam = fst->pending_keys[i].character;
158 msg.hwnd = GetFocus ();
160 DispatchMessageA (&msg);
163 fst->n_pending_keys = 0;
166 /* See comment for call below */
167 vststate_maybe_set_program (fst);
168 fst->want_program = -1;
170 /* If we don't have an editor window yet, we still need to
171 * set up the program, otherwise when we load a plugin without
172 * opening its window it will sound wrong. However, it seems
173 * that if you don't also load the program after opening the GUI,
174 * the GUI does not reflect the program properly. So we'll not
175 * mark that we've done this (ie we won't set want_program to -1)
176 * and so it will be done again if and when the GUI arrives.
178 if (fst->program_set_without_editor == 0) {
179 vststate_maybe_set_program (fst);
180 fst->program_set_without_editor = 1;
183 pthread_mutex_unlock (&fst->lock);
186 pthread_mutex_unlock (&plugin_mutex);
190 fst_idle_timer_add_plugin (VSTState* fst)
192 pthread_mutex_lock (&plugin_mutex);
194 if (fst_first == NULL) {
197 VSTState* p = fst_first;
204 pthread_mutex_unlock (&plugin_mutex);
208 fst_idle_timer_remove_plugin (VSTState* fst)
213 pthread_mutex_lock (&plugin_mutex);
215 for (p = fst_first, prev = NULL; p; prev = p, p = p->next) {
218 prev->next = p->next;
227 if (fst_first == fst) {
228 fst_first = fst_first->next;
231 pthread_mutex_unlock (&plugin_mutex);
237 VSTState* fst = (VSTState*) calloc (1, sizeof (VSTState));
240 #ifdef PLATFORM_WINDOWS
243 #else /* linux + wine */
251 fst_delete (VSTState* fst)
260 fst_handle_new (void)
262 VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
266 #ifndef PLATFORM_WINDOWS /* linux + wine */
268 g_idle_call (gpointer ignored) {
269 if (gui_quit) return FALSE;
271 if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
272 TranslateMessage (&msg);
273 DispatchMessageA (&msg);
275 idle_hands(NULL, 0, 0, 0);
276 g_main_context_iteration(NULL, FALSE);
277 return gui_quit ? FALSE : TRUE;
283 fst_init (void* possible_hmodule)
285 if (host_initialized) return 0;
288 if (possible_hmodule) {
289 #ifdef PLATFORM_WINDOWS
290 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
292 #else /* linux + wine */
293 hInst = (HMODULE) possible_hmodule;
295 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
296 fst_error ("can't get module handle");
301 fst_error ("Cannot initialise VST host");
307 wclass.cbSize = sizeof(WNDCLASSEX);
308 #ifdef PLATFORM_WINDOWS
309 wclass.style = (CS_HREDRAW | CS_VREDRAW);
311 wclass.hCursor = LoadCursor(0, IDC_ARROW);
312 #else /* linux + wine */
314 wclass.hIcon = LoadIcon(hInst, "FST");
315 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
317 wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
318 wclass.lpfnWndProc = vstedit_wndproc;
319 wclass.cbClsExtra = 0;
320 wclass.cbWndExtra = 0;
321 wclass.hInstance = hInst;
322 wclass.lpszMenuName = "MENU_FST";
323 wclass.lpszClassName = "FST";
326 pthread_mutex_init (&plugin_mutex, NULL);
327 host_initialized = -1;
329 if (!RegisterClassExA(&wclass)){
330 fst_error ("Error in fst_init(): (class registration failed");
337 fst_start_threading(void)
339 #ifndef PLATFORM_WINDOWS /* linux + wine */
342 idle_id = g_idle_add (g_idle_call, NULL);
348 fst_stop_threading(void) {
349 #ifndef PLATFORM_WINDOWS /* linux + wine */
353 g_main_context_iteration(NULL, FALSE);
354 //g_source_remove(idle_id);
363 if (!host_initialized) return;
365 // If any plugins are still open at this point, close them!
366 while ((fst = fst_first))
369 #ifdef PLATFORM_WINDOWS
370 if (idle_timer_id != 0) {
371 KillTimer(NULL, idle_timer_id);
373 #else /* linux + wine */
380 host_initialized = FALSE;
381 pthread_mutex_destroy (&plugin_mutex);
386 fst_run_editor (VSTState* fst, void* window_parent)
388 /* For safety, remove any pre-existing editor window */
389 fst_destroy_editor (fst);
391 if (fst->windows_window == NULL) {
394 struct ERect* er = NULL;
396 if (!(fst->plugin->flags & effFlagsHasEditor)) {
397 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
401 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
402 fst_error ("fst_create_editor() can't get module handle");
406 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
407 window_parent ? WS_CHILD : (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
408 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
409 (HWND)window_parent, NULL,
412 fst_error ("fst_create_editor() cannot create editor window");
416 if (!SetPropA (window, "fst_ptr", fst)) {
417 fst_error ("fst_create_editor() cannot set fst_ptr on window");
420 fst->windows_window = window;
423 // This is requiredv for some reason. Note the parent is set above when the window
424 // is created. Without this extra call the actual plugin window will draw outside
425 // of our plugin window.
426 SetParent((HWND)fst->windows_window, (HWND)window_parent);
428 #ifndef PLATFORM_WINDOWS /* linux + wine */
430 SetWindowPos (fst->windows_window, 0, 9999, 9999, 2, 2, 0);
431 ShowWindow (fst->windows_window, SW_SHOWNA);
432 fst->xid = (int) GetPropA (fst->windows_window, "__wine_x11_whole_window");
436 // This is the suggested order of calls.
437 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
438 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->windows_window, 0 );
439 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
442 fst->width = er->right - er->left;
443 fst->height = er->bottom - er->top;
446 fst->been_activated = TRUE;
450 if (fst->windows_window) {
451 #ifdef PLATFORM_WINDOWS
452 if (idle_timer_id == 0) {
453 // Init the idle timer if needed, so that the main window calls us.
454 idle_timer_id = SetTimer(NULL, idle_timer_id, 50, (TIMERPROC) idle_hands);
458 fst_idle_timer_add_plugin (fst);
461 return fst->windows_window == NULL ? -1 : 0;
465 fst_destroy_editor (VSTState* fst)
467 if (fst->windows_window) {
468 fprintf (stderr, "%s destroying edit window\n", fst->handle->name);
470 fst_idle_timer_remove_plugin (fst);
471 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
473 DestroyWindow ((HWND)(fst->windows_window));
475 fst->windows_window = NULL;
478 fst->been_activated = FALSE;
482 fst_move_window_into_view (VSTState* fst)
484 if (fst->windows_window) {
485 #ifdef PLATFORM_WINDOWS
486 SetWindowPos ((HWND)(fst->windows_window),
488 fst->hoffset, fst->voffset,
489 fst->width, fst->height,
490 SWP_NOACTIVATE|SWP_NOOWNERZORDER);
491 #else /* linux + wine */
492 SetWindowPos ((HWND)(fst->windows_window), 0, 0, 0, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
494 ShowWindow ((HWND)(fst->windows_window), SW_SHOWNA);
495 UpdateWindow ((HWND)(fst->windows_window));
500 fst_load_vst_library(const char * path)
502 char legalized_path[PATH_MAX];
503 strcpy (legalized_path, g_locale_from_utf8(path, -1, NULL, NULL, NULL));
504 return ( LoadLibraryA (legalized_path) );
508 fst_load (const char *path)
510 VSTHandle* fhandle = NULL;
512 if ((strlen(path)) && (NULL != (fhandle = fst_handle_new ())))
515 fhandle->path = strdup (path);
516 fhandle->name = g_path_get_basename(path);
517 if ((period = strrchr (fhandle->name, '.'))) {
521 // See if we can load the plugin DLL
522 if ((fhandle->dll = (HMODULE)fst_load_vst_library (path)) == NULL) {
523 fst_unload (&fhandle);
527 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "VSTPluginMain");
529 if (fhandle->main_entry == 0) {
530 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "main");
533 if (fhandle->main_entry == 0) {
534 fst_unload (&fhandle);
542 fst_unload (VSTHandle** fhandle)
548 if ((*fhandle)->plugincnt) {
552 if ((*fhandle)->dll) {
553 FreeLibrary ((HMODULE)(*fhandle)->dll);
554 (*fhandle)->dll = NULL;
557 if ((*fhandle)->path) {
558 free ((*fhandle)->path);
559 (*fhandle)->path = NULL;
562 if ((*fhandle)->name) {
563 free ((*fhandle)->name);
564 (*fhandle)->name = NULL;
574 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
576 VSTState* fst = NULL;
578 if( fhandle == NULL ) {
579 fst_error( "fst_instantiate(): (the handle was NULL)\n" );
586 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
587 fst_error ("fst_instantiate: %s could not be instantiated\n", fhandle->name);
592 fst->handle = fhandle;
593 fst->plugin->ptr1 = userptr;
595 if (fst->plugin->magic != kEffectMagic) {
596 fst_error ("fst_instantiate: %s is not a vst plugin\n", fhandle->name);
602 /* scanning.. or w/o master-callback userptr == 0, open now.
604 * Session::vst_callback needs a pointer to the AEffect
605 * ((VSTPlugin*)userptr)->_plugin = vstfx->plugin
606 * before calling effOpen, because effOpen may call back
608 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
609 fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
612 fst->handle->plugincnt++;
618 void fst_audio_master_idle(void) {
619 while(g_main_context_iteration(NULL, FALSE)) ;
623 fst_close (VSTState* fst)
626 fst_destroy_editor (fst);
629 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
630 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
635 if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
637 fst->handle->main_entry = NULL;
638 fst_unload (&fst->handle); // XXX
642 /* It might be good for this to be in it's own cleanup function
643 since it will free the memory for the fst leaving the caller
644 with an invalid pointer. Caller beware */
649 #if 0 // ?? who needs this, where?
650 float htonf (float v)
653 char * fin = (char*)&v;
654 char * fout = (char*)&result;