source: ext/midi/midi_alsa_seq.c @ ae7277c

feature/autosinkfeature/cnnfeature/cnn_orgfeature/constantqfeature/crepefeature/crepe_orgfeature/pitchshiftfeature/pydocstringsfeature/timestretchfix/ffmpeg5pitchshiftsamplertimestretchyinfft+
Last change on this file since ae7277c was ae7277c, checked in by Paul Brossier <piem@altern.org>, 18 years ago

removing ladcca from ext/midi/midi_alsa_seq.c
removing ladcca from ext/midi/midi_alsa_seq.c

  • Property mode set to 100644
File size: 14.0 KB
Line 
1/*
2 * Copyright 2004 Paul Brossier
3 *
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.
8 *
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.
13 * 
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
17 * 02111-1307, USA
18 */
19
20/* this file originally taken from Fluidsynth, Peter Hanappe and others. */
21
22/** \file
23 * Midi driver for the Advanced Linux Sound Architecture (sequencer mode)
24 */
25
26
27#include "aubio_priv.h"
28#include "midi.h"
29#include "midi_event.h"
30#include "midi_parser.h"
31#include "midi_driver.h"
32#include "config.h"
33
34#if ALSA_SUPPORT
35
36#define ALSA_PCM_NEW_HW_PARAMS_API
37#include <alsa/asoundlib.h>
38#include <pthread.h>
39#include <fcntl.h>
40#include <unistd.h>
41#include <sys/poll.h>
42/* #include <errno.h> //perror is in stdio.h */
43
44#define AUBIO_ALSA_DEFAULT_SEQ_DEVICE   "default"
45
46#define AUBIO_ALSA_BUFFER_LENGTH 512
47
48/* SCHED_FIFO priorities for ALSA threads (see pthread_attr_setschedparam) */
49#define ALSA_RAWMIDI_SCHED_PRIORITY 90
50#define ALSA_SEQ_SCHED_PRIORITY 90
51
52
53/** aubio_alsa_seq_driver_t */
54typedef struct {
55    aubio_midi_driver_t driver;
56    snd_seq_t *seq_handle;
57    int seq_port;
58    struct pollfd *pfd;
59    int npfd;
60    pthread_t thread;
61    int status;
62} aubio_alsa_seq_driver_t;
63
64aubio_midi_driver_t* new_aubio_alsa_seq_driver(//aubio_settings_t* settings,
65        handle_midi_event_func_t handler, 
66        void* data);
67int del_aubio_alsa_seq_driver(aubio_midi_driver_t* p);
68static void* aubio_alsa_seq_run(void* d);
69
70//void aubio_alsa_seq_driver_settings(aubio_settings_t* settings)
71//{
72//  aubio_settings_register_str(settings, "midi.alsa_seq.device", "default", 0, NULL, NULL);
73//  aubio_settings_register_str(settings, "midi.alsa_seq.id", "pid", 0, NULL, NULL);
74//}
75
76/** new_aubio_alsa_seq_driver */
77aubio_midi_driver_t*  new_aubio_alsa_seq_driver(//aubio_settings_t* settings,
78        handle_midi_event_func_t handler, void* data)
79{
80    int i, err;                     
81    aubio_alsa_seq_driver_t* dev;   /**< object to return */
82    pthread_attr_t attr;            /**< sequencer thread */
83    int sched = SCHED_FIFO;         /**< default scheduling policy */
84    struct sched_param priority;    /**< scheduling priority settings */
85    int count;                      /**< number of MIDI file descriptors */
86    struct pollfd *pfd = NULL;      /**< poll file descriptor array (copied in dev->pfd) */
87    char* device = NULL;            /**< the device name */
88    char* id = NULL;
89    char full_id[64];
90    char full_name[64];
91
92    /* not much use doing anything */
93    if (handler == NULL) {
94        AUBIO_ERR( "Invalid argument");
95        return NULL;
96    }
97
98    /* allocate the device */
99    dev = AUBIO_NEW(aubio_alsa_seq_driver_t);
100    if (dev == NULL) {
101        AUBIO_ERR( "Out of memory");
102        return NULL;
103    }
104    AUBIO_MEMSET(dev, 0, sizeof(aubio_alsa_seq_driver_t));
105    dev->seq_port = -1;
106    dev->driver.data = data;
107    dev->driver.handler = handler;
108
109    /* get the device name. if none is specified, use the default device. */
110    //aubio_settings_getstr(settings, "midi.alsa_seq.device", &device);
111    if (device == NULL) {
112        device = "default";
113    }
114
115    /* open the sequencer INPUT only, non-blocking */
116    //if ((err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_INPUT,
117    if ((err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_DUPLEX,
118                    SND_SEQ_NONBLOCK)) < 0) {
119        AUBIO_ERR( "Error opening ALSA sequencer");
120        goto error_recovery;
121    }
122
123    /* get # of MIDI file descriptors */
124    count = snd_seq_poll_descriptors_count(dev->seq_handle, POLLIN);
125    if (count > 0) {        /* make sure there are some */
126        pfd = AUBIO_MALLOC(sizeof (struct pollfd) * count);
127        dev->pfd = AUBIO_MALLOC(sizeof (struct pollfd) * count);
128        /* grab file descriptor POLL info structures */
129        count = snd_seq_poll_descriptors(dev->seq_handle, pfd, count, POLLIN);
130    }
131
132    for (i = 0; i < count; i++) {        /* loop over file descriptors */
133        /* copy the input FDs */
134        if (pfd[i].events & POLLIN) { /* use only the input FDs */
135            dev->pfd[dev->npfd].fd = pfd[i].fd;
136            dev->pfd[dev->npfd].events = POLLIN; 
137            dev->pfd[dev->npfd].revents = 0; 
138            dev->npfd++;
139        }
140    }
141    AUBIO_FREE(pfd);
142
143    //aubio_settings_getstr(settings, "midi.alsa_seq.id", &id);
144
145    if (id != NULL) {
146        if (AUBIO_STRCMP(id, "pid") == 0) {
147            snprintf(full_id, 64, "aubio (%d)", getpid());
148            snprintf(full_name, 64, "aubio_port (%d)", getpid());
149        } else {
150            snprintf(full_id, 64, "aubio (%s)", id);
151            snprintf(full_name, 64, "aubio_port (%s)", id);
152        }
153    } else {
154        snprintf(full_id, 64, "aubio");
155        snprintf(full_name, 64, "aubio_port");
156    }
157
158    /* set the client name */
159    snd_seq_set_client_name (dev->seq_handle, full_id);
160
161    if ((dev->seq_port = snd_seq_create_simple_port (dev->seq_handle,
162                    full_name,
163                    SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE |
164                    SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ | 
165                    SND_SEQ_PORT_CAP_DUPLEX,
166                    SND_SEQ_PORT_TYPE_APPLICATION)) < 0)
167    {
168        AUBIO_ERR( "Error creating ALSA sequencer port");
169        goto error_recovery;
170    }
171
172    dev->status = AUBIO_MIDI_READY;
173
174    /* create the midi thread */
175    if (pthread_attr_init(&attr)) {
176        AUBIO_ERR( "Couldn't initialize midi thread attributes");
177        goto error_recovery;
178    }
179
180    /* use fifo scheduling. if it fails, use default scheduling. */
181    while (1) {
182        err = pthread_attr_setschedpolicy(&attr, sched);
183        if (err) {
184            AUBIO_MSG( "Couldn't set high priority scheduling for the MIDI input");
185            if (sched == SCHED_FIFO) {
186                sched = SCHED_OTHER;
187                continue;
188            } else {
189                AUBIO_ERR( "Couldn't set scheduling policy.");
190                goto error_recovery;
191            }
192        }
193
194        /* SCHED_FIFO will not be active without setting the priority */
195        priority.sched_priority = (sched == SCHED_FIFO) ? ALSA_SEQ_SCHED_PRIORITY : 0;
196        pthread_attr_setschedparam (&attr, &priority);
197
198        err = pthread_create(&dev->thread, &attr, aubio_alsa_seq_run, (void*) dev);
199        if (err) {
200            AUBIO_ERR( "Couldn't set high priority scheduling for the MIDI input");
201            if (sched == SCHED_FIFO) {
202                sched = SCHED_OTHER;
203                continue;
204            } else {
205                //AUBIO_LOG(AUBIO_PANIC, "Couldn't create the midi thread.");
206                AUBIO_ERR( "Couldn't create the midi thread.");
207                goto error_recovery;
208            }
209        }
210        break;
211    }
212    return (aubio_midi_driver_t*) dev;
213
214
215error_recovery:
216    del_aubio_alsa_seq_driver((aubio_midi_driver_t*) dev);
217    return NULL;
218}
219
220/** del_aubio_alsa_seq_driver */
221int del_aubio_alsa_seq_driver(aubio_midi_driver_t* p)
222{
223    aubio_alsa_seq_driver_t* dev;
224
225    dev = (aubio_alsa_seq_driver_t*) p;
226    if (dev == NULL) {
227        return AUBIO_OK;
228    }
229
230    dev->status = AUBIO_MIDI_DONE;
231
232    /* cancel the thread and wait for it before cleaning up */
233    if (dev->thread) {
234        if (pthread_cancel(dev->thread)) {
235            AUBIO_ERR( "Failed to cancel the midi thread");
236            return AUBIO_FAIL;
237        }
238        if (pthread_join(dev->thread, NULL)) {
239            AUBIO_ERR( "Failed to join the midi thread");
240            return AUBIO_FAIL;
241        }
242    }
243    if (dev->seq_port >= 0) {
244        snd_seq_delete_simple_port (dev->seq_handle, dev->seq_port);
245    }
246    if (dev->seq_handle) {
247        snd_seq_drain_output(dev->seq_handle);
248        snd_seq_close(dev->seq_handle);
249    }
250    AUBIO_FREE(dev);
251    return AUBIO_OK;
252}
253
254/** aubio_alsa_seq_run */
255void* aubio_alsa_seq_run(void* d)
256{
257    int n;//, i;
258    snd_seq_event_t *seq_ev;
259    aubio_midi_event_t evt;
260    aubio_alsa_seq_driver_t* dev = (aubio_alsa_seq_driver_t*) d;
261
262    /* make sure the other threads can cancel this thread any time */
263    if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
264        AUBIO_ERR( "Failed to set the cancel state of the midi thread");
265        pthread_exit(NULL);
266    }
267    if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
268        AUBIO_ERR( "Failed to set the cancel state of the midi thread");
269        pthread_exit(NULL);
270    }
271
272    /* go into a loop until someone tells us to stop */
273    dev->status = AUBIO_MIDI_LISTENING;
274    while (dev->status == AUBIO_MIDI_LISTENING) {
275
276        /* is there something to read? */
277        n = poll(dev->pfd, dev->npfd, 1); /* use a 1 milliseconds timeout */
278        if (n < 0) {
279            perror("poll");
280        } else if (n > 0) {
281
282            /* read new events from the midi input port */
283            while ((n = snd_seq_event_input(dev->seq_handle, &seq_ev)) >= 0)
284            {
285                switch (seq_ev->type)
286                {
287                    case SND_SEQ_EVENT_NOTEON:
288                        evt.type = NOTE_ON;
289                        evt.channel = seq_ev->data.note.channel;
290                        evt.param1 = seq_ev->data.note.note;
291                        evt.param2 = seq_ev->data.note.velocity;
292                        break;
293                    case SND_SEQ_EVENT_NOTEOFF:
294                        evt.type = NOTE_OFF;
295                        evt.channel = seq_ev->data.note.channel;
296                        evt.param1 = seq_ev->data.note.note;
297                        evt.param2 = seq_ev->data.note.velocity;
298                        break;
299                    case SND_SEQ_EVENT_KEYPRESS:
300                        evt.type = KEY_PRESSURE;
301                        evt.channel = seq_ev->data.note.channel;
302                        evt.param1 = seq_ev->data.note.note;
303                        evt.param2 = seq_ev->data.note.velocity;
304                        break;
305                    case SND_SEQ_EVENT_CONTROLLER:
306                        evt.type = CONTROL_CHANGE;
307                        evt.channel = seq_ev->data.control.channel;
308                        evt.param1 = seq_ev->data.control.param;
309                        evt.param2 = seq_ev->data.control.value;
310                        break;
311                    case SND_SEQ_EVENT_PITCHBEND:
312                        evt.type = PITCH_BEND;
313                        evt.channel = seq_ev->data.control.channel;
314                        /* ALSA pitch bend is -8192 - 8191, we adjust it here */
315                        evt.param1 = seq_ev->data.control.value + 8192;
316                        break;
317                    case SND_SEQ_EVENT_PGMCHANGE:
318                        evt.type = PROGRAM_CHANGE;
319                        evt.channel = seq_ev->data.control.channel;
320                        evt.param1 = seq_ev->data.control.value;
321                        break;
322                    case SND_SEQ_EVENT_CHANPRESS:
323                        evt.type = CHANNEL_PRESSURE;
324                        evt.channel = seq_ev->data.control.channel;
325                        evt.param1 = seq_ev->data.control.value;
326                        break;
327                    default:
328                        continue;        /* unhandled event, next loop iteration */
329                }
330
331                /* send the events to the next link in the chain */
332                (*dev->driver.handler)(dev->driver.data, &evt);
333               
334                /* dump input on output */
335                //snd_seq_ev_set_source(new_ev, dev->seq_port);
336                //snd_seq_ev_set_dest(seq_ev,dev->seq_handle,dev->seq_client);
337                //snd_seq_ev_set_subs(new_ev);
338                //snd_seq_ev_set_direct(new_ev);
339                //snd_seq_event_output(dev->seq_handle, new_ev);
340                //snd_seq_drain_output(dev->seq_handle);
341
342            }
343        }
344
345        if ((n < 0) && (n != -EAGAIN)) {
346            AUBIO_ERR( "Error occured while reading ALSA sequencer events");
347            dev->status = AUBIO_MIDI_DONE;
348        }
349
350//        /* added by piem to handle new data to output */
351//        while (/* get new data, but from where ??? (n = snd_seq_event_output(dev->seq_handle, seq_ev)) >= 0*/ )
352//        {
353//            /* dump input on output */
354//            snd_seq_ev_set_source(new_ev, dev->seq_port);
355//            //snd_seq_ev_set_dest(seq_ev,dev->seq_handle,dev->seq_client);
356//            snd_seq_ev_set_subs(new_ev);
357//            snd_seq_ev_set_direct(new_ev);
358//            snd_seq_event_output(dev->seq_handle, new_ev);
359//            snd_seq_drain_output(dev->seq_handle);
360//        }
361
362    }
363    pthread_exit(NULL);
364}
365
366
367snd_seq_event_t ev;
368
369void aubio_midi_direct_output(aubio_midi_driver_t * d, aubio_midi_event_t * event) 
370{
371    aubio_alsa_seq_driver_t* dev = (aubio_alsa_seq_driver_t*) d;
372    switch(event->type) 
373    {
374        case NOTE_ON:
375            ev.type = SND_SEQ_EVENT_NOTEON;
376            ev.data.note.channel  = event->channel;
377            ev.data.note.note     = event->param1;
378            ev.data.note.velocity = event->param2;
379            //AUBIO_ERR( "NOTE_ON %d\n", event->param1);
380            break;
381        case NOTE_OFF:
382            ev.type = SND_SEQ_EVENT_NOTEOFF;
383            ev.data.note.channel  = event->channel;
384            ev.data.note.note     = event->param1;
385            ev.data.note.velocity = event->param2;
386            //AUBIO_ERR( "NOTE_OFF %d\n", event->param1);
387            break;
388        default:
389            break;
390    }
391    if (ev.type == SND_SEQ_EVENT_NOTEOFF || ev.type == SND_SEQ_EVENT_NOTEON ) { 
392        snd_seq_ev_set_subs(&ev);
393        snd_seq_ev_set_direct(&ev);
394        snd_seq_ev_set_source(&ev, dev->seq_port);
395        snd_seq_event_output_direct(dev->seq_handle, &ev);
396    }
397}
398
399#endif /* #if ALSA_SUPPORT */
Note: See TracBrowser for help on using the repository browser.