source: src/midi_alsa_raw.c @ 33bf500

feature/autosinkfeature/cnnfeature/cnn_orgfeature/constantqfeature/crepefeature/crepe_orgfeature/pitchshiftfeature/pydocstringsfeature/timestretchfix/ffmpeg5pitchshiftsamplertimestretchyinfft+
Last change on this file since 33bf500 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: 9.2 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
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
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#include "config.h"
45
46#ifdef LADCCA_SUPPORT
47#include <ladcca/ladcca.h>
48extern cca_client_t * aubio_cca_client;
49#endif /* LADCCA_SUPPORT */
50
51
52#define AUBIO_ALSA_DEFAULT_MIDI_DEVICE  "default"
53
54/** \bug double define? */
55#define AUBIO_ALSA_BUFFER_LENGTH 512
56
57/* SCHED_FIFO priorities for ALSA threads (see pthread_attr_setschedparam) */
58#define ALSA_RAWMIDI_SCHED_PRIORITY 90
59#define ALSA_SEQ_SCHED_PRIORITY 90
60
61/** aubio_midi_alsa_raw_driver_t */
62typedef struct {
63  aubio_midi_driver_t driver;
64  snd_rawmidi_t *rawmidi_in;
65  snd_rawmidi_t *rawmidi_out;
66  struct pollfd *pfd;
67  int npfd;
68  pthread_t thread;
69  int status;
70  unsigned char buffer[AUBIO_ALSA_BUFFER_LENGTH];
71  aubio_midi_parser_t* parser;
72} aubio_midi_alsa_raw_driver_t;
73
74aubio_midi_driver_t* new_aubio_midi_alsa_raw_driver(//aubio_settings_t* settings,
75    handle_midi_event_func_t handler, 
76    void* event_handler_data);
77int del_aubio_midi_alsa_raw_driver(aubio_midi_driver_t* p);
78static void* aubio_midi_alsa_raw_run(void* d);
79
80
81/**************************************************************
82 *
83 *        Alsa MIDI driver
84 *
85 */
86
87//void aubio_midi_alsa_raw_driver_settings(aubio_settings_t* settings)
88//{
89//  aubio_settings_register_str(settings, "midi.alsa.device", "default", 0, NULL, NULL);
90//}
91
92/** new_aubio_midi_alsa_raw_driver */
93aubio_midi_driver_t* new_aubio_midi_alsa_raw_driver(
94    //aubio_settings_t* settings,
95    handle_midi_event_func_t handler, 
96    void* data)
97{
98  int i, err;
99  aubio_midi_alsa_raw_driver_t* dev;
100  pthread_attr_t attr;
101  int sched = SCHED_FIFO;
102  struct sched_param priority;
103  int count;
104  struct pollfd *pfd = NULL;
105  char* device = NULL;
106
107  /* not much use doing anything */
108  if (handler == NULL) {
109    AUBIO_ERR("Invalid argument");
110    return NULL;
111  }
112
113  /* allocate the device */
114  dev = AUBIO_NEW(aubio_midi_alsa_raw_driver_t);
115  if (dev == NULL) {
116    AUBIO_ERR( "Out of memory");
117    return NULL;
118  }
119  AUBIO_MEMSET(dev, 0, sizeof(aubio_midi_alsa_raw_driver_t));
120
121  dev->driver.handler = handler;
122  dev->driver.data = data;
123
124  /* allocate one event to store the input data */
125  dev->parser = new_aubio_midi_parser();
126  if (dev->parser == NULL) {
127    AUBIO_ERR( "Out of memory");
128    goto error_recovery;
129  }
130
131  /* get the device name. if none is specified, use the default device. */
132  //aubio_settings_getstr(settings, "midi.alsa.device", &device);
133  if (device == NULL) {
134    device = "default";
135  }
136
137  /* open the hardware device. only use midi in. */
138  if ((err = snd_rawmidi_open(&dev->rawmidi_in, NULL, device, SND_RAWMIDI_NONBLOCK)) < 0) {
139  //if ((err = snd_rawmidi_open(&dev->rawmidi_in, &dev->rawmidi_out, device, SND_RAWMIDI_NONBLOCK)) < 0) {
140    AUBIO_ERR( "Error opening ALSA raw MIDI IN port");
141    goto error_recovery;
142  }
143
144  /* get # of MIDI file descriptors */
145  count = snd_rawmidi_poll_descriptors_count(dev->rawmidi_in);
146  if (count > 0) {              /* make sure there are some */
147    pfd = AUBIO_MALLOC(sizeof (struct pollfd) * count);
148    dev->pfd = AUBIO_MALLOC(sizeof (struct pollfd) * count);
149    /* grab file descriptor POLL info structures */
150    count = snd_rawmidi_poll_descriptors(dev->rawmidi_in, pfd, count);
151  }
152
153  /* copy the input FDs */
154  for (i = 0; i < count; i++) {         /* loop over file descriptors */
155    if (pfd[i].events & POLLIN) { /* use only the input FDs */
156      dev->pfd[dev->npfd].fd = pfd[i].fd;
157      dev->pfd[dev->npfd].events = POLLIN; 
158      dev->pfd[dev->npfd].revents = 0; 
159      dev->npfd++;
160    }
161  }
162  AUBIO_FREE(pfd);
163
164
165 
166  dev->status = AUBIO_MIDI_READY;
167
168  /* create the midi thread */
169  if (pthread_attr_init(&attr)) {
170    AUBIO_ERR( "Couldn't initialize midi thread attributes");
171    goto error_recovery;
172  }
173
174  /* Was: "use fifo scheduling. if it fails, use default scheduling." */
175  /* Now normal scheduling is used by default for the MIDI thread. The reason is,
176   * that fluidsynth works better with low latencies under heavy load, if only the
177   * audio thread is prioritized.
178   * With MIDI at ordinary priority, that could result in individual notes being played
179   * a bit late. On the other hand, if the audio thread is delayed, an audible dropout
180   * is the result.
181   * To reproduce this: Edirol UA-1 USB-MIDI interface, four buffers
182   * with 45 samples each (roughly 4 ms latency), ravewave soundfont. -MN
183   */ 
184
185  /* Not so sure anymore. We're losing MIDI data, if we can't keep up with
186   * the speed it is generated. */
187  /* AUBIO_MSG("Note: High-priority scheduling for the MIDI thread was intentionally disabled.");
188      sched=SCHED_OTHER;*/
189
190  while (1) {
191    err = pthread_attr_setschedpolicy(&attr, sched);
192    if (err) {
193      //AUBIO_LOG(AUBIO_WARN, "Couldn't set high priority scheduling for the MIDI input");
194      AUBIO_MSG( "Couldn't set high priority scheduling for the MIDI input");
195      if (sched == SCHED_FIFO) {
196        sched = SCHED_OTHER;
197        continue;
198      } else {
199        AUBIO_ERR( "Couldn't set scheduling policy.");
200        goto error_recovery;
201      }
202    }
203
204    /* SCHED_FIFO will not be active without setting the priority */
205    priority.sched_priority = (sched == SCHED_FIFO) ? 
206      ALSA_RAWMIDI_SCHED_PRIORITY : 0;
207    pthread_attr_setschedparam (&attr, &priority);
208    err = pthread_create(&dev->thread, &attr, aubio_midi_alsa_raw_run, (void*) dev);
209    if (err) {
210      AUBIO_MSG( "Couldn't set high priority scheduling for the MIDI input");
211      if (sched == SCHED_FIFO) {
212        sched = SCHED_OTHER;
213        continue;
214      } else {
215        AUBIO_ERR( "Couldn't create the midi thread.");
216        goto error_recovery;
217      }
218    }
219    break;
220  } 
221  return (aubio_midi_driver_t*) dev;
222
223error_recovery:
224  del_aubio_midi_alsa_raw_driver((aubio_midi_driver_t*) dev);
225  return NULL;
226
227}
228
229/** del_aubio_midi_alsa_raw_driver */
230int del_aubio_midi_alsa_raw_driver(aubio_midi_driver_t* p)
231{
232  aubio_midi_alsa_raw_driver_t* dev;
233
234  dev = (aubio_midi_alsa_raw_driver_t*) p;
235  if (dev == NULL) {
236    return AUBIO_OK;
237  }
238
239  dev->status = AUBIO_MIDI_DONE;
240
241  /* cancel the thread and wait for it before cleaning up */
242  if (dev->thread) {
243    if (pthread_cancel(dev->thread)) {
244      AUBIO_ERR( "Failed to cancel the midi thread");
245      return AUBIO_FAIL;
246    }
247    if (pthread_join(dev->thread, NULL)) {
248      AUBIO_ERR( "Failed to join the midi thread");
249      return AUBIO_FAIL;
250    }
251  }
252  if (dev->rawmidi_in) {
253    snd_rawmidi_drain(dev->rawmidi_in);
254    snd_rawmidi_close(dev->rawmidi_in);
255  }
256  if (dev->rawmidi_out) {
257    snd_rawmidi_drain(dev->rawmidi_out);
258    snd_rawmidi_close(dev->rawmidi_in);
259  }
260  if (dev->parser != NULL) {
261    del_aubio_midi_parser(dev->parser);
262  }
263  AUBIO_FREE(dev);
264  return AUBIO_OK;
265}
266
267/** aubio_midi_alsa_raw_run */
268void * aubio_midi_alsa_raw_run(void* d)
269{
270  int n, i;
271  aubio_midi_event_t* evt;
272  aubio_midi_alsa_raw_driver_t* dev = (aubio_midi_alsa_raw_driver_t*) d;
273
274  /* make sure the other threads can cancel this thread any time */
275  if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
276    AUBIO_ERR( "Failed to set the cancel state of the midi thread");
277    pthread_exit(NULL);
278  }
279  if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
280    AUBIO_ERR( "Failed to set the cancel state of the midi thread");
281    pthread_exit(NULL);
282  }
283
284  /* go into a loop until someone tells us to stop */
285  dev->status = AUBIO_MIDI_LISTENING;
286  while (dev->status == AUBIO_MIDI_LISTENING) {
287
288    /* is there something to read? */
289    /* use a 100 milliseconds timeout */
290    n = poll(dev->pfd, dev->npfd, 100); 
291    if (n < 0) {
292      perror("poll");
293    } else if (n > 0) {
294
295      /* read new data */
296      n = snd_rawmidi_read(dev->rawmidi_in, dev->buffer, 
297          AUBIO_ALSA_BUFFER_LENGTH);
298      if ((n < 0) && (n != -EAGAIN)) {
299        AUBIO_ERR( "Failed to read the midi input");
300        dev->status = AUBIO_MIDI_DONE;
301      }
302
303      /* let the parser convert the data into events */
304      for (i = 0; i < n; i++) {
305        evt = aubio_midi_parser_parse(dev->parser, dev->buffer[i]);
306        if (evt != NULL) {
307          (*dev->driver.handler)(dev->driver.data, evt);
308        }
309      }
310    };
311  }
312  pthread_exit(NULL);
313}
314
315#endif /* #if ALSA_SUPPORT */
Note: See TracBrowser for help on using the repository browser.