2 * Copyright 2004 Paul Brossier
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public License
6 * as published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 /* this file originally taken from Fluidsynth, Peter Hanappe and others. */
23 * Midi driver for the Advanced Linux Sound Architecture (sequencer mode)
27 #include "aubio_priv.h"
29 #include "midi_event.h"
30 #include "midi_parser.h"
31 #include "midi_driver.h"
36 #define ALSA_PCM_NEW_HW_PARAMS_API
37 #include <alsa/asoundlib.h>
42 /* #include <errno.h> //perror is in stdio.h */
46 #include <ladcca/ladcca.h>
47 extern cca_client_t * aubio_cca_client;
48 #endif /* LADCCA_SUPPORT */
50 #define AUBIO_ALSA_DEFAULT_SEQ_DEVICE "default"
52 #define AUBIO_ALSA_BUFFER_LENGTH 512
54 /* SCHED_FIFO priorities for ALSA threads (see pthread_attr_setschedparam) */
55 #define ALSA_RAWMIDI_SCHED_PRIORITY 90
56 #define ALSA_SEQ_SCHED_PRIORITY 90
59 /** aubio_alsa_seq_driver_t */
61 aubio_midi_driver_t driver;
62 snd_seq_t *seq_handle;
68 } aubio_alsa_seq_driver_t;
70 aubio_midi_driver_t* new_aubio_alsa_seq_driver(//aubio_settings_t* settings,
71 handle_midi_event_func_t handler,
73 int del_aubio_alsa_seq_driver(aubio_midi_driver_t* p);
74 static void* aubio_alsa_seq_run(void* d);
76 //void aubio_alsa_seq_driver_settings(aubio_settings_t* settings)
78 // aubio_settings_register_str(settings, "midi.alsa_seq.device", "default", 0, NULL, NULL);
79 // aubio_settings_register_str(settings, "midi.alsa_seq.id", "pid", 0, NULL, NULL);
82 /** new_aubio_alsa_seq_driver */
83 aubio_midi_driver_t* new_aubio_alsa_seq_driver(//aubio_settings_t* settings,
84 handle_midi_event_func_t handler, void* data)
87 aubio_alsa_seq_driver_t* dev; /**< object to return */
88 pthread_attr_t attr; /**< sequencer thread */
89 int sched = SCHED_FIFO; /**< default scheduling policy */
90 struct sched_param priority; /**< scheduling priority settings */
91 int count; /**< number of MIDI file descriptors */
92 struct pollfd *pfd = NULL; /**< poll file descriptor array (copied in dev->pfd) */
93 char* device = NULL; /**< the device name */
98 /* not much use doing anything */
99 if (handler == NULL) {
100 AUBIO_ERR( "Invalid argument");
104 /* allocate the device */
105 dev = AUBIO_NEW(aubio_alsa_seq_driver_t);
107 AUBIO_ERR( "Out of memory");
110 AUBIO_MEMSET(dev, 0, sizeof(aubio_alsa_seq_driver_t));
112 dev->driver.data = data;
113 dev->driver.handler = handler;
115 /* get the device name. if none is specified, use the default device. */
116 //aubio_settings_getstr(settings, "midi.alsa_seq.device", &device);
117 if (device == NULL) {
121 /* open the sequencer INPUT only, non-blocking */
122 //if ((err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_INPUT,
123 if ((err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_DUPLEX,
124 SND_SEQ_NONBLOCK)) < 0) {
125 AUBIO_ERR( "Error opening ALSA sequencer");
129 /* tell the ladcca server our client id */
130 #ifdef LADCCA_SUPPORT
132 int enable_ladcca = 1;
133 //aubio_settings_getint (settings, "ladcca.enable", &enable_ladcca);
135 cca_alsa_client_id (aubio_cca_client, snd_seq_client_id (dev->seq_handle));
137 #endif /* LADCCA_SUPPORT */
139 /* get # of MIDI file descriptors */
140 count = snd_seq_poll_descriptors_count(dev->seq_handle, POLLIN);
141 if (count > 0) { /* make sure there are some */
142 pfd = AUBIO_MALLOC(sizeof (struct pollfd) * count);
143 dev->pfd = AUBIO_MALLOC(sizeof (struct pollfd) * count);
144 /* grab file descriptor POLL info structures */
145 count = snd_seq_poll_descriptors(dev->seq_handle, pfd, count, POLLIN);
148 for (i = 0; i < count; i++) { /* loop over file descriptors */
149 /* copy the input FDs */
150 if (pfd[i].events & POLLIN) { /* use only the input FDs */
151 dev->pfd[dev->npfd].fd = pfd[i].fd;
152 dev->pfd[dev->npfd].events = POLLIN;
153 dev->pfd[dev->npfd].revents = 0;
159 //aubio_settings_getstr(settings, "midi.alsa_seq.id", &id);
162 if (AUBIO_STRCMP(id, "pid") == 0) {
163 snprintf(full_id, 64, "aubio (%d)", getpid());
164 snprintf(full_name, 64, "aubio_port (%d)", getpid());
166 snprintf(full_id, 64, "aubio (%s)", id);
167 snprintf(full_name, 64, "aubio_port (%s)", id);
170 snprintf(full_id, 64, "aubio");
171 snprintf(full_name, 64, "aubio_port");
174 /* set the client name */
175 snd_seq_set_client_name (dev->seq_handle, full_id);
177 if ((dev->seq_port = snd_seq_create_simple_port (dev->seq_handle,
179 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE |
180 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ |
181 SND_SEQ_PORT_CAP_DUPLEX,
182 SND_SEQ_PORT_TYPE_APPLICATION)) < 0)
184 AUBIO_ERR( "Error creating ALSA sequencer port");
188 dev->status = AUBIO_MIDI_READY;
190 /* create the midi thread */
191 if (pthread_attr_init(&attr)) {
192 AUBIO_ERR( "Couldn't initialize midi thread attributes");
196 /* use fifo scheduling. if it fails, use default scheduling. */
198 err = pthread_attr_setschedpolicy(&attr, sched);
200 AUBIO_MSG( "Couldn't set high priority scheduling for the MIDI input");
201 if (sched == SCHED_FIFO) {
205 AUBIO_ERR( "Couldn't set scheduling policy.");
210 /* SCHED_FIFO will not be active without setting the priority */
211 priority.sched_priority = (sched == SCHED_FIFO) ? ALSA_SEQ_SCHED_PRIORITY : 0;
212 pthread_attr_setschedparam (&attr, &priority);
214 err = pthread_create(&dev->thread, &attr, aubio_alsa_seq_run, (void*) dev);
216 AUBIO_ERR( "Couldn't set high priority scheduling for the MIDI input");
217 if (sched == SCHED_FIFO) {
221 //AUBIO_LOG(AUBIO_PANIC, "Couldn't create the midi thread.");
222 AUBIO_ERR( "Couldn't create the midi thread.");
228 return (aubio_midi_driver_t*) dev;
232 del_aubio_alsa_seq_driver((aubio_midi_driver_t*) dev);
236 /** del_aubio_alsa_seq_driver */
237 int del_aubio_alsa_seq_driver(aubio_midi_driver_t* p)
239 aubio_alsa_seq_driver_t* dev;
241 dev = (aubio_alsa_seq_driver_t*) p;
246 dev->status = AUBIO_MIDI_DONE;
248 /* cancel the thread and wait for it before cleaning up */
250 if (pthread_cancel(dev->thread)) {
251 AUBIO_ERR( "Failed to cancel the midi thread");
254 if (pthread_join(dev->thread, NULL)) {
255 AUBIO_ERR( "Failed to join the midi thread");
259 if (dev->seq_port >= 0) {
260 snd_seq_delete_simple_port (dev->seq_handle, dev->seq_port);
262 if (dev->seq_handle) {
263 snd_seq_drain_output(dev->seq_handle);
264 snd_seq_close(dev->seq_handle);
270 /** aubio_alsa_seq_run */
271 void* aubio_alsa_seq_run(void* d)
274 snd_seq_event_t *seq_ev;
275 aubio_midi_event_t evt;
276 aubio_alsa_seq_driver_t* dev = (aubio_alsa_seq_driver_t*) d;
278 /* make sure the other threads can cancel this thread any time */
279 if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
280 AUBIO_ERR( "Failed to set the cancel state of the midi thread");
283 if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
284 AUBIO_ERR( "Failed to set the cancel state of the midi thread");
288 /* go into a loop until someone tells us to stop */
289 dev->status = AUBIO_MIDI_LISTENING;
290 while (dev->status == AUBIO_MIDI_LISTENING) {
292 /* is there something to read? */
293 n = poll(dev->pfd, dev->npfd, 1); /* use a 1 milliseconds timeout */
298 /* read new events from the midi input port */
299 while ((n = snd_seq_event_input(dev->seq_handle, &seq_ev)) >= 0)
301 switch (seq_ev->type)
303 case SND_SEQ_EVENT_NOTEON:
305 evt.channel = seq_ev->data.note.channel;
306 evt.param1 = seq_ev->data.note.note;
307 evt.param2 = seq_ev->data.note.velocity;
309 case SND_SEQ_EVENT_NOTEOFF:
311 evt.channel = seq_ev->data.note.channel;
312 evt.param1 = seq_ev->data.note.note;
313 evt.param2 = seq_ev->data.note.velocity;
315 case SND_SEQ_EVENT_KEYPRESS:
316 evt.type = KEY_PRESSURE;
317 evt.channel = seq_ev->data.note.channel;
318 evt.param1 = seq_ev->data.note.note;
319 evt.param2 = seq_ev->data.note.velocity;
321 case SND_SEQ_EVENT_CONTROLLER:
322 evt.type = CONTROL_CHANGE;
323 evt.channel = seq_ev->data.control.channel;
324 evt.param1 = seq_ev->data.control.param;
325 evt.param2 = seq_ev->data.control.value;
327 case SND_SEQ_EVENT_PITCHBEND:
328 evt.type = PITCH_BEND;
329 evt.channel = seq_ev->data.control.channel;
330 /* ALSA pitch bend is -8192 - 8191, we adjust it here */
331 evt.param1 = seq_ev->data.control.value + 8192;
333 case SND_SEQ_EVENT_PGMCHANGE:
334 evt.type = PROGRAM_CHANGE;
335 evt.channel = seq_ev->data.control.channel;
336 evt.param1 = seq_ev->data.control.value;
338 case SND_SEQ_EVENT_CHANPRESS:
339 evt.type = CHANNEL_PRESSURE;
340 evt.channel = seq_ev->data.control.channel;
341 evt.param1 = seq_ev->data.control.value;
344 continue; /* unhandled event, next loop iteration */
347 /* send the events to the next link in the chain */
348 (*dev->driver.handler)(dev->driver.data, &evt);
350 /* dump input on output */
351 //snd_seq_ev_set_source(new_ev, dev->seq_port);
352 //snd_seq_ev_set_dest(seq_ev,dev->seq_handle,dev->seq_client);
353 //snd_seq_ev_set_subs(new_ev);
354 //snd_seq_ev_set_direct(new_ev);
355 //snd_seq_event_output(dev->seq_handle, new_ev);
356 //snd_seq_drain_output(dev->seq_handle);
361 if ((n < 0) && (n != -EAGAIN)) {
362 AUBIO_ERR( "Error occured while reading ALSA sequencer events");
363 dev->status = AUBIO_MIDI_DONE;
366 // /* added by piem to handle new data to output */
367 // while (/* get new data, but from where ??? (n = snd_seq_event_output(dev->seq_handle, seq_ev)) >= 0*/ )
369 // /* dump input on output */
370 // snd_seq_ev_set_source(new_ev, dev->seq_port);
371 // //snd_seq_ev_set_dest(seq_ev,dev->seq_handle,dev->seq_client);
372 // snd_seq_ev_set_subs(new_ev);
373 // snd_seq_ev_set_direct(new_ev);
374 // snd_seq_event_output(dev->seq_handle, new_ev);
375 // snd_seq_drain_output(dev->seq_handle);
385 void aubio_midi_direct_output(aubio_midi_driver_t * d, aubio_midi_event_t * event)
387 aubio_alsa_seq_driver_t* dev = (aubio_alsa_seq_driver_t*) d;
389 if (pthread_join(dev->thread, NULL)) {
390 AUBIO_ERR( "Failed to join the midi thread");
396 ev.type = SND_SEQ_EVENT_NOTEON;
397 ev.data.note.channel = event->channel;
398 ev.data.note.note = event->param1;
399 ev.data.note.velocity = event->param2;
400 //AUBIO_ERR( "NOTE_ON %d\n", event->param1);
403 ev.type = SND_SEQ_EVENT_NOTEOFF;
404 ev.data.note.channel = event->channel;
405 ev.data.note.note = event->param1;
406 ev.data.note.velocity = event->param2;
407 //AUBIO_ERR( "NOTE_OFF %d\n", event->param1);
412 if (ev.type == SND_SEQ_EVENT_NOTEOFF || ev.type == SND_SEQ_EVENT_NOTEON ) {
413 snd_seq_ev_set_subs(&ev);
414 snd_seq_ev_set_direct(&ev);
415 snd_seq_ev_set_source(&ev, dev->seq_port);
416 snd_seq_event_output_direct(dev->seq_handle, &ev);
419 if (pthread_detach(dev->thread)) {
420 AUBIO_ERR( "Failed to leave the midi thread");
425 #endif /* #if ALSA_SUPPORT */