int AlsaSeqMidiInDriver::read(unsigned char* buf, int max) { if (!this->is_open()) throw std::logic_error("Device not open"); int bytes_read= 0; int err; snd_seq_event_t *ev; do { if (snd_seq_event_input(m_impl->seq, &ev) > 0 ) { err = snd_midi_event_decode (m_impl->decoder, buf, max, ev); //snd_seq_free_event( ev ); if (err > 0) { buf += err; bytes_read += err; max -= err; } else { // error or buffer full -> drop midi event } } } while (snd_seq_event_input_pending(m_impl->seq, 0) > 0); return bytes_read; }
static int event_process_midi(struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop) { struct seq_midisynth *msynth = private_data; unsigned char msg[10]; /* buffer for constructing midi messages */ struct snd_rawmidi_substream *substream; int len; if (snd_BUG_ON(!msynth)) return -EINVAL; substream = msynth->output_rfile.output; if (substream == NULL) return -ENODEV; if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { /* special case, to save space */ if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) { /* invalid event */ snd_printd("seq_midi: invalid sysex event flags = 0x%x\n", ev->flags); return 0; } snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream); snd_midi_event_reset_decode(msynth->parser); } else { if (msynth->parser == NULL) return -EIO; len = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev); if (len < 0) return 0; if (dump_midi(substream, msg, len) < 0) snd_midi_event_reset_decode(msynth->parser); } return 0; }
static int event_process_midi(snd_seq_event_t * ev, int direct, void *private_data, int atomic, int hop) { seq_midisynth_t *msynth = (seq_midisynth_t *) private_data; unsigned char msg[10]; /* buffer for constructing midi messages */ snd_rawmidi_substream_t *substream; int res; snd_assert(msynth != NULL, return -EINVAL); substream = msynth->output_rfile.output; if (substream == NULL) return -EINVAL; if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { /* special case, to save space */ if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) { /* invalid event */ snd_printd("seq_midi: invalid sysex event flags = 0x%x\n", ev->flags); return 0; } res = snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream); snd_midi_event_reset_decode(msynth->parser); if (res < 0) return res; } else { if (msynth->parser == NULL) return -EIO; res = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev); if (res < 0) return res; if ((res = dump_midi(substream, msg, res)) < 0) { snd_midi_event_reset_decode(msynth->parser); return res; } } return 0; }
void run() { const int maxEventSize = 16 * 1024; snd_midi_event_t* midiParser; if (snd_midi_event_new (maxEventSize, &midiParser) >= 0) { HeapBlock <uint8> buffer (maxEventSize); const int numPfds = snd_seq_poll_descriptors_count (seqHandle, POLLIN); struct pollfd* const pfd = (struct pollfd*) alloca (numPfds * sizeof (struct pollfd)); snd_seq_poll_descriptors (seqHandle, pfd, numPfds, POLLIN); while (! threadShouldExit()) { if (poll (pfd, numPfds, 500) > 0) { snd_seq_event_t* inputEvent = nullptr; snd_seq_nonblock (seqHandle, 1); do { if (snd_seq_event_input (seqHandle, &inputEvent) >= 0) { // xxx what about SYSEXes that are too big for the buffer? const int numBytes = snd_midi_event_decode (midiParser, buffer, maxEventSize, inputEvent); snd_midi_event_reset_decode (midiParser); if (numBytes > 0) { const MidiMessage message ((const uint8*) buffer, numBytes, Time::getMillisecondCounter() * 0.001); callback->handleIncomingMidiMessage (midiInput, message); } snd_seq_free_event (inputEvent); } } while (snd_seq_event_input_pending (seqHandle, 0) > 0); snd_seq_free_event (inputEvent); } } snd_midi_event_free (midiParser); } };
static void input_event(alsa_seqmidi_t *self, snd_seq_event_t *alsa_event, struct process_info* info) { jack_midi_data_t data[MAX_EVENT_SIZE]; stream_t *str = &self->stream[PORT_INPUT]; long size; int64_t alsa_time, time_offset; int64_t frame_offset, event_frame; port_t *port; port = port_get(str->ports, alsa_event->source); if (!port) return; /* * RPNs, NRPNs, Bank Change, etc. need special handling * but seems, ALSA does it for us already. */ snd_midi_event_reset_decode(str->codec); if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0) return; // fixup NoteOn with vel 0 if ((data[0] & 0xF0) == 0x90 && data[2] == 0x00) { data[0] = 0x80 + (data[0] & 0x0F); data[2] = 0x40; } alsa_time = alsa_event->time.time.tv_sec * NSEC_PER_SEC + alsa_event->time.time.tv_nsec; time_offset = info->alsa_time - alsa_time; frame_offset = (info->sample_rate * time_offset) / NSEC_PER_SEC; event_frame = (int64_t)info->cur_frames - info->period_start - frame_offset + info->nframes; debug_log("input: %d bytes at event_frame = %d", (int)size, (int)event_frame); if (event_frame >= info->nframes && jack_ringbuffer_write_space(port->early_events) >= (sizeof(alsa_midi_event_t) + size)) { alsa_midi_event_t ev; ev.time = event_frame + info->period_start; ev.size = size; jack_ringbuffer_write(port->early_events, (char*)&ev, sizeof(ev)); jack_ringbuffer_write(port->early_events, (char*)data, size); debug_log("postponed to next frame +%d", (int) (event_frame - info->nframes)); return; } if (event_frame < 0) event_frame = 0; else if (event_frame >= info->nframes) event_frame = info->nframes - 1; jack_midi_event_write(port->jack_buf, event_frame, data, size); }
void Midi2UdpThread::run() { QUdpSocket *udpSocket; udpSocket = new QUdpSocket(0); forever { if (abort) { delete udpSocket; return; } if (poll(pfd, npfd, 250) > 0) { // Get MIDI event snd_seq_event_input(seq_handle, &midi_event); long len = snd_midi_event_decode(eventparser, midimsg, MAX_MIDI_MESSAGE_LENGTH, midi_event); if( len < 0 ) { printf("midi2udp: Error decoding midi event!\n"); } else { printf("midi2udp: got midi event: "); for(int i=0; i<len; ++i) { printf("0x%x ", midimsg[i]); } printf("\n"); // Send it over UDP for(set<string>::iterator ip_it = ds_ips.begin(); ip_it != ds_ips.end(); ++ip_it) { QString to_((*ip_it).c_str()); printf("sending to %s\n", (*ip_it).c_str()); QHostAddress to(to_); udpSocket->writeDatagram((char*)midimsg, len, to, DS_PORT); } } snd_seq_free_event(midi_event); snd_midi_event_reset_decode(eventparser); } } }
static ssize_t snd_rawmidi_virtual_read(snd_rawmidi_t *rmidi, void *buffer, size_t size) { snd_rawmidi_virtual_t *virt = rmidi->private_data; ssize_t result = 0; int size1, err; while (size > 0) { if (! virt->in_buf_ofs) { err = snd_seq_event_input_pending(virt->handle, 1); if (err <= 0 && result > 0) return result; err = snd_seq_event_input(virt->handle, &virt->in_event); if (err < 0) return result > 0 ? result : err; if (virt->in_event->type == SND_SEQ_EVENT_SYSEX) { virt->in_buf_ptr = virt->in_event->data.ext.ptr; virt->in_buf_size = virt->in_event->data.ext.len; } else { virt->in_buf_ptr = virt->in_tmp_buf; virt->in_buf_size = snd_midi_event_decode(virt->midi_event, (unsigned char *)virt->in_tmp_buf, sizeof(virt->in_tmp_buf), virt->in_event); } if (virt->in_buf_size <= 0) continue; } size1 = virt->in_buf_size - virt->in_buf_ofs; if ((size_t)size1 > size) { memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size); virt->in_buf_ofs += size; result += size; break; } memcpy(buffer, virt->in_buf_ptr + virt->in_buf_ofs, size1); size -= size1; result += size1; buffer += size1; virt->in_buf_ofs = 0; } return result; }
/* * decode event and send MIDI bytes to read queue */ static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq_oss_midi *mdev) { char msg[32]; int len; snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode); if (!dp->timer->running) len = snd_seq_oss_timer_start(dp->timer); if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev); } else { len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev); if (len > 0) snd_seq_oss_readq_puts(dp->readq, mdev->seq_device, msg, len); } return 0; }
/* this version uses the asynchronous "read()" ... */ void sys_alsa_poll_midi(void) { unsigned char buf[ALSA_MAX_EVENT_SIZE]; int count, alsa_source; int i; snd_seq_event_t *midievent = NULL; if (alsa_nmidiout == 0 && alsa_nmidiin == 0) return; snd_midi_event_init(midiev); if (!alsa_nmidiout && !alsa_nmidiin) return; count = snd_seq_event_input_pending(midi_handle,1); if (count != 0) count = snd_seq_event_input(midi_handle,&midievent); if (midievent != NULL) { count = snd_midi_event_decode(midiev,buf,sizeof(buf),midievent); alsa_source = midievent->dest.port; for(i=0;i<count;i++) sys_midibytein(alsa_source, (buf[i] & 0xff)); //post("received %d midi bytes\n",count); } }
static void a2j_input_event (struct a2j * self, snd_seq_event_t * alsa_event) { jack_midi_data_t data[MAX_EVENT_SIZE]; struct a2j_stream *str = &self->stream; long size; struct a2j_port *port; jack_nframes_t now; now = jack_frame_time (self->jack_client); if ((port = a2j_port_get(str->port_hash, alsa_event->source)) == NULL) { return; } /* * RPNs, NRPNs, Bank Change, etc. need special handling * but seems, ALSA does it for us already. */ snd_midi_event_reset_decode(str->codec); if ((size = snd_midi_event_decode(str->codec, data, sizeof(data), alsa_event))<0) { return; } // fixup NoteOn with vel 0 if ((data[0] & 0xF0) == 0x90 && data[2] == 0x00) { data[0] = 0x80 + (data[0] & 0x0F); data[2] = 0x40; } a2j_debug("input: %d bytes at event_frame=%u", (int)size, now); if (jack_ringbuffer_write_space(port->inbound_events) >= (sizeof(struct a2j_alsa_midi_event) + size)) { struct a2j_alsa_midi_event ev; char *ev_charp = (char*) &ev; size_t limit; size_t to_write = sizeof(ev); jack_ringbuffer_data_t vec[2]; jack_ringbuffer_get_write_vector( port->inbound_events, vec ); ev.time = now; ev.size = size; limit = (to_write > vec[0].len ? vec[0].len : to_write); if( limit ) { memcpy( vec[0].buf, ev_charp, limit ); to_write -= limit; ev_charp += limit; vec[0].buf += limit; vec[0].len -= limit; } if( to_write ) { memcpy( vec[1].buf, ev_charp, to_write ); vec[1].buf += to_write; vec[1].len -= to_write; } to_write = size; ev_charp = (char *)data; limit = (to_write > vec[0].len ? vec[0].len : to_write); if( limit ) memcpy( vec[0].buf, ev_charp, limit ); to_write -= limit; ev_charp += limit; if( to_write ) memcpy( vec[1].buf, ev_charp, to_write ); jack_ringbuffer_write_advance( port->inbound_events, sizeof(ev) + size ); } else { a2j_error ("MIDI data lost (incoming event buffer full): %ld bytes lost", size); } }
// alsa event capture. void samplv1_jack::alsa_capture ( snd_seq_event_t *ev ) { if (m_alsa_decoder == NULL) return; if (ev == NULL) return; // ignored events... switch(ev->type) { case SND_SEQ_EVENT_OSS: case SND_SEQ_EVENT_CLIENT_START: case SND_SEQ_EVENT_CLIENT_EXIT: case SND_SEQ_EVENT_CLIENT_CHANGE: case SND_SEQ_EVENT_PORT_START: case SND_SEQ_EVENT_PORT_EXIT: case SND_SEQ_EVENT_PORT_CHANGE: case SND_SEQ_EVENT_PORT_SUBSCRIBED: case SND_SEQ_EVENT_PORT_UNSUBSCRIBED: case SND_SEQ_EVENT_USR0: case SND_SEQ_EVENT_USR1: case SND_SEQ_EVENT_USR2: case SND_SEQ_EVENT_USR3: case SND_SEQ_EVENT_USR4: case SND_SEQ_EVENT_USR5: case SND_SEQ_EVENT_USR6: case SND_SEQ_EVENT_USR7: case SND_SEQ_EVENT_USR8: case SND_SEQ_EVENT_USR9: case SND_SEQ_EVENT_BOUNCE: case SND_SEQ_EVENT_USR_VAR0: case SND_SEQ_EVENT_USR_VAR1: case SND_SEQ_EVENT_USR_VAR2: case SND_SEQ_EVENT_USR_VAR3: case SND_SEQ_EVENT_USR_VAR4: case SND_SEQ_EVENT_NONE: return; } #ifdef CONFIG_DEBUG_0 // - show (input) event for debug purposes... fprintf(stderr, "ALSA MIDI In: 0x%02x", ev->type); if (ev->type == SND_SEQ_EVENT_SYSEX) { fprintf(stderr, " SysEx {"); unsigned char *data = (unsigned char *) ev->data.ext.ptr; for (unsigned int i = 0; i < ev->data.ext.len; ++i) fprintf(stderr, " %02x", data[i]); fprintf(stderr, " }\n"); } else { for (unsigned int i = 0; i < sizeof(ev->data.raw8.d); ++i) fprintf(stderr, " %3d", ev->data.raw8.d[i]); fprintf(stderr, "\n"); } #endif const unsigned int nlimit = ::jack_ringbuffer_write_space(m_alsa_buffer); if (nlimit > sizeof(jack_midi_event_t) + 4) { unsigned char ev_buff[nlimit]; unsigned char *ev_data = &ev_buff[0] + sizeof(jack_midi_event_t); const int ev_size = snd_midi_event_decode(m_alsa_decoder, ev_data, nlimit - sizeof(jack_midi_event_t), ev); if (ev_size > 0) { jack_midi_event_t *ev_head = (jack_midi_event_t *) &ev_buff[0]; ev_head->time = ::jack_frame_time(m_client); ev_head->size = ev_size; ev_head->buffer = (jack_midi_data_t *) ev_data; ::jack_ringbuffer_write(m_alsa_buffer, (const char *) ev_buff, sizeof(jack_midi_event_t) + ev_size); } snd_midi_event_reset_decode(m_alsa_decoder); } }
bool mastermidibus::get_midi_event( event *a_in ) { lock(); snd_seq_event_t *ev; bool sysex = false; /* temp for midi data */ unsigned char buffer[0x1000]; snd_seq_event_input(m_alsa_seq, &ev); bool ret = false; if (! global_manual_alsa_ports ) { switch( ev->type ){ case SND_SEQ_EVENT_PORT_START: { //printf("SND_SEQ_EVENT_PORT_START: addr[%d:%d]\n", // ev->data.addr.client, ev->data.addr.port ); port_start( ev->data.addr.client, ev->data.addr.port ); ret = true; break; } case SND_SEQ_EVENT_PORT_EXIT: { //printf("SND_SEQ_EVENT_PORT_EXIT: addr[%d:%d]\n", // ev->data.addr.client, ev->data.addr.port ); port_exit( ev->data.addr.client, ev->data.addr.port ); ret = true; break; } case SND_SEQ_EVENT_PORT_CHANGE: { //printf("SND_SEQ_EVENT_PORT_CHANGE: addr[%d:%d]\n", // ev->data.addr.client, // ev->data.addr.port ); ret = true; break; } default: break; } } if( ret ){ unlock(); return false; } /* alsa midi parser */ snd_midi_event_t *midi_ev; snd_midi_event_new( 0x1000, &midi_ev ); long bytes = snd_midi_event_decode( midi_ev, buffer, 0x1000, ev ); a_in->set_timestamp( ev->time.tick ); a_in->set_status( buffer[0] ); a_in->set_size( bytes ); /* we will only get EVENT_SYSEX on the first packet of midi data, the rest we have to poll for */ //if ( buffer[0] == EVENT_SYSEX ){ if ( 0 ){ /* set up for sysex if needed */ a_in->start_sysex( ); sysex = a_in->append_sysex( buffer, bytes ); } else { a_in->set_data( buffer[1], buffer[2] ); // some keyboards send on's with vel 0 for off if ( a_in->get_status() == EVENT_NOTE_ON && a_in->get_note_velocity() == 0x00 ){ a_in->set_status( EVENT_NOTE_OFF ); } sysex = false; } /* sysex messages might be more than one message */ while ( sysex ){ snd_seq_event_input(m_alsa_seq, &ev); bytes = snd_midi_event_decode( midi_ev, buffer, 0x1000, ev ); sysex = a_in->append_sysex( buffer, bytes ); } snd_seq_free_event( ev ); snd_midi_event_free( midi_ev ); unlock(); return true; }
bool mastermidibus::get_midi_event (event * inev) { #ifdef SEQ64_HAVE_LIBASOUND automutex locker(m_mutex); snd_seq_event_t * ev; bool sysex = false; bool result = false; midibyte buffer[0x1000]; /* temporary buffer for MIDI data */ snd_seq_event_input(m_alsa_seq, &ev); if (! rc().manual_alsa_ports()) { switch (ev->type) { case SND_SEQ_EVENT_PORT_START: { port_start(ev->data.addr.client, ev->data.addr.port); result = true; break; } case SND_SEQ_EVENT_PORT_EXIT: { port_exit(ev->data.addr.client, ev->data.addr.port); result = true; break; } case SND_SEQ_EVENT_PORT_CHANGE: { result = true; break; } default: break; } } if (result) return false; snd_midi_event_t * midi_ev; /* for ALSA MIDI parser */ snd_midi_event_new(sizeof(buffer), &midi_ev); /* make ALSA MIDI parser */ long bytes = snd_midi_event_decode(midi_ev, buffer, sizeof(buffer), ev); if (bytes <= 0) { /* * This happens even at startup, before anything is really happening. * Let's not show it. * * if (bytes < 0) * { * errprint("error decoding MIDI event"); * } */ return false; } inev->set_timestamp(ev->time.tick); inev->set_status_keep_channel(buffer[0]); /** * We will only get EVENT_SYSEX on the first packet of MIDI data; * the rest we have to poll for. SysEx processing is currently * disabled. */ #ifdef USE_SYSEX_PROCESSING /* currently disabled */ inev->set_sysex_size(bytes); if (buffer[0] == EVENT_MIDI_SYSEX) { inev->restart_sysex(); /* set up for sysex if needed */ sysex = inev->append_sysex(buffer, bytes); } else { #endif /* * Some keyboards send Note On with velocity 0 for Note Off, so we * take care of that situation here by creating a Note Off event, * with the channel nybble preserved. Note that we call * event :: set_status_keep_channel() instead of using stazed's * set_status function with the "record" parameter. A little more * confusing, but faster. */ inev->set_data(buffer[1], buffer[2]); if (inev->is_note_off_recorded()) inev->set_status_keep_channel(EVENT_NOTE_OFF); sysex = false; #ifdef USE_SYSEX_PROCESSING } #endif while (sysex) /* sysex messages might be more than one message */ { snd_seq_event_input(m_alsa_seq, &ev); long bytes = snd_midi_event_decode(midi_ev, buffer, sizeof(buffer), ev); if (bytes > 0) sysex = inev->append_sysex(buffer, bytes); else sysex = false; } snd_midi_event_free(midi_ev); #endif // SEQ64_HAVE_LIBASOUND return true; }
bool mastermidibus::get_midi_event (event * a_in) { #ifdef HAVE_LIBASOUND automutex locker(m_mutex); snd_seq_event_t * ev; bool sysex = false; bool result = false; unsigned char buffer[0x1000]; /* temporary buffer for midi data */ snd_seq_event_input(m_alsa_seq, &ev); if (! global_manual_alsa_ports) { switch (ev->type) { case SND_SEQ_EVENT_PORT_START: { port_start(ev->data.addr.client, ev->data.addr.port); result = true; break; } case SND_SEQ_EVENT_PORT_EXIT: { port_exit(ev->data.addr.client, ev->data.addr.port); result = true; break; } case SND_SEQ_EVENT_PORT_CHANGE: { result = true; break; } default: break; } } if (result) return false; snd_midi_event_t * midi_ev; /* alsa midi parser */ snd_midi_event_new(sizeof(buffer), &midi_ev); long bytes = snd_midi_event_decode(midi_ev, buffer, sizeof(buffer), ev); if (bytes <= 0) return false; a_in->set_timestamp(ev->time.tick); a_in->set_status(buffer[0]); a_in->set_size(bytes); /* * We will only get EVENT_SYSEX on the first packet of MIDI data; * the rest we have to poll for. */ #if 0 if ( buffer[0] == EVENT_SYSEX ) { a_in->start_sysex(); /* set up for sysex if needed */ sysex = a_in->append_sysex(buffer, bytes); } else { #endif /* some keyboards send Note On with velocity 0 for Note Off */ a_in->set_data(buffer[1], buffer[2]); if (a_in->get_status() == EVENT_NOTE_ON && a_in->get_note_velocity() == 0) a_in->set_status(EVENT_NOTE_OFF); sysex = false; #if 0 } #endif while (sysex) /* sysex messages might be more than one message */ { snd_seq_event_input(m_alsa_seq, &ev); long bytes = snd_midi_event_decode(midi_ev, buffer, sizeof(buffer), ev); if (bytes > 0) sysex = a_in->append_sysex(buffer, bytes); else sysex = false; } snd_midi_event_free(midi_ev); #endif // HAVE_LIBASOUND return true; }