Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Talk to the Yamaha 01v96i from Linux! Record and play back 16-channel 24-bit raw audio. This program pipes its standard input to the mixer, and pipes the mixer's output to standard output.
/*
* Copyright 2013 Exavideo LLC.
*
* This 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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <libusb.h>
const uint16_t vid_mixer = 0x0499;
const uint16_t pid_mixer = 0x5500;
void print_config_descriptor(const libusb_config_descriptor *confd);
int flag;
void main_loop(libusb_device_handle *);
void print_iso_packets(libusb_transfer *);
void write_iso_packets(libusb_transfer *);
int read_iso_packets(libusb_transfer *);
int main( ) {
int err;
flag = 0;
libusb_device_handle *mixer_handle;
libusb_device *mixer_dev;
libusb_config_descriptor *confd;
libusb_init(NULL);
mixer_handle = libusb_open_device_with_vid_pid(
NULL, vid_mixer, pid_mixer
);
if (mixer_handle == NULL) {
fprintf(stderr, "could not find device or error opening\n");
goto failed_to_open_device;
}
mixer_dev = libusb_get_device(mixer_handle);
/* if nothing else, this resets the other end */
err = libusb_set_configuration(mixer_handle, 1);
if (err != 0) {
fprintf(stderr, "could not get configuration 1\n");
goto failed_with_device_open;
}
/* try to read descriptor */
err = libusb_get_active_config_descriptor(mixer_dev, &confd);
if (err != 0) {
fprintf(stderr, "could not get config 1 descriptor\n");
goto failed_with_device_open;
}
print_config_descriptor(confd);
libusb_free_config_descriptor(confd);
/* try to claim interface 1 (audio capture) */
err = libusb_claim_interface(mixer_handle, 1);
if (err != 0) {
fprintf(stderr, "could not claim interface 1\n");
goto failed_with_device_open;
}
/* and set it to alt setting 1 (48kHz?) */
err = libusb_set_interface_alt_setting(mixer_handle, 1, 1);
if (err != 0) {
fprintf(stderr, "failed to set interface 1 to alternate setting 1\n");
goto failed_with_interface_claimed;
}
/* do same for interface 2 (audio capture) */
err = libusb_claim_interface(mixer_handle, 2);
if (err != 0) {
fprintf(stderr, "could not claim interface 2\n");
goto failed_with_interface_claimed;
}
err = libusb_set_interface_alt_setting(mixer_handle, 2, 1);
if (err != 0) {
fprintf(stderr, "failed to set interface 2 to alternate setting 1\n");
goto failed_with_interface_claimed;
}
/* start reading audio data? */
main_loop(mixer_handle);
failed_with_interface_claimed:
libusb_release_interface(mixer_handle, 1);
libusb_release_interface(mixer_handle, 2);
failed_with_device_open:
libusb_close(mixer_handle);
failed_to_open_device:
libusb_exit(NULL);
}
void print_endpoint_descriptor(const libusb_endpoint_descriptor *epd) {
fprintf(stderr, "\t\t\tbLength=%d\n", epd->bLength);
fprintf(stderr, "\t\t\tbDescriptorType=%d\n", epd->bDescriptorType);
fprintf(stderr, "\t\t\tbEndpointAddress=0x%x\n", epd->bEndpointAddress);
fprintf(stderr, "\t\t\tbmAttributes=0x%x\n", epd->bmAttributes);
fprintf(stderr, "\t\t\twMaxPacketSize=%d\n", epd->wMaxPacketSize);
fprintf(stderr, "\t\t\tbInterval=%d\n", epd->bInterval);
fprintf(stderr, "\t\t\tbRefresh=%d\n", epd->bRefresh);
fprintf(stderr, "\t\t\tbSynchAddress=%d\n", epd->bSynchAddress);
}
void print_interface_descriptor(const libusb_interface_descriptor *ifd) {
uint8_t i;
fprintf(stderr, "\t\tbLength=%d\n", ifd->bLength);
fprintf(stderr, "\t\tbDescriptorType=%d\n", ifd->bDescriptorType);
fprintf(stderr, "\t\tbInterfaceNumber=%d\n", ifd->bInterfaceNumber);
fprintf(stderr, "\t\tbAlternateSetting=%d\n", ifd->bAlternateSetting);
fprintf(stderr, "\t\tbNumEndpoints=%d\n", ifd->bNumEndpoints);
fprintf(stderr, "\t\tbInterfaceClass=%d\n", ifd->bInterfaceClass);
fprintf(stderr, "\t\tbInterfaceProtocol=%d\n", ifd->bInterfaceProtocol);
for (i = 0; i < ifd->bNumEndpoints; i++) {
fprintf(stderr, "\t\tendpoint %d:\n", i);
print_endpoint_descriptor(&ifd->endpoint[i]);
}
}
void print_interface_data(const libusb_interface *iface) {
int i;
for (i = 0; i < iface->num_altsetting; i++) {
fprintf(stderr, "\talternate setting %d:\n", i);
print_interface_descriptor(&iface->altsetting[i]);
}
}
void print_config_descriptor(const libusb_config_descriptor *confd) {
uint8_t i;
fprintf(stderr, "bLength=%d\n", confd->bLength);
fprintf(stderr, "bDescriptorType=%d\n", confd->bDescriptorType);
fprintf(stderr, "wTotalLength=%d\n", confd->wTotalLength);
fprintf(stderr, "bNumInterfaces=%d\n", confd->bNumInterfaces);
fprintf(stderr, "bConfigurationValue=%d\n", confd->bConfigurationValue);
fprintf(stderr, "iConfiguration=%d\n", confd->iConfiguration);
fprintf(stderr, "bmAttributes=0x%x\n", confd->bmAttributes);
fprintf(stderr, "MaxPower=%d\n", confd->MaxPower);
for (i = 0; i < confd->bNumInterfaces; i++) {
fprintf(stderr, "interface %d:\n", i);
print_interface_data(&confd->interface[i]);
}
}
void in_cb(struct libusb_transfer *isoxfer) {
switch (isoxfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
write_iso_packets(isoxfer);
break;
default:
break;
}
/* resubmit the transfer? */
libusb_submit_transfer(isoxfer);
}
void out_cb(struct libusb_transfer *isoxfer) {
switch (isoxfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
if (read_iso_packets(isoxfer) == 0) {
flag = 1;
}
break;
default:
break;
}
/* resubmit the transfer? */
libusb_submit_transfer(isoxfer);
}
libusb_transfer *alloc_iso_xfer(
libusb_device_handle *handle,
unsigned char endpt,
libusb_transfer_cb_fn cb,
int pktsz = -1
) {
struct libusb_transfer *isoxfer;
struct libusb_device *dev;
const int num_iso_packets = 256;
unsigned char *buf;
size_t bufsize;
int max_packet_size;
dev = libusb_get_device(handle);
max_packet_size = libusb_get_max_iso_packet_size(dev, endpt);
if (
max_packet_size == LIBUSB_ERROR_NOT_FOUND
|| max_packet_size == LIBUSB_ERROR_OTHER
) {
fprintf(stderr, "could not get max packet size for endpoint\n");
return NULL;
}
if (pktsz == -1) {
pktsz = max_packet_size;
}
if (pktsz > max_packet_size) {
fprintf(stderr, "invalid packet size\n");
return NULL;
}
bufsize = num_iso_packets * pktsz;
buf = new unsigned char[bufsize];
isoxfer = libusb_alloc_transfer(num_iso_packets);
if (isoxfer == NULL) {
fprintf(stderr, "failed to allocate isochronous transfer\n");
return NULL;
}
libusb_fill_iso_transfer(
isoxfer, handle, endpt,
buf, bufsize, num_iso_packets,
cb, NULL, 10000
);
libusb_set_iso_packet_lengths(isoxfer, pktsz);
return isoxfer;
}
void main_loop(libusb_device_handle *mixer_handle) {
const int num_transfers = 16;
libusb_transfer *xfer;
int i, err;
/* start incoming transfers */
for (i = 0; i < num_transfers; i++) {
xfer = alloc_iso_xfer(mixer_handle, 0x86, in_cb);
if (xfer == NULL) {
fprintf(stderr, "failed to allocate transfer\n");
continue;
}
err = libusb_submit_transfer(xfer);
if (err != 0) {
fprintf(stderr, "failed to submit transfer\n");
}
}
/* and outgoing transfers */
for (i = 0; i < num_transfers; i++) {
xfer = alloc_iso_xfer(mixer_handle, 0x07, out_cb, 288);
if (xfer == NULL) {
fprintf(stderr, "failed to allocate transfer\n");
continue;
}
read_iso_packets(xfer);
err = libusb_submit_transfer(xfer);
if (err != 0) {
fprintf(stderr, "failed to submit transfer\n");
}
}
/* let the callback do the rest of the work */
while (flag == 0) {
libusb_handle_events(NULL);
}
}
const char *transfer_status_string(libusb_transfer_status s) {
switch (s) {
case LIBUSB_TRANSFER_COMPLETED:
return "SUCCESS";
case LIBUSB_TRANSFER_ERROR:
return "ERROR";
case LIBUSB_TRANSFER_TIMED_OUT:
return "TIMEOUT";
case LIBUSB_TRANSFER_CANCELLED:
return "CANCELED";
case LIBUSB_TRANSFER_STALL:
return "STALL";
case LIBUSB_TRANSFER_NO_DEVICE:
return "DISCONNECT";
case LIBUSB_TRANSFER_OVERFLOW:
return "OVERFLOW";
default:
return "UNKNOWN";
}
}
void print_iso_packets(libusb_transfer *xfer) {
int i;
libusb_iso_packet_descriptor *isopkt;
for (i = 0; i < xfer->num_iso_packets; i++) {
isopkt = &(xfer->iso_packet_desc[i]);
fprintf(stderr, "packet %d length=%u actual_length=%u [%10s]\n",
i, isopkt->length, isopkt->actual_length,
transfer_status_string(isopkt->status)
);
}
}
void write_iso_packets(libusb_transfer *xfer) {
int i;
unsigned char *data;
size_t len;
/* write isochronous data to stdout */
for (i = 0; i < xfer->num_iso_packets; i++) {
data = libusb_get_iso_packet_buffer_simple(xfer, i);
len = xfer->iso_packet_desc[i].actual_length;
fwrite(data, len, 1, stdout);
}
}
int read_iso_packets(libusb_transfer *xfer) {
int i;
unsigned char *data;
size_t len;
/* write isochronous data to stdout */
for (i = 0; i < xfer->num_iso_packets; i++) {
data = libusb_get_iso_packet_buffer_simple(xfer, i);
len = xfer->iso_packet_desc[i].actual_length;
if (fread(data, len, 1, stdin) == 0) {
return 0;
}
}
return 1;
}
@grag38

This comment has been minimized.

Copy link

grag38 commented Jun 29, 2014

I try to use this code with an raspberry pi board, it sees the 01V96i but stops after few packets.
Can you help us, with an small exemple (c++ or bash script) of how to use it ?

The goal is to perform an very small 16 tracks recorder on an usb key with the raspberry board.
And why not doing the same in the other way, ie : playing until 16 tracks from the raspberry to the 01V96i.

Thanks a lot, if you can provide juste one or two exemples.

Grag38

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.