From c20130651c781d416dd47c2ee26f3330bde65e2d Mon Sep 17 00:00:00 2001 From: Paul Brossier Date: Fri, 25 Sep 2009 21:53:40 +0200 Subject: [PATCH] ext/jackio.{c,h}: add midi_out_ring for midi output event processing --- ext/jackio.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++--- ext/jackio.h | 8 ++++ 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/ext/jackio.c b/ext/jackio.c index f7f7b8ff..ebd7b43e 100644 --- a/ext/jackio.c +++ b/ext/jackio.c @@ -21,7 +21,6 @@ #include #if HAVE_JACK -#include #include "aubio_priv.h" #include "jackio.h" @@ -32,6 +31,8 @@ typedef jack_default_audio_sample_t jack_sample_t; #define AUBIO_JACK_NEEDS_CONVERSION #endif +#define RINGBUFFER_SIZE 1024*sizeof(jack_midi_event_t) + /** * jack device structure */ @@ -61,6 +62,8 @@ struct _aubio_jack_t 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 */ @@ -77,8 +80,7 @@ static void aubio_jack_shutdown (void *arg); aubio_jack_t * new_aubio_jack (uint_t ichan, uint_t ochan, - uint_t imidichan, uint_t omidichan, - aubio_process_func_t callback) + uint_t imidichan, uint_t omidichan, aubio_process_func_t callback) { aubio_jack_t *jack_setup = aubio_jack_alloc (ichan, ochan, imidichan, omidichan); @@ -92,6 +94,17 @@ new_aubio_jack (uint_t ichan, uint_t ochan, 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); @@ -137,8 +150,7 @@ new_aubio_jack (uint_t ichan, uint_t ochan, return jack_setup; beach: - AUBIO_ERR ("failed registering port \"%s:%s\"!\n", - client_name, name); + AUBIO_ERR ("failed registering port \"%s:%s\"!\n", client_name, name); jack_client_close (jack_setup->client); AUBIO_QUIT (AUBIO_FAIL); } @@ -172,6 +184,8 @@ aubio_jack_alloc (uint_t ichan, uint_t ochan, 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); @@ -194,6 +208,9 @@ aubio_jack_alloc (uint_t ichan, uint_t ochan, 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); @@ -210,6 +227,8 @@ aubio_jack_shutdown (void *arg UNUSED) AUBIO_QUIT (AUBIO_OK); } +static void process_midi_output (aubio_jack_t * dev, jack_nframes_t nframes); + static int aubio_jack_process (jack_nframes_t nframes, void *arg) { @@ -241,8 +260,83 @@ aubio_jack_process (jack_nframes_t nframes, void *arg) } } #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 /* HAVE_JACK */ diff --git a/ext/jackio.h b/ext/jackio.h index b97d6f00..dcb6fb25 100644 --- a/ext/jackio.h +++ b/ext/jackio.h @@ -33,6 +33,10 @@ extern "C" { #endif +#include +#include +#include + /** jack object */ typedef struct _aubio_jack_t aubio_jack_t; /** jack process function */ @@ -48,6 +52,10 @@ uint_t aubio_jack_activate (aubio_jack_t * jack_setup); /** close and delete jack client */ void aubio_jack_close (aubio_jack_t * jack_setup); +/** write a jack_midi_event_t to the midi output ringbuffer */ +void aubio_jack_midi_event_write (aubio_jack_t * jack_setup, + jack_midi_event_t * event); + #ifdef __cplusplus } #endif -- 2.26.2