Use a dedicated variable for triggering streaming thread shutdown.
[calfbox.git] / io.c
blobb952d028c50ce3e689469f58a75584cd303b8f88
1 /*
2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 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 "app.h"
20 #include "config.h"
21 #include "config-api.h"
22 #include "errors.h"
23 #include "hwcfg.h"
24 #include "io.h"
25 #include "meter.h"
26 #include "midi.h"
27 #include "recsrc.h"
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <glib.h>
34 const char *cbox_io_section = "io";
36 gboolean cbox_io_init(struct cbox_io *io, struct cbox_open_params *const params, struct cbox_command_target *fb, GError **error)
38 if (cbox_config_get_int(cbox_io_section, "use_usb", 0))
39 return cbox_io_init_usb(io, params, fb, error);
40 return cbox_io_init_jack(io, params, fb, error);
43 int cbox_io_get_sample_rate(struct cbox_io *io)
45 return io->impl->getsampleratefunc(io->impl);
48 void cbox_io_poll_ports(struct cbox_io *io, struct cbox_command_target *fb)
50 io->impl->pollfunc(io->impl, fb);
53 int cbox_io_get_midi_data(struct cbox_io *io, struct cbox_midi_buffer *destination)
55 return io->impl->getmidifunc(io->impl, destination);
58 int cbox_io_start(struct cbox_io *io, struct cbox_io_callbacks *cb, struct cbox_command_target *fb)
60 io->cb = cb;
61 return io->impl->startfunc(io->impl, fb, NULL);
64 gboolean cbox_io_get_disconnect_status(struct cbox_io *io, GError **error)
66 return io->impl->getstatusfunc(io->impl, error);
69 gboolean cbox_io_cycle(struct cbox_io *io, struct cbox_command_target *fb, GError **error)
71 return io->impl->cyclefunc(io->impl, fb, error);
74 int cbox_io_stop(struct cbox_io *io)
76 int result = io->impl->stopfunc(io->impl, NULL);
77 if (io->cb && io->cb->on_stopped)
78 io->cb->on_stopped(io->cb->user_data);
79 io->cb = NULL;
80 return result;
83 struct cbox_midi_output *cbox_io_get_midi_output(struct cbox_io *io, const char *name, const struct cbox_uuid *uuid)
85 if (uuid)
87 for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
89 struct cbox_midi_output *midiout = p->data;
90 if (!midiout->removing && cbox_uuid_equal(&midiout->uuid, uuid))
91 return midiout;
94 if (name)
96 for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
98 struct cbox_midi_output *midiout = p->data;
99 if (!midiout->removing && !strcmp(midiout->name, name))
100 return midiout;
103 return NULL;
106 struct cbox_midi_input *cbox_io_get_midi_input(struct cbox_io *io, const char *name, const struct cbox_uuid *uuid)
108 if (uuid)
110 for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
112 struct cbox_midi_input *midiin = p->data;
113 if (!midiin->removing && cbox_uuid_equal(&midiin->uuid, uuid))
114 return midiin;
117 if (name)
119 for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
121 struct cbox_midi_input *midiin = p->data;
122 if (!midiin->removing && !strcmp(midiin->name, name))
123 return midiin;
126 return NULL;
129 struct cbox_midi_output *cbox_io_create_midi_output(struct cbox_io *io, const char *name, GError **error)
131 struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, name, NULL);
132 if (midiout)
133 return midiout;
135 midiout = io->impl->createmidioutfunc(io->impl, name, error);
136 if (!midiout)
137 return NULL;
139 io->midi_outputs = g_slist_prepend(io->midi_outputs, midiout);
141 // Notify client code to connect to new outputs if needed
142 if (io->cb->on_midi_outputs_changed)
143 io->cb->on_midi_outputs_changed(io->cb->user_data);
144 return midiout;
147 void cbox_io_destroy_midi_output(struct cbox_io *io, struct cbox_midi_output *midiout)
149 midiout->removing = TRUE;
151 // This is not a very efficient way to do it. However, in this case,
152 // the list will rarely contain more than 10 elements, so simplicity
153 // and correctness may be more important.
154 GSList *copy = g_slist_copy(io->midi_outputs);
155 copy = g_slist_remove(copy, midiout);
157 GSList *old = io->midi_outputs;
158 io->midi_outputs = copy;
160 // Notify client code to disconnect the output and to make sure the RT code
161 // is not using the old list anymore
162 if (io->cb->on_midi_outputs_changed)
163 io->cb->on_midi_outputs_changed(io->cb->user_data);
165 g_slist_free(old);
166 io->impl->destroymidioutfunc(io->impl, midiout);
169 struct cbox_midi_input *cbox_io_create_midi_input(struct cbox_io *io, const char *name, GError **error)
171 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, name, NULL);
172 if (midiin)
173 return midiin;
175 midiin = io->impl->createmidiinfunc(io->impl, name, error);
176 if (!midiin)
177 return NULL;
179 io->midi_inputs = g_slist_prepend(io->midi_inputs, midiin);
181 // Notify client code to connect to new inputs if needed
182 if (io->cb->on_midi_inputs_changed)
183 io->cb->on_midi_inputs_changed(io->cb->user_data);
184 return midiin;
187 void cbox_io_destroy_midi_input(struct cbox_io *io, struct cbox_midi_input *midiin)
189 midiin->removing = TRUE;
191 // This is not a very efficient way to do it. However, in this case,
192 // the list will rarely contain more than 10 elements, so simplicity
193 // and correctness may be more important.
194 GSList *copy = g_slist_copy(io->midi_inputs);
195 copy = g_slist_remove(copy, midiin);
197 GSList *old = io->midi_inputs;
198 io->midi_inputs = copy;
200 // Notify client code to disconnect the input and to make sure the RT code
201 // is not using the old list anymore
202 if (io->cb->on_midi_inputs_changed)
203 io->cb->on_midi_inputs_changed(io->cb->user_data);
205 g_slist_free(old);
206 io->impl->destroymidiinfunc(io->impl, midiin);
209 void cbox_io_destroy_all_midi_ports(struct cbox_io *io)
211 for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
213 struct cbox_midi_output *midiout = p->data;
214 midiout->removing = TRUE;
216 for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
218 struct cbox_midi_output *midiin = p->data;
219 midiin->removing = TRUE;
222 GSList *old_i = io->midi_inputs, *old_o = io->midi_outputs;
223 io->midi_outputs = NULL;
224 io->midi_inputs = NULL;
225 // Notify client code to disconnect the output and to make sure the RT code
226 // is not using the old list anymore
227 if (io->cb && io->cb->on_midi_outputs_changed)
228 io->cb->on_midi_outputs_changed(io->cb->user_data);
229 if (io->cb && io->cb->on_midi_inputs_changed)
230 io->cb->on_midi_inputs_changed(io->cb->user_data);
232 while(old_o)
234 struct cbox_midi_output *midiout = old_o->data;
235 io->impl->destroymidioutfunc(io->impl, midiout);
236 old_o = g_slist_remove(old_o, midiout);
238 g_slist_free(old_o);
240 while(old_i)
242 struct cbox_midi_input *midiin = old_i->data;
243 io->impl->destroymidiinfunc(io->impl, midiin);
244 old_i = g_slist_remove(old_i, midiin);
246 g_slist_free(old_i);
249 gboolean cbox_io_process_cmd(struct cbox_io *io, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error, gboolean *cmd_handled)
251 *cmd_handled = FALSE;
252 if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
254 *cmd_handled = TRUE;
255 if (!cbox_check_fb_channel(fb, cmd->command, error))
256 return FALSE;
257 for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
259 struct cbox_midi_input *midiin = p->data;
260 if (!midiin->removing)
262 if (!cbox_execute_on(fb, NULL, "/midi_input", "su", error, midiin->name, &midiin->uuid))
263 return FALSE;
266 for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
268 struct cbox_midi_output *midiout = p->data;
269 if (!midiout->removing)
271 if (!cbox_execute_on(fb, NULL, "/midi_output", "su", error, midiout->name, &midiout->uuid))
272 return FALSE;
275 return cbox_execute_on(fb, NULL, "/client_type", "s", error, "USB") &&
276 cbox_execute_on(fb, NULL, "/audio_inputs", "i", error, io->io_env.input_count) &&
277 cbox_execute_on(fb, NULL, "/audio_outputs", "i", error, io->io_env.output_count) &&
278 cbox_execute_on(fb, NULL, "/sample_rate", "i", error, io->io_env.srate) &&
279 cbox_execute_on(fb, NULL, "/buffer_size", "i", error, io->io_env.buffer_size);
281 else if (io->impl->createmidiinfunc && !strcmp(cmd->command, "/create_midi_input") && !strcmp(cmd->arg_types, "s"))
283 *cmd_handled = TRUE;
284 struct cbox_midi_input *midiin;
285 midiin = cbox_io_create_midi_input(io, CBOX_ARG_S(cmd, 0), error);
286 if (!midiin)
287 return FALSE;
288 return cbox_uuid_report(&midiin->uuid, fb, error);
290 else if (!strcmp(cmd->command, "/route_midi_input") && !strcmp(cmd->arg_types, "ss"))
292 *cmd_handled = TRUE;
293 const char *uuidstr = CBOX_ARG_S(cmd, 0);
294 struct cbox_uuid uuid;
295 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
296 return FALSE;
297 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
298 if (!midiin)
300 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
301 return FALSE;
303 if (*CBOX_ARG_S(cmd, 1))
305 if (cbox_uuid_fromstring(&midiin->output, CBOX_ARG_S(cmd, 1), error))
306 midiin->output_set = TRUE;
308 else
309 midiin->output_set = FALSE;
310 if (io->impl->updatemidiinroutingfunc)
311 io->impl->updatemidiinroutingfunc(io->impl);
312 if (io->cb->on_midi_inputs_changed)
313 io->cb->on_midi_inputs_changed(io->cb->user_data);
314 return TRUE;
316 else if (!strcmp(cmd->command, "/set_appsink_for_midi_input") && !strcmp(cmd->arg_types, "si"))
318 *cmd_handled = TRUE;
319 const char *uuidstr = CBOX_ARG_S(cmd, 0);
320 struct cbox_uuid uuid;
321 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
322 return FALSE;
323 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
324 if (!midiin)
326 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
327 return FALSE;
329 midiin->enable_appsink = CBOX_ARG_I(cmd, 1);
330 return TRUE;
332 else if (!strcmp(cmd->command, "/get_new_events") && !strcmp(cmd->arg_types, "s"))
334 *cmd_handled = TRUE;
335 if (!cbox_check_fb_channel(fb, cmd->command, error))
336 return FALSE;
337 const char *uuidstr = CBOX_ARG_S(cmd, 0);
338 struct cbox_uuid uuid;
339 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
340 return FALSE;
341 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
342 if (!midiin)
344 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
345 return FALSE;
347 if (!midiin->enable_appsink)
349 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "App sink not enabled for port '%s'", uuidstr);
350 return FALSE;
352 midiin->appsink.rt = app.rt; // XXXKF this is a bad hack
353 return cbox_midi_appsink_send_to(&midiin->appsink, fb, error);
355 else if (io->impl->createmidioutfunc && !strcmp(cmd->command, "/create_midi_output") && !strcmp(cmd->arg_types, "s"))
357 *cmd_handled = TRUE;
358 struct cbox_midi_output *midiout;
359 midiout = cbox_io_create_midi_output(io, CBOX_ARG_S(cmd, 0), error);
360 if (!midiout)
361 return FALSE;
362 return cbox_uuid_report(&midiout->uuid, fb, error);
364 else if (io->impl->destroymidioutfunc && !strcmp(cmd->command, "/delete_midi_input") && !strcmp(cmd->arg_types, "s"))
366 *cmd_handled = TRUE;
367 const char *uuidstr = CBOX_ARG_S(cmd, 0);
368 struct cbox_uuid uuid;
369 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
370 return FALSE;
371 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
372 if (!midiin)
374 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
375 return FALSE;
377 cbox_io_destroy_midi_input(io, midiin);
378 return TRUE;
380 else if (io->impl->destroymidioutfunc && !strcmp(cmd->command, "/delete_midi_output") && !strcmp(cmd->arg_types, "s"))
382 *cmd_handled = TRUE;
383 const char *uuidstr = CBOX_ARG_S(cmd, 0);
384 struct cbox_uuid uuid;
385 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
386 return FALSE;
387 struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid);
388 if (!midiout)
390 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
391 return FALSE;
393 cbox_io_destroy_midi_output(io, midiout);
394 return TRUE;
396 return FALSE;
399 void cbox_io_close(struct cbox_io *io)
401 io->impl->destroyfunc(io->impl);
402 io->impl = NULL;