5 #ifdef PLATFORM_WINDOWS
7 #include <ardourext/misc.h>
8 #include <ardourext/pthread.h>
9 static UINT_PTR idle_timer_id = 0;
11 #else /* linux + wine */
13 #include <linux/limits.h> // PATH_MAX
14 #include <libgen.h> // basename
16 #include <wine/exception.h>
18 static int gui_quit = 0;
22 extern char * strdup (const char *);
33 static pthread_mutex_t plugin_mutex;
34 static VSTState* fst_first = NULL; /**< Head of linked list of all FSTs */
35 static int host_initialized = 0;
36 static const char magic[] = "FST Plugin State v002";
40 vstedit_wndproc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
48 /* we don't care about windows closing ...
49 * WM_CLOSE is used for minimizing the window.
50 * Our window has no frame so it shouldn't ever
51 * get sent - but if it does, we don't want our
52 * window to get minimized!
59 /* we don't care about windows being destroyed ... */
67 return DefWindowProcA (w, msg, wp, lp );
72 maybe_set_program (VSTState* fst)
74 if (fst->want_program != -1) {
75 if (fst->vst_version >= 2) {
76 fst->plugin->dispatcher (fst->plugin, effBeginSetProgram, 0, 0, NULL, 0);
79 fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
81 if (fst->vst_version >= 2) {
82 fst->plugin->dispatcher (fst->plugin, effEndSetProgram, 0, 0, NULL, 0);
84 fst->want_program = -1;
87 if (fst->want_chunk == 1) {
89 // 24 == audioMasterGetAutomationState,
90 // 48 == audioMasterGetChunkFile
91 fst->plugin->dispatcher (fst->plugin, 24 /* effSetChunk */, 1, fst->wanted_chunk_size, fst->wanted_chunk, 0);
98 HWND hwnd, // handle to window for timer messages
99 UINT message, // WM_TIMER message
100 UINT idTimer, // timer identifier
101 DWORD dwTime) // current system time
105 pthread_mutex_lock (&plugin_mutex);
107 for (fst = fst_first; fst; fst = fst->next) {
108 if (fst->gui_shown) {
109 // this seems insane, but some plugins will not draw their meters if you don't
110 // call this every time. Example Ambience by Magnus @ Smartelectron:x
111 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
114 fst->wantIdle = fst->plugin->dispatcher (fst->plugin, effIdle, 0, 0, NULL, 0);
118 #ifndef PLATFORM_WINDOWS /* linux + wine */
119 /* Dispatch messages to send keypresses to the plugin */
120 pthread_mutex_lock (&fst->lock);
123 for (i = 0; i < fst->n_pending_keys; ++i) {
125 /* I'm not quite sure what is going on here; it seems
126 * `special' keys must be delivered with WM_KEYDOWN,
127 * but that alphanumerics etc. must use WM_CHAR or
128 * they will be ignored. Ours is not to reason why ...
130 if (fst->pending_keys[i].special != 0) {
131 msg.message = WM_KEYDOWN;
132 msg.wParam = fst->pending_keys[i].special;
134 msg.message = WM_CHAR;
135 msg.wParam = fst->pending_keys[i].character;
137 msg.hwnd = GetFocus ();
139 DispatchMessageA (&msg);
142 fst->n_pending_keys = 0;
144 /* See comment for maybe_set_program call below */
145 maybe_set_program (fst);
146 fst->want_program = -1;
148 /* If we don't have an editor window yet, we still need to
149 * set up the program, otherwise when we load a plugin without
150 * opening its window it will sound wrong. However, it seems
151 * that if you don't also load the program after opening the GUI,
152 * the GUI does not reflect the program properly. So we'll not
153 * mark that we've done this (ie we won't set want_program to -1)
154 * and so it will be done again if and when the GUI arrives.
156 if (fst->program_set_without_editor == 0) {
157 maybe_set_program (fst);
158 fst->program_set_without_editor = 1;
162 pthread_mutex_unlock (&fst->lock);
165 pthread_mutex_unlock (&plugin_mutex);
169 fst_idle_timer_add_plugin (VSTState* fst)
171 pthread_mutex_lock (&plugin_mutex);
173 if (fst_first == NULL) {
176 VSTState* p = fst_first;
183 pthread_mutex_unlock (&plugin_mutex);
187 fst_idle_timer_remove_plugin (VSTState* fst)
192 pthread_mutex_lock (&plugin_mutex);
194 for (p = fst_first, prev = NULL; p; prev = p, p = p->next) {
197 prev->next = p->next;
206 if (fst_first == fst) {
207 fst_first = fst_first->next;
210 pthread_mutex_unlock (&plugin_mutex);
216 VSTState* fst = (VSTState*) calloc (1, sizeof (VSTState));
217 pthread_mutex_init (&fst->lock, NULL);
218 pthread_cond_init (&fst->window_status_change, NULL); // unused ?? -> TODO check gtk2ardour
219 pthread_cond_init (&fst->plugin_dispatcher_called, NULL); // unused ??
220 fst->want_program = -1;
222 fst->n_pending_keys = 0;
224 #ifdef PLATFORM_WINDOWS
226 #else /* linux + wine */
229 fst->program_set_without_editor = 0;
234 fst_delete (VSTState* fst)
243 fst_handle_new (void)
245 VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
249 #ifndef PLATFORM_WINDOWS /* linux + wine */
251 g_idle_call (gpointer ignored) {
253 if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
254 TranslateMessage (&msg);
255 DispatchMessageA (&msg);
257 idle_hands(NULL, 0, 0, 0);
258 return gui_quit ? FALSE : TRUE;
264 fst_init (void* possible_hmodule)
266 if (host_initialized) return 0;
269 if (possible_hmodule) {
270 #ifdef PLATFORM_WINDOWS
271 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
273 #else /* linux + wine */
274 hInst = (HMODULE) possible_hmodule;
276 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
277 fst_error ("can't get module handle");
282 fst_error ("Cannot initialise VST host");
288 wclass.cbSize = sizeof(WNDCLASSEX);
289 #ifdef PLATFORM_WINDOWS
290 wclass.style = (CS_HREDRAW | CS_VREDRAW);
292 wclass.hCursor = LoadCursor(0, IDC_ARROW);
293 #else /* linux + wine */
295 wclass.hIcon = LoadIcon(hInst, "FST");
296 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
298 wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
299 wclass.lpfnWndProc = vstedit_wndproc;
300 wclass.cbClsExtra = 0;
301 wclass.cbWndExtra = 0;
302 wclass.hInstance = hInst;
303 wclass.lpszMenuName = "MENU_FST";
304 wclass.lpszClassName = "FST";
307 pthread_mutex_init (&plugin_mutex, NULL);
308 host_initialized = -1;
310 if (!RegisterClassExA(&wclass)){
311 fst_error ("Error in fst_init(): (class registration failed");
314 #ifndef PLATFORM_WINDOWS /* linux + wine */
316 g_idle_add (g_idle_call, NULL); // XXX too early ?
317 //g_timeout_add(40, g_idle_call, NULL);
325 if (!host_initialized) return;
327 // If any plugins are still open at this point, close them!
328 while ((fst = fst_first))
331 #ifdef PLATFORM_WINDOWS
332 if (idle_timer_id != 0) {
333 KillTimer(NULL, idle_timer_id);
335 #else /* linux + wine */
340 host_initialized = FALSE;
341 pthread_mutex_destroy (&plugin_mutex);
346 fst_run_editor (VSTState* fst, void* window_parent)
348 if (fst->windows_window == NULL) {
353 if (!(fst->plugin->flags & effFlagsHasEditor)) {
354 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
358 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
359 fst_error ("fst_create_editor() can't get module handle");
363 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
364 window_parent ? WS_CHILD : (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
365 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
366 (HWND)window_parent, NULL,
369 fst_error ("fst_create_editor() cannot create editor window");
373 if (!SetPropA (window, "fst_ptr", fst)) {
374 fst_error ("fst_create_editor() cannot set fst_ptr on window");
377 fst->windows_window = window;
380 // This is requiredv for some reason. Note the parent is set above when the window
381 // is created. Without this extra call the actual plugin window will draw outside
382 // of our plugin window.
383 SetParent((HWND)fst->windows_window, (HWND)window_parent);
385 #ifndef PLATFORM_WINDOWS /* linux + wine */
387 SetWindowPos (fst->windows_window, 0, 9999, 9999, 2, 2, 0);
388 ShowWindow (fst->windows_window, SW_SHOWNA);
389 fst->xid = (int) GetPropA (fst->windows_window, "__wine_x11_whole_window");
393 // This is the suggested order of calls.
394 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
395 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->windows_window, 0 );
396 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
398 fst->width = er->right-er->left;
399 fst->height = er->bottom-er->top;
402 fst->been_activated = TRUE;
406 if (fst->windows_window) {
407 #ifdef PLATFORM_WINDOWS
408 if (idle_timer_id == 0) {
409 // Init the idle timer if needed, so that the main window calls us.
410 idle_timer_id = SetTimer(NULL, idle_timer_id, 50, (TIMERPROC) idle_hands);
414 fst_idle_timer_add_plugin (fst);
417 return fst->windows_window == NULL ? -1 : 0;
421 fst_destroy_editor (VSTState* fst)
423 if (fst->windows_window) {
424 fprintf (stderr, "%s destroying edit window\n", fst->handle->name);
426 fst_idle_timer_remove_plugin (fst);
427 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
429 DestroyWindow ((HWND)(fst->windows_window));
431 fst->windows_window = NULL;
434 fst->been_activated = FALSE;
438 fst_move_window_into_view (VSTState* fst)
440 if (fst->windows_window) {
441 #ifdef PLATFORM_WINDOWS
442 SetWindowPos ((HWND)(fst->windows_window), 0, 0, fst->voffset, fst->width, fst->height, 0);
443 #else /* linux + wine */
444 SetWindowPos ((HWND)(fst->windows_window), 0, 0, 0, fst->width, fst->height, 0);
446 ShowWindow ((HWND)(fst->windows_window), SW_SHOWNA);
451 fst_load_vst_library(const char * path)
453 char legalized_path[PATH_MAX];
454 strcpy (legalized_path, g_locale_from_utf8(path, -1, NULL, NULL, NULL));
455 return ( LoadLibraryA (legalized_path) );
459 fst_load (const char *path)
461 VSTHandle* fhandle = NULL;
463 if ((strlen(path)) && (NULL != (fhandle = fst_handle_new ())))
466 fhandle->nameptr = strdup (path);
467 fhandle->path = strdup (path);
468 fhandle->name = basename(fhandle->nameptr);
469 if ((period = strrchr (fhandle->name, '.'))) {
473 // See if we can load the plugin DLL
474 if ((fhandle->dll = (HMODULE)fst_load_vst_library (path)) == NULL) {
475 fst_unload (&fhandle);
479 fhandle->main_entry = (main_entry_t) GetProcAddress (fhandle->dll, "main");
481 if (fhandle->main_entry == 0) {
482 if ((fhandle->main_entry = (main_entry_t) GetProcAddress (fhandle->dll, "VSTPluginMain"))) {
483 fprintf(stderr, "VST >= 2.4 plugin '%s'\n", path);
484 //PBD::warning << path << _(": is a VST >= 2.4 - this plugin may or may not function correctly with this version of Ardour.") << endmsg;
488 if (fhandle->main_entry == 0) {
489 fst_unload (&fhandle);
497 fst_unload (VSTHandle** fhandle)
503 if ((*fhandle)->plugincnt) {
507 if ((*fhandle)->dll) {
508 FreeLibrary ((HMODULE)(*fhandle)->dll);
509 (*fhandle)->dll = NULL;
512 if ((*fhandle)->path) {
513 free ((*fhandle)->path);
514 (*fhandle)->path = NULL;
517 if ((*fhandle)->nameptr) {
518 free ((*fhandle)->nameptr);
519 (*fhandle)->nameptr = NULL;
520 (*fhandle)->name = NULL;
530 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
532 VSTState* fst = NULL;
534 if( fhandle == NULL ) {
535 fst_error( "fst_instantiate(): (the handle was NULL)\n" );
541 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
542 fst_error ("fst_instantiate: %s could not be instantiated\n", fhandle->name);
547 fst->handle = fhandle;
548 fst->plugin->user = userptr;
550 if (fst->plugin->magic != kEffectMagic) {
551 fst_error ("fst_instantiate: %s is not a vst plugin\n", fhandle->name);
556 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
557 fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
559 fst->handle->plugincnt++;
566 fst_close (VSTState* fst)
569 fst_destroy_editor (fst);
572 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
573 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
578 if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
580 fst->handle->main_entry = NULL;
581 fst_unload (&fst->handle);
585 /* It might be good for this to be in it's own cleanup function
586 since it will free the memory for the fst leaving the caller
587 with an invalid pointer. Caller beware */
592 #if 0 // ?? who needs this, where?
593 float htonf (float v)
596 char * fin = (char*)&v;
597 char * fout = (char*)&result;