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