view devuvuzelator-ladspa.cpp @ 19:0cdedb2fab81 tip

* OS/X build fixes
author Chris Cannam
date Fri, 18 Jun 2010 11:18:49 +0100
parents e7e8a8f57f35
children
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

#include "devuvuzelator-ladspa.h"

#include <alloca.h>
#include <iostream>
#include <cmath>

#include "params.h"

const char *const
Devuvuzelator::portNames[PortCount] =
{
    "Input",
    "Output",
    "latency",
    "Fundamental frequency (Hz)",
    "Bandwidth of fundamental (Hz)",
    "Number of partials",
    "Reduction (%)",
};

const LADSPA_PortDescriptor 
Devuvuzelator::ports[PortCount] =
{
    LADSPA_PORT_INPUT  | LADSPA_PORT_AUDIO,
    LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
    LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
    LADSPA_PORT_INPUT  | LADSPA_PORT_CONTROL,
};

const LADSPA_PortRangeHint 
Devuvuzelator::hints[PortCount] =
{
    { 0, 0, 0 },
    { 0, 0, 0 },
    { 0, 0, 0 },
    { LADSPA_HINT_DEFAULT_LOW |
      LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 50, 770 },
    { LADSPA_HINT_DEFAULT_MIDDLE |
      LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 20, 100 },
    { LADSPA_HINT_DEFAULT_MIDDLE | LADSPA_HINT_INTEGER |
      LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 6 },
    { LADSPA_HINT_DEFAULT_MIDDLE |
      LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, 0, 100 },
};

const LADSPA_Properties
Devuvuzelator::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;

const LADSPA_Descriptor 
Devuvuzelator::ladspaDescriptor =
{
    0xf0b374, // "Unique" ID
    "devuvuzelator", // Label
    properties,
    "Devuvuzelator", // Name
    "Queen Mary, University of London", // Maker
    "BSD", // Copyright
    PortCount,
    ports,
    portNames,
    hints,
    0, // Implementation data
    instantiate,
    connectPort,
    activate,
    run,
    0, // Run adding
    0, // Set run adding gain
    deactivate,
    cleanup
};

const LADSPA_Descriptor *
Devuvuzelator::getDescriptor(unsigned long index)
{
    if (index == 0) return &ladspaDescriptor;
    return 0;
}

Devuvuzelator::Devuvuzelator(int sampleRate) :
    m_sampleRate(sampleRate),
    m_input(0),
    m_output(0),
    m_platency(0),
    m_pfundamental(0),
    m_pbandwidth(0),
    m_pharmonics(0),
    m_preduction(0),
    m_fftsize(FFTSIZE),
    m_winsize(WINSIZE),
    m_increment(m_winsize/2),
    m_filtersecs(FILTERSECS),
    m_fill(0),
    m_read(0)
{
    m_buffer = new float[m_winsize];
    m_outacc = new float[m_winsize * 2];
    m_window = new double[m_winsize];
    m_real = new double[m_fftsize];
    m_imag = new double[m_fftsize];
    m_medians = new MedianFilter<double> *[m_fftsize/2+1];

    for (int i = 0; i < m_winsize; ++i) {
        m_window[i] = 0.5 - 0.5 * cos(2 * M_PI * i / m_winsize);
    }
    for (int i = 0; i < m_fftsize/2+1; ++i) {
        m_medians[i] = 0;
    }

    m_fundamental = 230;
    m_bandwidth = 60;
    m_harmonics = 3;
    m_reduction = 50;

    std::cerr << "note: latency = " << (float(m_winsize) / m_sampleRate)*1000 << " msec" << std::endl;

    reset();
}

Devuvuzelator::~Devuvuzelator()
{
    delete[] m_buffer;
    delete[] m_outacc;
    delete[] m_real;
    delete[] m_imag;
    delete[] m_window;
    for (int i = 0; i < m_fftsize/2+1; ++i) {
        delete m_medians[i];
    }
    delete[] m_medians;
}
    
LADSPA_Handle
Devuvuzelator::instantiate(const LADSPA_Descriptor *, unsigned long rate)
{
    Devuvuzelator *devuvu = new Devuvuzelator(rate);
    return devuvu;
}

void
Devuvuzelator::connectPort(LADSPA_Handle handle,
                           unsigned long port, LADSPA_Data *location)
{
    Devuvuzelator *devuvu = (Devuvuzelator *)handle;

    float **ports[PortCount] = {
	&devuvu->m_input,
	&devuvu->m_output,
        &devuvu->m_platency,
        &devuvu->m_pfundamental,
        &devuvu->m_pbandwidth,
        &devuvu->m_pharmonics,
        &devuvu->m_preduction,
    };

    *ports[port] = (float *)location;
}

void
Devuvuzelator::activate(LADSPA_Handle handle)
{
    Devuvuzelator *devuvu = (Devuvuzelator *)handle;
    devuvu->reset();
}

void
Devuvuzelator::run(LADSPA_Handle handle, unsigned long samples)
{
    Devuvuzelator *devuvu = (Devuvuzelator *)handle;
    devuvu->runImpl(samples);
}

void
Devuvuzelator::deactivate(LADSPA_Handle handle)
{
    activate(handle); // both functions just reset the plugin
}

void
Devuvuzelator::cleanup(LADSPA_Handle handle)
{
    delete (Devuvuzelator *)handle;
}

void
Devuvuzelator::reset()
{
    for (int i = 0; i < m_winsize; ++i) {
        m_buffer[i] = 0.f;
    }
    for (int i = 0; i < m_winsize*2; ++i) {
        m_outacc[i] = 0.f;
    }
    m_fill = 0;
    m_read = 0;
    for (int i = 0; i < m_fftsize/2+1; ++i) {
        if (m_medians[i]) m_medians[i]->reset();
    }
}

void
Devuvuzelator::updateParameters()
{
    if (m_platency) *m_platency = m_winsize;
    if (m_pfundamental) m_fundamental = *m_pfundamental;
    if (m_pbandwidth) m_bandwidth = *m_pbandwidth;
    if (m_pharmonics) m_harmonics = *m_pharmonics;
    if (m_preduction) m_reduction = *m_preduction;
}

void
Devuvuzelator::runImpl(unsigned long sampleCount)
{
    if (!m_input || !m_output) return;
    updateParameters();

    int ii = 0;
    int oi = 0;
    const int sc = sampleCount;

    float tmp_input;

    while (ii < sc) {

	tmp_input = m_input[ii++];

        m_output[oi++] = m_outacc[m_read++];

        if (m_fill == m_winsize) {

            processFrame();

            for (int j = m_increment; j < m_winsize; ++j) {
                m_buffer[j - m_increment] = m_buffer[j];
            }

            for (int j = m_increment; j < m_winsize*2; ++j) {
                m_outacc[j - m_increment] = m_outacc[j];
            }

            for (int j = m_winsize*2 - m_increment; j < m_winsize*2; ++j) {
                m_outacc[j] = 0.f;
            }

            m_fill -= m_increment;
            m_read -= m_increment;
        }

        m_buffer[m_fill++] = tmp_input;
    }
}

void
Devuvuzelator::processFrame()
{
    double *frame = (double *)alloca(m_fftsize * sizeof(double));
    for (int i = 0; i < m_fftsize; ++i) {
        frame[i] = 0.0;
    }

    int ix = m_fftsize - m_winsize/2;
    while (ix < 0) ix += m_fftsize;
    for (int i = 0; i < m_winsize; ++i) {
        frame[ix++] += m_buffer[i] * m_window[i];
        if (ix == m_fftsize) ix = 0;
    }

    fft(m_fftsize, false, frame, 0, m_real, m_imag);

    processSpectralFrame();

    for (int i = 0; i < m_fftsize/2-1; ++i) {
        m_real[m_fftsize-i-1] =  m_real[i+1];
        m_imag[m_fftsize-i-1] = -m_imag[i+1];
    }

    double *spare = (double *)alloca(m_fftsize * sizeof(double));
    fft(m_fftsize, true, m_real, m_imag, frame, spare);

    ix = m_fftsize - m_winsize/2;
    while (ix < 0) ix += m_fftsize;
    for (int i = 0; i < m_winsize; ++i) {
        m_outacc[m_winsize + i] += frame[ix++];
        if (ix == m_fftsize) ix = 0;
    }
}

const LADSPA_Descriptor *
ladspa_descriptor(unsigned long ix)
{
    return Devuvuzelator::getDescriptor(ix);
}