Fix crash on device reconnect. Use less ad-hoc method to display warnings on bad...
[calfbox.git] / usbmidi.c
blob85149e95328bdf34478ce90fe0fe9d583d86940d
1 /*
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/>.
19 #include "config.h"
20 #include "config-api.h"
21 #include "errors.h"
22 #include "hwcfg.h"
23 #include "io.h"
24 #include "meter.h"
25 #include "midi.h"
26 #include "recsrc.h"
27 #include "usbio_impl.h"
29 #include <unistd.h>
31 static void midi_transfer_cb(struct libusb_transfer *transfer)
33 struct usbio_transfer *xf = transfer->user_data;
34 struct cbox_usb_midi_input *umi = xf->user_data;
35 xf->pending = FALSE;
37 if (transfer->status == LIBUSB_TRANSFER_CANCELLED)
39 xf->cancel_confirm = 1;
40 return;
42 if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT || transfer->status == LIBUSB_TRANSFER_ERROR || transfer->status == LIBUSB_TRANSFER_STALL)
44 if (transfer->status != LIBUSB_TRANSFER_TIMED_OUT)
45 g_warning("USB error on device %03d:%03d: transfer status %d", umi->busdevadr >> 8, umi->busdevadr & 255, transfer->status);
46 if (umi->uii->no_resubmit)
47 return;
48 int res = usbio_transfer_submit(xf);
49 if (res != 0)
50 g_warning("Error submitting URB to MIDI endpoint: error code %d", res);
51 return;
53 if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE)
55 g_debug("No device %03d:%03d, unlinking", umi->busdevadr >> 8, umi->busdevadr & 255);
56 umi->uii->rt_midi_input_ports = g_list_remove(umi->uii->rt_midi_input_ports, umi);
57 return;
60 const struct cbox_usb_device_info *udi = umi->devinfo;
61 if (udi->vid == 0x09e8 && udi->pid == 0x0062) // MPD16
63 for (int i = 0; i < transfer->actual_length;)
65 uint8_t *data = &transfer->buffer[i];
66 uint8_t len = data[0] & 15;
67 if (!len || i + len >= transfer->actual_length)
68 break;
69 cbox_midi_buffer_write_inline(&umi->midi_buffer, 0, data[1], len > 1 ? data[2] : 0, len > 2 ? data[3] : 0);
70 i += len + 1;
73 else
74 if (udi->vid == 0x1235 && udi->pid == 0x000a) // Nocturn
76 uint8_t control = 0;
77 for (int i = 0; i < transfer->actual_length;)
79 uint8_t *data = &transfer->buffer[i];
80 if (*data >= 128)
82 control = *data;
83 i++;
84 continue;
86 if (control != 176 || i + 2 > transfer->actual_length)
88 g_warning("Unrecognized combination of control, data and length: %02x %02x %02x", control, data[0], transfer->actual_length - i);
89 break;
91 cbox_midi_buffer_write_inline(&umi->midi_buffer, 0, control, data[0], data[1]);
92 i += 2;
95 else
97 for (int i = 0; i + 3 < transfer->actual_length; i += 4)
99 uint8_t *data = &transfer->buffer[i];
100 uint8_t etype = data[0] & 15;
101 if (etype >= 8)
103 // normalise: note on with vel 0 -> note off
104 if ((data[1] & 0xF0) == 0x90 && data[3] == 0)
105 cbox_midi_buffer_write_inline(&umi->midi_buffer, 0, data[1] - 0x10, data[2], data[3]);
106 else
107 cbox_midi_buffer_write_event(&umi->midi_buffer, 0, data + 1, midi_cmd_size(data[1]));
109 else
110 if (etype == 2 || etype == 3)
112 cbox_midi_buffer_write_event(&umi->midi_buffer, 0, data + 1, etype);
114 else
115 if (etype == 4)
117 if (umi->current_sysex_length + 3 <= MAX_SYSEX_SIZE)
118 memcpy(&umi->sysex_data[umi->current_sysex_length], data + 1, 3);
119 umi->current_sysex_length += 3;
121 else
122 if (etype >= 5 && etype <= 7)
124 int len = etype - 4;
125 if (umi->current_sysex_length + len <= MAX_SYSEX_SIZE)
126 memcpy(&umi->sysex_data[umi->current_sysex_length], data + 1, len);
127 umi->current_sysex_length += len;
128 if (umi->current_sysex_length <= MAX_SYSEX_SIZE)
129 cbox_midi_buffer_write_event(&umi->midi_buffer, 0, umi->sysex_data, umi->current_sysex_length);
130 else
131 g_warning("Dropping oversized SysEx: length %d", umi->current_sysex_length);
132 umi->current_sysex_length = 0;
135 else
136 g_warning("Unrecognized USB MIDI initiating byte %02x\n", data[0]);
139 if (umi->uii->no_resubmit)
140 return;
141 usbio_transfer_submit(xf);
144 void usbio_start_midi_capture(struct cbox_usb_io_impl *uii)
146 uii->rt_midi_input_ports = g_list_copy(uii->midi_input_ports);
148 for(GList *p = uii->rt_midi_input_ports; p; p = p->next)
150 struct cbox_usb_midi_input *umi = p->data;
151 cbox_midi_buffer_clear(&umi->midi_buffer);
152 cbox_midi_merger_connect(&uii->midi_input_merger, &umi->midi_buffer, NULL);
153 umi->current_sysex_length = 0;
154 umi->transfer = usbio_transfer_new(uii->usbctx, "MIDI In", 0, 0, umi);
155 if (umi->interrupt)
156 libusb_fill_interrupt_transfer(umi->transfer->transfer, umi->handle, umi->endpoint, umi->midi_recv_data, umi->max_packet_size, midi_transfer_cb, umi->transfer, 0);
157 else
158 libusb_fill_bulk_transfer(umi->transfer->transfer, umi->handle, umi->endpoint, umi->midi_recv_data, umi->max_packet_size, midi_transfer_cb, umi->transfer, 0);
160 for(GList *p = uii->rt_midi_input_ports; p; p = p->next)
162 struct cbox_usb_midi_input *umi = p->data;
163 int res = usbio_transfer_submit(umi->transfer);
164 if (res != 0)
166 usbio_transfer_destroy(umi->transfer);
167 umi->transfer = NULL;
172 void usbio_stop_midi_capture(struct cbox_usb_io_impl *uii)
174 for(GList *p = uii->rt_midi_input_ports; p; p = p->next)
176 struct cbox_usb_midi_input *umi = p->data;
178 if (!umi->transfer)
179 continue;
181 usbio_transfer_shutdown(umi->transfer);
182 usbio_transfer_destroy(umi->transfer);
183 umi->transfer = NULL;
184 cbox_midi_buffer_clear(&umi->midi_buffer);
186 for(GList *p = uii->rt_midi_input_ports; p; p = p->next)
188 struct cbox_usb_midi_input *umi = p->data;
189 cbox_midi_merger_disconnect(&uii->midi_input_merger, &umi->midi_buffer, NULL);
191 g_list_free(uii->rt_midi_input_ports);
194 void cbox_usb_midi_info_init(struct cbox_usb_midi_info *umi, struct cbox_usb_device_info *udi)
196 umi->udi = udi;
197 umi->intf = -1;
198 umi->alt_setting = -1;
199 umi->epdesc.found = FALSE;
202 struct cbox_usb_midi_input *usbio_open_midi_interface(struct cbox_usb_io_impl *uii, const struct cbox_usb_midi_info *uminf, struct libusb_device_handle *handle)
204 struct cbox_usb_device_info *devinfo = uminf->udi;
205 int bus = devinfo->bus;
206 int devadr = devinfo->devadr;
207 GError *error = NULL;
208 // printf("Has MIDI port\n");
209 // printf("Output endpoint address = %02x\n", ep->bEndpointAddress);
210 if (!configure_usb_interface(handle, bus, devadr, uminf->intf, uminf->alt_setting, "MIDI (class driver)", &error))
212 g_warning("%s", error->message);
213 g_error_free(error);
214 return NULL;
217 struct cbox_usb_midi_input *umi = malloc(sizeof(struct cbox_usb_midi_input));
218 umi->uii = uii;
219 umi->devinfo = devinfo;
220 umi->handle = handle;
221 umi->busdevadr = devinfo->busdevadr;
222 umi->endpoint = uminf->epdesc.bEndpointAddress;
223 umi->interrupt = uminf->epdesc.interrupt;
224 cbox_midi_buffer_init(&umi->midi_buffer);
225 uii->midi_input_ports = g_list_prepend(uii->midi_input_ports, umi);
226 int len = uminf->epdesc.wMaxPacketSize;
227 if (len > 256)
228 len = 256;
229 umi->max_packet_size = len;
231 // Drain the output buffer of the device - otherwise playing a few notes and running the program will cause
232 // those notes to play.
233 unsigned char flushbuf[256];
234 int transferred = 0;
235 if (umi->interrupt)
237 while(0 == libusb_interrupt_transfer(handle, umi->endpoint, flushbuf, umi->max_packet_size, &transferred, 10) && transferred > 0)
238 usleep(1000);
240 else
242 while(0 == libusb_bulk_transfer(handle, umi->endpoint, flushbuf, umi->max_packet_size, &transferred, 10) && transferred > 0)
243 usleep(1000);
245 devinfo->status = CBOX_DEVICE_STATUS_OPENED;
247 return umi;