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/>.
21 #include "config-api.h"
28 #include "usbio_impl.h"
32 static void decode_events_mpd16(struct cbox_usb_midi_interface
*umi
, struct libusb_transfer
*transfer
)
34 for (int i
= 0; i
< transfer
->actual_length
;)
36 uint8_t *data
= &transfer
->buffer
[i
];
37 uint8_t len
= data
[0] & 15;
38 if (!len
|| i
+ len
>= transfer
->actual_length
)
40 cbox_midi_buffer_write_inline(&umi
->input_port
->hdr
.buffer
, 0, data
[1], len
> 1 ? data
[2] : 0, len
> 2 ? data
[3] : 0);
45 static void decode_events_nocturn(struct cbox_usb_midi_interface
*umi
, struct libusb_transfer
*transfer
)
48 for (int i
= 0; i
< transfer
->actual_length
;)
50 uint8_t *data
= &transfer
->buffer
[i
];
57 if (control
!= 176 || i
+ 2 > transfer
->actual_length
)
59 g_warning("Unrecognized combination of control, data and length: %02x %02x %02x", control
, data
[0], transfer
->actual_length
- i
);
62 cbox_midi_buffer_write_inline(&umi
->input_port
->hdr
.buffer
, 0, control
, data
[0], data
[1]);
67 static void decode_events_class(struct cbox_usb_midi_interface
*umi
, struct libusb_transfer
*transfer
)
69 for (int i
= 0; i
+ 3 < transfer
->actual_length
; i
+= 4)
71 uint8_t *data
= &transfer
->buffer
[i
];
72 uint8_t etype
= data
[0] & 15;
75 // normalise: note on with vel 0 -> note off
76 if ((data
[1] & 0xF0) == 0x90 && data
[3] == 0)
77 cbox_midi_buffer_write_inline(&umi
->input_port
->hdr
.buffer
, 0, data
[1] - 0x10, data
[2], data
[3]);
79 cbox_midi_buffer_write_event(&umi
->input_port
->hdr
.buffer
, 0, data
+ 1, midi_cmd_size(data
[1]));
82 if (etype
== 2 || etype
== 3)
84 cbox_midi_buffer_write_event(&umi
->input_port
->hdr
.buffer
, 0, data
+ 1, etype
);
89 if (umi
->current_sysex_length
+ 3 <= MAX_SYSEX_SIZE
)
90 memcpy(&umi
->sysex_data
[umi
->current_sysex_length
], data
+ 1, 3);
91 umi
->current_sysex_length
+= 3;
94 if (etype
>= 5 && etype
<= 7)
97 if (umi
->current_sysex_length
+ len
<= MAX_SYSEX_SIZE
)
98 memcpy(&umi
->sysex_data
[umi
->current_sysex_length
], data
+ 1, len
);
99 umi
->current_sysex_length
+= len
;
100 if (umi
->current_sysex_length
<= MAX_SYSEX_SIZE
)
101 cbox_midi_buffer_write_event(&umi
->input_port
->hdr
.buffer
, 0, umi
->sysex_data
, umi
->current_sysex_length
);
103 g_warning("Dropping oversized SysEx: length %d", umi
->current_sysex_length
);
104 umi
->current_sysex_length
= 0;
108 g_warning("Unrecognized USB MIDI initiating byte %02x\n", data
[0]);
112 static void midi_transfer_cb(struct libusb_transfer
*transfer
)
114 struct usbio_transfer
*xf
= transfer
->user_data
;
115 struct cbox_usb_midi_interface
*umi
= xf
->user_data
;
118 if (transfer
->status
== LIBUSB_TRANSFER_CANCELLED
)
120 xf
->cancel_confirm
= 1;
123 if (transfer
->status
== LIBUSB_TRANSFER_TIMED_OUT
|| transfer
->status
== LIBUSB_TRANSFER_ERROR
|| transfer
->status
== LIBUSB_TRANSFER_STALL
)
125 if (transfer
->status
!= LIBUSB_TRANSFER_TIMED_OUT
)
126 g_warning("USB error on device %03d:%03d: transfer status %d", umi
->busdevadr
>> 8, umi
->busdevadr
& 255, transfer
->status
);
127 if (umi
->uii
->no_resubmit
)
129 int res
= usbio_transfer_submit(xf
);
131 g_warning("Error submitting URB to MIDI endpoint: error code %d", res
);
134 if (transfer
->status
== LIBUSB_TRANSFER_NO_DEVICE
)
136 g_debug("No device %03d:%03d, unlinking", umi
->busdevadr
>> 8, umi
->busdevadr
& 255);
137 umi
->uii
->rt_midi_ports
= g_list_remove(umi
->uii
->rt_midi_ports
, umi
);
141 if (umi
->protocol
== USBMIDI_PROTOCOL_MPD16
) // MPD16
142 decode_events_mpd16(umi
, transfer
);
144 if (umi
->protocol
== USBMIDI_PROTOCOL_NOCTURN
) // Nocturn
145 decode_events_nocturn(umi
, transfer
);
147 decode_events_class(umi
, transfer
);
149 if (umi
->uii
->no_resubmit
)
151 usbio_transfer_submit(xf
);
154 static gboolean
push_data_to_umo(struct cbox_usb_midi_output
*umo
, const uint8_t *pdata
, uint32_t size
, uint8_t first_byte
)
156 if (umo
->endpoint_buffer_pos
+ 4 <= USB_MIDI_OUTPUT_QUEUE
)
158 umo
->endpoint_buffer
[umo
->endpoint_buffer_pos
] = first_byte
;
159 memcpy(&umo
->endpoint_buffer
[umo
->endpoint_buffer_pos
+ 1], pdata
, size
);
160 umo
->endpoint_buffer_pos
+= 4;
164 g_warning("Class MIDI buffer overflow.");
170 static void encode_events_class(struct cbox_usb_midi_output
*umo
)
172 for (int i
= 0; i
< umo
->hdr
.buffer
.count
; i
++)
174 const struct cbox_midi_event
*event
= cbox_midi_buffer_get_event(&umo
->hdr
.buffer
, i
);
175 const uint8_t *pdata
= cbox_midi_event_get_data(event
);
176 if (event
->size
<= 3)
178 if (!push_data_to_umo(umo
, pdata
, event
->size
, pdata
[0] >> 4))
184 while(i
+ 3 < event
->size
)
186 push_data_to_umo(umo
, pdata
+ i
, 3, 4);
189 push_data_to_umo(umo
, pdata
+ i
, 3, 4 + event
->size
- i
);
194 static void encode_events_nocturn(struct cbox_usb_midi_output
*umo
)
196 for (int i
= 0; i
< umo
->hdr
.buffer
.count
; i
++)
198 const struct cbox_midi_event
*event
= cbox_midi_buffer_get_event(&umo
->hdr
.buffer
, i
);
199 const uint8_t *pdata
= cbox_midi_event_get_data(event
);
200 // Only encode control change events on channel 1 - it's the only
201 // recognized type of events
202 if (event
->size
== 3 && pdata
[0] == 0xB0)
204 if (umo
->endpoint_buffer_pos
+ 2 <= 8)
206 umo
->endpoint_buffer
[umo
->endpoint_buffer_pos
] = pdata
[1];
207 umo
->endpoint_buffer
[umo
->endpoint_buffer_pos
+ 1] = pdata
[2];
208 umo
->endpoint_buffer_pos
+= 2;
211 g_warning("Nocturn MIDI buffer overflow.");
216 void usbio_fill_midi_output_buffer(struct cbox_usb_midi_output
*umo
)
218 cbox_midi_merger_render(&umo
->hdr
.merger
);
219 if (!umo
->hdr
.buffer
.count
)
222 if (umo
->ifptr
->protocol
== USBMIDI_PROTOCOL_CLASS
)
223 encode_events_class(umo
);
225 if (umo
->ifptr
->protocol
== USBMIDI_PROTOCOL_NOCTURN
)
226 encode_events_nocturn(umo
);
229 void usbio_send_midi_to_output(struct cbox_usb_midi_output
*umo
)
231 if (!umo
->endpoint_buffer_pos
)
236 if (umo
->ifptr
->epdesc_out
.interrupt
)
237 res
= libusb_interrupt_transfer(umo
->ifptr
->handle
, umo
->ifptr
->epdesc_out
.bEndpointAddress
, umo
->endpoint_buffer
, umo
->endpoint_buffer_pos
, &transferred
, 10);
239 res
= libusb_bulk_transfer(umo
->ifptr
->handle
, umo
->ifptr
->epdesc_out
.bEndpointAddress
, umo
->endpoint_buffer
, umo
->endpoint_buffer_pos
, &transferred
, 10);
240 if (res
== 0 && transferred
== umo
->endpoint_buffer_pos
)
241 umo
->endpoint_buffer_pos
= 0;
243 g_warning("Failed to send MIDI events, transferred = %d out of %d, result = %d", (int)transferred
, (int)umo
->endpoint_buffer_pos
, res
);
246 void usbio_update_port_routing(struct cbox_io_impl
*ioi
)
248 struct cbox_usb_io_impl
*uii
= (struct cbox_usb_io_impl
*)ioi
;
249 for(GList
*p
= uii
->rt_midi_ports
; p
; p
= p
->next
)
251 struct cbox_usb_midi_interface
*umi
= p
->data
;
254 if (!umi
->input_port
->hdr
.output_set
)
255 cbox_midi_merger_connect(&uii
->midi_input_merger
, &umi
->input_port
->hdr
.buffer
, app
.rt
);
257 cbox_midi_merger_disconnect(&uii
->midi_input_merger
, &umi
->input_port
->hdr
.buffer
, app
.rt
);
262 void usbio_start_midi_capture(struct cbox_usb_io_impl
*uii
)
264 uii
->rt_midi_ports
= g_list_copy(uii
->midi_ports
);
266 for(GList
*p
= uii
->rt_midi_ports
; p
; p
= p
->next
)
268 struct cbox_usb_midi_interface
*umi
= p
->data
;
269 cbox_midi_buffer_clear(&umi
->input_port
->hdr
.buffer
);
270 if (umi
->epdesc_in
.found
)
272 umi
->current_sysex_length
= 0;
273 umi
->transfer_in
= usbio_transfer_new(uii
->usbctx
, "MIDI In", 0, 0, umi
);
274 int pktsize
= umi
->epdesc_in
.wMaxPacketSize
;
275 if (pktsize
> MAX_MIDI_PACKET_SIZE
)
276 pktsize
= MAX_MIDI_PACKET_SIZE
;
277 if (umi
->epdesc_in
.interrupt
)
278 libusb_fill_interrupt_transfer(umi
->transfer_in
->transfer
, umi
->handle
, umi
->epdesc_in
.bEndpointAddress
, umi
->midi_recv_data
, pktsize
, midi_transfer_cb
, umi
->transfer_in
, 0);
280 libusb_fill_bulk_transfer(umi
->transfer_in
->transfer
, umi
->handle
, umi
->epdesc_in
.bEndpointAddress
, umi
->midi_recv_data
, pktsize
, midi_transfer_cb
, umi
->transfer_in
, 0);
283 umi
->transfer_in
= NULL
;
284 if (umi
->epdesc_out
.found
)
285 umi
->transfer_out
= usbio_transfer_new(uii
->usbctx
, "MIDI Out", 0, 0, umi
);
287 umi
->transfer_out
= NULL
;
289 for(GList
*p
= uii
->rt_midi_ports
; p
; p
= p
->next
)
291 struct cbox_usb_midi_interface
*umi
= p
->data
;
292 int res
= usbio_transfer_submit(umi
->transfer_in
);
295 usbio_transfer_destroy(umi
->transfer_in
);
296 umi
->transfer_in
= NULL
;
301 void usbio_stop_midi_capture(struct cbox_usb_io_impl
*uii
)
303 for(GList
*p
= uii
->rt_midi_ports
; p
; p
= p
->next
)
305 struct cbox_usb_midi_interface
*umi
= p
->data
;
307 if (umi
->transfer_in
)
309 usbio_transfer_shutdown(umi
->transfer_in
);
310 usbio_transfer_destroy(umi
->transfer_in
);
311 umi
->transfer_in
= NULL
;
312 cbox_midi_buffer_clear(&umi
->input_port
->hdr
.buffer
);
314 if (umi
->transfer_out
)
316 usbio_transfer_shutdown(umi
->transfer_out
);
317 usbio_transfer_destroy(umi
->transfer_out
);
318 umi
->transfer_out
= NULL
;
321 for(GList
*p
= uii
->rt_midi_ports
; p
; p
= p
->next
)
323 struct cbox_usb_midi_interface
*umi
= p
->data
;
324 if (umi
->epdesc_in
.found
)
325 cbox_midi_merger_disconnect(&uii
->midi_input_merger
, &umi
->input_port
->hdr
.buffer
, NULL
);
327 g_list_free(uii
->rt_midi_ports
);
330 void cbox_usb_midi_info_init(struct cbox_usb_midi_info
*umi
, struct cbox_usb_device_info
*udi
)
334 umi
->alt_setting
= -1;
335 umi
->epdesc_in
.found
= FALSE
;
336 umi
->epdesc_out
.found
= FALSE
;
339 struct cbox_usb_midi_interface
*usbio_open_midi_interface(struct cbox_usb_io_impl
*uii
, const struct cbox_usb_midi_info
*uminf
, struct libusb_device_handle
*handle
)
341 struct cbox_usb_device_info
*devinfo
= uminf
->udi
;
342 int bus
= devinfo
->bus
;
343 int devadr
= devinfo
->devadr
;
344 GError
*error
= NULL
;
345 // printf("Has MIDI port\n");
346 // printf("Output endpoint address = %02x\n", ep->bEndpointAddress);
347 if (!configure_usb_interface(handle
, bus
, devadr
, uminf
->intf
, uminf
->alt_setting
, "MIDI (class driver)", &error
))
349 g_warning("%s", error
->message
);
354 struct cbox_usb_midi_interface
*umi
= calloc(sizeof(struct cbox_usb_midi_interface
), 1);
356 umi
->devinfo
= devinfo
;
357 umi
->handle
= handle
;
358 umi
->busdevadr
= devinfo
->busdevadr
;
359 uii
->midi_ports
= g_list_prepend(uii
->midi_ports
, umi
);
360 umi
->protocol
= uminf
->protocol
;
361 memcpy(&umi
->epdesc_in
, &uminf
->epdesc_in
, sizeof(umi
->epdesc_in
));
362 memcpy(&umi
->epdesc_out
, &uminf
->epdesc_out
, sizeof(umi
->epdesc_out
));
364 // Drain the output buffer of the device - otherwise playing a few notes and running the program will cause
365 // those notes to play.
366 unsigned char flushbuf
[256];
368 int len
= umi
->epdesc_in
.wMaxPacketSize
;
369 if (len
> MAX_MIDI_PACKET_SIZE
)
370 len
= MAX_MIDI_PACKET_SIZE
;
371 if (umi
->epdesc_in
.interrupt
)
373 while(0 == libusb_interrupt_transfer(handle
, umi
->epdesc_in
.bEndpointAddress
, flushbuf
, len
, &transferred
, 10) && transferred
> 0)
378 while(0 == libusb_bulk_transfer(handle
, umi
->epdesc_in
.bEndpointAddress
, flushbuf
, len
, &transferred
, 10) && transferred
> 0)
381 devinfo
->status
= CBOX_DEVICE_STATUS_OPENED
;
383 // Initialise device - only used for Novation Nocturn, and it performs a
384 // device reset. Perhaps not the best implementation of hot swap - it
385 // will reset the device even when some other device was connected.
386 if (umi
->protocol
== USBMIDI_PROTOCOL_NOCTURN
)
388 static uint8_t data1
[] = { 0xB0, 0, 0 };
389 libusb_interrupt_transfer(handle
, umi
->epdesc_out
.bEndpointAddress
, data1
, sizeof(data1
), &transferred
, 10);