use a note tracker to resolve notes cut off during render by the end of the region
[ardour.git] / libs / fst / vstwin.c
1 /*
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>
6  *
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.
11  *
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.
16  *
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.
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <windows.h>
25
26 #define fst_error(...) fprintf(stderr, __VA_ARGS__)
27
28 #ifdef PLATFORM_WINDOWS
29
30 #include <pthread.h>
31 static UINT_PTR idle_timer_id   = 0;
32
33 #else /* linux + wine */
34
35 #include <linux/limits.h> // PATH_MAX
36 #include <winnt.h>
37 #include <wine/exception.h>
38 #include <pthread.h>
39 static int gui_quit = 0;
40 static unsigned int idle_id = 0;
41
42 #endif
43
44 #ifndef COMPILER_MSVC
45 extern char * strdup (const char *);
46 #endif
47
48 #include <glib.h>
49 #include "fst.h"
50
51 struct ERect {
52         short top;
53         short left;
54         short bottom;
55         short right;
56 };
57
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";
62
63
64 static LRESULT WINAPI
65 vstedit_wndproc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
66 {
67         switch (msg) {
68                 case WM_KEYUP:
69                 case WM_KEYDOWN:
70                         break;
71
72                 case WM_SIZE:
73 #ifdef PLATFORM_WINDOWS
74                         {
75                                 LRESULT rv = DefWindowProcA (w, msg, wp, lp);
76                                 RECT rect;
77                                 GetClientRect(w, &rect);
78 #ifndef NDEBUG
79                                 printf("VST WM_SIZE.. %ld %ld %ld %ld\n", rect.top, rect.left, (rect.right - rect.left), (rect.bottom - rect.top));
80 #endif
81                                 VSTState* fst = (VSTState*) GetProp (w, "fst_ptr");
82                                 if (fst) {
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);
87                                         }
88                                 }
89                                 return rv;
90                         }
91 #endif
92                         break;
93                 case WM_CLOSE:
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!
99                          */
100                         return 0;
101                         break;
102
103                 case WM_DESTROY:
104                 case WM_NCDESTROY:
105                         /* we don't care about windows being destroyed ... */
106                         return 0;
107                         break;
108
109                 default:
110                         break;
111         }
112
113         return DefWindowProcA (w, msg, wp, lp);
114 }
115
116
117 static VOID CALLBACK
118 idle_hands(
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
123 {
124         VSTState* fst;
125
126         pthread_mutex_lock (&plugin_mutex);
127
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);
133
134                         if (fst->wantIdle) {
135                                 fst->wantIdle = fst->plugin->dispatcher (fst->plugin, effIdle, 0, 0, NULL, 0);
136                         }
137                 }
138
139                 pthread_mutex_lock (&fst->lock);
140 #ifndef PLATFORM_WINDOWS /* linux + wine */
141                 /* Dispatch messages to send keypresses to the plugin */
142                 int i;
143
144                 for (i = 0; i < fst->n_pending_keys; ++i) {
145                         MSG msg;
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 ...
150                          */
151                         if (fst->pending_keys[i].special != 0) {
152                                 msg.message = WM_KEYDOWN;
153                                 msg.wParam = fst->pending_keys[i].special;
154                         } else {
155                                 msg.message = WM_CHAR;
156                                 msg.wParam = fst->pending_keys[i].character;
157                         }
158                         msg.hwnd = GetFocus ();
159                         msg.lParam = 0;
160                         DispatchMessageA (&msg);
161                 }
162
163                 fst->n_pending_keys = 0;
164 #endif
165
166                 /* See comment for call below */
167                 vststate_maybe_set_program (fst);
168                 fst->want_program = -1;
169                 fst->want_chunk = 0;
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.
177                  */
178                 if (fst->program_set_without_editor == 0) {
179                         vststate_maybe_set_program (fst);
180                         fst->program_set_without_editor = 1;
181                 }
182
183                 pthread_mutex_unlock (&fst->lock);
184         }
185
186         pthread_mutex_unlock (&plugin_mutex);
187 }
188
189 static void
190 fst_idle_timer_add_plugin (VSTState* fst)
191 {
192         pthread_mutex_lock (&plugin_mutex);
193
194         if (fst_first == NULL) {
195                 fst_first = fst;
196         } else {
197                 VSTState* p = fst_first;
198                 while (p->next) {
199                         p = p->next;
200                 }
201                 p->next = fst;
202         }
203
204         pthread_mutex_unlock (&plugin_mutex);
205 }
206
207 static void
208 fst_idle_timer_remove_plugin (VSTState* fst)
209 {
210         VSTState* p;
211         VSTState* prev;
212
213         pthread_mutex_lock (&plugin_mutex);
214
215         for (p = fst_first, prev = NULL; p; prev = p, p = p->next) {
216                 if (p == fst) {
217                         if (prev) {
218                                 prev->next = p->next;
219                         }
220                         break;
221                 }
222                 if (!p->next) {
223                         break;
224                 }
225         }
226
227         if (fst_first == fst) {
228                 fst_first = fst_first->next;
229         }
230
231         pthread_mutex_unlock (&plugin_mutex);
232 }
233
234 static VSTState*
235 fst_new (void)
236 {
237         VSTState* fst = (VSTState*) calloc (1, sizeof (VSTState));
238         vststate_init (fst);
239
240 #ifdef PLATFORM_WINDOWS
241         fst->voffset = 45;
242         fst->hoffset = 0;
243 #else /* linux + wine */
244         fst->voffset = 24;
245         fst->hoffset = 6;
246 #endif
247         return fst;
248 }
249
250 static void
251 fst_delete (VSTState* fst)
252 {
253         if (fst) {
254                 free((void*)fst);
255                 fst = NULL;
256         }
257 }
258
259 static VSTHandle*
260 fst_handle_new (void)
261 {
262         VSTHandle* fst = (VSTHandle*) calloc (1, sizeof (VSTHandle));
263         return fst;
264 }
265
266 #ifndef PLATFORM_WINDOWS /* linux + wine */
267 static gboolean
268 g_idle_call (gpointer ignored) {
269         if (gui_quit) return FALSE;
270         MSG msg;
271         if (PeekMessageA (&msg, NULL, 0, 0, 1)) {
272                 TranslateMessage (&msg);
273                 DispatchMessageA (&msg);
274         }
275         idle_hands(NULL, 0, 0, 0);
276         g_main_context_iteration(NULL, FALSE);
277         return gui_quit ? FALSE : TRUE;
278 }
279 #endif
280
281
282 int
283 fst_init (void* possible_hmodule)
284 {
285         if (host_initialized) return 0;
286         HMODULE hInst;
287
288         if (possible_hmodule) {
289 #ifdef PLATFORM_WINDOWS
290                 fst_error ("Error in fst_init(): (module handle is unnecessary for Win32 build)");
291                 return -1;
292 #else /* linux + wine */
293                 hInst = (HMODULE) possible_hmodule;
294 #endif
295         } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
296                 fst_error ("can't get module handle");
297                 return -1;
298         }
299
300         if (!hInst) {
301                 fst_error ("Cannot initialise VST host");
302                 return -1;
303         }
304
305         WNDCLASSEX wclass;
306
307         wclass.cbSize = sizeof(WNDCLASSEX);
308 #ifdef PLATFORM_WINDOWS
309         wclass.style = (CS_HREDRAW | CS_VREDRAW);
310         wclass.hIcon = NULL;
311         wclass.hCursor = LoadCursor(0, IDC_ARROW);
312 #else /* linux + wine */
313         wclass.style = 0;
314         wclass.hIcon = LoadIcon(hInst, "FST");
315         wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
316 #endif
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";
324         wclass.hIconSm = 0;
325
326         pthread_mutex_init (&plugin_mutex, NULL);
327         host_initialized = -1;
328
329         if (!RegisterClassExA(&wclass)){
330                 fst_error ("Error in fst_init(): (class registration failed");
331                 return -1;
332         }
333         return 0;
334 }
335
336 void
337 fst_start_threading(void)
338 {
339 #ifndef PLATFORM_WINDOWS /* linux + wine */
340         if (idle_id == 0) {
341                 gui_quit = 0;
342                 idle_id = g_idle_add (g_idle_call, NULL);
343         }
344 #endif
345 }
346
347 void
348 fst_stop_threading(void) {
349 #ifndef PLATFORM_WINDOWS /* linux + wine */
350         if (idle_id != 0) {
351                 gui_quit = 1;
352                 PostQuitMessage (0);
353                 g_main_context_iteration(NULL, FALSE);
354                 //g_source_remove(idle_id);
355                 idle_id = 0;
356         }
357 #endif
358 }
359
360 void
361 fst_exit (void)
362 {
363         if (!host_initialized) return;
364         VSTState* fst;
365         // If any plugins are still open at this point, close them!
366         while ((fst = fst_first))
367                 fst_close (fst);
368
369 #ifdef PLATFORM_WINDOWS
370         if (idle_timer_id != 0) {
371                 KillTimer(NULL, idle_timer_id);
372         }
373 #else /* linux + wine */
374         if (idle_id) {
375                 gui_quit = 1;
376                 PostQuitMessage (0);
377         }
378 #endif
379
380         host_initialized = FALSE;
381         pthread_mutex_destroy (&plugin_mutex);
382 }
383
384
385 int
386 fst_run_editor (VSTState* fst, void* window_parent)
387 {
388         /* For safety, remove any pre-existing editor window */ 
389         fst_destroy_editor (fst);
390         
391         if (fst->windows_window == NULL) {
392                 HMODULE hInst;
393                 HWND window;
394                 struct ERect* er = NULL;
395
396                 if (!(fst->plugin->flags & effFlagsHasEditor)) {
397                         fst_error ("Plugin \"%s\" has no editor", fst->handle->name);
398                         return -1;
399                 }
400
401                 if ((hInst = GetModuleHandleA (NULL)) == NULL) {
402                         fst_error ("fst_create_editor() can't get module handle");
403                         return 1;
404                 }
405
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,
410                                                 hInst,
411                                                 NULL) ) == NULL) {
412                         fst_error ("fst_create_editor() cannot create editor window");
413                         return 1;
414                 }
415
416                 if (!SetPropA (window, "fst_ptr", fst)) {
417                         fst_error ("fst_create_editor() cannot set fst_ptr on window");
418                 }
419
420                 fst->windows_window = window;
421
422                 if (window_parent) {
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);
427                         fst->xid = 0;
428 #ifndef PLATFORM_WINDOWS /* linux + wine */
429                 } else {
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");
433 #endif
434                 }
435
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 );
440
441                 if (er != NULL) {
442                         fst->width = er->right - er->left;
443                         fst->height = er->bottom - er->top;
444                 }
445
446                 fst->been_activated = TRUE;
447
448         }
449
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);
455                 }
456 #endif
457
458                 fst_idle_timer_add_plugin (fst);
459         }
460
461         return fst->windows_window == NULL ? -1 : 0;
462 }
463
464 void
465 fst_destroy_editor (VSTState* fst)
466 {
467         if (fst->windows_window) {
468                 fprintf (stderr, "%s destroying edit window\n", fst->handle->name);
469
470                 fst_idle_timer_remove_plugin (fst);
471                 fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
472
473                 DestroyWindow ((HWND)(fst->windows_window));
474
475                 fst->windows_window = NULL;
476         }
477
478         fst->been_activated = FALSE;
479 }
480
481 void
482 fst_move_window_into_view (VSTState* fst)
483 {
484         if (fst->windows_window) {
485 #ifdef PLATFORM_WINDOWS
486                 SetWindowPos ((HWND)(fst->windows_window),
487                                 HWND_TOP /*0*/,
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);
493 #endif
494                 ShowWindow ((HWND)(fst->windows_window), SW_SHOWNA);
495                 UpdateWindow ((HWND)(fst->windows_window));
496         }
497 }
498
499 static HMODULE
500 fst_load_vst_library(const char * path)
501 {
502         char legalized_path[PATH_MAX];
503         strcpy (legalized_path, g_locale_from_utf8(path, -1, NULL, NULL, NULL));
504         return ( LoadLibraryA (legalized_path) );
505 }
506
507 VSTHandle *
508 fst_load (const char *path)
509 {
510         VSTHandle* fhandle = NULL;
511
512         if ((strlen(path)) && (NULL != (fhandle = fst_handle_new ())))
513         {
514                 char* period;
515                 fhandle->path = strdup (path);
516                 fhandle->name = g_path_get_basename(path);
517                 if ((period = strrchr (fhandle->name, '.'))) {
518                         *period = '\0';
519                 }
520
521                 // See if we can load the plugin DLL
522                 if ((fhandle->dll = (HMODULE)fst_load_vst_library (path)) == NULL) {
523                         fst_unload (&fhandle);
524                         return NULL;
525                 }
526
527                 fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "VSTPluginMain");
528
529                 if (fhandle->main_entry == 0) {
530                         fhandle->main_entry = (main_entry_t) GetProcAddress ((HMODULE)fhandle->dll, "main");
531                 }
532
533                 if (fhandle->main_entry == 0) {
534                         fst_unload (&fhandle);
535                         return NULL;
536                 }
537         }
538         return fhandle;
539 }
540
541 int
542 fst_unload (VSTHandle** fhandle)
543 {
544         if (!(*fhandle)) {
545                 return -1;
546         }
547
548         if ((*fhandle)->plugincnt) {
549                 return -1;
550         }
551
552         if ((*fhandle)->dll) {
553                 FreeLibrary ((HMODULE)(*fhandle)->dll);
554                 (*fhandle)->dll = NULL;
555         }
556
557         if ((*fhandle)->path) {
558                 free ((*fhandle)->path);
559                 (*fhandle)->path = NULL;
560         }
561
562         if ((*fhandle)->name) {
563                 free ((*fhandle)->name);
564                 (*fhandle)->name = NULL;
565         }
566
567         free (*fhandle);
568         *fhandle = NULL;
569
570         return 0;
571 }
572
573 VSTState*
574 fst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
575 {
576         VSTState* fst = NULL;
577
578         if( fhandle == NULL ) {
579                 fst_error( "fst_instantiate(): (the handle was NULL)\n" );
580                 return NULL;
581         }
582
583         fst = fst_new ();
584         fst->amc = amc;
585
586         if ((fst->plugin = fhandle->main_entry (amc)) == NULL)  {
587                 fst_error ("fst_instantiate: %s could not be instantiated\n", fhandle->name);
588                 free (fst);
589                 return NULL;
590         }
591
592         fst->handle = fhandle;
593         fst->plugin->ptr1 = userptr;
594
595         if (fst->plugin->magic != kEffectMagic) {
596                 fst_error ("fst_instantiate: %s is not a vst plugin\n", fhandle->name);
597                 fst_close(fst);
598                 return NULL;
599         }
600
601         if (!userptr) {
602                 /* scanning.. or w/o master-callback userptr == 0, open now.
603                  *
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
607                  */
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);
610         }
611
612         fst->handle->plugincnt++;
613         fst->wantIdle = 0;
614
615         return fst;
616 }
617
618 void fst_audio_master_idle(void) {
619         while(g_main_context_iteration(NULL, FALSE)) ;
620 }
621
622 void
623 fst_close (VSTState* fst)
624 {
625         if (fst != NULL) {
626                 fst_destroy_editor (fst);
627
628                 if (fst->plugin) {
629                         fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
630                         fst->plugin->dispatcher (fst->plugin, effClose, 0, 0, 0, 0);
631                         fst->plugin = NULL;
632                 }
633
634                 if (fst->handle) {
635                         if (fst->handle->plugincnt && --fst->handle->plugincnt == 0) {
636
637                                 fst->handle->main_entry = NULL;
638                                 fst_unload (&fst->handle); // XXX
639                         }
640                 }
641
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 */
645                 fst_delete(fst);
646         }
647 }
648
649 #if 0 // ?? who needs this, where?
650 float htonf (float v)
651 {
652         float result;
653         char * fin = (char*)&v;
654         char * fout = (char*)&result;
655         fout[0] = fin[3];
656         fout[1] = fin[2];
657         fout[2] = fin[1];
658         fout[3] = fin[0];
659         return result;
660 }
661 #endif