380 lines · 10.5 KB · C
RawDownload
/*  Copyright (C) 2003-2013 Paul Brossier <piem@aubio.org>   This file is part of aubio.   aubio is free software: you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation, either version 3 of the License, or  (at your option) any later version.   aubio is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License for more details.   You should have received a copy of the GNU General Public License  along with aubio.  If not, see <http://www.gnu.org/licenses/>. */ #include <aubio.h>#include "config.h" #ifdef HAVE_JACK#include "utils.h" // for aubio_process_func_t#include "jackio.h"#include "aubio_priv.h" typedef jack_default_audio_sample_t jack_sample_t; #if HAVE_AUBIO_DOUBLE#define AUBIO_JACK_MAX_FRAMES 4096#define AUBIO_JACK_NEEDS_CONVERSION#endif #define RINGBUFFER_SIZE 1024*sizeof(jack_midi_event_t) /** * jack device structure */struct _aubio_jack_t{  /** jack client */  jack_client_t *client;  /** jack output ports */  jack_port_t **oports;  /** jack input ports */  jack_port_t **iports;  /** jack input buffer */  jack_sample_t **ibufs;  /** jack output buffer */  jack_sample_t **obufs;#ifdef AUBIO_JACK_NEEDS_CONVERSION  /** converted jack input buffer */  smpl_t **sibufs;  /** converted jack output buffer */  smpl_t **sobufs;#endif  /** jack input audio channels */  uint_t ichan;  /** jack output audio channels */  uint_t ochan;  /** jack input midi channels */  uint_t imidichan;  /** jack output midi channels */  uint_t omidichan;  /** midi output ringbuffer */  jack_ringbuffer_t *midi_out_ring;  /** jack samplerate (Hz) */  uint_t samplerate;  /** jack processing function */  aubio_process_func_t callback;  /** internal fvec */  fvec_t *ibuf;  fvec_t *obuf;  uint_t hop_size;  int pos;}; /* static memory management */static aubio_jack_t *aubio_jack_alloc (uint_t ichan, uint_t ochan,    uint_t imidichan, uint_t omidichan);/* jack callback functions */static int aubio_jack_process (jack_nframes_t nframes, void *arg);static void aubio_jack_shutdown (void *arg); aubio_jack_t *new_aubio_jack (uint_t hop_size, uint_t ichan, uint_t ochan,    uint_t imidichan, uint_t omidichan){  aubio_jack_t *jack_setup = aubio_jack_alloc (ichan, ochan,      imidichan, omidichan);  uint_t i;  char *client_name = "aubio";  char *jack_port_type;  char name[64];  /* initial jack client setup */  jack_options_t options = JackNullOption;  jack_status_t *status = NULL;  if ((jack_setup->client = jack_client_open (client_name, options, status)) == 0) {    AUBIO_ERR ("jack server not running?\n");    AUBIO_QUIT (AUBIO_FAIL);  }   if (jack_setup->omidichan) {    jack_setup->midi_out_ring = jack_ringbuffer_create (RINGBUFFER_SIZE);     if (jack_setup->midi_out_ring == NULL) {      AUBIO_ERR ("Failed creating jack midi output ringbuffer.");      AUBIO_QUIT (AUBIO_FAIL);    }     jack_ringbuffer_mlock (jack_setup->midi_out_ring);  }   /* set callbacks */  jack_set_process_callback (jack_setup->client, aubio_jack_process,      (void *) jack_setup);  jack_on_shutdown (jack_setup->client, aubio_jack_shutdown,      (void *) jack_setup);   /* register jack output audio and midi ports */  for (i = 0; i < ochan + omidichan; i++) {    if (i < ochan) {      jack_port_type = JACK_DEFAULT_AUDIO_TYPE;      AUBIO_SPRINTF (name, "out_%d", i + 1);    } else {      jack_port_type = JACK_DEFAULT_MIDI_TYPE;      AUBIO_SPRINTF (name, "midi_out_%d", i - ochan + 1);    }    if ((jack_setup->oports[i] =            jack_port_register (jack_setup->client, name,                jack_port_type, JackPortIsOutput, 0)) == 0) {      goto beach;    }    AUBIO_DBG ("%s:%s\n", client_name, name);  }   /* register jack input audio ports */  for (i = 0; i < ichan + imidichan; i++) {    if (i < ichan) {      jack_port_type = JACK_DEFAULT_AUDIO_TYPE;      AUBIO_SPRINTF (name, "in_%d", i + 1);    } else {      jack_port_type = JACK_DEFAULT_MIDI_TYPE;      AUBIO_SPRINTF (name, "midi_in_%d", i - ichan + 1);    }    if ((jack_setup->iports[i] =            jack_port_register (jack_setup->client, name,                jack_port_type, JackPortIsInput, 0)) == 0) {      goto beach;    }    AUBIO_DBG ("%s:%s\n", client_name, name);  }   /* get sample rate */  jack_setup->samplerate = jack_get_sample_rate (jack_setup->client);   jack_setup->hop_size = hop_size;  jack_setup->ibuf = new_fvec(hop_size);  jack_setup->obuf = new_fvec(hop_size);  jack_setup->pos = 0;  return jack_setup; beach:  AUBIO_ERR ("failed registering port \"%s:%s\"!\n", client_name, name);  jack_client_close (jack_setup->client);  AUBIO_QUIT (AUBIO_FAIL);} uint_taubio_jack_get_samplerate (aubio_jack_t * jack_setup) {  return jack_setup->samplerate;} uint_taubio_jack_activate (aubio_jack_t * jack_setup, aubio_process_func_t callback){  /* set processing callback */  jack_setup->callback = callback;  /* actual jack process activation */  if (jack_activate (jack_setup->client)) {    AUBIO_ERR ("jack client activation failed");    return 1;  }  return 0;} voidaubio_jack_close (aubio_jack_t * jack_setup){  /* bug : should disconnect all ports first */  jack_client_close (jack_setup->client);} /* memory management */static aubio_jack_t *aubio_jack_alloc (uint_t ichan, uint_t ochan,    uint_t imidichan, uint_t omidichan){  aubio_jack_t *jack_setup = AUBIO_NEW (aubio_jack_t);  jack_setup->ichan = ichan;  jack_setup->ochan = ochan;  jack_setup->imidichan = imidichan;  jack_setup->omidichan = omidichan;  jack_setup->oports = AUBIO_ARRAY (jack_port_t *, ichan + imidichan);  jack_setup->iports = AUBIO_ARRAY (jack_port_t *, ochan + omidichan);  jack_setup->ibufs = AUBIO_ARRAY (jack_sample_t *, ichan);  jack_setup->obufs = AUBIO_ARRAY (jack_sample_t *, ochan);#ifdef AUBIO_JACK_NEEDS_CONVERSION  /* allocate arrays for data conversion */  jack_setup->sibufs = AUBIO_ARRAY (smpl_t *, ichan);  uint_t i;  for (i = 0; i < ichan; i++) {    jack_setup->sibufs[i] = AUBIO_ARRAY (smpl_t, AUBIO_JACK_MAX_FRAMES);  }  jack_setup->sobufs = AUBIO_ARRAY (smpl_t *, ochan);  for (i = 0; i < ochan; i++) {    jack_setup->sobufs[i] = AUBIO_ARRAY (smpl_t, AUBIO_JACK_MAX_FRAMES);  }#endif  return jack_setup;} voiddel_aubio_jack (aubio_jack_t * jack_setup){  if (jack_setup->omidichan && jack_setup->midi_out_ring) {    jack_ringbuffer_free (jack_setup->midi_out_ring);  }  del_fvec (jack_setup->ibuf);  del_fvec (jack_setup->obuf);  AUBIO_FREE (jack_setup->oports);  AUBIO_FREE (jack_setup->iports);  AUBIO_FREE (jack_setup->ibufs);  AUBIO_FREE (jack_setup->obufs);  AUBIO_FREE (jack_setup);} /* jack callback functions */static voidaubio_jack_shutdown (void *arg UNUSED){  AUBIO_ERR ("jack shutdown\n");  AUBIO_QUIT (AUBIO_OK);} static void process_midi_output (aubio_jack_t * dev, jack_nframes_t nframes); static int block_process(aubio_jack_t *dev,    smpl_t **input, smpl_t **output, int nframes) {  unsigned int j;       /*frames*/  for (j=0;j<(unsigned)nframes;j++) {    /* put synthnew in output */    output[0][j] = fvec_get_sample(dev->obuf, dev->pos);    /* write input to datanew */    fvec_set_sample(dev->ibuf, input[0][j], dev->pos);    /*time for fft*/    if (dev->pos == (int)(dev->hop_size) - 1) {      /* block loop */      dev->callback(dev->ibuf, dev->obuf);      /* end of block loop */      dev->pos = -1; /* so it will be zero next j loop */    }    dev->pos++;  }  return 1;} static intaubio_jack_process (jack_nframes_t nframes, void *arg){  aubio_jack_t *dev = (aubio_jack_t *) arg;  uint_t i;  for (i = 0; i < dev->ichan; i++) {    /* get readable input */    dev->ibufs[i] =        (jack_sample_t *) jack_port_get_buffer (dev->iports[i], nframes);  }  for (i = 0; i < dev->ochan; i++) {    /* get writable output */    dev->obufs[i] =        (jack_sample_t *) jack_port_get_buffer (dev->oports[i], nframes);  }#ifndef AUBIO_JACK_NEEDS_CONVERSION  block_process(dev, dev->ibufs, dev->obufs, nframes);#else  uint_t j;  for (j = 0; j < MIN (nframes, AUBIO_JACK_MAX_FRAMES); j++) {    for (i = 0; i < dev->ichan; i++) {      dev->sibufs[i][j] = (smpl_t) dev->ibufs[i][j];    }  }  block_process(dev, dev->sibufs, dev->sobufs, nframes);  for (j = 0; j < MIN (nframes, AUBIO_JACK_MAX_FRAMES); j++) {    for (i = 0; i < dev->ochan; i++) {      dev->obufs[i][j] = (jack_sample_t) dev->sobufs[i][j];    }  }#endif   /* now process midi stuff */  if (dev->omidichan) {    process_midi_output (dev, nframes);  }   return 0;} voidaubio_jack_midi_event_write (aubio_jack_t * dev, jack_midi_event_t * event){  int written;   if (jack_ringbuffer_write_space (dev->midi_out_ring) < sizeof (*event)) {    AUBIO_ERR ("Not enough space to write midi output, midi event lost!\n");    return;  }   written = jack_ringbuffer_write (dev->midi_out_ring,      (char *) event, sizeof (*event));   if (written != sizeof (*event)) {    AUBIO_WRN ("Call to jack_ringbuffer_write failed, midi event lost! \n");  }} static voidprocess_midi_output (aubio_jack_t * dev, jack_nframes_t nframes){  int read, sendtime;  jack_midi_event_t ev;  unsigned char *buffer;  jack_nframes_t last_frame_time = jack_last_frame_time (dev->client);  // TODO for each omidichan  void *port_buffer = jack_port_get_buffer (dev->oports[dev->ochan], nframes);   if (port_buffer == NULL) {    AUBIO_WRN ("Failed to get jack midi output port, will not send anything\n");    return;  }   jack_midi_clear_buffer (port_buffer);   // TODO add rate_limit   while (jack_ringbuffer_read_space (dev->midi_out_ring)) {    read = jack_ringbuffer_peek (dev->midi_out_ring, (char *) &ev, sizeof (ev));     if (read != sizeof (ev)) {      AUBIO_WRN ("Short read from the ringbuffer, possible note loss.\n");      jack_ringbuffer_read_advance (dev->midi_out_ring, read);      continue;    }     sendtime = ev.time + nframes - last_frame_time;     /* send time is after current period, will do this one later */    if (sendtime >= (int) nframes) {      break;    }     if (sendtime < 0) {      sendtime = 0;    }     jack_ringbuffer_read_advance (dev->midi_out_ring, sizeof (ev));     buffer = jack_midi_event_reserve (port_buffer, sendtime, ev.size);     if (buffer == NULL) {      AUBIO_WRN ("Call to jack_midi_event_reserve failed, note lost.\n");      break;    }     AUBIO_MEMCPY (buffer, ev.buffer, ev.size);  }} #endif /* HAVE_JACK */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t