fcfa8368935baaa8c87dc41c00c8817aac05df4c
[ardour.git] / libs / fst / vstwin.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <windows.h>
4
5 #define fst_error(...) fprintf(stderr, __VA_ARGS__)
6
7 #ifdef PLATFORM_WINDOWS
8
9 #include <pthread.h>
10 static UINT_PTR idle_timer_id   = 0;
11
12 #else /* linux + wine */
13
14 #include <linux/limits.h> // PATH_MAX
15 #include <winnt.h>
16 #include <wine/exception.h>
17 #include <pthread.h>
18 static int gui_quit = 0;
19 static unsigned int idle_id = 0;
20
21 #endif
22
23 #ifndef COMPILER_MSVC
24 extern char * strdup (const char *);
25 #endif
26
27 #include <glib.h>
28 #include "fst.h"
29
30 struct ERect {
31         short top;
32         short left;
33         short bottom;
34         short right;
35 };
36
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";
41
42
43 static LRESULT WINAPI
44 vstedit_wndproc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
45 {
46         switch (msg) {
47                 case WM_KEYUP:
48                 case WM_KEYDOWN:
49                         break;
50
51                 case WM_CLOSE:
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!
57                          */
58                         return 0;
59                         break;
60
61                 case WM_DESTROY:
62                 case WM_NCDESTROY:
63                         /* we don't care about windows being destroyed ... */
64                         return 0;
65                         break;
66
67                 default:
68                         break;
69         }
70
71         return DefWindowProcA (w, msg, wp, lp );
72 }
73
74
75 static VOID CALLBACK
76 idle_hands(
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
81 {
82         VSTState* fst;
83
84         pthread_mutex_lock (&plugin_mutex);
85
86         for (fst = fst_first; fst; fst = fst->next) {
87                 if (fst->gui_shown) {
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);
91
92                         if (fst->wantIdle) {
93                                 fst->wantIdle = fst->plugin->dispatcher (fst->plugin, effIdle, 0, 0, NULL, 0);
94                         }
95                 }
96
97                 pthread_mutex_lock (&fst->lock);
98 #ifndef PLATFORM_WINDOWS /* linux + wine */
99                 /* Dispatch messages to send keypresses to the plugin */
100                 int i;
101
102                 for (i = 0; i < fst->n_pending_keys; ++i) {
103                         MSG msg;
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 ...
108                          */
109                         if (fst->pending_keys[i].special != 0) {
110                                 msg.message = WM_KEYDOWN;
111                                 msg.wParam = fst->pending_keys[i].special;
112                         } else {
113                                 msg.message = WM_CHAR;
114                                 msg.wParam = fst->pending_keys[i].character;
115                         }
116                         msg.hwnd = GetFocus ();
117                         msg.lParam = 0;
118                         DispatchMessageA (&msg);
119                 }
120
121                 fst->n_pending_keys = 0;
122 #endif
123
124                 /* See comment for call below */
125                 vststate_maybe_set_program (fst);
126                 fst->want_program = -1;
127                 fst->want_chunk = 0;
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.
135                  */
136                 if (fst->program_set_without_editor == 0) {
137                         vststate_maybe_set_program (fst);
138                         fst->program_set_without_editor = 1;
139                 }
140
141                 pthread_mutex_unlock (&fst->lock);
142         }
143
144         pthread_mutex_unlock (&plugin_mutex);
145 }
146
147 static void
148 fst_idle_timer_add_plugin (VSTState* fst)
149 {
150         pthread_mutex_lock (&plugin_mutex);
151
152         if (fst_first == NULL) {
153                 fst_first = fst;
154         } else {
155                 VSTState* p = fst_first;
156                 while (p->next) {
157                         p = p->next;
158                 }
159                 p->next = fst;
160         }
161
162         pthread_mutex_unlock (&plugin_mutex);
163 }
164
165 static void
166 fst_idle_timer_remove_plugin (VSTState* fst)
167 {
168         VSTState* p;
169         VSTState* prev;
170
171         pthread_mutex_lock (&plugin_mutex);
172
173         for (p = fst_first, prev = NULL; p; prev = p, p = p->next) {
174                 if (p == fst) {
175                         if (prev) {
176                                 prev->next = p->next;
177                         }
178                         break;
179                 }
180                 if (!p->next) {
181                         break;
182                 }
183         }
184
185         if (fst_first == fst) {
186                 fst_first = fst_first->next;
187         }
188
189         pthread_mutex_unlock (&plugin_mutex);
190 }
191
192 static VSTState*
193 fst_new (void)
194 {
195         VSTState* fst = (VSTState*) calloc (1, sizeof (VSTState));
196         vststate_init (fst);
197
198 #ifdef PLATFORM_WINDOWS
199         fst->voffset = 50;
200         fst->hoffset = 0;
201 #else /* linux + wine */
202         fst->voffset = 24;
203         fst->hoffset = 6;
204 #endif
205         return fst;
206 }
207
208 static void
209 fst_delete (VSTState* fst)
210 {
211         if (fst) {
212                 free((void*)fst);
213                 fst = NULL;
214         }
215 }
216
217 static VSTHandle*
218 fst_handle_new (void)
219 {
220         VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
221         return fst;
222 }
223
224 #ifndef PLATFORM_WINDOWS /* linux + wine */
225 static gboolean
226 g_idle_call (gpointer ignored) {
227         if (gui_quit) return FALSE;
228         MSG msg;
229         if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
230                 TranslateMessage (&msg);
231                 DispatchMessageA (&msg);
232         }
233         idle_hands(NULL, 0, 0, 0);
234         g_main_context_iteration(NULL, FALSE);
235         return gui_quit ? FALSE : TRUE;
236 }
237 #endif
238
239
240 int
241 fst_init (void* possible_hmodule)
242 {
243         if (host_initialized) return 0;
244         HMODULE hInst;
245
246         if (possible_hmodule) {
247 #ifdef PLATFORM_WINDOWS
248                 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
249                 return -1;
250 #else /* linux + wine */
251                 hInst = (HMODULE) possible_hmodule;
252 #endif
253         } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
254                 fst_error ("can't get module handle");
255                 return -1;
256         }
257
258         if (!hInst) {
259                 fst_error ("Cannot initialise VST host");
260                 return -1;
261         }
262
263         WNDCLASSEX wclass;
264
265         wclass.cbSize = sizeof(WNDCLASSEX);
266 #ifdef PLATFORM_WINDOWS
267         wclass.style = (CS_HREDRAW | CS_VREDRAW);
268         wclass.hIcon = NULL;
269         wclass.hCursor = LoadCursor(0, IDC_ARROW);
270 #else /* linux + wine */
271         wclass.style = 0;
272         wclass.hIcon = LoadIcon(hInst, "FST");
273         wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
274 #endif
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";
282         wclass.hIconSm = 0;
283
284         pthread_mutex_init (&plugin_mutex, NULL);
285         host_initialized = -1;
286
287         if (!RegisterClassExA(&wclass)){
288                 fst_error ("Error in fst_init(): (class registration failed");
289                 return -1;
290         }
291         return 0;
292 }
293
294 void
295 fst_start_threading(void)
296 {
297 #ifndef PLATFORM_WINDOWS /* linux + wine */
298         if (idle_id == 0) {
299                 gui_quit = 0;
300                 idle_id = g_idle_add (g_idle_call, NULL);
301         }
302 #endif
303 }
304
305 void
306 fst_stop_threading(void) {
307 #ifndef PLATFORM_WINDOWS /* linux + wine */
308         if (idle_id != 0) {
309                 gui_quit = 1;
310                 PostQuitMessage (0);
311                 g_main_context_iteration(NULL, FALSE);
312                 //g_source_remove(idle_id);
313                 idle_id = 0;
314         }
315 #endif
316 }
317
318 void
319 fst_exit (void)
320 {
321         if (!host_initialized) return;
322         VSTState* fst;
323         // If any plugins are still open at this point, close them!
324         while ((fst = fst_first))
325                 fst_close (fst);
326
327 #ifdef PLATFORM_WINDOWS
328         if (idle_timer_id != 0) {
329                 KillTimer(NULL, idle_timer_id);
330         }
331 #else /* linux + wine */
332         if (idle_id) {
333                 gui_quit = 1;
334                 PostQuitMessage (0);
335         }
336 #endif
337
338         host_initialized = FALSE;
339         pthread_mutex_destroy (&plugin_mutex);
340 }
341
342
343 int
344 fst_run_editor (VSTState* fst, void* window_parent)
345 {
346         /* For safety, remove any pre-existing editor window */ 
347         fst_destroy_editor (fst);
348         
349         if (fst->windows_window == NULL) {
350                 HMODULE hInst;
351                 HWND window;
352                 struct ERect* er = NULL;
353
354                 if (!(fst->plugin->flags & effFlagsHasEditor)) {
355                         fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
356                         return -1;
357                 }
358
359                 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
360                         fst_error ("fst_create_editor() can't get module handle");
361                         return 1;
362                 }
363
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,
368                                                 hInst,
369                                                 NULL) ) == NULL) {
370                         fst_error ("fst_create_editor() cannot create editor window");
371                         return 1;
372                 }
373
374                 if (!SetPropA (window, "fst_ptr", fst)) {
375                         fst_error ("fst_create_editor() cannot set fst_ptr on window");
376                 }
377
378                 fst->windows_window = window;
379
380                 if (window_parent) {
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);
385                         fst->xid = 0;
386 #ifndef PLATFORM_WINDOWS /* linux + wine */
387                 } else {
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");
391 #endif
392                 }
393
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 );
398
399                 if (er != NULL) {
400                         fst->width = er->right - er->left;
401                         fst->height = er->bottom - er->top;
402                 }
403
404                 fst->been_activated = TRUE;
405
406         }
407
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);
413                 }
414 #endif
415
416                 fst_idle_timer_add_plugin (fst);
417         }
418
419         return fst->windows_window == NULL ? -1 : 0;
420 }
421
422 void
423 fst_destroy_editor (VSTState* fst)
424 {
425         if (fst->windows_window) {
426                 fprintf (stderr, "%s destroying edit window\n", fst->handle->name);
427
428                 fst_idle_timer_remove_plugin (fst);
429                 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
430
431                 DestroyWindow ((HWND)(fst->windows_window));
432
433                 fst->windows_window = NULL;
434         }
435
436         fst->been_activated = FALSE;
437 }
438
439 void
440 fst_move_window_into_view (VSTState* fst)
441 {
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);
447 #endif
448                 ShowWindow ((HWND)(fst->windows_window), SW_SHOWNA);
449         }
450 }
451
452 static HMODULE
453 fst_load_vst_library(const char * path)
454 {
455         char legalized_path[PATH_MAX];
456         strcpy (legalized_path, g_locale_from_utf8(path, -1, NULL, NULL, NULL));
457         return ( LoadLibraryA (legalized_path) );
458 }
459
460 VSTHandle *
461 fst_load (const char *path)
462 {
463         VSTHandle* fhandle = NULL;
464
465         if ((strlen(path)) && (NULL != (fhandle = fst_handle_new ())))
466         {
467                 char* period;
468                 fhandle->path = strdup (path);
469                 fhandle->name = g_path_get_basename(path);
470                 if ((period = strrchr (fhandle->name, '.'))) {
471                         *period = '\0';
472                 }
473
474                 // See if we can load the plugin DLL
475                 if ((fhandle->dll = (HMODULE)fst_load_vst_library (path)) == NULL) {
476                         fst_unload (&fhandle);
477                         return NULL;
478                 }
479
480                 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "main");
481
482                 if (fhandle->main_entry == 0) {
483                         if ((fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "VSTPluginMain"))) {
484                                 fprintf(stderr, "VST >= 2.4 plugin '%s'\n", path);
485                                 //PBD::warning << path << _(": is a VST >= 2.4 - this plugin may or may not function correctly with this version of Ardour.") << endmsg;
486                         }
487                 }
488
489                 if (fhandle->main_entry == 0) {
490                         fst_unload (&fhandle);
491                         return NULL;
492                 }
493         }
494         return fhandle;
495 }
496
497 int
498 fst_unload (VSTHandle** fhandle)
499 {
500         if (!(*fhandle)) {
501                 return -1;
502         }
503
504         if ((*fhandle)->plugincnt) {
505                 return -1;
506         }
507
508         if ((*fhandle)->dll) {
509                 FreeLibrary ((HMODULE)(*fhandle)->dll);
510                 (*fhandle)->dll = NULL;
511         }
512
513         if ((*fhandle)->path) {
514                 free ((*fhandle)->path);
515                 (*fhandle)->path = NULL;
516         }
517
518         if ((*fhandle)->name) {
519                 free ((*fhandle)->name);
520                 (*fhandle)->name = NULL;
521         }
522
523         free (*fhandle);
524         *fhandle = NULL;
525
526         return 0;
527 }
528
529 VSTState*
530 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
531 {
532         VSTState* fst = NULL;
533
534         if( fhandle == NULL ) {
535                 fst_error( "fst_instantiate(): (the handle was NULL)\n" );
536                 return NULL;
537         }
538
539         fst = fst_new ();
540
541         if ((fst->plugin = fhandle->main_entry (amc)) == NULL)  {
542                 fst_error ("fst_instantiate: %s could not be instantiated\n", fhandle->name);
543                 free (fst);
544                 return NULL;
545         }
546
547         fst->handle = fhandle;
548         fst->plugin->user = userptr;
549
550         if (fst->plugin->magic != kEffectMagic) {
551                 fst_error ("fst_instantiate: %s is not a vst plugin\n", fhandle->name);
552                 fst_close(fst);
553                 return NULL;
554         }
555
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);
558
559         fst->handle->plugincnt++;
560         fst->wantIdle = 0;
561
562         return fst;
563 }
564
565 void fst_audio_master_idle(void) {
566         while(g_main_context_iteration(NULL, FALSE)) ;
567 }
568
569 void
570 fst_close (VSTState* fst)
571 {
572         if (fst != NULL) {
573                 fst_destroy_editor (fst);
574
575                 if (fst->plugin) {
576                         fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
577                         fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
578                         fst->plugin = NULL;
579                 }
580
581                 if (fst->handle) {
582                         if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
583
584                                 fst->handle->main_entry = NULL;
585                                 fst_unload (&fst->handle); // XXX
586                         }
587                 }
588
589                 /* It might be good for this to be in it's own cleanup function
590                         since it will free the memory for the fst leaving the caller
591                         with an invalid pointer.  Caller beware */
592                 fst_delete(fst);
593         }
594 }
595
596 #if 0 // ?? who needs this, where?
597 float htonf (float v)
598 {
599         float result;
600         char * fin = (char*)&v;
601         char * fout = (char*)&result;
602         fout[0] = fin[3];
603         fout[1] = fin[2];
604         fout[2] = fin[1];
605         fout[3] = fin[0];
606         return result;
607 }
608 #endif