Make prefetch-piped samples stop correctly.
[calfbox.git] / io.c
blob29aeb5d93de8c5121b4e04238ef345654d9ebdfe
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 USE_JACK
39 if (cbox_config_get_int(cbox_io_section, "use_usb", 0))
40 return cbox_io_init_usb(io, params, fb, error);
41 return cbox_io_init_jack(io, params, fb, error);
42 #else
43 return cbox_io_init_usb(io, params, fb, error);
44 #endif
47 int cbox_io_get_sample_rate(struct cbox_io *io)
49 return io->impl->getsampleratefunc(io->impl);
52 void cbox_io_poll_ports(struct cbox_io *io, struct cbox_command_target *fb)
54 io->impl->pollfunc(io->impl, fb);
57 int cbox_io_get_midi_data(struct cbox_io *io, struct cbox_midi_buffer *destination)
59 return io->impl->getmidifunc(io->impl, destination);
62 int cbox_io_start(struct cbox_io *io, struct cbox_io_callbacks *cb, struct cbox_command_target *fb)
64 io->cb = cb;
65 return io->impl->startfunc(io->impl, fb, NULL);
68 gboolean cbox_io_get_disconnect_status(struct cbox_io *io, GError **error)
70 return io->impl->getstatusfunc(io->impl, error);
73 gboolean cbox_io_cycle(struct cbox_io *io, struct cbox_command_target *fb, GError **error)
75 return io->impl->cyclefunc(io->impl, fb, error);
78 int cbox_io_stop(struct cbox_io *io)
80 int result = io->impl->stopfunc(io->impl, NULL);
81 if (io->cb && io->cb->on_stopped)
82 io->cb->on_stopped(io->cb->user_data);
83 io->cb = NULL;
84 return result;
87 struct cbox_midi_output *cbox_io_get_midi_output(struct cbox_io *io, const char *name, const struct cbox_uuid *uuid)
89 if (uuid)
91 for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
93 struct cbox_midi_output *midiout = p->data;
94 if (!midiout->removing && cbox_uuid_equal(&midiout->uuid, uuid))
95 return midiout;
98 if (name)
100 for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
102 struct cbox_midi_output *midiout = p->data;
103 if (!midiout->removing && !strcmp(midiout->name, name))
104 return midiout;
107 return NULL;
110 struct cbox_midi_input *cbox_io_get_midi_input(struct cbox_io *io, const char *name, const struct cbox_uuid *uuid)
112 if (uuid)
114 for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
116 struct cbox_midi_input *midiin = p->data;
117 if (!midiin->removing && cbox_uuid_equal(&midiin->uuid, uuid))
118 return midiin;
121 if (name)
123 for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
125 struct cbox_midi_input *midiin = p->data;
126 if (!midiin->removing && !strcmp(midiin->name, name))
127 return midiin;
130 return NULL;
133 struct cbox_midi_output *cbox_io_create_midi_output(struct cbox_io *io, const char *name, GError **error)
135 struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, name, NULL);
136 if (midiout)
137 return midiout;
139 midiout = io->impl->createmidioutfunc(io->impl, name, error);
140 if (!midiout)
141 return NULL;
143 io->midi_outputs = g_slist_prepend(io->midi_outputs, midiout);
145 // Notify client code to connect to new outputs if needed
146 if (io->cb->on_midi_outputs_changed)
147 io->cb->on_midi_outputs_changed(io->cb->user_data);
148 return midiout;
151 void cbox_io_destroy_midi_output(struct cbox_io *io, struct cbox_midi_output *midiout)
153 midiout->removing = TRUE;
155 // This is not a very efficient way to do it. However, in this case,
156 // the list will rarely contain more than 10 elements, so simplicity
157 // and correctness may be more important.
158 GSList *copy = g_slist_copy(io->midi_outputs);
159 copy = g_slist_remove(copy, midiout);
161 GSList *old = io->midi_outputs;
162 io->midi_outputs = copy;
164 // Notify client code to disconnect the output and to make sure the RT code
165 // is not using the old list anymore
166 if (io->cb->on_midi_outputs_changed)
167 io->cb->on_midi_outputs_changed(io->cb->user_data);
169 g_slist_free(old);
170 io->impl->destroymidioutfunc(io->impl, midiout);
173 struct cbox_midi_input *cbox_io_create_midi_input(struct cbox_io *io, const char *name, GError **error)
175 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, name, NULL);
176 if (midiin)
177 return midiin;
179 midiin = io->impl->createmidiinfunc(io->impl, name, error);
180 if (!midiin)
181 return NULL;
183 io->midi_inputs = g_slist_prepend(io->midi_inputs, midiin);
185 // Notify client code to connect to new inputs if needed
186 if (io->cb->on_midi_inputs_changed)
187 io->cb->on_midi_inputs_changed(io->cb->user_data);
188 return midiin;
191 void cbox_io_destroy_midi_input(struct cbox_io *io, struct cbox_midi_input *midiin)
193 midiin->removing = TRUE;
195 // This is not a very efficient way to do it. However, in this case,
196 // the list will rarely contain more than 10 elements, so simplicity
197 // and correctness may be more important.
198 GSList *copy = g_slist_copy(io->midi_inputs);
199 copy = g_slist_remove(copy, midiin);
201 GSList *old = io->midi_inputs;
202 io->midi_inputs = copy;
204 // Notify client code to disconnect the input and to make sure the RT code
205 // is not using the old list anymore
206 if (io->cb->on_midi_inputs_changed)
207 io->cb->on_midi_inputs_changed(io->cb->user_data);
209 g_slist_free(old);
210 io->impl->destroymidiinfunc(io->impl, midiin);
213 void cbox_io_destroy_all_midi_ports(struct cbox_io *io)
215 for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
217 struct cbox_midi_output *midiout = p->data;
218 midiout->removing = TRUE;
220 for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
222 struct cbox_midi_output *midiin = p->data;
223 midiin->removing = TRUE;
226 GSList *old_i = io->midi_inputs, *old_o = io->midi_outputs;
227 io->midi_outputs = NULL;
228 io->midi_inputs = NULL;
229 // Notify client code to disconnect the output and to make sure the RT code
230 // is not using the old list anymore
231 if (io->cb && io->cb->on_midi_outputs_changed)
232 io->cb->on_midi_outputs_changed(io->cb->user_data);
233 if (io->cb && io->cb->on_midi_inputs_changed)
234 io->cb->on_midi_inputs_changed(io->cb->user_data);
236 while(old_o)
238 struct cbox_midi_output *midiout = old_o->data;
239 io->impl->destroymidioutfunc(io->impl, midiout);
240 old_o = g_slist_remove(old_o, midiout);
242 g_slist_free(old_o);
244 while(old_i)
246 struct cbox_midi_input *midiin = old_i->data;
247 io->impl->destroymidiinfunc(io->impl, midiin);
248 old_i = g_slist_remove(old_i, midiin);
250 g_slist_free(old_i);
253 gboolean cbox_io_process_cmd(struct cbox_io *io, struct cbox_command_target *fb, struct cbox_osc_command *cmd, GError **error, gboolean *cmd_handled)
255 *cmd_handled = FALSE;
256 if (!strcmp(cmd->command, "/status") && !strcmp(cmd->arg_types, ""))
258 *cmd_handled = TRUE;
259 if (!cbox_check_fb_channel(fb, cmd->command, error))
260 return FALSE;
261 for (GSList *p = io->midi_inputs; p; p = g_slist_next(p))
263 struct cbox_midi_input *midiin = p->data;
264 if (!midiin->removing)
266 if (!cbox_execute_on(fb, NULL, "/midi_input", "su", error, midiin->name, &midiin->uuid))
267 return FALSE;
270 for (GSList *p = io->midi_outputs; p; p = g_slist_next(p))
272 struct cbox_midi_output *midiout = p->data;
273 if (!midiout->removing)
275 if (!cbox_execute_on(fb, NULL, "/midi_output", "su", error, midiout->name, &midiout->uuid))
276 return FALSE;
279 return cbox_execute_on(fb, NULL, "/client_type", "s", error, "USB") &&
280 cbox_execute_on(fb, NULL, "/audio_inputs", "i", error, io->io_env.input_count) &&
281 cbox_execute_on(fb, NULL, "/audio_outputs", "i", error, io->io_env.output_count) &&
282 cbox_execute_on(fb, NULL, "/sample_rate", "i", error, io->io_env.srate) &&
283 cbox_execute_on(fb, NULL, "/buffer_size", "i", error, io->io_env.buffer_size);
285 else if (io->impl->createmidiinfunc && !strcmp(cmd->command, "/create_midi_input") && !strcmp(cmd->arg_types, "s"))
287 *cmd_handled = TRUE;
288 struct cbox_midi_input *midiin;
289 midiin = cbox_io_create_midi_input(io, CBOX_ARG_S(cmd, 0), error);
290 if (!midiin)
291 return FALSE;
292 return cbox_uuid_report(&midiin->uuid, fb, error);
294 else if (!strcmp(cmd->command, "/route_midi_input") && !strcmp(cmd->arg_types, "ss"))
296 *cmd_handled = TRUE;
297 const char *uuidstr = CBOX_ARG_S(cmd, 0);
298 struct cbox_uuid uuid;
299 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
300 return FALSE;
301 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
302 if (!midiin)
304 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
305 return FALSE;
307 if (*CBOX_ARG_S(cmd, 1))
309 if (cbox_uuid_fromstring(&midiin->output, CBOX_ARG_S(cmd, 1), error))
310 midiin->output_set = TRUE;
312 else
313 midiin->output_set = FALSE;
314 if (io->impl->updatemidiinroutingfunc)
315 io->impl->updatemidiinroutingfunc(io->impl);
316 if (io->cb->on_midi_inputs_changed)
317 io->cb->on_midi_inputs_changed(io->cb->user_data);
318 return TRUE;
320 else if (!strcmp(cmd->command, "/set_appsink_for_midi_input") && !strcmp(cmd->arg_types, "si"))
322 *cmd_handled = TRUE;
323 const char *uuidstr = CBOX_ARG_S(cmd, 0);
324 struct cbox_uuid uuid;
325 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
326 return FALSE;
327 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
328 if (!midiin)
330 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
331 return FALSE;
333 midiin->enable_appsink = CBOX_ARG_I(cmd, 1);
334 return TRUE;
336 else if (!strcmp(cmd->command, "/get_new_events") && !strcmp(cmd->arg_types, "s"))
338 *cmd_handled = TRUE;
339 if (!cbox_check_fb_channel(fb, cmd->command, error))
340 return FALSE;
341 const char *uuidstr = CBOX_ARG_S(cmd, 0);
342 struct cbox_uuid uuid;
343 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
344 return FALSE;
345 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
346 if (!midiin)
348 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
349 return FALSE;
351 if (!midiin->enable_appsink)
353 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "App sink not enabled for port '%s'", uuidstr);
354 return FALSE;
356 midiin->appsink.rt = app.rt; // XXXKF this is a bad hack
357 return cbox_midi_appsink_send_to(&midiin->appsink, fb, error);
359 else if (io->impl->createmidioutfunc && !strcmp(cmd->command, "/create_midi_output") && !strcmp(cmd->arg_types, "s"))
361 *cmd_handled = TRUE;
362 struct cbox_midi_output *midiout;
363 midiout = cbox_io_create_midi_output(io, CBOX_ARG_S(cmd, 0), error);
364 if (!midiout)
365 return FALSE;
366 return cbox_uuid_report(&midiout->uuid, fb, error);
368 else if (io->impl->destroymidioutfunc && !strcmp(cmd->command, "/delete_midi_input") && !strcmp(cmd->arg_types, "s"))
370 *cmd_handled = TRUE;
371 const char *uuidstr = CBOX_ARG_S(cmd, 0);
372 struct cbox_uuid uuid;
373 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
374 return FALSE;
375 struct cbox_midi_input *midiin = cbox_io_get_midi_input(io, NULL, &uuid);
376 if (!midiin)
378 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
379 return FALSE;
381 cbox_io_destroy_midi_input(io, midiin);
382 return TRUE;
384 else if (io->impl->destroymidioutfunc && !strcmp(cmd->command, "/delete_midi_output") && !strcmp(cmd->arg_types, "s"))
386 *cmd_handled = TRUE;
387 const char *uuidstr = CBOX_ARG_S(cmd, 0);
388 struct cbox_uuid uuid;
389 if (!cbox_uuid_fromstring(&uuid, uuidstr, error))
390 return FALSE;
391 struct cbox_midi_output *midiout = cbox_io_get_midi_output(io, NULL, &uuid);
392 if (!midiout)
394 g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Port '%s' not found", uuidstr);
395 return FALSE;
397 cbox_io_destroy_midi_output(io, midiout);
398 return TRUE;
400 return FALSE;
403 void cbox_io_close(struct cbox_io *io)
405 io->impl->destroyfunc(io->impl);
406 io->impl = NULL;