source: examples/jackio.c @ 7816f2b

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

examples/jackio.c: update jack_client_new ot jack_client_open

  • Property mode set to 100644
File size: 9.5 KB
RevLine 
[96fb8ad]1/*
[1274e9f]2  Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
[96fb8ad]3
[1274e9f]4  This file is part of aubio.
[96fb8ad]5
[1274e9f]6  aubio is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
[96fb8ad]10
[1274e9f]11  aubio is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15
16  You should have received a copy of the GNU General Public License
17  along with aubio.  If not, see <http://www.gnu.org/licenses/>.
[96fb8ad]18
19*/
20
[194ef6b]21#include <aubio.h>
[9817026]22#include "config.h"
[194ef6b]23
24#if HAVE_JACK
[96fb8ad]25#include "aubio_priv.h"
26#include "jackio.h"
27
[194ef6b]28typedef jack_default_audio_sample_t jack_sample_t;
29
[46044ed]30#if HAVE_AUBIO_DOUBLE
[194ef6b]31#define AUBIO_JACK_MAX_FRAMES 4096
32#define AUBIO_JACK_NEEDS_CONVERSION
33#endif
[96fb8ad]34
[c201306]35#define RINGBUFFER_SIZE 1024*sizeof(jack_midi_event_t)
36
[96fb8ad]37/**
38 * jack device structure
39 */
[1274e9f]40struct _aubio_jack_t
41{
[96fb8ad]42  /** jack client */
43  jack_client_t *client;
44  /** jack output ports */
45  jack_port_t **oports;
46  /** jack input ports */
47  jack_port_t **iports;
48  /** jack input buffer */
49  jack_sample_t **ibufs;
50  /** jack output buffer */
51  jack_sample_t **obufs;
[1274e9f]52#ifdef AUBIO_JACK_NEEDS_CONVERSION
[194ef6b]53  /** converted jack input buffer */
54  smpl_t **sibufs;
55  /** converted jack output buffer */
56  smpl_t **sobufs;
57#endif
[bccac6b]58  /** jack input audio channels */
[96fb8ad]59  uint_t ichan;
[bccac6b]60  /** jack output audio channels */
[96fb8ad]61  uint_t ochan;
[bccac6b]62  /** jack input midi channels */
63  uint_t imidichan;
64  /** jack output midi channels */
65  uint_t omidichan;
[c201306]66  /** midi output ringbuffer */
67  jack_ringbuffer_t *midi_out_ring;
[96fb8ad]68  /** jack samplerate (Hz) */
69  uint_t samplerate;
70  /** jack processing function */
[1274e9f]71  aubio_process_func_t callback;
[96fb8ad]72};
73
74/* static memory management */
[bccac6b]75static aubio_jack_t *aubio_jack_alloc (uint_t ichan, uint_t ochan,
76    uint_t imidichan, uint_t omidichan);
[1274e9f]77static uint_t aubio_jack_free (aubio_jack_t * jack_setup);
[96fb8ad]78/* jack callback functions */
[1274e9f]79static int aubio_jack_process (jack_nframes_t nframes, void *arg);
[96fb8ad]80static void aubio_jack_shutdown (void *arg);
81
[1274e9f]82aubio_jack_t *
[bccac6b]83new_aubio_jack (uint_t ichan, uint_t ochan,
[c201306]84    uint_t imidichan, uint_t omidichan, aubio_process_func_t callback)
[1274e9f]85{
[bccac6b]86  aubio_jack_t *jack_setup = aubio_jack_alloc (ichan, ochan,
87      imidichan, omidichan);
[96fb8ad]88  uint_t i;
[1274e9f]89  char *client_name = "aubio";
[bccac6b]90  char *jack_port_type;
[96fb8ad]91  char name[64];
92  /* initial jack client setup */
[5bfb0fd]93  jack_options_t options = JackNullOption;
94  jack_status_t *status = NULL;
95  if ((jack_setup->client = jack_client_open (client_name, options, status)) == 0) {
[96fb8ad]96    AUBIO_ERR ("jack server not running?\n");
[1274e9f]97    AUBIO_QUIT (AUBIO_FAIL);
[96fb8ad]98  }
99
[c201306]100  if (jack_setup->omidichan) {
101    jack_setup->midi_out_ring = jack_ringbuffer_create (RINGBUFFER_SIZE);
102
103    if (jack_setup->midi_out_ring == NULL) {
104      AUBIO_ERR ("Failed creating jack midi output ringbuffer.");
105      AUBIO_QUIT (AUBIO_FAIL);
106    }
107
108    jack_ringbuffer_mlock (jack_setup->midi_out_ring);
109  }
110
[96fb8ad]111  /* set callbacks */
[1274e9f]112  jack_set_process_callback (jack_setup->client, aubio_jack_process,
113      (void *) jack_setup);
114  jack_on_shutdown (jack_setup->client, aubio_jack_shutdown,
115      (void *) jack_setup);
[96fb8ad]116
[bccac6b]117  /* register jack output audio and midi ports */
118  for (i = 0; i < ochan + omidichan; i++) {
119    if (i < ochan) {
120      jack_port_type = JACK_DEFAULT_AUDIO_TYPE;
121      AUBIO_SPRINTF (name, "out_%d", i + 1);
122    } else {
123      jack_port_type = JACK_DEFAULT_MIDI_TYPE;
124      AUBIO_SPRINTF (name, "midi_out_%d", i - ochan + 1);
125    }
[1274e9f]126    if ((jack_setup->oports[i] =
127            jack_port_register (jack_setup->client, name,
[bccac6b]128                jack_port_type, JackPortIsOutput, 0)) == 0) {
129      goto beach;
[96fb8ad]130    }
[bccac6b]131    AUBIO_DBG ("%s:%s\n", client_name, name);
[96fb8ad]132  }
133
[bccac6b]134  /* register jack input audio ports */
135  for (i = 0; i < ichan + imidichan; i++) {
136    if (i < ichan) {
137      jack_port_type = JACK_DEFAULT_AUDIO_TYPE;
138      AUBIO_SPRINTF (name, "in_%d", i + 1);
139    } else {
140      jack_port_type = JACK_DEFAULT_MIDI_TYPE;
141      AUBIO_SPRINTF (name, "midi_in_%d", i - ichan + 1);
142    }
[1274e9f]143    if ((jack_setup->iports[i] =
144            jack_port_register (jack_setup->client, name,
[bccac6b]145                jack_port_type, JackPortIsInput, 0)) == 0) {
146      goto beach;
[96fb8ad]147    }
[bccac6b]148    AUBIO_DBG ("%s:%s\n", client_name, name);
[96fb8ad]149  }
150
151  /* set processing callback */
152  jack_setup->callback = callback;
153  return jack_setup;
[bccac6b]154
155beach:
[c201306]156  AUBIO_ERR ("failed registering port \"%s:%s\"!\n", client_name, name);
[bccac6b]157  jack_client_close (jack_setup->client);
158  AUBIO_QUIT (AUBIO_FAIL);
[96fb8ad]159}
160
[1274e9f]161uint_t
162aubio_jack_activate (aubio_jack_t * jack_setup)
163{
[96fb8ad]164  /* get sample rate */
165  jack_setup->samplerate = jack_get_sample_rate (jack_setup->client);
166  /* actual jack process activation */
[1274e9f]167  if (jack_activate (jack_setup->client)) {
168    AUBIO_ERR ("jack client activation failed");
[96fb8ad]169    return 1;
170  }
171  return 0;
172}
173
[1274e9f]174void
175aubio_jack_close (aubio_jack_t * jack_setup)
176{
[96fb8ad]177  /* bug : should disconnect all ports first */
[1274e9f]178  jack_client_close (jack_setup->client);
179  aubio_jack_free (jack_setup);
[96fb8ad]180}
181
182/* memory management */
[1274e9f]183static aubio_jack_t *
[bccac6b]184aubio_jack_alloc (uint_t ichan, uint_t ochan,
185    uint_t imidichan, uint_t omidichan)
[1274e9f]186{
187  aubio_jack_t *jack_setup = AUBIO_NEW (aubio_jack_t);
[96fb8ad]188  jack_setup->ichan = ichan;
189  jack_setup->ochan = ochan;
[c201306]190  jack_setup->imidichan = imidichan;
191  jack_setup->omidichan = omidichan;
[bccac6b]192  jack_setup->oports = AUBIO_ARRAY (jack_port_t *, ichan + imidichan);
193  jack_setup->iports = AUBIO_ARRAY (jack_port_t *, ochan + omidichan);
[1274e9f]194  jack_setup->ibufs = AUBIO_ARRAY (jack_sample_t *, ichan);
195  jack_setup->obufs = AUBIO_ARRAY (jack_sample_t *, ochan);
196#ifdef AUBIO_JACK_NEEDS_CONVERSION
[bccac6b]197  /* allocate arrays for data conversion */
[1274e9f]198  jack_setup->sibufs = AUBIO_ARRAY (smpl_t *, ichan);
[194ef6b]199  uint_t i;
200  for (i = 0; i < ichan; i++) {
[1274e9f]201    jack_setup->sibufs[i] = AUBIO_ARRAY (smpl_t, AUBIO_JACK_MAX_FRAMES);
[194ef6b]202  }
[1274e9f]203  jack_setup->sobufs = AUBIO_ARRAY (smpl_t *, ochan);
[194ef6b]204  for (i = 0; i < ochan; i++) {
[1274e9f]205    jack_setup->sobufs[i] = AUBIO_ARRAY (smpl_t, AUBIO_JACK_MAX_FRAMES);
[194ef6b]206  }
207#endif
[96fb8ad]208  return jack_setup;
209}
210
[1274e9f]211static uint_t
212aubio_jack_free (aubio_jack_t * jack_setup)
213{
[c201306]214  if (jack_setup->omidichan && jack_setup->midi_out_ring) {
215    jack_ringbuffer_free (jack_setup->midi_out_ring);
216  }
[1274e9f]217  AUBIO_FREE (jack_setup->oports);
218  AUBIO_FREE (jack_setup->iports);
219  AUBIO_FREE (jack_setup->ibufs);
220  AUBIO_FREE (jack_setup->obufs);
221  AUBIO_FREE (jack_setup);
[96fb8ad]222  return AUBIO_OK;
223}
224
225/* jack callback functions */
[1274e9f]226static void
227aubio_jack_shutdown (void *arg UNUSED)
228{
229  AUBIO_ERR ("jack shutdown\n");
230  AUBIO_QUIT (AUBIO_OK);
[96fb8ad]231}
232
[c201306]233static void process_midi_output (aubio_jack_t * dev, jack_nframes_t nframes);
234
[1274e9f]235static int
236aubio_jack_process (jack_nframes_t nframes, void *arg)
237{
238  aubio_jack_t *dev = (aubio_jack_t *) arg;
[96fb8ad]239  uint_t i;
[1274e9f]240  for (i = 0; i < dev->ichan; i++) {
[96fb8ad]241    /* get readable input */
[1274e9f]242    dev->ibufs[i] =
243        (jack_sample_t *) jack_port_get_buffer (dev->iports[i], nframes);
[58779e3]244  }
245  for (i = 0; i < dev->ochan; i++) {
[96fb8ad]246    /* get writable output */
[1274e9f]247    dev->obufs[i] =
248        (jack_sample_t *) jack_port_get_buffer (dev->oports[i], nframes);
[96fb8ad]249  }
[194ef6b]250#ifndef AUBIO_JACK_NEEDS_CONVERSION
[1274e9f]251  dev->callback (dev->ibufs, dev->obufs, nframes);
[194ef6b]252#else
253  uint_t j;
[1274e9f]254  for (j = 0; j < MIN (nframes, AUBIO_JACK_MAX_FRAMES); j++) {
255    for (i = 0; i < dev->ichan; i++) {
256      dev->sibufs[i][j] = (smpl_t) dev->ibufs[i][j];
[194ef6b]257    }
258  }
[1274e9f]259  dev->callback (dev->sibufs, dev->sobufs, nframes);
260  for (j = 0; j < MIN (nframes, AUBIO_JACK_MAX_FRAMES); j++) {
[52ecf09]261    for (i = 0; i < dev->ochan; i++) {
[1274e9f]262      dev->obufs[i][j] = (jack_sample_t) dev->sobufs[i][j];
[194ef6b]263    }
264  }
265#endif
[c201306]266
267  /* now process midi stuff */
268  if (dev->omidichan) {
269    process_midi_output (dev, nframes);
270  }
271
[96fb8ad]272  return 0;
273}
274
[c201306]275void
276aubio_jack_midi_event_write (aubio_jack_t * dev, jack_midi_event_t * event)
277{
278  int written;
279
280  if (jack_ringbuffer_write_space (dev->midi_out_ring) < sizeof (*event)) {
281    AUBIO_ERR ("Not enough space to write midi output, midi event lost!\n");
282    return;
283  }
284
285  written = jack_ringbuffer_write (dev->midi_out_ring,
286      (char *) event, sizeof (*event));
287
288  if (written != sizeof (*event)) {
289    AUBIO_WRN ("Call to jack_ringbuffer_write failed, midi event lost! \n");
290  }
291}
292
293static void
294process_midi_output (aubio_jack_t * dev, jack_nframes_t nframes)
295{
296  int read, sendtime;
297  jack_midi_event_t ev;
298  unsigned char *buffer;
299  jack_nframes_t last_frame_time = jack_last_frame_time (dev->client);
300  // TODO for each omidichan
301  void *port_buffer = jack_port_get_buffer (dev->oports[dev->ochan], nframes);
302
303  if (port_buffer == NULL) {
304    AUBIO_WRN ("Failed to get jack midi output port, will not send anything\n");
305    return;
306  }
307
308  jack_midi_clear_buffer (port_buffer);
309
310  // TODO add rate_limit
311
312  while (jack_ringbuffer_read_space (dev->midi_out_ring)) {
313    read = jack_ringbuffer_peek (dev->midi_out_ring, (char *) &ev, sizeof (ev));
314
315    if (read != sizeof (ev)) {
316      AUBIO_WRN ("Short read from the ringbuffer, possible note loss.\n");
317      jack_ringbuffer_read_advance (dev->midi_out_ring, read);
318      continue;
319    }
320
321    sendtime = ev.time + nframes - last_frame_time;
322
323    /* send time is after current period, will do this one later */
324    if (sendtime >= (int) nframes) {
325      break;
326    }
327
328    if (sendtime < 0) {
329      sendtime = 0;
330    }
331
332    jack_ringbuffer_read_advance (dev->midi_out_ring, sizeof (ev));
333
334    buffer = jack_midi_event_reserve (port_buffer, sendtime, ev.size);
335
336    if (buffer == NULL) {
337      AUBIO_WRN ("Call to jack_midi_event_reserve failed, note lost.\n");
338      break;
339    }
340
341    AUBIO_MEMCPY (buffer, ev.buffer, ev.size);
342  }
343}
[96fb8ad]344
[b511fa9]345#endif /* HAVE_JACK */
Note: See TracBrowser for help on using the repository browser.