source: src/midi_alsa_seq.c @ 96fb8ad

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

import 0.1.7.1

  • Property mode set to 100644
File size: 14.7 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
45#ifdef LADCCA_SUPPORT
46#include <ladcca/ladcca.h>
47extern cca_client_t * aubio_cca_client;
48#endif /* LADCCA_SUPPORT */
49
50#define AUBIO_ALSA_DEFAULT_SEQ_DEVICE   "default"
51
52#define AUBIO_ALSA_BUFFER_LENGTH 512
53
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
57
58
59/** aubio_alsa_seq_driver_t */
60typedef struct {
61    aubio_midi_driver_t driver;
62    snd_seq_t *seq_handle;
63    int seq_port;
64    struct pollfd *pfd;
65    int npfd;
66    pthread_t thread;
67    int status;
68} aubio_alsa_seq_driver_t;
69
70aubio_midi_driver_t* new_aubio_alsa_seq_driver(//aubio_settings_t* settings,
71        handle_midi_event_func_t handler, 
72        void* data);
73int del_aubio_alsa_seq_driver(aubio_midi_driver_t* p);
74static void* aubio_alsa_seq_run(void* d);
75
76//void aubio_alsa_seq_driver_settings(aubio_settings_t* settings)
77//{
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);
80//}
81
82/** new_aubio_alsa_seq_driver */
83aubio_midi_driver_t*  new_aubio_alsa_seq_driver(//aubio_settings_t* settings,
84        handle_midi_event_func_t handler, void* data)
85{
86    int i, err;                     
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 */
94    char* id = NULL;
95    char full_id[64];
96    char full_name[64];
97
98    /* not much use doing anything */
99    if (handler == NULL) {
100        AUBIO_ERR( "Invalid argument");
101        return NULL;
102    }
103
104    /* allocate the device */
105    dev = AUBIO_NEW(aubio_alsa_seq_driver_t);
106    if (dev == NULL) {
107        AUBIO_ERR( "Out of memory");
108        return NULL;
109    }
110    AUBIO_MEMSET(dev, 0, sizeof(aubio_alsa_seq_driver_t));
111    dev->seq_port = -1;
112    dev->driver.data = data;
113    dev->driver.handler = handler;
114
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) {
118        device = "default";
119    }
120
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");
126        goto error_recovery;
127    }
128
129    /* tell the ladcca server our client id */
130#ifdef LADCCA_SUPPORT
131    {
132        int enable_ladcca = 1;
133        //aubio_settings_getint (settings, "ladcca.enable", &enable_ladcca);
134        if (enable_ladcca)
135            cca_alsa_client_id (aubio_cca_client, snd_seq_client_id (dev->seq_handle));
136    }
137#endif /* LADCCA_SUPPORT */
138
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);
146    }
147
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; 
154            dev->npfd++;
155        }
156    }
157    AUBIO_FREE(pfd);
158
159    //aubio_settings_getstr(settings, "midi.alsa_seq.id", &id);
160
161    if (id != NULL) {
162        if (AUBIO_STRCMP(id, "pid") == 0) {
163            snprintf(full_id, 64, "aubio (%d)", getpid());
164            snprintf(full_name, 64, "aubio_port (%d)", getpid());
165        } else {
166            snprintf(full_id, 64, "aubio (%s)", id);
167            snprintf(full_name, 64, "aubio_port (%s)", id);
168        }
169    } else {
170        snprintf(full_id, 64, "aubio");
171        snprintf(full_name, 64, "aubio_port");
172    }
173
174    /* set the client name */
175    snd_seq_set_client_name (dev->seq_handle, full_id);
176
177    if ((dev->seq_port = snd_seq_create_simple_port (dev->seq_handle,
178                    full_name,
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)
183    {
184        AUBIO_ERR( "Error creating ALSA sequencer port");
185        goto error_recovery;
186    }
187
188    dev->status = AUBIO_MIDI_READY;
189
190    /* create the midi thread */
191    if (pthread_attr_init(&attr)) {
192        AUBIO_ERR( "Couldn't initialize midi thread attributes");
193        goto error_recovery;
194    }
195
196    /* use fifo scheduling. if it fails, use default scheduling. */
197    while (1) {
198        err = pthread_attr_setschedpolicy(&attr, sched);
199        if (err) {
200            AUBIO_MSG( "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_ERR( "Couldn't set scheduling policy.");
206                goto error_recovery;
207            }
208        }
209
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);
213
214        err = pthread_create(&dev->thread, &attr, aubio_alsa_seq_run, (void*) dev);
215        if (err) {
216            AUBIO_ERR( "Couldn't set high priority scheduling for the MIDI input");
217            if (sched == SCHED_FIFO) {
218                sched = SCHED_OTHER;
219                continue;
220            } else {
221                //AUBIO_LOG(AUBIO_PANIC, "Couldn't create the midi thread.");
222                AUBIO_ERR( "Couldn't create the midi thread.");
223                goto error_recovery;
224            }
225        }
226        break;
227    }
228    return (aubio_midi_driver_t*) dev;
229
230
231error_recovery:
232    del_aubio_alsa_seq_driver((aubio_midi_driver_t*) dev);
233    return NULL;
234}
235
236/** del_aubio_alsa_seq_driver */
237int del_aubio_alsa_seq_driver(aubio_midi_driver_t* p)
238{
239    aubio_alsa_seq_driver_t* dev;
240
241    dev = (aubio_alsa_seq_driver_t*) p;
242    if (dev == NULL) {
243        return AUBIO_OK;
244    }
245
246    dev->status = AUBIO_MIDI_DONE;
247
248    /* cancel the thread and wait for it before cleaning up */
249    if (dev->thread) {
250        if (pthread_cancel(dev->thread)) {
251            AUBIO_ERR( "Failed to cancel the midi thread");
252            return AUBIO_FAIL;
253        }
254        if (pthread_join(dev->thread, NULL)) {
255            AUBIO_ERR( "Failed to join the midi thread");
256            return AUBIO_FAIL;
257        }
258    }
259    if (dev->seq_port >= 0) {
260        snd_seq_delete_simple_port (dev->seq_handle, dev->seq_port);
261    }
262    if (dev->seq_handle) {
263        snd_seq_drain_output(dev->seq_handle);
264        snd_seq_close(dev->seq_handle);
265    }
266    AUBIO_FREE(dev);
267    return AUBIO_OK;
268}
269
270/** aubio_alsa_seq_run */
271void* aubio_alsa_seq_run(void* d)
272{
273    int n;//, i;
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;
277
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");
281        pthread_exit(NULL);
282    }
283    if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
284        AUBIO_ERR( "Failed to set the cancel state of the midi thread");
285        pthread_exit(NULL);
286    }
287
288    /* go into a loop until someone tells us to stop */
289    dev->status = AUBIO_MIDI_LISTENING;
290    while (dev->status == AUBIO_MIDI_LISTENING) {
291
292        /* is there something to read? */
293        n = poll(dev->pfd, dev->npfd, 1); /* use a 1 milliseconds timeout */
294        if (n < 0) {
295            perror("poll");
296        } else if (n > 0) {
297
298            /* read new events from the midi input port */
299            while ((n = snd_seq_event_input(dev->seq_handle, &seq_ev)) >= 0)
300            {
301                switch (seq_ev->type)
302                {
303                    case SND_SEQ_EVENT_NOTEON:
304                        evt.type = NOTE_ON;
305                        evt.channel = seq_ev->data.note.channel;
306                        evt.param1 = seq_ev->data.note.note;
307                        evt.param2 = seq_ev->data.note.velocity;
308                        break;
309                    case SND_SEQ_EVENT_NOTEOFF:
310                        evt.type = NOTE_OFF;
311                        evt.channel = seq_ev->data.note.channel;
312                        evt.param1 = seq_ev->data.note.note;
313                        evt.param2 = seq_ev->data.note.velocity;
314                        break;
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;
320                        break;
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;
326                        break;
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;
332                        break;
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;
337                        break;
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;
342                        break;
343                    default:
344                        continue;        /* unhandled event, next loop iteration */
345                }
346
347                /* send the events to the next link in the chain */
348                (*dev->driver.handler)(dev->driver.data, &evt);
349               
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);
357
358            }
359        }
360
361        if ((n < 0) && (n != -EAGAIN)) {
362            AUBIO_ERR( "Error occured while reading ALSA sequencer events");
363            dev->status = AUBIO_MIDI_DONE;
364        }
365
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*/ )
368//        {
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);
376//        }
377
378    }
379    pthread_exit(NULL);
380}
381
382
383snd_seq_event_t ev;
384
385void aubio_midi_direct_output(aubio_midi_driver_t * d, aubio_midi_event_t * event) 
386{
387    aubio_alsa_seq_driver_t* dev = (aubio_alsa_seq_driver_t*) d;
388    /*
389    if (pthread_join(dev->thread, NULL)) {
390        AUBIO_ERR( "Failed to join the midi thread");
391    }
392    */
393    switch(event->type) 
394    {
395        case NOTE_ON:
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);
401            break;
402        case NOTE_OFF:
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);
408            break;
409        default:
410            break;
411    }
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);
417    }
418    /*
419    if (pthread_detach(dev->thread)) {
420        AUBIO_ERR( "Failed to leave the midi thread");
421    }
422    */
423}
424
425#endif /* #if ALSA_SUPPORT */
Note: See TracBrowser for help on using the repository browser.