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 );
77 HWND hwnd, // handle to window for timer messages
78 UINT message, // WM_TIMER message
79 UINT idTimer, // timer identifier
80 DWORD dwTime) // current system time
84 pthread_mutex_lock (&plugin_mutex);
86 for (fst = fst_first; fst; fst = fst->next) {
88 // this seems insane, but some plugins will not draw their meters if you don't
89 // call this every time. Example Ambience by Magnus @ Smartelectron:x
90 fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
93 fst->wantIdle = fst->plugin->dispatcher (fst->plugin, effIdle, 0, 0, NULL, 0);
97 pthread_mutex_lock (&fst->lock);
98 #ifndef PLATFORM_WINDOWS /* linux + wine */
99 /* Dispatch messages to send keypresses to the plugin */
102 for (i = 0; i < fst->n_pending_keys; ++i) {
104 /* I'm not quite sure what is going on here; it seems
105 * `special' keys must be delivered with WM_KEYDOWN,
106 * but that alphanumerics etc. must use WM_CHAR or
107 * they will be ignored. Ours is not to reason why ...
109 if (fst->pending_keys[i].special != 0) {
110 msg.message = WM_KEYDOWN;
111 msg.wParam = fst->pending_keys[i].special;
113 msg.message = WM_CHAR;
114 msg.wParam = fst->pending_keys[i].character;
116 msg.hwnd = GetFocus ();
118 DispatchMessageA (&msg);
121 fst->n_pending_keys = 0;
124 /* See comment for call below */
125 vststate_maybe_set_program (fst);
126 fst->want_program = -1;
128 /* If we don't have an editor window yet, we still need to
129 * set up the program, otherwise when we load a plugin without
130 * opening its window it will sound wrong. However, it seems
131 * that if you don't also load the program after opening the GUI,
132 * the GUI does not reflect the program properly. So we'll not
133 * mark that we've done this (ie we won't set want_program to -1)
134 * and so it will be done again if and when the GUI arrives.
136 if (fst->program_set_without_editor == 0) {
137 vststate_maybe_set_program (fst);
138 fst->program_set_without_editor = 1;
141 pthread_mutex_unlock (&fst->lock);
144 pthread_mutex_unlock (&plugin_mutex);
148 fst_idle_timer_add_plugin (VSTState* fst)
150 pthread_mutex_lock (&plugin_mutex);
152 if (fst_first == NULL) {
155 VSTState* p = fst_first;
162 pthread_mutex_unlock (&plugin_mutex);
166 fst_idle_timer_remove_plugin (VSTState* fst)
171 pthread_mutex_lock (&plugin_mutex);
173 for (p = fst_first, prev = NULL; p; prev = p, p = p->next) {
176 prev->next = p->next;
185 if (fst_first == fst) {
186 fst_first = fst_first->next;
189 pthread_mutex_unlock (&plugin_mutex);
195 VSTState* fst = (VSTState*) calloc (1, sizeof (VSTState));
198 #ifdef PLATFORM_WINDOWS
201 #else /* linux + wine */
209 fst_delete (VSTState* fst)
218 fst_handle_new (void)
220 VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
224 #ifndef PLATFORM_WINDOWS /* linux + wine */
226 g_idle_call (gpointer ignored) {
227 if (gui_quit) return FALSE;
229 if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
230 TranslateMessage (&msg);
231 DispatchMessageA (&msg);
233 idle_hands(NULL, 0, 0, 0);
234 g_main_context_iteration(NULL, FALSE);
235 return gui_quit ? FALSE : TRUE;
241 fst_init (void* possible_hmodule)
243 if (host_initialized) return 0;
246 if (possible_hmodule) {
247 #ifdef PLATFORM_WINDOWS
248 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
250 #else /* linux + wine */
251 hInst = (HMODULE) possible_hmodule;
253 } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
254 fst_error ("can't get module handle");
259 fst_error ("Cannot initialise VST host");
265 wclass.cbSize = sizeof(WNDCLASSEX);
266 #ifdef PLATFORM_WINDOWS
267 wclass.style = (CS_HREDRAW | CS_VREDRAW);
269 wclass.hCursor = LoadCursor(0, IDC_ARROW);
270 #else /* linux + wine */
272 wclass.hIcon = LoadIcon(hInst, "FST");
273 wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
275 wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
276 wclass.lpfnWndProc = vstedit_wndproc;
277 wclass.cbClsExtra = 0;
278 wclass.cbWndExtra = 0;
279 wclass.hInstance = hInst;
280 wclass.lpszMenuName = "MENU_FST";
281 wclass.lpszClassName = "FST";
284 pthread_mutex_init (&plugin_mutex, NULL);
285 host_initialized = -1;
287 if (!RegisterClassExA(&wclass)){
288 fst_error ("Error in fst_init(): (class registration failed");
295 fst_start_threading(void)
297 #ifndef PLATFORM_WINDOWS /* linux + wine */
300 idle_id = g_idle_add (g_idle_call, NULL);
306 fst_stop_threading(void) {
307 #ifndef PLATFORM_WINDOWS /* linux + wine */
311 g_main_context_iteration(NULL, FALSE);
312 //g_source_remove(idle_id);
321 if (!host_initialized) return;
323 // If any plugins are still open at this point, close them!
324 while ((fst = fst_first))
327 #ifdef PLATFORM_WINDOWS
328 if (idle_timer_id != 0) {
329 KillTimer(NULL, idle_timer_id);
331 #else /* linux + wine */
338 host_initialized = FALSE;
339 pthread_mutex_destroy (&plugin_mutex);
344 fst_run_editor (VSTState* fst, void* window_parent)
346 /* For safety, remove any pre-existing editor window */
347 fst_destroy_editor (fst);
349 if (fst->windows_window == NULL) {
352 struct ERect* er = NULL;
354 if (!(fst->plugin->flags & effFlagsHasEditor)) {
355 fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
359 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
360 fst_error ("fst_create_editor() can't get module handle");
364 if ((window = CreateWindowExA (0, "FST", fst->handle->name,
365 window_parent ? WS_CHILD : (WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX),
366 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
367 (HWND)window_parent, NULL,
370 fst_error ("fst_create_editor() cannot create editor window");
374 if (!SetPropA (window, "fst_ptr", fst)) {
375 fst_error ("fst_create_editor() cannot set fst_ptr on window");
378 fst->windows_window = window;
381 // This is requiredv for some reason. Note the parent is set above when the window
382 // is created. Without this extra call the actual plugin window will draw outside
383 // of our plugin window.
384 SetParent((HWND)fst->windows_window, (HWND)window_parent);
386 #ifndef PLATFORM_WINDOWS /* linux + wine */
388 SetWindowPos (fst->windows_window, 0, 9999, 9999, 2, 2, 0);
389 ShowWindow (fst->windows_window, SW_SHOWNA);
390 fst->xid = (int) GetPropA (fst->windows_window, "__wine_x11_whole_window");
394 // This is the suggested order of calls.
395 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
396 fst->plugin->dispatcher (fst->plugin, effEditOpen, 0, 0, fst->windows_window, 0 );
397 fst->plugin->dispatcher (fst->plugin, effEditGetRect, 0, 0, &er, 0 );
400 fst->width = er->right - er->left;
401 fst->height = er->bottom - er->top;
404 fst->been_activated = TRUE;
408 if (fst->windows_window) {
409 #ifdef PLATFORM_WINDOWS
410 if (idle_timer_id == 0) {
411 // Init the idle timer if needed, so that the main window calls us.
412 idle_timer_id = SetTimer(NULL, idle_timer_id, 50, (TIMERPROC) idle_hands);
416 fst_idle_timer_add_plugin (fst);
419 return fst->windows_window == NULL ? -1 : 0;
423 fst_destroy_editor (VSTState* fst)
425 if (fst->windows_window) {
426 fprintf (stderr, "%s destroying edit window\n", fst->handle->name);
428 fst_idle_timer_remove_plugin (fst);
429 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
431 DestroyWindow ((HWND)(fst->windows_window));
433 fst->windows_window = NULL;
436 fst->been_activated = FALSE;
440 fst_move_window_into_view (VSTState* fst)
442 if (fst->windows_window) {
443 #ifdef PLATFORM_WINDOWS
444 SetWindowPos ((HWND)(fst->windows_window), 0, fst->hoffset, fst->voffset, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
445 #else /* linux + wine */
446 SetWindowPos ((HWND)(fst->windows_window), 0, 0, 0, fst->width + fst->hoffset, fst->height + fst->voffset, 0);
448 ShowWindow ((HWND)(fst->windows_window), SW_SHOWNA);
453 fst_load_vst_library(const char * path)
455 char legalized_path[PATH_MAX];
456 strcpy (legalized_path, g_locale_from_utf8(path, -1, NULL, NULL, NULL));
457 return ( LoadLibraryA (legalized_path) );
461 fst_load (const char *path)
463 VSTHandle* fhandle = NULL;
465 if ((strlen(path)) && (NULL != (fhandle = fst_handle_new ())))
468 fhandle->path = strdup (path);
469 fhandle->name = g_path_get_basename(path);
470 if ((period = strrchr (fhandle->name, '.'))) {
474 // See if we can load the plugin DLL
475 if ((fhandle->dll = (HMODULE)fst_load_vst_library (path)) == NULL) {
476 fst_unload (&fhandle);
480 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "VSTPluginMain");
482 if (fhandle->main_entry == 0) {
483 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "main");
486 if (fhandle->main_entry == 0) {
487 fst_unload (&fhandle);
495 fst_unload (VSTHandle** fhandle)
501 if ((*fhandle)->plugincnt) {
505 if ((*fhandle)->dll) {
506 FreeLibrary ((HMODULE)(*fhandle)->dll);
507 (*fhandle)->dll = NULL;
510 if ((*fhandle)->path) {
511 free ((*fhandle)->path);
512 (*fhandle)->path = NULL;
515 if ((*fhandle)->name) {
516 free ((*fhandle)->name);
517 (*fhandle)->name = NULL;
527 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
529 VSTState* fst = NULL;
531 if( fhandle == NULL ) {
532 fst_error( "fst_instantiate(): (the handle was NULL)\n" );
538 if ((fst->plugin = fhandle->main_entry (amc)) == NULL) {
539 fst_error ("fst_instantiate: %s could not be instantiated\n", fhandle->name);
544 fst->handle = fhandle;
545 fst->plugin->user = userptr;
547 if (fst->plugin->magic != kEffectMagic) {
548 fst_error ("fst_instantiate: %s is not a vst plugin\n", fhandle->name);
553 fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
554 fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
556 fst->handle->plugincnt++;
562 void fst_audio_master_idle(void) {
563 while(g_main_context_iteration(NULL, FALSE)) ;
567 fst_close (VSTState* fst)
570 fst_destroy_editor (fst);
573 fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
574 fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
579 if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
581 fst->handle->main_entry = NULL;
582 fst_unload (&fst->handle); // XXX
586 /* It might be good for this to be in it's own cleanup function
587 since it will free the memory for the fst leaving the caller
588 with an invalid pointer. Caller beware */
593 #if 0 // ?? who needs this, where?
594 float htonf (float v)
597 char * fin = (char*)&v;
598 char * fout = (char*)&result;