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;
}
Example #2
0
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;
}
Example #3
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);
        }
    };
Example #5
0
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);
}
Example #6
0
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);
		}
	}
}
Example #7
0
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;
}
Example #8
0
/*
 * 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;
}
Example #9
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);
   }
}
Example #10
0
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);
	}

}
Example #11
0
// 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);
    }
}
Example #12
0
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;
}
Example #14
0
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;
}