1 /*
2  * Copyright (c) 2015-2016 Hanspeter Portner (dev@open-music-kontrollers.ch)
3  *
4  * This is free software: you can redistribute it and/or modify
5  * it under the terms of the Artistic License 2.0 as published by
6  * The Perl Foundation.
7  *
8  * This source is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * Artistic License 2.0 for more details.
12  *
13  * You should have received a copy of the Artistic License 2.0
14  * along the source as a COPYING file. If not, obtain it from
15  * http://www.perlfoundation.org/artistic_license_2_0.
16  */
17 
18 #include <stdatomic.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <signal.h>
24 #include <time.h>
25 
26 #define CROSS_CLOCK_IMPLEMENTATION
27 #include <cross_clock/cross_clock.h>
28 
29 #include <sandbox_slave.h>
30 #include <lv2_external_ui.h>
31 #include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
32 
33 typedef struct _app_t app_t;
34 
35 struct _app_t {
36 	sandbox_slave_t *sb;
37 
38 	LV2_External_UI_Host host;
39 	LV2_External_UI_Widget *widget;
40 	cross_clock_t clk_mono;
41 };
42 
43 static atomic_bool done = ATOMIC_VAR_INIT(false);
44 
45 static inline void
_sig(int signum)46 _sig(int signum)
47 {
48 	atomic_store_explicit(&done, true, memory_order_relaxed);
49 }
50 
51 static inline void
_ui_closed(LV2UI_Controller controller)52 _ui_closed(LV2UI_Controller controller)
53 {
54 	sandbox_slave_t *sb = controller;
55 	(void)sb;
56 
57 	atomic_store_explicit(&done, true, memory_order_relaxed);
58 }
59 
60 static inline int
_init(sandbox_slave_t * sb,void * data)61 _init(sandbox_slave_t *sb, void *data)
62 {
63 	app_t *app= data;
64 
65 	signal(SIGINT, _sig);
66 
67 	app->host.ui_closed = _ui_closed;
68 	app->host.plugin_human_id = NULL; //FIXME
69 
70 	const LV2_Feature parent_feature = {
71 		.URI = LV2_EXTERNAL_UI__Host,
72 		.data = &app->host
73 	};
74 
75 	if(!sandbox_slave_instantiate(sb, &parent_feature, &app->widget))
76 		return -1;
77 	if(!app->widget)
78 		return -1;
79 
80 	LV2_EXTERNAL_UI_SHOW(app->widget);
81 
82 	cross_clock_init(&app->clk_mono, CROSS_CLOCK_MONOTONIC);
83 
84 	return 0; //success
85 }
86 
87 static inline void
_run(sandbox_slave_t * sb,float update_rate,void * data)88 _run(sandbox_slave_t *sb, float update_rate, void *data)
89 {
90 	app_t *app = data;
91 	const unsigned ns = 1000000000 / update_rate;
92 	struct timespec to;
93 	cross_clock_gettime(&app->clk_mono, &to);
94 
95 	while(!atomic_load_explicit(&done, memory_order_relaxed))
96 	{
97 		to.tv_nsec += ns;
98 		while(to.tv_nsec >= 1000000000)
99 		{
100 			to.tv_nsec -= 1000000000;
101 			to.tv_sec += 1;
102 		}
103 
104 		cross_clock_nanosleep(&app->clk_mono, true, &to);
105 
106 		if(sandbox_slave_recv(sb))
107 			atomic_store_explicit(&done, true, memory_order_relaxed);
108 		LV2_EXTERNAL_UI_RUN(app->widget);
109 	}
110 
111 	LV2_EXTERNAL_UI_HIDE(app->widget);
112 }
113 
114 static inline void
_deinit(void * data)115 _deinit(void *data)
116 {
117 	app_t *app = data;
118 
119 	cross_clock_deinit(&app->clk_mono);
120 }
121 
122 static const sandbox_slave_driver_t driver = {
123 	.init_cb = _init,
124 	.run_cb = _run,
125 	.deinit_cb = _deinit,
126 	.resize_cb = NULL
127 };
128 
129 int
main(int argc,char ** argv)130 main(int argc, char **argv)
131 {
132 	static app_t app;
133 	int res;
134 
135 	app.sb = sandbox_slave_new(argc, argv, &driver, &app, &res);
136 	if(app.sb)
137 	{
138 		sandbox_slave_run(app.sb);
139 		sandbox_slave_free(app.sb);
140 		return res;
141 	}
142 
143 	return res;
144 }
145