/* Calf Box, an open source musical instrument. Copyright (C) 2010-2013 Krzysztof Foltman This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "config.h" #if USE_LIBUSB #include #include #include "usbio_impl.h" #include #include #include #define NUM_MULTIMIX_SYNC_PACKETS 10 #define MULTIMIX_EP_PLAYBACK 0x02 //#define MULTIMIX_EP_CAPTURE 0x86 #define MULTIMIX_EP_SYNC 0x81 #define NUM_CPUTIME_ENTRIES 100 static int register_cpu_time = 1; static float real_time_registry[NUM_CPUTIME_ENTRIES]; static float cpu_time_registry[NUM_CPUTIME_ENTRIES]; static int cpu_time_write_ptr = 0; static void usbio_play_buffer_adaptive(struct cbox_usb_io_impl *uii); /////////////////////////////////////////////////////////////////////////////// static gboolean set_endpoint_sample_rate(struct libusb_device_handle *h, int sample_rate, int ep) { uint8_t freq_data[3]; freq_data[0] = sample_rate & 0xFF; freq_data[1] = (sample_rate & 0xFF00) >> 8; freq_data[2] = (sample_rate & 0xFF0000) >> 16; if (libusb_control_transfer(h, 0x22, 0x01, 256, ep, freq_data, 3, USB_DEVICE_SETUP_TIMEOUT) != 3) return FALSE; return TRUE; } /////////////////////////////////////////////////////////////////////////////// gboolean usbio_open_audio_interface(struct cbox_usb_io_impl *uii, struct cbox_usb_audio_info *uainf, struct libusb_device_handle *handle, GError **error) { if (uii->output_resolution != 2 && uii->output_resolution != 3) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Only 16-bit or 24-bit output resolution is supported."); return FALSE; } if (!configure_usb_interface(handle, uainf->udi->bus, uainf->udi->devadr, uainf->intf, uainf->alt_setting, "audio (class driver)", error)) return FALSE; if (!set_endpoint_sample_rate(handle, uii->sample_rate, uainf->epdesc.bEndpointAddress)) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot set sample rate on class-compliant USB audio device."); return FALSE; } uii->is_hispeed = FALSE; uii->sync_protocol = uainf->sync_protocol; uii->play_function = uainf->sync_protocol == USBAUDIOSYNC_PROTOCOL_CLASS ? usbio_play_buffer_asynchronous : usbio_play_buffer_adaptive; uii->handle_audiodev = handle; uii->audio_output_endpoint = uainf->epdesc.bEndpointAddress; uii->audio_output_pktsize = uainf->epdesc.wMaxPacketSize; // 48 * 2 * uii->output_resolution; uii->audio_sync_endpoint = uainf->sync_protocol == USBAUDIOSYNC_PROTOCOL_CLASS ? uainf->sync_epdesc.bEndpointAddress : 0; return TRUE; } /////////////////////////////////////////////////////////////////////////////// static gboolean claim_multimix_interfaces(struct cbox_usb_io_impl *uii, struct libusb_device_handle *handle, int bus, int devadr, GError **error) { for (int ifno = 0; ifno < 2; ifno++) { if (!configure_usb_interface(handle, bus, devadr, ifno, 1, "audio (MultiMix driver)", error)) return FALSE; } return TRUE; } gboolean usbio_open_audio_interface_multimix(struct cbox_usb_io_impl *uii, int bus, int devadr, struct libusb_device_handle *handle, GError **error) { if (uii->output_resolution != 3) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Only 24-bit output resolution is supported."); return FALSE; } if (!claim_multimix_interfaces(uii, handle, bus, devadr, error)) return FALSE; if (!set_endpoint_sample_rate(handle, uii->sample_rate, MULTIMIX_EP_PLAYBACK)) { g_set_error(error, CBOX_MODULE_ERROR, CBOX_MODULE_ERROR_FAILED, "Cannot set sample rate on Alesis Multimix."); return FALSE; } uii->is_hispeed = TRUE; uii->play_function = usbio_play_buffer_asynchronous; uii->handle_audiodev = handle; uii->sync_protocol = USBAUDIOSYNC_PROTOCOL_MULTIMIX8; uii->audio_output_endpoint = MULTIMIX_EP_PLAYBACK; uii->audio_output_pktsize = 156; uii->audio_sync_endpoint = MULTIMIX_EP_SYNC; return TRUE; } /////////////////////////////////////////////////////////////////////////////// static void calc_output_buffer(struct cbox_usb_io_impl *uii) { struct timespec tvs1, tve1, tvs2, tve2; if (register_cpu_time) { clock_gettime(CLOCK_MONOTONIC_RAW, &tvs1); clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tvs2); } struct cbox_io *io = uii->ioi.pio; uint32_t buffer_size = io->io_env.buffer_size; for (int b = 0; b < uii->output_channels; b++) memset(io->output_buffers[b], 0, buffer_size * sizeof(float)); for (GList *p = uii->rt_midi_ports; p; p = p->next) { struct cbox_usb_midi_interface *umi = p->data; if (umi->input_port->hdr.enable_appsink && umi->input_port && umi->input_port->hdr.buffer.count) cbox_midi_appsink_supply(&umi->input_port->hdr.appsink, &umi->input_port->hdr.buffer, io->free_running_frame_counter); } io->cb->process(io->cb->user_data, io, buffer_size); for (GList *p = uii->rt_midi_ports; p; p = p->next) { struct cbox_usb_midi_interface *umi = p->data; if (umi->input_port) cbox_midi_buffer_clear(&umi->input_port->hdr.buffer); } for (GSList *p = io->midi_outputs; p; p = p->next) { struct cbox_usb_midi_output *umo = p->data; usbio_fill_midi_output_buffer(umo); } if (register_cpu_time) { clock_gettime(CLOCK_MONOTONIC_RAW, &tve1); clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tve2); float time1 = tve1.tv_sec - tvs1.tv_sec + (tve1.tv_nsec - tvs1.tv_nsec) / 1000000000.0; float time2 = tve2.tv_sec - tvs2.tv_sec + (tve2.tv_nsec - tvs2.tv_nsec) / 1000000000.0; real_time_registry[cpu_time_write_ptr] = time1; cpu_time_registry[cpu_time_write_ptr] = time2; cpu_time_write_ptr = (cpu_time_write_ptr + 1) % NUM_CPUTIME_ENTRIES; if (time1 > 0.0008 || time2 > 0.0008) g_warning("CPU time = %f ms, real time = %f ms", time2 * 1000, time1 * 1000); } io->free_running_frame_counter += buffer_size; } static void fill_playback_buffer(struct cbox_usb_io_impl *uii, struct libusb_transfer *transfer) { struct cbox_io *io = uii->ioi.pio; uint32_t buffer_size = io->io_env.buffer_size; uint8_t *data8 = (uint8_t*)transfer->buffer; int16_t *data = (int16_t*)transfer->buffer; int resolution = uii->output_resolution; unsigned int oc = uii->output_channels; uint32_t rptr = uii->read_ptr; uint32_t nframes = transfer->length / (resolution * oc); uint32_t i, b, j; for (i = 0; i < nframes; ) { if (rptr == buffer_size) { calc_output_buffer(uii); rptr = 0; } unsigned int left1 = nframes - i; unsigned int left2 = buffer_size - rptr; if (left1 > left2) left1 = left2; for (b = 0; b < oc; b++) { float *obuf = io->output_buffers[b] + rptr; if (resolution == 2) { int16_t *tbuf = data + oc * i + b; for (j = 0; j < left1; j++) { float v = 32767 * obuf[j]; if (v < -32768) v = -32768; if (v > +32767) v = +32767; *tbuf = (int16_t)v; tbuf += oc; } } if (resolution == 3) { uint8_t *tbuf = data8 + (oc * i + b) * 3; for (j = 0; j < left1; j++) { float v = 0x7FFFFF * obuf[j]; if (v < -0x800000) v = -0x800000; if (v > +0x7FFFFF) v = +0x7FFFFF; int vi = (int)v; tbuf[0] = vi & 255; tbuf[1] = (vi >> 8) & 255; tbuf[2] = (vi >> 16) & 255; tbuf += oc * 3; } } } i += left1; rptr += left1; } uii->read_ptr = rptr; } static void play_callback_adaptive(struct libusb_transfer *transfer) { struct usbio_transfer *xf = transfer->user_data; struct cbox_usb_io_impl *uii = xf->user_data; xf->pending = FALSE; if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { xf->cancel_confirm = 1; return; } if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) { uii->device_removed++; return; } int resolution = uii->output_resolution; int oc = uii->output_channels; gboolean init_finished = uii->playback_counter == uii->playback_buffers; if (uii->playback_counter < uii->playback_buffers) { // send another URB for the next transfer before re-submitting // this one usbio_play_buffer_adaptive(uii); } // printf("Play Callback! %d %p status %d\n", (int)transfer->length, transfer->buffer, (int)transfer->status); int tlen = 0, olen = 0; for (int i = 0; i < transfer->num_iso_packets; i++) { tlen += transfer->iso_packet_desc[i].actual_length; olen += transfer->iso_packet_desc[i].length; if (transfer->iso_packet_desc[i].status) printf("ISO error: index = %d i = %d status = %d\n", (int)xf->index, i, transfer->iso_packet_desc[i].status); } uii->samples_played += olen / (oc * resolution); uint32_t nsamps = uii->sample_rate / 1000; // If time elapsed is greater than int lag = uii->desync / (1000 * transfer->num_iso_packets); if (lag > 0 && nsamps < uii->audio_output_pktsize) { nsamps++; lag--; } transfer->length = nsamps * transfer->num_iso_packets * oc * resolution; libusb_set_iso_packet_lengths(transfer, nsamps * oc * resolution); if (init_finished) { fill_playback_buffer(uii, transfer); } // desync value is expressed in milli-frames, i.e. desync of 1000 means 1 frame of lag // It takes 1ms for each iso packet to be transmitted. Each transfer consists of // num_iso_packets packets. So, this transfer took uii->sample_rate milli-frames. uii->desync += transfer->num_iso_packets * uii->sample_rate; // ... but during that time, tlen/4 samples == tlen/4*1000 millisamples have been // transmitted. uii->desync -= transfer->num_iso_packets * nsamps * 1000; if (uii->no_resubmit) return; int err = usbio_transfer_submit(xf); if (err) { if (err == LIBUSB_ERROR_NO_DEVICE) { uii->device_removed++; transfer->status = LIBUSB_TRANSFER_NO_DEVICE; } g_warning("Cannot resubmit isochronous transfer, error = %s", libusb_error_name(err)); } } void usbio_play_buffer_adaptive(struct cbox_usb_io_impl *uii) { struct usbio_transfer *t; int err; int packets = uii->iso_packets; t = usbio_transfer_new(uii->usbctx, "play", uii->playback_counter, packets, uii); int tsize = uii->sample_rate * 2 * uii->output_resolution / 1000; uint8_t *buf = (uint8_t *)calloc(packets, uii->audio_output_pktsize); libusb_fill_iso_transfer(t->transfer, uii->handle_audiodev, uii->audio_output_endpoint, buf, tsize * packets, packets, play_callback_adaptive, t, 20000); libusb_set_iso_packet_lengths(t->transfer, tsize); uii->playback_transfers[uii->playback_counter++] = t; err = usbio_transfer_submit(t); if (!err) return; g_warning("Cannot resubmit isochronous transfer, error = %s", libusb_error_name(err)); uii->playback_counter--; free(buf); usbio_transfer_destroy(t); uii->playback_transfers[uii->playback_counter] = NULL; } ////////////////////////////////////////////////////////////////////////////////////////// static int calc_packet_lengths(struct cbox_usb_io_impl *uii, struct libusb_transfer *t, int packets) { int packets_per_sec = uii->is_hispeed ? 8000 : 1000; int tsize = 0; int i; // printf("sync_freq = %d\n", sync_freq); for (i = 0; i < packets; i++) { int nsamps = (uii->samples_per_sec - uii->desync) / packets_per_sec; // assert(nsamps > 0); if ((uii->samples_per_sec - uii->desync) % packets_per_sec) nsamps++; //printf("%d sfreq=%d desync=%d nsamps=%d\n", i, uii->sync_freq, uii->desync, nsamps); uii->desync = (uii->desync + nsamps * packets_per_sec) % uii->samples_per_sec; int v = (nsamps) * 2 * uii->output_resolution; t->iso_packet_desc[i].length = v; tsize += v; } return tsize; } void play_callback_asynchronous(struct libusb_transfer *transfer) { struct usbio_transfer *xf = transfer->user_data; struct cbox_usb_io_impl *uii = xf->user_data; xf->pending = FALSE; if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { xf->cancel_confirm = TRUE; return; } if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) { xf->cancel_confirm = TRUE; uii->device_removed++; return; } gboolean init_finished = uii->playback_counter == uii->playback_buffers; if (uii->playback_counter < uii->playback_buffers) { // send another URB for the next transfer before re-submitting // this one usbio_play_buffer_asynchronous(uii); } /* printf("Play Callback! %d status %d\n", (int)transfer->length, (int)transfer->status); for (i = 0; i < transfer->num_iso_packets; i++) { if (transfer->iso_packet_desc[i].actual_length) { printf("%d: %d %d\n", i, transfer->iso_packet_desc[i].actual_length, transfer->iso_packet_desc[i].status); } } */ transfer->length = calc_packet_lengths(uii, transfer, transfer->num_iso_packets); if (init_finished) { fill_playback_buffer(uii, transfer); } if (uii->no_resubmit) return; int err = usbio_transfer_submit(xf); if (err) { if (err == LIBUSB_ERROR_NO_DEVICE) { transfer->status = LIBUSB_TRANSFER_NO_DEVICE; uii->device_removed++; } g_warning("Cannot submit isochronous transfer, error = %s", libusb_error_name(err)); } } static struct usbio_transfer *sync_stuff_asynchronous(struct cbox_usb_io_impl *uii, int index); void usbio_play_buffer_asynchronous(struct cbox_usb_io_impl *uii) { struct usbio_transfer *t; int err; int packets = uii->iso_packets_multimix; t = usbio_transfer_new(uii->usbctx, "play", uii->playback_counter, packets, uii); int tsize = calc_packet_lengths(uii, t->transfer, packets); int bufsize = uii->audio_output_pktsize * packets; uint8_t *buf = (uint8_t *)calloc(1, bufsize); if (!uii->playback_counter) { for(uii->sync_counter = 0; uii->sync_counter < uii->sync_buffers; uii->sync_counter++) uii->sync_transfers[uii->sync_counter] = sync_stuff_asynchronous(uii, uii->sync_counter); } libusb_fill_iso_transfer(t->transfer, uii->handle_audiodev, uii->audio_output_endpoint, buf, tsize, packets, play_callback_asynchronous, t, 20000); uii->playback_transfers[uii->playback_counter++] = t; err = usbio_transfer_submit(t); if (err) { g_warning("Cannot submit playback urb: %s, error = %s (index = %d, tsize = %d)", libusb_error_name(err), strerror(errno), uii->playback_counter, tsize); free(buf); usbio_transfer_destroy(t); uii->playback_transfers[--uii->playback_counter] = NULL; } } ////////////////////////////////////////////////////////////////////////////////////////// /* * The Multimix device controls the data rate of the playback stream using a * device-to-host isochronous endpoint. The incoming packets consist of 3 bytes: * a current value of sample rate (kHz) + 2 historical values. I'm only using * the first byte, I haven't yet encountered a situation where using the * second and third byte would be necessary. This seems to work for all * sample rates supported by the Windows driver - 44100, 48000, 88200 and * 96000. It is possible to set sample rate to 64000, but it doesn't work * correctly, and isn't supported by the Windows driver either - it may * require special handling or may be a half-implemented feature in hardware. * The isochronous transfer using 10 packets seems to give acceptable resolution * and latency to avoid over/underruns with supported sample rates. * * The non-integer multiples of 1 kHz (like 44.1) are passed as a sequence of * values that average to a desired value (9 values of 44 and one value of 45). * * In order to compensate for clock rate difference * between host clock and DAC clock, the sample rate values sent by the device * are either larger (to increase data rate from the host) or smaller than * the nominal frequency value - the driver uses that to adjust the sample frame * counts of individual packets in an isochronous transfer. * * A similar mechanism is used with USB audio class asynchronous sinks: the * device sends a 10.14 representation of number of audio samples (frames) * per USB frame, and this is used to control packet sizes. */ static void use_audioclass_sync_feedback(const uint8_t *data, uint32_t actual_length, int *prate) { // 10.14 representation of 'samples' per ms value, see 5.12.4.2 of the USB spec uint32_t value = data[0] + 256 * data[1] + 65536 * data[2]; // printf("Ff estimate = %f Hz\n", value * 1000 / 16384.0); // only 1 packet *prate = (1000 * value + 8192) >> 14; } static inline void use_multimix_sync_feedback(const uint8_t *data, uint32_t actual_length, int *prate, const uint8_t *prev_data) { // Those assertions never failed, so my understanding of the protocol was likely // correct. They should probably be removed just to not crash the program when // used with flaky devices. assert(actual_length == 3); // this is averaged across all packets in the transfer *prate += 1000 * data[0]; if (prev_data) assert(data[1] == prev_data[0]); } static void sync_callback(struct libusb_transfer *transfer) { struct usbio_transfer *xf = transfer->user_data; struct cbox_usb_io_impl *uii = xf->user_data; uint8_t *data = transfer->buffer; int i, ofs, pkts; int rate_est = 0; xf->pending = FALSE; if (transfer->status == LIBUSB_TRANSFER_CANCELLED) { xf->cancel_confirm = 1; return; } if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) { xf->cancel_confirm = 1; return; } // XXXKF handle device disconnected error if (uii->debug_sync) printf("Sync callback! %p %d packets:", transfer, transfer->num_iso_packets); ofs = 0; pkts = 0; rate_est = 0; const uint8_t *prev_data = NULL; for (i = 0; i < transfer->num_iso_packets; i++) { if (transfer->iso_packet_desc[i].status) { printf("[%02d: actual length is %4d, status is %2d] ", i, transfer->iso_packet_desc[i].actual_length, transfer->iso_packet_desc[i].status); continue; } else if (transfer->iso_packet_desc[i].actual_length) { if (uii->sync_protocol == USBAUDIOSYNC_PROTOCOL_MULTIMIX8) use_multimix_sync_feedback(&data[ofs], transfer->iso_packet_desc[i].actual_length, &rate_est, prev_data); else use_audioclass_sync_feedback(&data[ofs], transfer->iso_packet_desc[i].actual_length, &rate_est); prev_data = &data[ofs]; //printf("%d\n", (int)data[ofs]); if (uii->debug_sync) printf("%3d ", (int)data[ofs]); pkts++; } else if (uii->debug_sync) printf("? "); ofs += transfer->iso_packet_desc[i].length; } if (uii->debug_sync) printf(" (%d of %d)", pkts, transfer->num_iso_packets); if (pkts == transfer->num_iso_packets) { // Divide by the number of packets to compute the mean rate (in case // of Multimix we don't have a proper fractional value, just an integer, // so averaging is required to get more accuracy). if (rate_est) uii->samples_per_sec = rate_est / pkts; if (uii->debug_sync) printf("rate_est = %d sync_freq = %d\n", rate_est, uii->samples_per_sec); } if (uii->no_resubmit) return; int err = usbio_transfer_submit(xf); if (err) { if (err == LIBUSB_ERROR_NO_DEVICE) { return; } } if (uii->debug_sync) printf("\n"); } struct usbio_transfer *sync_stuff_asynchronous(struct cbox_usb_io_impl *uii, int index) { struct usbio_transfer *t; int err; int syncbufsize = uii->sync_protocol == USBAUDIOSYNC_PROTOCOL_MULTIMIX8 ? 64 : 3; int syncbufcount = uii->sync_protocol == USBAUDIOSYNC_PROTOCOL_MULTIMIX8 ? NUM_MULTIMIX_SYNC_PACKETS : 1; t = usbio_transfer_new(uii->usbctx, "sync", index, syncbufcount, uii); uint8_t *sync_buf = (uint8_t *)calloc(syncbufcount, syncbufsize); libusb_fill_iso_transfer(t->transfer, uii->handle_audiodev, uii->audio_sync_endpoint, sync_buf, syncbufsize * syncbufcount, syncbufcount, sync_callback, t, 20000); libusb_set_iso_packet_lengths(t->transfer, syncbufsize); err = libusb_submit_transfer(t->transfer); if (err) { g_warning("Cannot submit sync urb: %s", libusb_error_name(err)); free(sync_buf); usbio_transfer_destroy(t); return NULL; } return t; } /////////////////////////////////////////////////////////////////////////// void cbox_usb_audio_info_init(struct cbox_usb_audio_info *uai, struct cbox_usb_device_info *udi) { uai->udi = udi; uai->intf = -1; uai->alt_setting = -1; uai->epdesc.found = FALSE; uai->sync_protocol = USBAUDIOSYNC_PROTOCOL_NONE; uai->sync_epdesc.found = FALSE; } void usbio_start_audio_playback(struct cbox_usb_io_impl *uii) { uii->desync = 0; uii->samples_played = 0; uii->read_ptr = uii->ioi.pio->io_env.buffer_size; uii->playback_transfers = malloc(sizeof(struct libusb_transfer *) * uii->playback_buffers); uii->sync_transfers = malloc(sizeof(struct libusb_transfer *) * uii->sync_buffers); uii->playback_counter = 0; uii->device_removed = 0; uii->samples_per_sec = uii->sample_rate; uii->play_function(uii); uii->setup_error = uii->playback_counter == 0; if (!uii->setup_error) { while(uii->playback_counter < uii->playback_buffers && !uii->device_removed) libusb_handle_events(uii->usbctx); } } void usbio_stop_audio_playback(struct cbox_usb_io_impl *uii) { if (uii->device_removed) { // Wait until all the transfers pending are finished while(uii->device_removed < uii->playback_counter) libusb_handle_events(uii->usbctx); } if (uii->device_removed || uii->setup_error) { // Run the DSP code and send output to bit bucket until engine is stopped. // This ensures that the command queue will still be processed. // Otherwise the GUI thread would hang waiting for the command from // the queue to be completed. g_message("USB Audio output device has been disconnected - switching to null output."); usbio_run_idle_loop(uii); } else { // Cancel all transfers pending, and wait until they get cancelled for (unsigned int i = 0; i < uii->playback_counter; i++) { if (uii->playback_transfers[i]) usbio_transfer_shutdown(uii->playback_transfers[i]); } } // Free the transfers for the buffers allocated so far. In case of setup // failure, some buffers transfers might not have been created yet. for (unsigned int i = 0; i < uii->playback_counter; i++) { if (uii->playback_transfers[i]) { free(uii->playback_transfers[i]->transfer->buffer); usbio_transfer_destroy(uii->playback_transfers[i]); uii->playback_transfers[i] = NULL; } } if (uii->playback_counter && uii->audio_sync_endpoint) { for (unsigned int i = 0; i < uii->sync_counter; i++) { if (uii->sync_transfers[i]) usbio_transfer_shutdown(uii->sync_transfers[i]); } for (unsigned int i = 0; i < uii->sync_counter; i++) { if (uii->sync_transfers[i]) { free(uii->sync_transfers[i]->transfer->buffer); usbio_transfer_destroy(uii->sync_transfers[i]); uii->sync_transfers[i] = NULL; } } } free(uii->playback_transfers); free(uii->sync_transfers); } #endif