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
)
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
)
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
);
83 struct cbox_midi_output
*cbox_io_get_midi_output(struct cbox_io
*io
, const char *name
, const struct cbox_uuid
*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
))
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
))
106 struct cbox_midi_input
*cbox_io_get_midi_input(struct cbox_io
*io
, const char *name
, const struct cbox_uuid
*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
))
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
))
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
);
135 midiout
= io
->impl
->createmidioutfunc(io
->impl
, name
, error
);
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
);
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
);
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
);
175 midiin
= io
->impl
->createmidiinfunc(io
->impl
, name
, error
);
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
);
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
);
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
);
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
);
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
);
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
, ""))
255 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
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
))
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
))
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"))
284 struct cbox_midi_input
*midiin
;
285 midiin
= cbox_io_create_midi_input(io
, CBOX_ARG_S(cmd
, 0), error
);
288 return cbox_uuid_report(&midiin
->uuid
, fb
, error
);
290 else if (!strcmp(cmd
->command
, "/route_midi_input") && !strcmp(cmd
->arg_types
, "ss"))
293 const char *uuidstr
= CBOX_ARG_S(cmd
, 0);
294 struct cbox_uuid uuid
;
295 if (!cbox_uuid_fromstring(&uuid
, uuidstr
, error
))
297 struct cbox_midi_input
*midiin
= cbox_io_get_midi_input(io
, NULL
, &uuid
);
300 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Port '%s' not found", uuidstr
);
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
;
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
);
316 else if (!strcmp(cmd
->command
, "/set_appsink_for_midi_input") && !strcmp(cmd
->arg_types
, "si"))
319 const char *uuidstr
= CBOX_ARG_S(cmd
, 0);
320 struct cbox_uuid uuid
;
321 if (!cbox_uuid_fromstring(&uuid
, uuidstr
, error
))
323 struct cbox_midi_input
*midiin
= cbox_io_get_midi_input(io
, NULL
, &uuid
);
326 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Port '%s' not found", uuidstr
);
329 midiin
->enable_appsink
= CBOX_ARG_I(cmd
, 1);
332 else if (!strcmp(cmd
->command
, "/get_new_events") && !strcmp(cmd
->arg_types
, "s"))
335 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
337 const char *uuidstr
= CBOX_ARG_S(cmd
, 0);
338 struct cbox_uuid uuid
;
339 if (!cbox_uuid_fromstring(&uuid
, uuidstr
, error
))
341 struct cbox_midi_input
*midiin
= cbox_io_get_midi_input(io
, NULL
, &uuid
);
344 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Port '%s' not found", uuidstr
);
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
);
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"))
358 struct cbox_midi_output
*midiout
;
359 midiout
= cbox_io_create_midi_output(io
, CBOX_ARG_S(cmd
, 0), error
);
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"))
367 const char *uuidstr
= CBOX_ARG_S(cmd
, 0);
368 struct cbox_uuid uuid
;
369 if (!cbox_uuid_fromstring(&uuid
, uuidstr
, error
))
371 struct cbox_midi_input
*midiin
= cbox_io_get_midi_input(io
, NULL
, &uuid
);
374 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Port '%s' not found", uuidstr
);
377 cbox_io_destroy_midi_input(io
, midiin
);
380 else if (io
->impl
->destroymidioutfunc
&& !strcmp(cmd
->command
, "/delete_midi_output") && !strcmp(cmd
->arg_types
, "s"))
383 const char *uuidstr
= CBOX_ARG_S(cmd
, 0);
384 struct cbox_uuid uuid
;
385 if (!cbox_uuid_fromstring(&uuid
, uuidstr
, error
))
387 struct cbox_midi_output
*midiout
= cbox_io_get_midi_output(io
, NULL
, &uuid
);
390 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Port '%s' not found", uuidstr
);
393 cbox_io_destroy_midi_output(io
, midiout
);
399 void cbox_io_close(struct cbox_io
*io
)
401 io
->impl
->destroyfunc(io
->impl
);