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

lv2api.c

/*
 * NASPRO - NASPRO Architecture for Sound Processing
 * LADSPA bridge
 *
 * Copyright (C) 2007-2010 Stefano D'Angelo <zanga.mail@gmail.com>
 *
 * See the COPYING file for license conditions.
 */

#include <stdlib.h>
#include <string.h>

#include <alsa/seq_event.h>
#include <alsa/seq_midi_event.h>

#include <dssi.h>
#include <ladspa.h>

#include <lv2.h>
#include "uri-map.h"
#include "event.h"

#include <NASPRO/core/lib.h>

#include "pluglib.h"
#include "lv2api.h"

#define ALSA_EV_BUF_SIZE      128
#define DSSI_MAX_EVS          4096

struct ld_desc
  {
      LV2_Descriptor           lv2_desc;
      DSSI_Descriptor         *d_desc;
  };

struct instance
  {
      struct ld_desc          *ld_desc;
      LADSPA_Handle            l_handle;
      uint16_t           midi_ev_id;
      LV2_Event_Feature *lv2_ev_feat;
      snd_midi_event_t  *alsa_ev_parser;
      LV2_Event_Buffer  *lv2_ev_buf;
      snd_seq_event_t          dssi_evs[DSSI_MAX_EVS];
  };

static struct ld_desc *descs = NULL;
static size_t descs_count = 0;

LV2_Handle
_nadssi_lv2api_instantiate(const LV2_Descriptor *descriptor,
                     double sample_rate, const char *bundle_path,
                     const LV2_Feature * const *features)
{
      const LADSPA_Descriptor *ldesc;
      LADSPA_Handle *handle;
      struct instance *instance;
      LV2_URI_Map_Feature *lv2_uri_map_feat;
      size_t i;

      instance = malloc(sizeof(struct instance));
      if (instance == NULL)
            return NULL;

      lv2_uri_map_feat = NULL;
      instance->lv2_ev_feat = NULL;
      for (i = 0; features[i] != NULL; i++)
        {
            if (!strcmp(features[i]->URI,
                      "http://lv2plug.in/ns/ext/uri-map"))
              {
                  lv2_uri_map_feat = features[i]->data;
                  continue;
              }
            if (!strcmp(features[i]->URI, "http://lv2plug.in/ns/ext/event"))
              {
                  instance->lv2_ev_feat = features[i]->data;
                  continue;
              }
        }

      if ((lv2_uri_map_feat == NULL) || (instance->lv2_ev_feat == NULL))
        {
            free(instance);
            return NULL;
        }

      instance->midi_ev_id =
            lv2_uri_map_feat->uri_to_id(lv2_uri_map_feat->callback_data,
                  "http://lv2plug.in/ns/ext/event",
                  "http://lv2plug.in/ns/ext/midi#MidiEvent");
      if (instance->midi_ev_id == 0)
        {
            free(instance);
            return NULL;
        }

      if (snd_midi_event_new(ALSA_EV_BUF_SIZE, &instance->alsa_ev_parser) < 0)
        {
            free(instance);
            return NULL;
        }
      snd_midi_event_init(instance->alsa_ev_parser);

      /* This should work correctly according to the ANSI C standard. */
      ldesc = ((struct ld_desc *)descriptor)->d_desc->LADSPA_Plugin;

      handle = ldesc->instantiate(ldesc, sample_rate);
      if (handle == NULL)
        {
            snd_midi_event_free(instance->alsa_ev_parser);
            free(instance);
            return NULL;
        }

      instance->ld_desc = (struct ld_desc *)descriptor;
      instance->l_handle = handle;

      return (LV2_Handle)instance;
}

void
_nadssi_lv2api_connect_port(LV2_Handle instance, uint32_t port,
                      void *data_location)
{
      struct instance *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 = ((struct instance *)instance);

      if (port == i->ld_desc->d_desc->LADSPA_Plugin->PortCount)
            i->lv2_ev_buf = (LV2_Event_Buffer *)data_location;
      else
            i->ld_desc->d_desc->LADSPA_Plugin->connect_port(i->l_handle,
                  port, data_location);
}

void
_nadssi_lv2api_activate(LV2_Handle instance)
{
      struct instance *i;

      i = (struct instance *)instance;

      i->ld_desc->d_desc->LADSPA_Plugin->activate(i->l_handle);
}

static int
cmp_timestamp(const void *e1, const void *e2)
{
      if (((snd_seq_event_t *)e1)->time.tick
          < ((snd_seq_event_t *)e2)->time.tick)
            return -1;
      else if (((snd_seq_event_t *)e1)->time.tick
             > ((snd_seq_event_t *)e2)->time.tick)
            return 1;
      else
            return 0;
}

void
_nadssi_lv2api_run(LV2_Handle instance, uint32_t sample_count)
{
      struct instance *i;
      size_t j;
      unsigned char *p, *data;
      LV2_Event *lv2_ev;
      snd_seq_event_t alsa_ev;
      snd_seq_event_t *dssi_ev_p;
      unsigned long cnt;
      long err;

      i = (struct instance *)instance;

      if (i->ld_desc->d_desc->run_synth != NULL)
        {
            /* Convert LV2 MIDI events to ALSA sequencer events */
            p = i->lv2_ev_buf->data;
            dssi_ev_p = i->dssi_evs;
            cnt = 0;
            for (j = 0; j < (i->lv2_ev_buf->event_count)
                      && ((dssi_ev_p - i->dssi_evs) < DSSI_MAX_EVS); j++)
              {
                  lv2_ev = (LV2_Event *)p;
                  p += sizeof(LV2_Event);
                  data = p;
                  p += lv2_ev->size + (((lv2_ev->size + 4) % 8)
                                   ? (8 - (lv2_ev->size+4) % 8) : 0);

                  if (lv2_ev->type == 0)
                    {
                        i->lv2_ev_feat->lv2_event_unref(
                              i->lv2_ev_feat->callback_data, lv2_ev);
                        continue;
                    }
                  else if (lv2_ev->type != i->midi_ev_id)
                        continue;

                  err = snd_midi_event_encode(i->alsa_ev_parser, data,
                                        lv2_ev->size, &alsa_ev);
                  if (err < 0)
                    {
                        snd_midi_event_reset_encode(i->alsa_ev_parser);
                        break;
                    }

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

                  alsa_ev.time.tick = lv2_ev->frames;

                  *dssi_ev_p = alsa_ev;
                  dssi_ev_p++;
                  cnt++;
              }

            /* Order ALSA sequencer events by timestamp */
            qsort(i->dssi_evs, cnt, sizeof(snd_seq_event_t), cmp_timestamp);

            i->ld_desc->d_desc->run_synth(i->l_handle, sample_count,
                                    i->dssi_evs, cnt);
        }
      else
            i->ld_desc->d_desc->LADSPA_Plugin->run(i->l_handle,
                                           sample_count);
}

void
_nadssi_lv2api_deactivate(LV2_Handle instance)
{
      struct instance *i;

      i = (struct instance *)instance;

      i->ld_desc->d_desc->LADSPA_Plugin->deactivate(i->l_handle);
}

void
_nadssi_lv2api_cleanup(LV2_Handle instance)
{
      struct instance *i;

      i = (struct instance *)instance;

      i->ld_desc->d_desc->LADSPA_Plugin->cleanup(i->l_handle);
      snd_midi_event_free(i->alsa_ev_parser);
      free(i);
}

static void
generate_desc(void *content, void *data)
{
      struct nacore_descriptor *ndesc;
      DSSI_Descriptor *ddesc;
      struct ld_desc *lddesc;
      size_t *n;

      n = (size_t *)data;
      lddesc = descs + *n;
      ndesc = (struct nacore_descriptor *)content;
      ddesc = (DSSI_Descriptor *)ndesc->data;

      nacore_lv2api_fill_desc(&lddesc->lv2_desc, ndesc);
      lddesc->d_desc = ddesc;

      (*n)++;
}

int
_nadssi_lv2api_generate_descs()
{
      size_t n;

      n = nacore_avl_tree_get_nodes_count(_nadssi_pluglib_desc_tree);
      descs = malloc(n * sizeof(struct ld_desc));
      if (descs == NULL)
            return -1;

      descs_count = n;

      n = 0;
      nacore_avl_tree_for_each(_nadssi_pluglib_desc_tree, generate_desc,
                         &n);

      return 0;
}

void
_nadssi_lv2api_free_descs()
{
      free(descs);
      descs = NULL;
      descs_count = 0;
}

const LV2_Descriptor *
lv2_descriptor(uint32_t index)
{
      if (index >= descs_count)
            return NULL;

      return &descs[index].lv2_desc;
}

Generated by  Doxygen 1.6.0   Back to index