diff --git a/alsa.c b/alsa.c index 2178b6e..87d13ff 100644 --- a/alsa.c +++ b/alsa.c @@ -4,11 +4,15 @@ #include #include "alsa.h" #include "usb.h" +#include "log.h" #include "dump.h" static snd_seq_t *snd_handle; static int seq_port; -static snd_seq_event_t *ev; +static snd_midi_event_t *midi_event_parser; + +#define ALSA_BUFSIZE 4096 + int alsa_setup(const char *name) @@ -24,9 +28,21 @@ alsa_setup(const char *name) SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_MIDI_GENERIC); + // Allocate parser object for converting to and from MIDI + if (snd_midi_event_new(ALSA_BUFSIZE, &midi_event_parser) < 0) { + fatal("ALSA cannot allocate MIDI event parser"); + } + return 0; } +void +alsa_close() +{ + snd_midi_event_free(midi_event_parser); +} + + #define MAX_PFDS 20 int npfd; struct pollfd pfd[MAX_PFDS]; @@ -38,8 +54,7 @@ alsa_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds) int i; if (npfd > MAX_PFDS) { - fprintf(stderr, "ALSA wants too many file descriptors\n"); - abort(); + fatal("ALSA wants too many file descriptors"); } snd_seq_poll_descriptors(snd_handle, pfd, npfd, POLLIN); @@ -55,34 +70,33 @@ alsa_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds) } -#define ALSA_BUFSIZE 4096 - void alsa_read_ready() { - static snd_midi_event_t *midi_event_parser; - - if (snd_midi_event_new(ALSA_BUFSIZE, &midi_event_parser) < 0) { - fprintf(stderr, "ALSA cannot allocate MIDI event parser\n"); - abort(); - } + static snd_seq_event_t *ev; for (;;) { unsigned char buf[ALSA_BUFSIZE]; long converted; - - if (snd_seq_event_input(snd_handle, &ev) < 0) { + int r; + + r = snd_seq_event_input(snd_handle, &ev); + + if (r == -EAGAIN) { break; } + if (r == -ENOSPC) { + warn("Out of space on input queue"); + } converted = snd_midi_event_decode(midi_event_parser, buf, ALSA_BUFSIZE, ev); if (converted < 0) { - fprintf(stderr, "Can't decode MIDI event type %d\n", ev->type); + warn("Can't decode MIDI event type %d", ev->type); } else { + DUMP_d(converted); usb_write(buf, converted); } } - snd_midi_event_free(midi_event_parser); } void @@ -103,28 +117,40 @@ alsa_check_fds(fd_set *rfds, fd_set *wfds) void alsa_write(uint8_t *data, size_t datalen) { - static snd_midi_event_t *midi_event_parser; - snd_seq_event_t ev; - long r; - - if (snd_midi_event_new(ALSA_BUFSIZE, &midi_event_parser) < 0) { - fprintf(stderr, "ALSA cannot allocate MIDI event parser\n"); - abort(); - } + size_t offset = 0; - r = snd_midi_event_encode(midi_event_parser, data, datalen, &ev); - if (r < datalen) { - fprintf(stderr, "ALSA didn't parse that message\n"); - abort(); - } - - snd_seq_ev_set_direct(&ev); - snd_seq_ev_set_source(&ev, seq_port); - snd_seq_ev_set_subs(&ev); - if ((r = snd_seq_event_output_direct(snd_handle, &ev)) < 0) { - fprintf(stderr, "ALSA couldn't write an event: %ld\n", r); - abort(); - } + for (; datalen > offset;) { + snd_seq_event_t ev; + long encoded; + int r; + + encoded = snd_midi_event_encode(midi_event_parser, data + offset, datalen - offset, &ev); + if (encoded <= 1) { + int i; - snd_midi_event_free(midi_event_parser); -} \ No newline at end of file + warn("Unable to encode MIDI message (%ld < %ld)", encoded, datalen); + fprintf(stderr, " "); + for (i = offset; i < datalen; i += 1) { + fprintf(stderr, "%02x ", data[i]); + } + fprintf(stderr, "\n"); + + return; + } + + snd_seq_ev_set_direct(&ev); + snd_seq_ev_set_source(&ev, seq_port); + snd_seq_ev_set_subs(&ev); + r = snd_seq_event_output(snd_handle, &ev); + + if (r < 0) { + warn("Couldn't write an output event"); + } + if (r > 200) { + warn("Output buffer size %d", r); + } + + offset += encoded; + } + snd_seq_drain_output(snd_handle); +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..47b9c0c --- /dev/null +++ b/log.h @@ -0,0 +1,13 @@ +#ifndef __LOG_H__ +#define __LOG_H__ + +#include +#include + +#define __log__(fmt, args...) fprintf(stderr, "%s:%d " fmt "\n", __FILE__, __LINE__, ##args) + +#define warn(fmt, args...) __log__("Warning: %s:%d " fmt, __FILE__, __LINE__, ##args) +#define fatal(fmt, args...) do { __log__("Fatal: " fmt, ##args); abort(); } while (0) + +#endif + diff --git a/usb.c b/usb.c index 482c7c2..70b5206 100644 --- a/usb.c +++ b/usb.c @@ -6,6 +6,7 @@ #include #include "usb.h" #include "alsa.h" +#include "log.h" #include "dump.h" static struct libusb_device_handle *usb_dev; @@ -16,14 +17,15 @@ static int reads_pending = 0; struct device { uint16_t product_id; + uint8_t interface_number; uint8_t ep_in; uint8_t ep_out; }; const struct device devices[] = { - { 0xb102, 0x83, 0x04 }, // Steel - { 0xb105, 0x82, 0x03 }, // MP3e2 - { 0, 0, 0 } + { 0xb102, 1, 0x83, 0x04 }, // Steel + { 0xb105, 1, 0x82, 0x03 }, // MP3e2 + { 0, 0, 0, 0 } }; void usb_xfer_done(struct libusb_transfer *transfer); @@ -64,7 +66,7 @@ usb_setup(char *name, size_t namelen) } if (libusb_pollfds_handle_timeouts(NULL) == 0) { - printf("I'm too dumb to handle events on such an old system.\n"); + fatal("I'm too dumb to handle events on such an old system."); return -1; } @@ -75,8 +77,7 @@ usb_setup(char *name, size_t namelen) } } if (! usb_dev) { - printf("Couldn't find a controller.\n"); - return -1; + fatal("Couldn't find a controller."); } // Figure out what it's called @@ -94,10 +95,15 @@ usb_setup(char *name, size_t namelen) ret = libusb_get_string_descriptor_ascii(usb_dev, ddesc.iProduct, (unsigned char *)p, namelen - ret - 1); } if (ret < 0) { - printf("Warning: I can't figure out what to call this thing.\n"); + warn("I can't figure out what to call this thing."); } printf("Opened [%s]\n", name); } + + if (0 != libusb_claim_interface(usb_dev, d->interface_number)) { + fatal("Couldn't claim interface %d", d->interface_number); + } + usb_initiate_transfer(); @@ -125,7 +131,7 @@ usb_fd_setup(int *nfds, fd_set *rfds, fd_set *wfds) } if (reads_pending + writes_pending > 10) { - fprintf(stderr, "Warning: %d+%d = %d outstanding USB transactions!\n", reads_pending, writes_pending, reads_pending + writes_pending); + warn("%d(r)+%d(w) = %d outstanding USB transactions!", reads_pending, writes_pending, reads_pending + writes_pending); } } @@ -150,6 +156,7 @@ usb_check_fds(fd_set *rfds, fd_set *wfds) void usb_write_done(struct libusb_transfer *xfer) { + DUMP_d(xfer->status); writes_pending -= 1; free(xfer->buffer); libusb_free_transfer(xfer); @@ -160,6 +167,13 @@ usb_write(uint8_t *data, size_t datalen) { struct libusb_transfer *xfer; unsigned char *buf; + int i; + + DUMP_d(datalen); + for (i = 0; i < datalen; i += 1) { + fprintf(stderr, " %02x", data[i]); + } + fprintf(stderr, "\n"); writes_pending += 1; xfer = libusb_alloc_transfer(0);