int main()
{
    snd_seq_t *handle;
    int err;
    err = snd_seq_open(&handle, "default", SND_SEQ_OPEN_INPUT, 0);
    if (err < 0) {
            fprintf(stderr, "%s\n", snd_strerror(-err));
            exit(1);
    }
    snd_seq_set_client_name(handle, "Yo!");
    int port_number = snd_seq_create_simple_port(handle, "my port",
            SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
            SND_SEQ_PORT_TYPE_MIDI_GENERIC);
    snd_seq_event_t *event;
    for (;;){
        snd_seq_event_input(handle, &event);
        printf("Type: %d\n", event->type);
        if (snd_seq_ev_is_note_type(event)){
            printf("Note: %d\n", event->data.note.note);
            printf("Velocity: %d\n", event->data.note.velocity);
        }
        printf("Source: %d:%d\n", event->source.client, event->source.port);
        printf("Destination: %d:%d\n", event->dest.client, event->dest.port);
    }

    return 0;
}
void AlsaMidiInputThread::readEvent()
{
    m_mutex.lock();

    /* Wait for input data */
    do
    {
        AlsaMidiInputDevice* device = NULL;
        snd_seq_event_t* ev = NULL;

        /* Receive an event */
        snd_seq_event_input(m_alsa, &ev);

        // Find a device matching the event's address. If one isn't
        // found, skip this event, since we're not interested in it.
        uint uid = AlsaMidiUtil::addressToVariant(&ev->source).toUInt();
        if (m_devices.contains(uid) == true)
            device = m_devices[uid];
        else
            continue;
        Q_ASSERT(device != NULL);

        uchar cmd = 0;
        uchar data1 = 0;
        uchar data2 = 0;

        //qDebug() << "ALSA MIDI event received !" << ev->type;

        if (snd_seq_ev_is_control_type(ev))
        {
            switch (ev->type)
            {
            case SND_SEQ_EVENT_PGMCHANGE:
                cmd = MIDI_PROGRAM_CHANGE;
                data1 = ev->data.control.value;
                data2 = 127;
                break;

            case SND_SEQ_EVENT_CONTROLLER:
                cmd = MIDI_CONTROL_CHANGE | ev->data.control.channel;
                data1 = ev->data.control.param;
                data2 = ev->data.control.value;
                break;

            case SND_SEQ_EVENT_PITCHBEND:
                cmd = MIDI_PITCH_WHEEL | ev->data.control.channel;
                data1 = (ev->data.control.value + 8192) & 0x7f;
                data2 = (ev->data.control.value + 8192) >> 7;
                break;

            case SND_SEQ_EVENT_KEYPRESS:
                cmd = MIDI_NOTE_AFTERTOUCH | ev->data.note.channel;
                data1 = ev->data.note.note;
                data2 = ev->data.note.velocity;
                break;

            case SND_SEQ_EVENT_CHANPRESS:
                cmd = MIDI_CHANNEL_AFTERTOUCH | ev->data.control.channel;
                data1 = ev->data.control.value;
                break;
 
            default:
                break;
            }
        }
        else if (snd_seq_ev_is_note_type(ev))
        {
            if (ev->type == SND_SEQ_EVENT_NOTEOFF)
                cmd = MIDI_NOTE_OFF | ev->data.note.channel;
            else if (ev->data.note.velocity == 0 && ev->data.note.off_velocity == 0)
                cmd = MIDI_NOTE_OFF | ev->data.note.channel;
            else
                cmd = MIDI_NOTE_ON | ev->data.note.channel;
            data1 = ev->data.note.note;
            data2 = ev->data.note.velocity;
        }
        else if (snd_seq_ev_is_queue_type(ev))
        {
            if (device->processMBC(ev->type) == false)
                continue;
            if (ev->type == SND_SEQ_EVENT_START)
                cmd = MIDI_BEAT_START;
            else if(ev->type == SND_SEQ_EVENT_STOP)
                cmd = MIDI_BEAT_STOP;
            else if(ev->type == SND_SEQ_EVENT_CONTINUE)
                cmd = MIDI_BEAT_CONTINUE;
            else if(ev->type == SND_SEQ_EVENT_CLOCK)
                cmd = MIDI_BEAT_CLOCK;

            qDebug()  << "MIDI clock: " << cmd;
        }

        // ALSA API is a bit controversial on this. snd_seq_event_input() says
        // it ALLOCATES the event but snd_seq_free_event() says this is not
        // needed because the event IS NOT allocated. No crashes observed
        // either way, so I guess freeing nevertheless is a bit safer.
        snd_seq_free_event(ev);

        uint channel = 0;
        uchar value = 0;
        if (QLCMIDIProtocol::midiToInput(cmd, data1, data2, device->midiChannel(),
                                         &channel, &value) == true)
        {
            device->emitValueChanged(channel, value);
            // for MIDI beat clock signals,
            // generate a synthetic release event
            if (cmd >= MIDI_BEAT_CLOCK && cmd <= MIDI_BEAT_STOP)
                device->emitValueChanged(channel, 0);
        }
    } while (snd_seq_event_input_pending(m_alsa, 0) > 0);