L'exemple seqdemo.c montre comment créer un simple client pour le séquenceur ALSA. Ce client peut recevoir des données MIDI d'autres clients et il affiche NOTE ON/OFF, 7-bit CONTROLLER and PITCHBENDER events.
/* seqdemo.c by Matthias Nagorni */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <alsa/asoundlib.h> snd_seq_t *open_seq(); void midi_action(snd_seq_t *seq_handle); snd_seq_t *open_seq() { snd_seq_t *seq_handle; int portid; if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT, 0) < 0) { fprintf(stderr, "Error opening ALSA sequencer.\n"); exit(1); } snd_seq_set_client_name(seq_handle, "ALSA Sequencer Demo"); if ((portid = snd_seq_create_simple_port(seq_handle, "ALSA Sequencer Demo", SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION)) < 0) { fprintf(stderr, "Error creating sequencer port.\n"); exit(1); } return(seq_handle); } void midi_action(snd_seq_t *seq_handle) { snd_seq_event_t *ev; do { snd_seq_event_input(seq_handle, &ev); switch (ev->type) { case SND_SEQ_EVENT_CONTROLLER: fprintf(stderr, "Control event on Channel %2d: %5d \r", ev->data.control.channel, ev->data.control.value); break; case SND_SEQ_EVENT_PITCHBEND: fprintf(stderr, "Pitchbender event on Channel %2d: %5d \r", ev->data.control.channel, ev->data.control.value); break; case SND_SEQ_EVENT_NOTEON: fprintf(stderr, "Note On event on Channel %2d: %5d \r", ev->data.control.channel, ev->data.note.note); break; case SND_SEQ_EVENT_NOTEOFF: fprintf(stderr, "Note Off event on Channel %2d: %5d \r", ev->data.control.channel, ev->data.note.note); break; } snd_seq_free_event(ev); } while (snd_seq_event_input_pending(seq_handle, 0) > 0); } int main(int argc, char *argv[]) { snd_seq_t *seq_handle; int npfd; struct pollfd *pfd; seq_handle = open_seq(); npfd = snd_seq_poll_descriptors_count(seq_handle, POLLIN); pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd)); snd_seq_poll_descriptors(seq_handle, pfd, npfd, POLLIN); while (1) { if (poll(pfd, npfd, 100000) > 0) { midi_action(seq_handle); } } }
Détaillons un peu ce programme
A)
snd_seq_t *open_seq()
Cette fonction utilise snd_seq_open pour créer un nouveau client pour le séquenceur ALSA. Puisque nous voulons seulement recevoir des événements MIDI, le paramètre de stream est défini à
snd_seq_open_input
Le client obtient un nom en utilisant
snd_seq_set_client_name
Maintenant nous avons besoin d'un port qui peut recevoir des événements MIDI. Nous utilisons donc
snd_seq_create_simple_port
Nous devons indiquer les possibilités du port pour permettre l'accès en écriture,
snd_seq_port_cap_write
et pour permettre à d'autres clients de l'utiliser, de souscrire, au port en tant que port d'écriture.
snd_seq_port_cap_subs_write
Puisque notre application peut lire à partir de port, nous devrions ajouter snd_seq_cap_read, mais pour le moment, ceci peut être omis.
B)
void midi_action(snd_seq_t *seq_handle)
Cette fonction récupére un événement à partir de l'entrée du buffer du séquenceur ALSA en utlisant
snd_seq_event_input
L'événement est traité puis libéré avec
snd_seq_free_event
La boucle est répétée jusqu'à ce que l'entrée du buffer soit vide. Ceci est controlé avec le renvoi de la taille en byte des événements restants dans l'entrée du buffer :
snd_seq_input_pending
C)
int main(int argc, char *argv[])
Cette exemple utilise le "polling" pour controler les événements MIDI arrivant.
snd_seq_poll_descriptors_count
renvoi le nombre de poll descripteurs pour les événements polling entrant(paramètre POLLIN), pour l'instant le nombre est toujours 1.
struct pollfd
est assigné sur la pile et initialisé en utilisant
snd_seq_poll_descriptors
L'utilisation de poll renvoie un nombre seulement si un événement MIDI peut être lu à partir du séquenceur ALSA ou après timeout. Vous pouvez lire le manuel de poll si celui ci ne vous est pas familier.