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
= cbox_fifo_new(sizeof(struct cbox_rt_cmd_instance
) * RT_CMD_QUEUE_ITEMS
);
95 rt
->rb_cleanup
= cbox_fifo_new(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 cbox_fifo_destroy(rt
->rb_execute
);
119 cbox_fifo_destroy(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_on_stopped(void *user_data
)
193 struct cbox_rt
*rt
= user_data
;
197 gboolean
cbox_rt_on_transport_sync(void *user_data
, enum cbox_transport_state state
, uint32_t frame
)
199 struct cbox_rt
*rt
= user_data
;
202 return cbox_engine_on_transport_sync(rt
->engine
, state
, frame
);
205 void cbox_rt_start(struct cbox_rt
*rt
, struct cbox_command_target
*fb
)
209 rt
->cbs
= calloc(1, sizeof(struct cbox_io_callbacks
));
210 rt
->cbs
->user_data
= rt
;
211 rt
->cbs
->process
= cbox_rt_process
;
212 rt
->cbs
->on_started
= cbox_rt_on_started
;
213 rt
->cbs
->on_stopped
= cbox_rt_on_stopped
;
214 rt
->cbs
->on_disconnected
= cbox_rt_on_disconnected
;
215 rt
->cbs
->on_reconnected
= cbox_rt_on_reconnected
;
216 rt
->cbs
->on_midi_inputs_changed
= cbox_rt_on_midi_inputs_changed
;
217 rt
->cbs
->on_midi_outputs_changed
= cbox_rt_on_midi_outputs_changed
;
218 rt
->cbs
->on_transport_sync
= cbox_rt_on_transport_sync
;
220 assert(!rt
->started
);
221 cbox_io_start(rt
->io
, rt
->cbs
, fb
);
226 void cbox_rt_stop(struct cbox_rt
*rt
)
231 cbox_io_stop(rt
->io
);
234 assert(!rt
->started
);
238 void cbox_rt_handle_cmd_queue(struct cbox_rt
*rt
)
240 struct cbox_rt_cmd_instance cmd
;
242 while(cbox_fifo_read_atomic(rt
->rb_cleanup
, &cmd
, sizeof(cmd
)))
244 cmd
.definition
->cleanup(cmd
.user_data
);
248 static void wait_write_space(struct cbox_fifo
*rb
)
251 while (cbox_fifo_writespace(rb
) < sizeof(struct cbox_rt_cmd_instance
))
253 // wait until some space frees up in the execute queue
258 fprintf(stderr
, "Execute queue full, waiting...\n");
264 void cbox_rt_execute_cmd_sync(struct cbox_rt
*rt
, struct cbox_rt_cmd_definition
*def
, void *user_data
)
266 struct cbox_rt_cmd_instance cmd
;
269 if (def
->prepare(user_data
))
272 // No realtime thread - do it all in the main thread
273 if (!rt
|| !rt
->started
|| rt
->disconnected
)
275 while (!def
->execute(user_data
))
278 def
->cleanup(user_data
);
282 memset(&cmd
, 0, sizeof(cmd
));
283 cmd
.definition
= def
;
284 cmd
.user_data
= user_data
;
287 wait_write_space(rt
->rb_execute
);
288 cbox_fifo_write_atomic(rt
->rb_execute
, &cmd
, sizeof(cmd
));
291 struct cbox_rt_cmd_instance cmd2
;
293 if (!cbox_fifo_read_atomic(rt
->rb_cleanup
, &cmd2
, sizeof(cmd2
)))
295 // still no result in cleanup queue - wait
299 if (!memcmp(&cmd
, &cmd2
, sizeof(cmd
)))
302 def
->cleanup(user_data
);
305 // async command - clean it up
306 if (cmd2
.definition
->cleanup
)
307 cmd2
.definition
->cleanup(cmd2
.user_data
);
311 void cbox_rt_execute_cmd_async(struct cbox_rt
*rt
, struct cbox_rt_cmd_definition
*def
, void *user_data
)
313 struct cbox_rt_cmd_instance cmd
= { def
, user_data
, 1 };
317 if (def
->prepare(user_data
))
320 // No realtime thread - do it all in the main thread
321 if (!rt
|| !rt
->started
|| rt
->disconnected
)
323 while (!def
->execute(user_data
))
326 def
->cleanup(user_data
);
330 wait_write_space(rt
->rb_execute
);
331 cbox_fifo_write_atomic(rt
->rb_execute
, &cmd
, sizeof(cmd
));
333 // will be cleaned up by next sync call or by cbox_rt_cmd_handle_queue
336 ////////////////////////////////////////////////////////////////////////////////////////
338 void cbox_rt_process(void *user_data
, struct cbox_io
*io
, uint32_t nframes
)
340 struct cbox_rt
*rt
= user_data
;
342 cbox_engine_process(rt
->engine
, io
, nframes
, io
->output_buffers
);
344 cbox_rt_handle_rt_commands(rt
);
347 ////////////////////////////////////////////////////////////////////////////////////////
349 void cbox_rt_handle_rt_commands(struct cbox_rt
*rt
)
351 struct cbox_rt_cmd_instance cmd
;
353 // Process command queue, needs engine's MIDI aux buf to be initialised to work
355 while(cost
< RT_MAX_COST_PER_CALL
&& cbox_fifo_peek(rt
->rb_execute
, &cmd
, sizeof(cmd
)))
357 int result
= (cmd
.definition
->execute
)(cmd
.user_data
);
361 cbox_fifo_consume(rt
->rb_execute
, sizeof(cmd
));
362 if (cmd
.definition
->cleanup
|| !cmd
.is_async
)
364 gboolean success
= cbox_fifo_write_atomic(rt
->rb_cleanup
, (const char *)&cmd
, sizeof(cmd
));
366 g_error("Clean-up FIFO full. Main thread deadlock?");
371 ////////////////////////////////////////////////////////////////////////////////////////
373 #define cbox_rt_swap_pointers_args(ARG) ARG(void **, ptr) ARG(void *, new_value)
375 DEFINE_RT_FUNC(void *, cbox_rt
, rt
, cbox_rt_swap_pointers
)
377 void *old_value
= *ptr
;
382 #define cbox_rt_swap_pointers_and_update_count_args(ARG) ARG(void **, ptr) ARG(void *, new_value) ARG(int *, pcount) ARG(int, new_count)
384 DEFINE_RT_FUNC(void *, cbox_rt
, rt
, cbox_rt_swap_pointers_and_update_count
)
386 void *old_value
= *ptr
;
393 void cbox_rt_array_insert(struct cbox_rt
*rt
, void ***ptr
, int *pcount
, int index
, void *new_value
)
396 assert(index
<= *pcount
);
397 assert(*pcount
>= 0);
398 void **new_array
= stm_array_clone_insert(*ptr
, *pcount
, index
, new_value
);
399 free(cbox_rt_swap_pointers_and_update_count(rt
, (void **)ptr
, new_array
, pcount
, *pcount
+ 1));
402 void *cbox_rt_array_remove(struct cbox_rt
*rt
, void ***ptr
, int *pcount
, int index
)
407 assert(index
< *pcount
);
409 void *p
= (*ptr
)[index
];
410 void **new_array
= stm_array_clone_remove(*ptr
, *pcount
, index
);
411 free(cbox_rt_swap_pointers_and_update_count(rt
, (void **)ptr
, new_array
, pcount
, *pcount
- 1));
415 gboolean
cbox_rt_array_remove_by_value(struct cbox_rt
*rt
, void ***ptr
, int *pcount
, void *value_to_remove
)
417 for (int i
= 0; i
< *pcount
; i
++)
419 if ((*ptr
)[i
] == value_to_remove
)
421 cbox_rt_array_remove(rt
, ptr
, pcount
, i
);
428 ////////////////////////////////////////////////////////////////////////////////////////
430 struct cbox_midi_merger
*cbox_rt_get_midi_output(struct cbox_rt
*rt
, struct cbox_uuid
*uuid
)
434 struct cbox_midi_merger
*merger
= cbox_engine_get_midi_output(rt
->engine
, uuid
);
441 struct cbox_midi_output
*midiout
= cbox_io_get_midi_output(rt
->io
, NULL
, uuid
);
442 return midiout
? &midiout
->merger
: NULL
;
445 ////////////////////////////////////////////////////////////////////////////////////////