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/>.
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
;
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
))
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
);
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
);
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
);
78 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Already connected");
80 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Cannot cycle connection in off-line mode");
84 else if (!strncmp(cmd
->command
, "/engine/", 8))
85 return cbox_execute_sub(&rt
->engine
->cmd_target
, fb
, cmd
, cmd
->command
+ 7, error
);
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);
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
);
110 struct cbox_objhdr
*cbox_rt_newfunc(struct cbox_class
*class_ptr
, struct cbox_document
*doc
)
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
);
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
;
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
;
147 cbox_engine_update_input_connections(rt
->engine
);
150 void cbox_rt_on_update_io_env(struct cbox_rt
*rt
)
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
);
165 cbox_io_env_copy(&rt
->io_env
, &io
->io_env
);
166 cbox_rt_on_update_io_env(rt
);
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
);
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
;
191 void cbox_rt_start(struct cbox_rt
*rt
, struct cbox_command_target
*fb
)
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
)
213 cbox_io_stop(rt
->io
);
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
)
233 while (jack_ringbuffer_write_space(rb
) < sizeof(struct cbox_rt_cmd_instance
))
235 // wait until some space frees up in the execute queue
240 fprintf(stderr
, "Execute queue full, waiting...\n");
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
;
251 if (def
->prepare(user_data
))
254 // No realtime thread - do it all in the main thread
255 if (!rt
|| !rt
->started
|| rt
->disconnected
)
257 while (!def
->execute(user_data
))
260 def
->cleanup(user_data
);
264 memset(&cmd
, 0, sizeof(cmd
));
265 cmd
.definition
= def
;
266 cmd
.user_data
= user_data
;
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
281 jack_ringbuffer_read(rt
->rb_cleanup
, (char *)&cmd2
, sizeof(cmd2
));
282 if (!memcmp(&cmd
, &cmd2
, sizeof(cmd
)))
285 def
->cleanup(user_data
);
288 // async command - clean it up
289 if (cmd2
.definition
->cleanup
)
290 cmd2
.definition
->cleanup(cmd2
.user_data
);
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 };
300 if (def
->prepare(user_data
))
303 // No realtime thread - do it all in the main thread
304 if (!rt
|| !rt
->started
|| rt
->disconnected
)
306 while (!def
->execute(user_data
))
309 def
->cleanup(user_data
);
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
;
325 cbox_engine_process(rt
->engine
, io
, nframes
, io
->output_buffers
);
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
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
);
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
;
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
;
374 void cbox_rt_array_insert(struct cbox_rt
*rt
, void ***ptr
, int *pcount
, int index
, void *new_value
)
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
)
388 assert(index
< *pcount
);
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));
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
);
409 ////////////////////////////////////////////////////////////////////////////////////////
411 struct cbox_midi_merger
*cbox_rt_get_midi_output(struct cbox_rt
*rt
, struct cbox_uuid
*uuid
)
415 struct cbox_midi_merger
*merger
= cbox_engine_get_midi_output(rt
->engine
, uuid
);
422 struct cbox_midi_output
*midiout
= cbox_io_get_midi_output(rt
->io
, NULL
, uuid
);
423 return midiout
? &midiout
->merger
: NULL
;
426 ////////////////////////////////////////////////////////////////////////////////////////