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/lv2plug.in/ns/extensions/ui/ui.h>
31 
32 typedef struct _app_t app_t;
33 
34 struct _app_t {
35 	sandbox_slave_t *sb;
36 	LV2UI_Handle *handle;
37 	const LV2UI_Idle_Interface *idle_iface;
38 	const LV2UI_Show_Interface *show_iface;
39 	cross_clock_t clk_mono;
40 };
41 
42 static atomic_bool done = ATOMIC_VAR_INIT(false);
43 
44 static inline void
_sig(int signum)45 _sig(int signum)
46 {
47 	atomic_store_explicit(&done, true, memory_order_relaxed);
48 }
49 
50 static inline int
_init(sandbox_slave_t * sb,void * data)51 _init(sandbox_slave_t *sb, void *data)
52 {
53 	app_t *app= data;
54 
55 	signal(SIGINT, _sig);
56 
57 	void *widget = NULL;
58 	if(!(app->handle = sandbox_slave_instantiate(sb, NULL, &widget)))
59 		return -1;
60 
61 	app->idle_iface = sandbox_slave_extension_data(sb, LV2_UI__idleInterface);
62 	app->show_iface = sandbox_slave_extension_data(sb, LV2_UI__showInterface);
63 
64 	if(app->show_iface)
65 		app->show_iface->show(app->handle);
66 
67 	cross_clock_init(&app->clk_mono, CROSS_CLOCK_MONOTONIC);
68 
69 	return 0; //success
70 }
71 
72 static inline void
_run(sandbox_slave_t * sb,float update_rate,void * data)73 _run(sandbox_slave_t *sb, float update_rate, void *data)
74 {
75 	app_t *app = data;
76 	const unsigned ns = 1000000000 / update_rate;
77 	struct timespec to;
78 	cross_clock_gettime(&app->clk_mono, &to);
79 
80 	while(!atomic_load_explicit(&done, memory_order_relaxed))
81 	{
82 		to.tv_nsec += ns;
83 		while(to.tv_nsec >= 1000000000)
84 		{
85 			to.tv_nsec -= 1000000000;
86 			to.tv_sec += 1;
87 		}
88 
89 		cross_clock_nanosleep(&app->clk_mono, true, &to);
90 
91 		if(sandbox_slave_recv(sb))
92 			atomic_store_explicit(&done, true, memory_order_relaxed);
93 		if(app->idle_iface)
94 		{
95 			if(app->idle_iface->idle(app->handle))
96 				atomic_store_explicit(&done, true, memory_order_relaxed);
97 		}
98 	}
99 
100 	if(app->show_iface)
101 		app->show_iface->hide(app->handle);
102 }
103 
104 static inline void
_deinit(void * data)105 _deinit(void *data)
106 {
107 	app_t *app = data;
108 
109 	cross_clock_deinit(&app->clk_mono);
110 }
111 
112 static const sandbox_slave_driver_t driver = {
113 	.init_cb = _init,
114 	.run_cb = _run,
115 	.deinit_cb = _deinit,
116 	.resize_cb = NULL
117 };
118 
119 int
main(int argc,char ** argv)120 main(int argc, char **argv)
121 {
122 	static app_t app;
123 	int res;
124 
125 	app.sb = sandbox_slave_new(argc, argv, &driver, &app, &res);
126 	if(app.sb)
127 	{
128 		sandbox_slave_run(app.sb);
129 		sandbox_slave_free(app.sb);
130 		return res;
131 	}
132 
133 	return res;
134 }
135