Logo Search packages:      
Sourcecode: tap-plugins version File versions  Download package

tap_reflector.c

/*                                                     -*- linux-c -*-
    Copyright (C) 2004 Tom Szilagyi
    
    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 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.

    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.

    $Id: tap_reflector.c,v 1.1 2004/06/18 20:12:41 tszilagyi Exp $
*/


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

#include "ladspa.h"
#include "tap_utils.h"


/* The Unique ID of the plugin: */

#define ID_MONO         2154

/* The port numbers for the plugin: */

#define FRAGMENT        0
#define DRYLEVEL        1
#define WETLEVEL        2
#define INPUT           3
#define OUTPUT          4

/* Total number of ports */


#define PORTCOUNT_MONO   5


/* minimum & maximum fragment length [ms] */
#define MIN_FRAGMENT_LEN 20
#define MAX_FRAGMENT_LEN 1600

/* in kHz */
#define MAX_SAMPLE_RATE 192


#define COS_TABLE_SIZE 1024
LADSPA_Data cos_table[COS_TABLE_SIZE];



/* The structure used to hold port connection information and state */

00064 typedef struct {
      LADSPA_Data * fragment;
      LADSPA_Data * drylevel;
      LADSPA_Data * wetlevel;
      LADSPA_Data * input;
      LADSPA_Data * output;

      LADSPA_Data * ring0;
      unsigned long buflen0;
      unsigned long pos0;
      LADSPA_Data * ring1;
      unsigned long buflen1;
      unsigned long pos1;
      LADSPA_Data * delay1;
      unsigned long delay_buflen1;
      unsigned long delay_pos1;
      LADSPA_Data * ring2;
      unsigned long buflen2;
      unsigned long pos2;
      LADSPA_Data * delay2;
      unsigned long delay_buflen2;
      unsigned long delay_pos2;

      unsigned long fragment_pos;

      unsigned long sample_rate;
      LADSPA_Data run_adding_gain;
} Reflector;



/* Construct a new plugin instance. */
LADSPA_Handle 
instantiate_Reflector(const LADSPA_Descriptor * Descriptor,
                  unsigned long             sample_rate) {
  
        LADSPA_Handle * ptr;
      
      if ((ptr = malloc(sizeof(Reflector))) != NULL) {
            ((Reflector *)ptr)->sample_rate = sample_rate;
            ((Reflector *)ptr)->run_adding_gain = 1.0f;

            if ((((Reflector *)ptr)->ring0 = 
                 calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL)
                  return NULL;
            ((Reflector *)ptr)->buflen0 = 2 * MAX_FRAGMENT_LEN * sample_rate / 1000;
            ((Reflector *)ptr)->pos0 = 0;

            if ((((Reflector *)ptr)->ring1 = 
                 calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL)
                  return NULL;
            ((Reflector *)ptr)->buflen1 = 2 * MAX_FRAGMENT_LEN * sample_rate / 1000;
            ((Reflector *)ptr)->pos1 = 0;

            if ((((Reflector *)ptr)->delay1 = 
                 calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL)
                  return NULL;
            ((Reflector *)ptr)->delay_buflen1 = 2 * MAX_FRAGMENT_LEN * sample_rate / 3000;
            ((Reflector *)ptr)->pos1 = 0;

            if ((((Reflector *)ptr)->ring2 = 
                 calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL)
                  return NULL;
            ((Reflector *)ptr)->buflen2 = 2 * MAX_FRAGMENT_LEN * sample_rate / 1000;
            ((Reflector *)ptr)->pos2 = 0;

            if ((((Reflector *)ptr)->delay2 = 
                 calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL)
                  return NULL;
            ((Reflector *)ptr)->delay_buflen2 = 4 * MAX_FRAGMENT_LEN * sample_rate / 3000;
            ((Reflector *)ptr)->pos2 = 0;

            return ptr;
      }
            return NULL;
}


void
activate_Reflector(LADSPA_Handle Instance) {

      Reflector * ptr = (Reflector *)Instance;
      unsigned long i;

      for (i = 0; i < ptr->buflen0; i++)
            ptr->ring0[i] = 0.0f;
      ptr->pos0 = 0;
      for (i = 0; i < ptr->buflen1; i++)
            ptr->ring1[i] = 0.0f;
      ptr->pos1 = 0;
      for (i = 0; i < ptr->buflen2; i++)
            ptr->ring2[i] = 0.0f;
      ptr->pos2 = 0;

      for (i = 0; i < ptr->delay_buflen1; i++)
            ptr->delay1[i] = 0.0f;
      ptr->delay_pos1 = 0;
      for (i = 0; i < ptr->delay_buflen2; i++)
            ptr->delay2[i] = 0.0f;
      ptr->delay_pos2 = 0;

      ptr->fragment_pos = 0;
}





/* Connect a port to a data location. */
void 
connect_port_Reflector(LADSPA_Handle Instance,
                   unsigned long Port,
                   LADSPA_Data * DataLocation) {
      
      Reflector * ptr = (Reflector *)Instance;

      switch (Port) {
      case FRAGMENT:
            ptr->fragment = DataLocation;
            break;
      case DRYLEVEL:
            ptr->drylevel = DataLocation;
            break;
      case WETLEVEL:
            ptr->wetlevel = DataLocation;
            break;
      case INPUT:
            ptr->input = DataLocation;
            break;
      case OUTPUT:
            ptr->output = DataLocation;
            break;
      }
}



void 
run_Reflector(LADSPA_Handle Instance,
            unsigned long SampleCount) {
  
      Reflector * ptr = (Reflector *)Instance;
      LADSPA_Data * input = ptr->input;
      LADSPA_Data * output = ptr->output;
      LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f));
      LADSPA_Data wetlevel = 0.333333f * db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f));
      LADSPA_Data fragment = LIMIT(*(ptr->fragment),(float)MIN_FRAGMENT_LEN,(float)MAX_FRAGMENT_LEN);

      unsigned long sample_index;
      unsigned long sample_count = SampleCount;

      LADSPA_Data in = 0.0f;
      LADSPA_Data in1 = 0.0f;
      LADSPA_Data in2 = 0.0f;
      LADSPA_Data out_0 = 0.0f;
      LADSPA_Data out_1 = 0.0f;
      LADSPA_Data out_2 = 0.0f;

      unsigned long fragment_pos1 = 0;
      unsigned long fragment_pos2 = 0;

      unsigned long arg_0 = 0;
      LADSPA_Data am_0 = 0.0f;
      unsigned long arg_1 = 0;
      LADSPA_Data am_1 = 0.0f;
      unsigned long arg_2 = 0;
      LADSPA_Data am_2 = 0.0f;

      ptr->buflen0 = 2 * fragment * ptr->sample_rate / 1000.0f;
      ptr->buflen1 = ptr->buflen0;
      ptr->buflen2 = ptr->buflen0;
      ptr->delay_buflen1 = ptr->buflen0 / 3;
      ptr->delay_buflen2 = 2 * ptr->buflen0 / 3;

      for (sample_index = 0; sample_index < sample_count; sample_index++) {

            in = *(input++);
            in1 = push_buffer(in, ptr->delay1, ptr->delay_buflen1, &(ptr->delay_pos1));
            in2 = push_buffer(in, ptr->delay2, ptr->delay_buflen2, &(ptr->delay_pos2));

            push_buffer(in2, ptr->ring0, ptr->buflen0, &(ptr->pos0));
            push_buffer(in1, ptr->ring1, ptr->buflen1, &(ptr->pos1));
            push_buffer(in, ptr->ring2, ptr->buflen2, &(ptr->pos2));

            fragment_pos1 = (ptr->fragment_pos + ptr->buflen0 / 3) % ptr->buflen0;
            fragment_pos2 = (ptr->fragment_pos + 2 * ptr->buflen1 / 3) % ptr->buflen1;

            out_0 = read_buffer(ptr->ring0, ptr->buflen0, ptr->pos0,
                            ptr->buflen0 - ptr->fragment_pos - 1);
            out_1 = read_buffer(ptr->ring1, ptr->buflen1, ptr->pos1,
                            ptr->buflen1 - fragment_pos1 - 1);
            out_2 = read_buffer(ptr->ring2, ptr->buflen2, ptr->pos2,
                            ptr->buflen2 - fragment_pos2 - 1);

            ptr->fragment_pos += 2;
            if (ptr->fragment_pos >= ptr->buflen0)
                  ptr->fragment_pos = 0;

            arg_0 = (float)ptr->fragment_pos / (float)ptr->buflen0 * COS_TABLE_SIZE;
            am_0 = 1.0f - cos_table[arg_0];
            arg_1 = (float)fragment_pos1 / (float)ptr->buflen1 * COS_TABLE_SIZE;
            am_1 = 1.0f - cos_table[arg_1];
            arg_2 = (float)fragment_pos2 / (float)ptr->buflen2 * COS_TABLE_SIZE;
            am_2 = 1.0f - cos_table[arg_2];

            *(output++) = drylevel * in + wetlevel *
                  (am_0 * out_0 + am_1 * out_1 + am_2 * out_2);
      }
}



void
set_run_adding_gain_Reflector(LADSPA_Handle Instance, LADSPA_Data gain) {

      Reflector * ptr = (Reflector *)Instance;

      ptr->run_adding_gain = gain;
}



void 
run_adding_Reflector(LADSPA_Handle Instance,
                 unsigned long SampleCount) {
  
      Reflector * ptr = (Reflector *)Instance;
      LADSPA_Data * input = ptr->input;
      LADSPA_Data * output = ptr->output;
      LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f));
      LADSPA_Data wetlevel = 0.333333f * db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f));
      LADSPA_Data fragment = LIMIT(*(ptr->fragment),(float)MIN_FRAGMENT_LEN,(float)MAX_FRAGMENT_LEN);

      unsigned long sample_index;
      unsigned long sample_count = SampleCount;

      LADSPA_Data in = 0.0f;
      LADSPA_Data in1 = 0.0f;
      LADSPA_Data in2 = 0.0f;
      LADSPA_Data out_0 = 0.0f;
      LADSPA_Data out_1 = 0.0f;
      LADSPA_Data out_2 = 0.0f;

      unsigned long fragment_pos1 = 0;
      unsigned long fragment_pos2 = 0;

      unsigned long arg_0 = 0;
      LADSPA_Data am_0 = 0.0f;
      unsigned long arg_1 = 0;
      LADSPA_Data am_1 = 0.0f;
      unsigned long arg_2 = 0;
      LADSPA_Data am_2 = 0.0f;

      ptr->buflen0 = 2 * fragment * ptr->sample_rate / 1000.0f;
      ptr->buflen1 = ptr->buflen0;
      ptr->buflen2 = ptr->buflen0;
      ptr->delay_buflen1 = ptr->buflen0 / 3;
      ptr->delay_buflen2 = 2 * ptr->buflen0 / 3;

      for (sample_index = 0; sample_index < sample_count; sample_index++) {

            in = *(input++);
            in1 = push_buffer(in, ptr->delay1, ptr->delay_buflen1, &(ptr->delay_pos1));
            in2 = push_buffer(in, ptr->delay2, ptr->delay_buflen2, &(ptr->delay_pos2));

            push_buffer(in2, ptr->ring0, ptr->buflen0, &(ptr->pos0));
            push_buffer(in1, ptr->ring1, ptr->buflen1, &(ptr->pos1));
            push_buffer(in, ptr->ring2, ptr->buflen2, &(ptr->pos2));

            fragment_pos1 = (ptr->fragment_pos + ptr->buflen0 / 3) % ptr->buflen0;
            fragment_pos2 = (ptr->fragment_pos + 2 * ptr->buflen1 / 3) % ptr->buflen1;

            out_0 = read_buffer(ptr->ring0, ptr->buflen0, ptr->pos0,
                            ptr->buflen0 - ptr->fragment_pos - 1);
            out_1 = read_buffer(ptr->ring1, ptr->buflen1, ptr->pos1,
                            ptr->buflen1 - fragment_pos1 - 1);
            out_2 = read_buffer(ptr->ring2, ptr->buflen2, ptr->pos2,
                            ptr->buflen2 - fragment_pos2 - 1);

            ptr->fragment_pos += 2;
            if (ptr->fragment_pos >= ptr->buflen0)
                  ptr->fragment_pos = 0;

            arg_0 = (float)ptr->fragment_pos / (float)ptr->buflen0 * COS_TABLE_SIZE;
            am_0 = 1.0f - cos_table[arg_0];
            arg_1 = (float)fragment_pos1 / (float)ptr->buflen1 * COS_TABLE_SIZE;
            am_1 = 1.0f - cos_table[arg_1];
            arg_2 = (float)fragment_pos2 / (float)ptr->buflen2 * COS_TABLE_SIZE;
            am_2 = 1.0f - cos_table[arg_2];

            *(output++) += ptr->run_adding_gain *
                  (drylevel * in + wetlevel * (am_0 * out_0 + am_1 * out_1 + am_2 * out_2));
      }
}




/* Throw away a Reflector effect instance. */
void 
cleanup_Reflector(LADSPA_Handle Instance) {

      Reflector * ptr = (Reflector *)Instance;
      free(ptr->ring0);
      free(ptr->ring1);
      free(ptr->ring2);
      free(ptr->delay1);
      free(ptr->delay2);
      free(Instance);
}



LADSPA_Descriptor * mono_descriptor = NULL;



/* _init() is called automatically when the plugin library is first
   loaded. */
void 
_init() {
      
      int i;
      char ** port_names;
      LADSPA_PortDescriptor * port_descriptors;
      LADSPA_PortRangeHint * port_range_hints;
      
      if ((mono_descriptor = 
           (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL)
            exit(1);
      
      for (i = 0; i < COS_TABLE_SIZE; i++)
            cos_table[i] = cosf(i * 2.0f * M_PI / COS_TABLE_SIZE);


      mono_descriptor->UniqueID = ID_MONO;
      mono_descriptor->Label = strdup("tap_reflector");
      mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
      mono_descriptor->Name = strdup("TAP Reflector");
      mono_descriptor->Maker = strdup("Tom Szilagyi");
      mono_descriptor->Copyright = strdup("GPL");
      mono_descriptor->PortCount = PORTCOUNT_MONO;

      if ((port_descriptors =
           (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL)
            exit(1);

      mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors;
      port_descriptors[FRAGMENT] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
      port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
      port_descriptors[WETLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL;
      port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO;
      port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;

      if ((port_names = 
           (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL)
            exit(1);

      mono_descriptor->PortNames = (const char **)port_names;
      port_names[FRAGMENT] = strdup("Fragment Length [ms]");
      port_names[DRYLEVEL] = strdup("Dry Level [dB]");
      port_names[WETLEVEL] = strdup("Wet Level [dB]");
      port_names[INPUT] = strdup("Input");
      port_names[OUTPUT] = strdup("Output");

      if ((port_range_hints = 
           ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL)
            exit(1);

      mono_descriptor->PortRangeHints     = (const LADSPA_PortRangeHint *)port_range_hints;
      port_range_hints[FRAGMENT].HintDescriptor = 
            (LADSPA_HINT_BOUNDED_BELOW |
             LADSPA_HINT_BOUNDED_ABOVE |
             LADSPA_HINT_DEFAULT_LOW);
      port_range_hints[DRYLEVEL].HintDescriptor = 
            (LADSPA_HINT_BOUNDED_BELOW |
             LADSPA_HINT_BOUNDED_ABOVE |
             LADSPA_HINT_DEFAULT_MINIMUM);
      port_range_hints[WETLEVEL].HintDescriptor = 
            (LADSPA_HINT_BOUNDED_BELOW |
             LADSPA_HINT_BOUNDED_ABOVE |
             LADSPA_HINT_DEFAULT_0);
      port_range_hints[FRAGMENT].LowerBound = (float)MIN_FRAGMENT_LEN;
      port_range_hints[FRAGMENT].UpperBound = (float)MAX_FRAGMENT_LEN;
      port_range_hints[DRYLEVEL].LowerBound = -90.0f;
      port_range_hints[DRYLEVEL].UpperBound = 20.0f;
      port_range_hints[WETLEVEL].LowerBound = -90.0f;
      port_range_hints[WETLEVEL].UpperBound = 20.0f;
      port_range_hints[INPUT].HintDescriptor = 0;
      port_range_hints[OUTPUT].HintDescriptor = 0;
      mono_descriptor->instantiate = instantiate_Reflector;
      mono_descriptor->connect_port = connect_port_Reflector;
      mono_descriptor->activate = activate_Reflector;
      mono_descriptor->run = run_Reflector;
      mono_descriptor->run_adding = run_adding_Reflector;
      mono_descriptor->set_run_adding_gain = set_run_adding_gain_Reflector;
      mono_descriptor->deactivate = NULL;
      mono_descriptor->cleanup = cleanup_Reflector;
}


void
delete_descriptor(LADSPA_Descriptor * descriptor) {
      unsigned long index;
      if (descriptor) {
            free((char *)descriptor->Label);
            free((char *)descriptor->Name);
            free((char *)descriptor->Maker);
            free((char *)descriptor->Copyright);
            free((LADSPA_PortDescriptor *)descriptor->PortDescriptors);
            for (index = 0; index < descriptor->PortCount; index++)
                  free((char *)(descriptor->PortNames[index]));
            free((char **)descriptor->PortNames);
            free((LADSPA_PortRangeHint *)descriptor->PortRangeHints);
            free(descriptor);
      }
}


/* _fini() is called automatically when the library is unloaded. */
void
_fini() {
      delete_descriptor(mono_descriptor);
}


/* Return a descriptor of the requested plugin type. */
const LADSPA_Descriptor * 
ladspa_descriptor(unsigned long Index) {

      switch (Index) {
      case 0:
            return mono_descriptor;
      default:
            return NULL;
      }
}

Generated by  Doxygen 1.6.0   Back to index