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/>.
21 #include "config-api.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
)
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
);
43 return cbox_io_init_usb(io
, params
, fb
, error
);
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
)
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
);
87 struct cbox_midi_output
*cbox_io_get_midi_output(struct cbox_io
*io
, const char *name
, const struct cbox_uuid
*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
))
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
))
110 struct cbox_midi_input
*cbox_io_get_midi_input(struct cbox_io
*io
, const char *name
, const struct cbox_uuid
*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
))
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
))
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
);
139 midiout
= io
->impl
->createmidioutfunc(io
->impl
, name
, error
);
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
);
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
);
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
);
179 midiin
= io
->impl
->createmidiinfunc(io
->impl
, name
, error
);
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
);
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
);
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
);
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
);
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
);
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
, ""))
259 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
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
))
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
))
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"))
288 struct cbox_midi_input
*midiin
;
289 midiin
= cbox_io_create_midi_input(io
, CBOX_ARG_S(cmd
, 0), error
);
292 return cbox_uuid_report(&midiin
->uuid
, fb
, error
);
294 else if (!strcmp(cmd
->command
, "/route_midi_input") && !strcmp(cmd
->arg_types
, "ss"))
297 const char *uuidstr
= CBOX_ARG_S(cmd
, 0);
298 struct cbox_uuid uuid
;
299 if (!cbox_uuid_fromstring(&uuid
, uuidstr
, error
))
301 struct cbox_midi_input
*midiin
= cbox_io_get_midi_input(io
, NULL
, &uuid
);
304 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Port '%s' not found", uuidstr
);
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
;
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
);
320 else if (!strcmp(cmd
->command
, "/set_appsink_for_midi_input") && !strcmp(cmd
->arg_types
, "si"))
323 const char *uuidstr
= CBOX_ARG_S(cmd
, 0);
324 struct cbox_uuid uuid
;
325 if (!cbox_uuid_fromstring(&uuid
, uuidstr
, error
))
327 struct cbox_midi_input
*midiin
= cbox_io_get_midi_input(io
, NULL
, &uuid
);
330 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Port '%s' not found", uuidstr
);
333 midiin
->enable_appsink
= CBOX_ARG_I(cmd
, 1);
336 else if (!strcmp(cmd
->command
, "/get_new_events") && !strcmp(cmd
->arg_types
, "s"))
339 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
341 const char *uuidstr
= CBOX_ARG_S(cmd
, 0);
342 struct cbox_uuid uuid
;
343 if (!cbox_uuid_fromstring(&uuid
, uuidstr
, error
))
345 struct cbox_midi_input
*midiin
= cbox_io_get_midi_input(io
, NULL
, &uuid
);
348 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Port '%s' not found", uuidstr
);
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
);
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"))
362 struct cbox_midi_output
*midiout
;
363 midiout
= cbox_io_create_midi_output(io
, CBOX_ARG_S(cmd
, 0), error
);
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"))
371 const char *uuidstr
= CBOX_ARG_S(cmd
, 0);
372 struct cbox_uuid uuid
;
373 if (!cbox_uuid_fromstring(&uuid
, uuidstr
, error
))
375 struct cbox_midi_input
*midiin
= cbox_io_get_midi_input(io
, NULL
, &uuid
);
378 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Port '%s' not found", uuidstr
);
381 cbox_io_destroy_midi_input(io
, midiin
);
384 else if (io
->impl
->destroymidioutfunc
&& !strcmp(cmd
->command
, "/delete_midi_output") && !strcmp(cmd
->arg_types
, "s"))
387 const char *uuidstr
= CBOX_ARG_S(cmd
, 0);
388 struct cbox_uuid uuid
;
389 if (!cbox_uuid_fromstring(&uuid
, uuidstr
, error
))
391 struct cbox_midi_output
*midiout
= cbox_io_get_midi_output(io
, NULL
, &uuid
);
394 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Port '%s' not found", uuidstr
);
397 cbox_io_destroy_midi_output(io
, midiout
);
403 void cbox_io_close(struct cbox_io
*io
)
405 io
->impl
->destroyfunc(io
->impl
);