static int midi_update_pfds(process_midi_t *proc) { midi_port_t *port = proc->port; if (port->npfds == 0) { port->npfds = snd_rawmidi_poll_descriptors_count(port->rawmidi); if (port->npfds > proc->max_pfds) { debug_log("midi: not enough pfds for port %s", port->name); return 0; } snd_rawmidi_poll_descriptors(port->rawmidi, proc->wpfds, port->npfds); } else if (proc->rpfds != proc->wpfds) { memmove(proc->wpfds, proc->rpfds, sizeof(struct pollfd) * port->npfds); } return 1; }
MidiAlsaRaw::MidiAlsaRaw() : MidiClientRaw(), m_inputp( &m_input ), m_outputp( &m_output ), m_quit( false ) { int err; if( ( err = snd_rawmidi_open( m_inputp, m_outputp, probeDevice().toLatin1().constData(), 0 ) ) < 0 ) { printf( "cannot open MIDI-device: %s\n", snd_strerror( err ) ); return; } snd_rawmidi_read( m_input, NULL, 0 ); snd_rawmidi_nonblock( m_input, 1 ); m_npfds = snd_rawmidi_poll_descriptors_count( m_input ); m_pfds = new pollfd[m_npfds]; snd_rawmidi_poll_descriptors( m_input, m_pfds, m_npfds ); start( QThread::LowPriority ); }
int main(int argc, char **argv) { int inputf, e, err; int sock; struct input_event buffer; int npfds; struct pollfd *pfds; struct sockaddr_in si_me, si_other; int len, slen = sizeof(si_other); int optval = 1; if(argc < 2) { fprintf(stderr, "%s <device>\n", argv[0]); exit(-1); } e = snd_rawmidi_open(&input, &output, argv[1], SND_RAWMIDI_NONBLOCK); if (e == -1) { fprintf(stderr, "snd:rawmidi:open-%X\n", e); return 1; } if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { perror("udp socket"); return 1; } memset((void *) &si_me, 0, sizeof(si_me)); si_me.sin_family = AF_INET; si_me.sin_port = htons(UDPMIDI_PORT); si_me.sin_addr.s_addr = htonl(INADDR_ANY); memset((void *) &si_other, 0, sizeof(si_me)); si_other.sin_family = AF_INET; si_other.sin_port = htons(UDPMIDI_PORT); si_other.sin_addr.s_addr = htonl(INADDR_BROADCAST); if (bind(sock, (const struct sockaddr*)&si_me, sizeof(si_me)) == -1) { perror("udp port"); close(sock); return 1; } if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof (optval)) ==- 1) { perror("udp broadcast"); close(sock); return 1; } npfds = snd_rawmidi_poll_descriptors_count(input) + 1; pfds = malloc((npfds + 1) * sizeof(struct pollfd)); snd_rawmidi_poll_descriptors(input, pfds, npfds); pfds[npfds-1].fd = sock; pfds[npfds-1].events = POLLRDNORM; setvbuf (stdout, NULL, _IONBF, BUFSIZ); while(1) { int i,rlen, midiin; err = poll(pfds, npfds, 200); midiin = 0; for (i = 0; i < npfds; ++i) { if (pfds[i].revents & POLLIN) midiin = 1; } if (midiin) { unsigned char buf[10]; unsigned char outbuf[12]; printf("m"); rlen = snd_rawmidi_read(input, buf, sizeof(buf)); if (rlen == -EAGAIN) continue; if (rlen < 0) { fprintf(stderr, "Cannot read from port \"%s\": %s", argv[1], snd_strerror(err)); break; } // UDP broadcast memcpy(outbuf, packet_signature, 2); if (rlen > 10) continue; memcpy(outbuf + 2, buf, rlen); if (sendto(sock, outbuf, 2 + rlen, 0, (struct sockaddr *)&si_other, sizeof(si_other)) == -1) { fprintf(stderr, "Error sending broadcast packet.\n"); } memcpy(last_packet, outbuf, rlen + 2); } if (pfds[npfds-1].revents & POLLRDNORM) { int len,slen; unsigned char buffer[10]; slen = sizeof(si_other); len = recvfrom(sock, buffer, 10, 0, (struct sockaddr *)&si_other, &slen); // Drop our own broadcast packets if (memcmp(last_packet, buffer, len) == 0) continue; printf("u"); if (len > 2 && memcmp(buffer, packet_signature, 2) == 0) { int wlen = snd_rawmidi_write(output, buffer + 2, len - 2); if (wlen < len - 2) { fprintf(stderr, "Midi out: Wrote %d of %d bytes\n", wlen, len - 2); } } } } return 0; }
gpointer read_data_thread(gboolean *stop) { /* This is mostly taken straight from alsa-utils-1.0.19 amidi/amidi.c by Clemens Ladisch <*****@*****.**> */ int err; int npfds; struct pollfd *pfds; GString *string = NULL; npfds = snd_rawmidi_poll_descriptors_count(input); pfds = alloca(npfds * sizeof(struct pollfd)); snd_rawmidi_poll_descriptors(input, pfds, npfds); do { unsigned char buf[256]; int i, length; unsigned short revents; /* SysEx messages can't contain bytes with 8th bit set. memset our buffer to 0xFF, so if for some reason we'll get out of reply bounds, we'll catch it */ memset(buf, '\0', sizeof(buf)); err = poll(pfds, npfds, 200); if (err < 0 && errno == EINTR) break; if (err < 0) { g_error("poll failed: %s", strerror(errno)); break; } if ((err = snd_rawmidi_poll_descriptors_revents(input, pfds, npfds, &revents)) < 0) { g_error("cannot get poll events: %s", snd_strerror(errno)); break; } if (revents & (POLLERR | POLLHUP)) break; if (!(revents & POLLIN)) continue; err = snd_rawmidi_read(input, buf, sizeof(buf)); if (err == -EAGAIN) continue; if (err < 0) { g_error("cannot read: %s", snd_strerror(err)); break; } length = 0; for (i = 0; i < err; ++i) if ((unsigned char)buf[i] != 0xFE) /* ignore active sensing */ buf[length++] = buf[i]; i = 0; while (i < length) { int pos; int bytes; if (string == NULL) { while (buf[i] != 0xF0 && i < length) i++; } pos = i; for (bytes = 0; (bytes<length-i) && (buf[i+bytes] != 0xF7); bytes++); if (buf[i+bytes] == 0xF7) bytes++; i += bytes; if (string == NULL) string = g_string_new_len((gchar*)&buf[pos], bytes); else g_string_append_len(string, (gchar*)&buf[pos], bytes); if ((unsigned char)string->str[string->len-1] == 0xF7) { /* push message on stack */ push_message(string); string = NULL; } } } while (*stop == FALSE); if (string) { g_string_free(string, TRUE); string = NULL; } return NULL; }