Logo Search packages:      
Sourcecode: naspro-bridges version File versions  Download package

lv2api.c

/*
 * NASPRO - The NASPRO Architecture for Sound Processing
 * A collection of bridges to LV2
 * DSSI bridge
 *
 * Copyright (C) 2007-2011 NASPRO bridges development team
 *
 * See the COPYING file for license conditions.
 */

#include "internal.h"

/* libdssialsacompat has this one commented out */
void snd_midi_event_init(snd_midi_event_t *dev);

#define LV2_MIDI_URI "http://lv2plug.in/ns/ext/midi"

/* Taken from ALSA */
#define MAX_MIDI_EVENT_BUF    256

#define MAX_MIDI_EVENTS       4096

00023 typedef struct
  {
      LADSPA_Handle            handle;
      DSSI_Descriptor         *descriptor;
      uint16_t           ev_id_midi;
      LV2_Event_Buffer  *ev_buf;
      snd_midi_event_t  *alsa_ev_parser;
      snd_seq_event_t          alsa_ev_buf[MAX_MIDI_EVENTS];
  } instance_t;

static LV2_Handle
instantiate(const LV2_Descriptor *descriptor, double sample_rate,
          const char *bundle_path, const LV2_Feature * const *features)
{
      instance_t *ret;
      DSSI_Descriptor *ddesc;
      LV2_URI_Map_Feature *um_feat;
      size_t i;

      ddesc = nabrit_plugin_get_opaque(
                  nabrit_plugin_from_descriptor(descriptor));

      ret = malloc(sizeof(instance_t));
      if (ret == NULL)
            return NULL;

      if (ddesc->run_synth != NULL)
        {
            um_feat = NULL;
            for (i = 0; features[i] != NULL; i++)
              {
                  if (strcmp(features[i]->URI, LV2_URI_MAP_URI) == 0)
                        um_feat = features[i]->data;
              }

            if (um_feat == NULL)
              {
                  free(ret);
                  return NULL;
              }

            ret->ev_id_midi = um_feat->uri_to_id(um_feat->callback_data,
                                         LV2_EVENT_URI,
                                         LV2_MIDI_URI "#MidiEvent");
            if (ret->ev_id_midi == 0)
              {
                  free(ret);
                  return NULL;
              }

            if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &ret->alsa_ev_parser)
                < 0)
              {
                  free(ret);
                  return NULL;
              }
            snd_midi_event_init(ret->alsa_ev_parser);
        }
      else
            ret->alsa_ev_parser = NULL;

      ret->descriptor = ddesc;
      ret->handle = ddesc->LADSPA_Plugin->instantiate(ddesc->LADSPA_Plugin,
                                          sample_rate);
      if (ret->handle == NULL)
        {
            free(ret);
            return NULL;
        }

      return (LV2_Handle)ret;
}

static void
connect_port(LV2_Handle instance, uint32_t port, void *data_location)
{
      instance_t *i;

      /* This is needed to avoid a little incompatibility beetween LADSPA and
         LV2. LADSPA's connect_port() does not specify whether data_location
         is valid at the time it is being run, while LV2 mandates the plugin
         not to trust the memory location indicated by the pointer at the time
         connect_port() is run. */
      if (data_location == NULL)
            return;

      i = (instance_t *)instance;

      if (port == i->descriptor->LADSPA_Plugin->PortCount)
            i->ev_buf = (LV2_Event_Buffer *)data_location;
      else
            i->descriptor->LADSPA_Plugin->connect_port(i->handle, port,
                                             data_location);
}

static void
activate(LV2_Handle instance)
{
      instance_t *i;

      i = (instance_t *)instance;

      i->descriptor->LADSPA_Plugin->activate(i->handle);
}

static void
run(LV2_Handle instance, uint32_t sample_count)
{
      instance_t *i;

      i = (instance_t *)instance;

      i->descriptor->LADSPA_Plugin->run(i->handle, sample_count);
}

static void
deactivate(LV2_Handle instance)
{
      instance_t *i;

      i = (instance_t *)instance;

      i->descriptor->LADSPA_Plugin->deactivate(i->handle);
}

static void
cleanup(LV2_Handle instance)
{
      instance_t *i;

      i = (instance_t *)instance;

      if (i->alsa_ev_parser != NULL)
            snd_midi_event_free(i->alsa_ev_parser);
      
      i->descriptor->LADSPA_Plugin->cleanup(i->handle);

      free(i);
}

NACORE_PRIVATE LV2_Descriptor stub_desc =
  {
      /* .URI                 = */ NULL,
      /* .instantiate         = */ instantiate,
      /* .connect_port  = */ connect_port,
      /* .activate            = */ activate,
      /* .run                 = */ run,
      /* .deactivate          = */ deactivate,
      /* .cleanup       = */ cleanup,
      /* .extension_data      = */ NULL
  };

static int
cmp_stamp(const void *v1, const void *v2)
{
      snd_seq_event_t *e1, *e2;

      e1 = (snd_seq_event_t *)v1;
      e2 = (snd_seq_event_t *)v2;

      return ((e1->time.tick < e2->time.tick)
            ? -1 : ((e1->time.tick > e2->time.tick) ? 1 : 0));
}

NACORE_PRIVATE void
run_synth(LV2_Handle instance, uint32_t sample_count)
{
      instance_t *i;
      snd_seq_event_t *alsa_ev;
      snd_seq_event_t alsa_tmp_ev;
      LV2_Event *ev;
      unsigned char *p, *data;
      unsigned long count;
      size_t j;

      i = (instance_t *)instance;

      /* Convert MIDI events to ALSA Sequencer events */
      p = i->ev_buf->data;
      alsa_ev  = i->alsa_ev_buf;
      count = 0;
      for (j = 0; (j < i->ev_buf->event_count)
                && ((alsa_ev - i->alsa_ev_buf) < MAX_MIDI_EVENTS); j++)
        {
            ev = (LV2_Event *)p;
            p += sizeof(LV2_Event);
            data = p;
            p += ev->size;
            if (((ev->size + sizeof(LV2_Event)) % 8) != 0)
                  p += 8 - (sizeof(LV2_Event) + ev->size) % 8;

            /* Let's pretend ev->type is never 0... LV2 Events bug? */
            if (ev->type != i->ev_id_midi)
                  continue;

            if (snd_midi_event_encode(i->alsa_ev_parser, data, ev->size,
                                &alsa_tmp_ev) < 0)
              {
                  snd_midi_event_reset_encode(i->alsa_ev_parser);
                  continue;
              }

            if ((alsa_tmp_ev.type == SND_SEQ_EVENT_CONTROLLER)
                || (alsa_tmp_ev.type == SND_SEQ_EVENT_PGMCHANGE))
                  continue;

            alsa_tmp_ev.time.tick = ev->frames;
            *alsa_ev = alsa_tmp_ev;

            alsa_ev++;
            count++;
        }

      /* Order events by timestamp */
      if (count > 1)
            qsort(i->alsa_ev_buf, count, sizeof(snd_seq_event_t),
                  cmp_stamp);

      i->descriptor->run_synth(i->handle, sample_count, i->alsa_ev_buf,
                         count);
}

API const LV2_Descriptor *
lv2_descriptor(uint32_t index)
{
      return nabrit_bridge_get_descriptor(bridge, index);
}

Generated by  Doxygen 1.6.0   Back to index