Implement sending SysEx events to USB MIDI devices.
[calfbox.git] / rt.c
blob40718994ba75600c0885a9d7fc48cf678242540e
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2013 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "dom.h"
20 #include "engine.h"
21 #include "io.h"
22 #include "midi.h"
23 #include "module.h"
24 #include "rt.h"
25 #include "stm.h"
26 #include <assert.h>
27 #include <stdio.h>
28 #include <unistd.h>
30 CBOX_CLASS_DEFINITION_ROOT(cbox_rt)
32 static void cbox_rt_process(void *user_data, struct cbox_io *io, uint32_t nframes);
34 struct cbox_rt_cmd_instance
36 struct cbox_rt_cmd_definition *definition;
37 void *user_data;
38 int is_async;
41 static gboolean cbox_rt_process_cmd(struct cbox_command_target *ct, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error)
43 struct cbox_rt *rt = ct->user_data;
44 if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
46 if (!cbox_check_fb_channel(fb, cmd->command, error))
47 return FALSE;
48 if (rt->io)
50 GError *cerror = NULL;
51 if (cbox_io_get_disconnect_status(rt->io, &cerror))
53 return cbox_execute_on(fb, NULL, "/audio_channels", "ii", error, rt->io->io_env.input_count, rt->io->io_env.output_count) &&
54 cbox_execute_on(fb, NULL, "/state", "is", error, 1, "OK") &&
55 CBOX_OBJECT_DEFAULT_STATUS(rt, fb, error);
57 else
59 return cbox_execute_on(fb, NULL, "/audio_channels", "ii", error, rt->io->io_env.input_count, rt->io->io_env.output_count) &&
60 cbox_execute_on(fb, NULL, "/state", "is", error, -1, cerror ? cerror->message : "Unknown error") &&
61 CBOX_OBJECT_DEFAULT_STATUS(rt, fb, error);
64 else
65 return cbox_execute_on(fb, NULL, "/audio_channels", "ii", error, 0, 2) &&
66 cbox_execute_on(fb, NULL, "/state", "is", error, 0, "Offline") &&
67 CBOX_OBJECT_DEFAULT_STATUS(rt, fb, error);
69 else if (!strcmp(cmd->command, "/cycle") && !strcmp(cmd->arg_types, ""))
71 if (rt->io && !cbox_io_get_disconnect_status(rt->io, NULL))
73 return cbox_io_cycle(rt->io, fb, error);
75 else
77 if (rt->io)
78 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Already connected");
79 else
80 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot cycle connection in off-line mode");
81 return FALSE;
84 else if (!strncmp(cmd->command, "/engine/", 8))
85 return cbox_execute_sub(&rt->engine->cmd_target, fb, cmd, cmd->command + 7, error);
86 else
87 return cbox_object_default_process_cmd(ct, fb, cmd, error);
90 struct cbox_rt *cbox_rt_new(struct cbox_document *doc)
92 struct cbox_rt *rt = malloc(sizeof(struct cbox_rt));
93 CBOX_OBJECT_HEADER_INIT(rt, cbox_rt, doc);
94 rt->rb_execute = jack_ringbuffer_create(sizeof(struct cbox_rt_cmd_instance) * RT_CMD_QUEUE_ITEMS);
95 rt->rb_cleanup = jack_ringbuffer_create(sizeof(struct cbox_rt_cmd_instance) * RT_CMD_QUEUE_ITEMS * 2);
96 rt->io = NULL;
97 rt->engine = NULL;
98 rt->started = FALSE;
99 rt->disconnected = FALSE;
100 rt->io_env.srate = 0;
101 rt->io_env.buffer_size = 0;
103 cbox_command_target_init(&rt->cmd_target, cbox_rt_process_cmd, rt);
104 CBOX_OBJECT_REGISTER(rt);
105 cbox_document_set_service(doc, "rt", &rt->_obj_hdr);
107 return rt;
110 struct cbox_objhdr *cbox_rt_newfunc(struct cbox_class *class_ptr, struct cbox_document *doc)
112 return NULL;
115 void cbox_rt_destroyfunc(struct cbox_objhdr *obj_ptr)
117 struct cbox_rt *rt = (void *)obj_ptr;
118 jack_ringbuffer_free(rt->rb_execute);
119 jack_ringbuffer_free(rt->rb_cleanup);
121 free(rt);
124 static void cbox_rt_on_disconnected(void *user_data)
126 struct cbox_rt *rt = user_data;
127 rt->disconnected = TRUE;
130 static void cbox_rt_on_reconnected(void *user_data)
132 struct cbox_rt *rt = user_data;
133 rt->disconnected = FALSE;
136 static void cbox_rt_on_midi_outputs_changed(void *user_data)
138 struct cbox_rt *rt = user_data;
139 if (rt->engine)
140 cbox_engine_update_song_playback(rt->engine);
143 static void cbox_rt_on_midi_inputs_changed(void *user_data)
145 struct cbox_rt *rt = user_data;
146 if (rt->engine)
147 cbox_engine_update_input_connections(rt->engine);
150 void cbox_rt_on_update_io_env(struct cbox_rt *rt)
152 if (rt->engine)
154 cbox_io_env_copy(&rt->engine->io_env, &rt->io_env);
155 cbox_master_set_sample_rate(rt->engine->master, rt->io_env.srate);
159 void cbox_rt_set_io(struct cbox_rt *rt, struct cbox_io *io)
161 assert(!rt->started);
162 rt->io = io;
163 if (io)
165 cbox_io_env_copy(&rt->io_env, &io->io_env);
166 cbox_rt_on_update_io_env(rt);
168 else
170 cbox_io_env_clear(&rt->io_env);
174 void cbox_rt_set_offline(struct cbox_rt *rt, int sample_rate, int buffer_size)
176 assert(!rt->started);
177 rt->io = NULL;
178 rt->io_env.srate = sample_rate;
179 rt->io_env.buffer_size = buffer_size;
180 rt->io_env.input_count = 0;
181 rt->io_env.output_count = 2;
182 cbox_rt_on_update_io_env(rt);
185 void cbox_rt_on_started(void *user_data)
187 struct cbox_rt *rt = user_data;
188 rt->started = 1;
191 void cbox_rt_start(struct cbox_rt *rt, struct cbox_command_target *fb)
193 if (rt->io)
195 rt->cbs = malloc(sizeof(struct cbox_io_callbacks));
196 rt->cbs->user_data = rt;
197 rt->cbs->process = cbox_rt_process;
198 rt->cbs->on_started = cbox_rt_on_started;
199 rt->cbs->on_disconnected = cbox_rt_on_disconnected;
200 rt->cbs->on_reconnected = cbox_rt_on_reconnected;
201 rt->cbs->on_midi_inputs_changed = cbox_rt_on_midi_inputs_changed;
202 rt->cbs->on_midi_outputs_changed = cbox_rt_on_midi_outputs_changed;
204 cbox_io_start(rt->io, rt->cbs, fb);
208 void cbox_rt_stop(struct cbox_rt *rt)
210 if (rt->io)
212 assert(rt->started);
213 cbox_io_stop(rt->io);
214 free(rt->cbs);
215 rt->cbs = NULL;
216 rt->started = 0;
220 void cbox_rt_handle_cmd_queue(struct cbox_rt *rt)
222 struct cbox_rt_cmd_instance cmd;
224 while(jack_ringbuffer_read(rt->rb_cleanup, (char *)&cmd, sizeof(cmd)))
226 cmd.definition->cleanup(cmd.user_data);
230 static void wait_write_space(jack_ringbuffer_t *rb)
232 int t = 0;
233 while (jack_ringbuffer_write_space(rb) < sizeof(struct cbox_rt_cmd_instance))
235 // wait until some space frees up in the execute queue
236 usleep(1000);
237 t++;
238 if (t >= 1000)
240 fprintf(stderr, "Execute queue full, waiting...\n");
241 t = 0;
246 void cbox_rt_execute_cmd_sync(struct cbox_rt *rt, struct cbox_rt_cmd_definition *def, void *user_data)
248 struct cbox_rt_cmd_instance cmd;
250 if (def->prepare)
251 if (def->prepare(user_data))
252 return;
254 // No realtime thread - do it all in the main thread
255 if (!rt || !rt->started || rt->disconnected)
257 while (!def->execute(user_data))
259 if (def->cleanup)
260 def->cleanup(user_data);
261 return;
264 memset(&cmd, 0, sizeof(cmd));
265 cmd.definition = def;
266 cmd.user_data = user_data;
267 cmd.is_async = 0;
269 wait_write_space(rt->rb_execute);
270 jack_ringbuffer_write(rt->rb_execute, (const char *)&cmd, sizeof(cmd));
273 struct cbox_rt_cmd_instance cmd2;
275 if (jack_ringbuffer_read_space(rt->rb_cleanup) < sizeof(cmd2))
277 // still no result in cleanup queue - wait
278 usleep(10000);
279 continue;
281 jack_ringbuffer_read(rt->rb_cleanup, (char *)&cmd2, sizeof(cmd2));
282 if (!memcmp(&cmd, &cmd2, sizeof(cmd)))
284 if (def->cleanup)
285 def->cleanup(user_data);
286 break;
288 // async command - clean it up
289 if (cmd2.definition->cleanup)
290 cmd2.definition->cleanup(cmd2.user_data);
291 } while(1);
294 void cbox_rt_execute_cmd_async(struct cbox_rt *rt, struct cbox_rt_cmd_definition *def, void *user_data)
296 struct cbox_rt_cmd_instance cmd = { def, user_data, 1 };
298 if (def->prepare)
300 if (def->prepare(user_data))
301 return;
303 // No realtime thread - do it all in the main thread
304 if (!rt || !rt->started || rt->disconnected)
306 while (!def->execute(user_data))
308 if (def->cleanup)
309 def->cleanup(user_data);
310 return;
313 wait_write_space(rt->rb_execute);
314 jack_ringbuffer_write(rt->rb_execute, (const char *)&cmd, sizeof(cmd));
316 // will be cleaned up by next sync call or by cbox_rt_cmd_handle_queue
319 ////////////////////////////////////////////////////////////////////////////////////////
321 void cbox_rt_process(void *user_data, struct cbox_io *io, uint32_t nframes)
323 struct cbox_rt *rt = user_data;
324 if (rt->engine)
325 cbox_engine_process(rt->engine, io, nframes, io->output_buffers);
326 else
327 cbox_rt_handle_rt_commands(rt);
330 ////////////////////////////////////////////////////////////////////////////////////////
332 void cbox_rt_handle_rt_commands(struct cbox_rt *rt)
334 struct cbox_rt_cmd_instance cmd;
336 // Process command queue, needs engine's MIDI aux buf to be initialised to work
337 int cost = 0;
338 while(cost < RT_MAX_COST_PER_CALL && jack_ringbuffer_peek(rt->rb_execute, (char *)&cmd, sizeof(cmd)))
340 int result = (cmd.definition->execute)(cmd.user_data);
341 if (!result)
342 break;
343 cost += result;
344 jack_ringbuffer_read_advance(rt->rb_execute, sizeof(cmd));
345 if (cmd.definition->cleanup || !cmd.is_async)
347 jack_ringbuffer_write(rt->rb_cleanup, (const char *)&cmd, sizeof(cmd));
352 ////////////////////////////////////////////////////////////////////////////////////////
354 #define cbox_rt_swap_pointers_args(ARG) ARG(void **, ptr) ARG(void *, new_value)
356 DEFINE_RT_FUNC(void *, cbox_rt, rt, cbox_rt_swap_pointers)
358 void *old_value = *ptr;
359 *ptr = new_value;
360 return old_value;
363 #define cbox_rt_swap_pointers_and_update_count_args(ARG) ARG(void **, ptr) ARG(void *, new_value) ARG(int *, pcount) ARG(int, new_count)
365 DEFINE_RT_FUNC(void *, cbox_rt, rt, cbox_rt_swap_pointers_and_update_count)
367 void *old_value = *ptr;
368 *ptr = new_value;
369 if (pcount)
370 *pcount = new_count;
371 return old_value;
374 void cbox_rt_array_insert(struct cbox_rt *rt, void ***ptr, int *pcount, int index, void *new_value)
376 assert(index >= -1);
377 assert(index <= *pcount);
378 assert(*pcount >= 0);
379 void **new_array = stm_array_clone_insert(*ptr, *pcount, index, new_value);
380 free(cbox_rt_swap_pointers_and_update_count(rt, (void **)ptr, new_array, pcount, *pcount + 1));
383 void *cbox_rt_array_remove(struct cbox_rt *rt, void ***ptr, int *pcount, int index)
385 if (index == -1)
386 index = *pcount - 1;
387 assert(index >= 0);
388 assert(index < *pcount);
389 assert(*pcount > 0);
390 void *p = (*ptr)[index];
391 void **new_array = stm_array_clone_remove(*ptr, *pcount, index);
392 free(cbox_rt_swap_pointers_and_update_count(rt, (void **)ptr, new_array, pcount, *pcount - 1));
393 return p;
396 gboolean cbox_rt_array_remove_by_value(struct cbox_rt *rt, void ***ptr, int *pcount, void *value_to_remove)
398 for (int i = 0; i < *pcount; i++)
400 if ((*ptr)[i] == value_to_remove)
402 cbox_rt_array_remove(rt, ptr, pcount, i);
403 return TRUE;
406 return FALSE;
409 ////////////////////////////////////////////////////////////////////////////////////////
411 struct cbox_midi_merger *cbox_rt_get_midi_output(struct cbox_rt *rt, struct cbox_uuid *uuid)
413 if (rt->engine)
415 struct cbox_midi_merger *merger = cbox_engine_get_midi_output(rt->engine, uuid);
416 if (merger)
417 return merger;
419 if (!rt->io)
420 return NULL;
422 struct cbox_midi_output *midiout = cbox_io_get_midi_output(rt->io, NULL, uuid);
423 return midiout ? &midiout->merger : NULL;
426 ////////////////////////////////////////////////////////////////////////////////////////