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 fst->plugin->dispatcher (fst->plugin, 24 /* effSetChunk */, 1, fst->wanted_chunk_size, fst->wanted_chunk, 0);
102 HWND hwnd, // handle to window for timer messages
103 UINT message, // WM_TIMER message
104 UINT idTimer, // timer identifier
105 DWORD dwTime) // current system time
109 pthread_mutex_lock (&plugin_mutex);
111 for (fst = fst_first; fst; fst = fst->next) {
112 if (fst->gui_shown) {
113 // this seems insane, but some plugins will not draw their meters if you don't
114 // call this every time. Example Ambience by Magnus @ Smartelectron:x
115 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
118 fst->wantIdle = fst->plugin->dispatcher (fst->plugin, effIdle, 0, 0, NULL, 0);
122 pthread_mutex_lock (&fst->lock);
123 #ifndef PLATFORM_WINDOWS /* linux + wine */
124 /* Dispatch messages to send keypresses to the plugin */
127 for (i = 0; i < fst->n_pending_keys; ++i) {
129 /* I'm not quite sure what is going on here; it seems
130 * `special' keys must be delivered with WM_KEYDOWN,
131 * but that alphanumerics etc. must use WM_CHAR or
132 * they will be ignored. Ours is not to reason why ...
134 if (fst->pending_keys[i].special != 0) {
135 msg.message = WM_KEYDOWN;
136 msg.wParam = fst->pending_keys[i].special;
138 msg.message = WM_CHAR;
139 msg.wParam = fst->pending_keys[i].character;
141 msg.hwnd = GetFocus ();
143 DispatchMessageA (&msg);
146 fst->n_pending_keys = 0;
149 /* See comment for maybe_set_program call below */
150 maybe_set_program (fst);
151 fst->want_program = -1;
153 /* If we don't have an editor window yet, we still need to
154 * set up the program, otherwise when we load a plugin without
155 * opening its window it will sound wrong. However, it seems
156 * that if you don't also load the program after opening the GUI,
157 * the GUI does not reflect the program properly. So we'll not
158 * mark that we've done this (ie we won't set want_program to -1)
159 * and so it will be done again if and when the GUI arrives.
161 if (fst->program_set_without_editor == 0) {
162 maybe_set_program (fst);
163 fst->program_set_without_editor = 1;
166 pthread_mutex_unlock (&fst->lock);
169 pthread_mutex_unlock (&plugin_mutex);
173 fst_idle_timer_add_plugin (VSTState* fst)
175 pthread_mutex_lock (&plugin_mutex);
177 if (fst_first == NULL) {
180 VSTState* p = fst_first;
187 pthread_mutex_unlock (&plugin_mutex);
191 fst_idle_timer_remove_plugin (VSTState* fst)
196 pthread_mutex_lock (&plugin_mutex);
198 for (p = fst_first, prev = NULL; p; prev = p, p = p->next) {
201 prev->next = p->next;
210 if (fst_first == fst) {
211 fst_first = fst_first->next;
214 pthread_mutex_unlock (&plugin_mutex);
220 VSTState* fst = (VSTState*) calloc (1, sizeof (VSTState));
221 pthread_mutex_init (&fst->lock, NULL);
222 pthread_cond_init (&fst->window_status_change, NULL); // unused ?? -> TODO check gtk2ardour
223 pthread_cond_init (&fst->plugin_dispatcher_called, NULL); // unused ??
224 fst->want_program = -1;
226 fst->n_pending_keys = 0;
228 #ifdef PLATFORM_WINDOWS
231 #else /* linux + wine */
235 fst->program_set_without_editor = 0;
240 fst_delete (VSTState* fst)
249 fst_handle_new (void)
251 VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
255 #ifndef PLATFORM_WINDOWS /* linux + wine */
257 g_idle_call (gpointer ignored) {
258 if (gui_quit) return FALSE;
260 if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
261 TranslateMessage (&msg);
262 DispatchMessageA (&msg);
264 idle_hands(NULL, 0, 0, 0);
265 g_main_context_iteration(NULL, FALSE);
266 return gui_quit ? FALSE : TRUE;
272 fst_init (void* possible_hmodule)
274 if (host_initialized) return 0;
277 if (possible_hmodule) {
278 #ifdef PLATFORM_WINDOWS
279 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
281 #else /* linux + wine */
282 hInst = (HMODULE) possible_hmodule;
284 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
285 fst_error ("can't get module handle");
290 fst_error ("Cannot initialise VST host");
296 wclass.cbSize = sizeof(WNDCLASSEX);
297 #ifdef PLATFORM_WINDOWS
298 wclass.style = (CS_HREDRAW | CS_VREDRAW);
300 wclass.hCursor = LoadCursor(0, IDC_ARROW);
301 #else /* linux + wine */
303 wclass.hIcon = LoadIcon(hInst, "FST");
304 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
306 wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
307 wclass.lpfnWndProc = vstedit_wndproc;
308 wclass.cbClsExtra = 0;
309 wclass.cbWndExtra = 0;
310 wclass.hInstance = hInst;
311 wclass.lpszMenuName = "MENU_FST";
312 wclass.lpszClassName = "FST";
315 pthread_mutex_init (&plugin_mutex, NULL);
316 host_initialized = -1;
318 if (!RegisterClassExA(&wclass)){
319 fst_error ("Error in fst_init(): (class registration failed");
326 fst_start_threading(void)
328 #ifndef PLATFORM_WINDOWS /* linux + wine */
331 idle_id = g_idle_add (g_idle_call, NULL);
337 fst_stop_threading(void) {
338 #ifndef PLATFORM_WINDOWS /* linux + wine */
342 g_main_context_iteration(NULL, FALSE);
343 //g_source_remove(idle_id);
352 if (!host_initialized) return;
354 // If any plugins are still open at this point, close them!
355 while ((fst = fst_first))
358 #ifdef PLATFORM_WINDOWS
359 if (idle_timer_id != 0) {
360 KillTimer(NULL, idle_timer_id);
362 #else /* linux + wine */
369 host_initialized = FALSE;
370 pthread_mutex_destroy (&plugin_mutex);
375 fst_run_editor (VSTState* fst, void* window_parent)
377 /* For safety, remove any pre-existing editor window */
378 fst_destroy_editor (fst);
380 if (fst->windows_window == NULL) {
383 struct ERect* er = NULL;
385 if (!(fst->plugin->flags & effFlagsHasEditor)) {
386 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
390 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
391 fst_error ("fst_create_editor() can't get module handle");
395 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
396 window_parent ? WS_CHILD : (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
397 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
398 (HWND)window_parent, NULL,
401 fst_error ("fst_create_editor() cannot create editor window");
405 if (!SetPropA (window, "fst_ptr", fst)) {
406 fst_error ("fst_create_editor() cannot set fst_ptr on window");
409 fst->windows_window = window;
412 // This is requiredv for some reason. Note the parent is set above when the window
413 // is created. Without this extra call the actual plugin window will draw outside
414 // of our plugin window.
415 SetParent((HWND)fst->windows_window, (HWND)window_parent);
417 #ifndef PLATFORM_WINDOWS /* linux + wine */
419 SetWindowPos (fst->windows_window, 0, 9999, 9999, 2, 2, 0);
420 ShowWindow (fst->windows_window, SW_SHOWNA);
421 fst->xid = (int) GetPropA (fst->windows_window, "__wine_x11_whole_window");
425 // This is the suggested order of calls.
426 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
427 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->windows_window, 0 );
428 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
431 fst->width = er->right - er->left;
432 fst->height = er->bottom - er->top;
435 fst->been_activated = TRUE;
439 if (fst->windows_window) {
440 #ifdef PLATFORM_WINDOWS
441 if (idle_timer_id == 0) {
442 // Init the idle timer if needed, so that the main window calls us.
443 idle_timer_id = SetTimer(NULL, idle_timer_id, 50, (TIMERPROC) idle_hands);
447 fst_idle_timer_add_plugin (fst);
450 return fst->windows_window == NULL ? -1 : 0;
454 fst_destroy_editor (VSTState* fst)
456 if (fst->windows_window) {
457 fprintf (stderr, "%s destroying edit window\n", fst->handle->name);
459 fst_idle_timer_remove_plugin (fst);
460 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
462 DestroyWindow ((HWND)(fst->windows_window));
464 fst->windows_window = NULL;
467 fst->been_activated = FALSE;
471 fst_move_window_into_view (VSTState* fst)
473 if (fst->windows_window) {
474 #ifdef PLATFORM_WINDOWS
475 SetWindowPos ((HWND)(fst->windows_window), 0, fst->hoffset, fst->voffset, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
476 #else /* linux + wine */
477 SetWindowPos ((HWND)(fst->windows_window), 0, 0, 0, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
479 ShowWindow ((HWND)(fst->windows_window), SW_SHOWNA);
484 fst_load_vst_library(const char * path)
486 char legalized_path[PATH_MAX];
487 strcpy (legalized_path, g_locale_from_utf8(path, -1, NULL, NULL, NULL));
488 return ( LoadLibraryA (legalized_path) );
492 fst_load (const char *path)
494 VSTHandle* fhandle = NULL;
496 if ((strlen(path)) && (NULL != (fhandle = fst_handle_new ())))
499 fhandle->path = strdup (path);
500 fhandle->name = g_path_get_basename(path);
501 if ((period = strrchr (fhandle->name, '.'))) {
505 // See if we can load the plugin DLL
506 if ((fhandle->dll = (HMODULE)fst_load_vst_library (path)) == NULL) {
507 fst_unload (&fhandle);
511 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "main");
513 if (fhandle->main_entry == 0) {
514 if ((fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "VSTPluginMain"))) {
515 fprintf(stderr, "VST >= 2.4 plugin '%s'\n", path);
516 //PBD::warning << path << _(": is a VST >= 2.4 - this plugin may or may not function correctly with this version of Ardour.") << endmsg;
520 if (fhandle->main_entry == 0) {
521 fst_unload (&fhandle);
529 fst_unload (VSTHandle** fhandle)
535 if ((*fhandle)->plugincnt) {
539 if ((*fhandle)->dll) {
540 FreeLibrary ((HMODULE)(*fhandle)->dll);
541 (*fhandle)->dll = NULL;
544 if ((*fhandle)->path) {
545 free ((*fhandle)->path);
546 (*fhandle)->path = NULL;
549 if ((*fhandle)->name) {
550 free ((*fhandle)->name);
551 (*fhandle)->name = NULL;
561 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
563 VSTState* fst = NULL;
565 if( fhandle == NULL ) {
566 fst_error( "fst_instantiate(): (the handle was NULL)\n" );
572 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
573 fst_error ("fst_instantiate: %s could not be instantiated\n", fhandle->name);
578 fst->handle = fhandle;
579 fst->plugin->user = userptr;
581 if (fst->plugin->magic != kEffectMagic) {
582 fst_error ("fst_instantiate: %s is not a vst plugin\n", fhandle->name);
587 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
588 fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
590 fst->handle->plugincnt++;
596 void fst_audio_master_idle(void) {
597 while(g_main_context_iteration(NULL, FALSE)) ;
601 fst_close (VSTState* fst)
604 fst_destroy_editor (fst);
607 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
608 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
613 if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
615 fst->handle->main_entry = NULL;
616 fst_unload (&fst->handle); // XXX
620 /* It might be good for this to be in it's own cleanup function
621 since it will free the memory for the fst leaving the caller
622 with an invalid pointer. Caller beware */
627 #if 0 // ?? who needs this, where?
628 float htonf (float v)
631 char * fin = (char*)&v;
632 char * fout = (char*)&result;