/*
- Copyright (C) 2003 Paul Brossier
+ Copyright (C) 2003-2009 Paul Brossier <piem@aubio.org>
- This program 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 2 of the License, or
- (at your option) any later version.
+ This file is part of aubio.
- This program 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.
+ 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.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ 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 "config.h"
-#ifdef JACK_SUPPORT
-#include <jack/jack.h>
+#include <aubio.h>
+
+#if HAVE_JACK
#include "aubio_priv.h"
#include "jackio.h"
-/*typedef jack_default_audio_sample_t jack_sample_t; */
-/* work with float, never tried in double */
-typedef smpl_t jack_sample_t;
+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 {
+struct _aubio_jack_t
+{
/** jack client */
jack_client_t *client;
/** jack output ports */
jack_sample_t **ibufs;
/** jack output buffer */
jack_sample_t **obufs;
- /** jack input channels */
+#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 channels */
+ /** 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;
+ aubio_process_func_t callback;
};
/* static memory management */
-static aubio_jack_t * aubio_jack_alloc(uint_t ichan, uint_t ochan);
-static uint_t aubio_jack_free(aubio_jack_t * jack_setup);
+static aubio_jack_t *aubio_jack_alloc (uint_t ichan, uint_t ochan,
+ uint_t imidichan, uint_t omidichan);
+static uint_t aubio_jack_free (aubio_jack_t * jack_setup);
/* jack callback functions */
-static int aubio_jack_process(jack_nframes_t nframes, void *arg);
+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 ichan, uint_t ochan,
- aubio_process_func_t callback) {
- aubio_jack_t * jack_setup = aubio_jack_alloc (ichan, ochan);
+aubio_jack_t *
+new_aubio_jack (uint_t ichan, uint_t ochan,
+ uint_t imidichan, uint_t omidichan, aubio_process_func_t callback)
+{
+ aubio_jack_t *jack_setup = aubio_jack_alloc (ichan, ochan,
+ imidichan, omidichan);
uint_t i;
- char * client_name = "aubio";
+ char *client_name = "aubio";
+ char *jack_port_type;
char name[64];
/* initial jack client setup */
if ((jack_setup->client = jack_client_new (client_name)) == 0) {
AUBIO_ERR ("jack server not running?\n");
- AUBIO_QUIT(AUBIO_FAIL);
+ 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 ports */
- for (i = 0; i < ochan; i++)
- {
- AUBIO_SPRINTF(name, "out_%d", i+1);
- AUBIO_MSG("%s\n", name);
- if ((jack_setup->oports[i] =
- jack_port_register (jack_setup->client, name,
- JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == 0)
- {
- AUBIO_ERR("failed registering output port \"%s\"!\n", name);
- jack_client_close (jack_setup->client);
- AUBIO_QUIT(AUBIO_FAIL);
+ 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 ports */
- for (i = 0; i < ichan; i++)
- {
- AUBIO_SPRINTF(name, "in_%d", i+1);
- AUBIO_MSG("%s\n", name);
- if ((jack_setup->iports[i] =
- jack_port_register (jack_setup->client, name,
- JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == 0)
- {
- AUBIO_ERR("failed registering input port \"%s\"!\n", name);
- jack_client_close (jack_setup->client);
- AUBIO_QUIT(AUBIO_FAIL);
+ /* 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);
}
/* set processing callback */
jack_setup->callback = callback;
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_t aubio_jack_activate(aubio_jack_t *jack_setup) {
+uint_t
+aubio_jack_activate (aubio_jack_t * jack_setup)
+{
/* get sample rate */
jack_setup->samplerate = jack_get_sample_rate (jack_setup->client);
/* actual jack process activation */
- if (jack_activate (jack_setup->client))
- {
- AUBIO_ERR("jack client activation failed");
+ if (jack_activate (jack_setup->client)) {
+ AUBIO_ERR ("jack client activation failed");
return 1;
}
return 0;
}
-void aubio_jack_close(aubio_jack_t *jack_setup) {
+void
+aubio_jack_close (aubio_jack_t * jack_setup)
+{
/* bug : should disconnect all ports first */
- jack_client_close(jack_setup->client);
- aubio_jack_free(jack_setup);
+ jack_client_close (jack_setup->client);
+ aubio_jack_free (jack_setup);
}
/* memory management */
-static aubio_jack_t * aubio_jack_alloc(uint_t ichan, uint_t ochan) {
- aubio_jack_t *jack_setup = AUBIO_NEW(aubio_jack_t);
+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->oports = AUBIO_ARRAY(jack_port_t*, ichan);
- jack_setup->iports = AUBIO_ARRAY(jack_port_t*, ochan);
- jack_setup->ibufs = AUBIO_ARRAY(jack_sample_t*, ichan);
- jack_setup->obufs = AUBIO_ARRAY(jack_sample_t*, 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;
}
-static uint_t aubio_jack_free(aubio_jack_t * jack_setup) {
- AUBIO_FREE(jack_setup->oports);
- AUBIO_FREE(jack_setup->iports);
- AUBIO_FREE(jack_setup->ibufs );
- AUBIO_FREE(jack_setup->obufs );
- AUBIO_FREE(jack_setup);
+static uint_t
+aubio_jack_free (aubio_jack_t * jack_setup)
+{
+ if (jack_setup->omidichan && jack_setup->midi_out_ring) {
+ jack_ringbuffer_free (jack_setup->midi_out_ring);
+ }
+ AUBIO_FREE (jack_setup->oports);
+ AUBIO_FREE (jack_setup->iports);
+ AUBIO_FREE (jack_setup->ibufs);
+ AUBIO_FREE (jack_setup->obufs);
+ AUBIO_FREE (jack_setup);
return AUBIO_OK;
}
/* jack callback functions */
-static void aubio_jack_shutdown (void *arg){
- AUBIO_ERR("jack shutdown\n");
- AUBIO_QUIT(AUBIO_OK);
+static void
+aubio_jack_shutdown (void *arg UNUSED)
+{
+ AUBIO_ERR ("jack shutdown\n");
+ AUBIO_QUIT (AUBIO_OK);
}
-static int aubio_jack_process(jack_nframes_t nframes, void *arg) {
- aubio_jack_t* dev = (aubio_jack_t *)arg;
+static void process_midi_output (aubio_jack_t * dev, jack_nframes_t nframes);
+
+static int
+aubio_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++) {
+ for (i = 0; i < dev->ichan; i++) {
/* get readable input */
- dev->ibufs[i] =
- (jack_sample_t *) jack_port_get_buffer (dev->iports[i], nframes);
+ 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);
+ dev->obufs[i] =
+ (jack_sample_t *) jack_port_get_buffer (dev->oports[i], nframes);
}
- dev->callback(dev->ibufs,dev->obufs,nframes);
+#ifndef AUBIO_JACK_NEEDS_CONVERSION
+ dev->callback (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];
+ }
+ }
+ dev->callback (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;
}
+void
+aubio_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 void
+process_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 /* JACK_SUPPORT */
+#endif /* HAVE_JACK */