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
vstedit_wndproc(HWND w,UINT msg,WPARAM wp,LPARAM lp)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
idle_hands(HWND hwnd,UINT message,UINT idTimer,DWORD dwTime)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
fst_idle_timer_add_plugin(VSTState * fst)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
fst_idle_timer_remove_plugin(VSTState * fst)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*
fst_new(void)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
fst_delete(VSTState * fst)251 fst_delete (VSTState* fst)
252 {
253 	if (fst) {
254 		free((void*)fst);
255 		fst = NULL;
256 	}
257 }
258 
259 static VSTHandle*
fst_handle_new(void)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
g_idle_call(gpointer ignored)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
fst_init(void * possible_hmodule)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
fst_start_threading(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
fst_stop_threading(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
fst_exit(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
fst_run_editor(VSTState * fst,void * window_parent)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
fst_destroy_editor(VSTState * fst)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
fst_move_window_into_view(VSTState * fst)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
fst_load_vst_library(const char * path)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 *
fst_load(const char * path)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
fst_unload(VSTHandle ** fhandle)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*
fst_instantiate(VSTHandle * fhandle,audioMasterCallback amc,void * userptr)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 
fst_audio_master_idle(void)618 void fst_audio_master_idle(void) {
619 	while(g_main_context_iteration(NULL, FALSE)) ;
620 }
621 
622 void
fst_close(VSTState * fst)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
662