Mercurial > hg > flattendynamics
view flattendynamics-ladspa.cpp @ 3:12d364f12d37
delete/delete[] fix; max gain
author | Chris Cannam |
---|---|
date | Thu, 17 Jul 2014 16:23:17 +0100 |
parents | 57990edc441b |
children | e36fe9312ad4 |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ #include "flattendynamics-ladspa.h" #include <iostream> #include <cmath> using std::cerr; using std::endl; const float historySeconds = 4.f; const float catchUpSeconds = 0.5f; const float targetRMS = 0.1f; const float maxGain = 20.f; const char *const FlattenDynamics::portNames[PortCount] = { "Input", "Output", "Gain", }; const LADSPA_PortDescriptor FlattenDynamics::ports[PortCount] = { LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, }; const LADSPA_PortRangeHint FlattenDynamics::hints[PortCount] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, }; const LADSPA_Properties FlattenDynamics::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; const LADSPA_Descriptor FlattenDynamics::ladspaDescriptor = { 0xf0b375, // "Unique" ID "flattendynamics", // Label properties, "Flatten Dynamics", // 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 * FlattenDynamics::getDescriptor(unsigned long index) { if (index == 0) return &ladspaDescriptor; return 0; } FlattenDynamics::FlattenDynamics(int sampleRate) : m_sampleRate(sampleRate), m_input(0), m_output(0), m_pgain(0), m_history(0), m_histlen(0), m_histwrite(0), m_histread(0), m_sumOfSquares(0), m_rms(0), m_gain(1.f) { reset(); } FlattenDynamics::~FlattenDynamics() { delete[] m_history; } LADSPA_Handle FlattenDynamics::instantiate(const LADSPA_Descriptor *, unsigned long rate) { FlattenDynamics *flatten = new FlattenDynamics(rate); return flatten; } void FlattenDynamics::connectPort(LADSPA_Handle handle, unsigned long port, LADSPA_Data *location) { FlattenDynamics *flatten = (FlattenDynamics *)handle; float **ports[PortCount] = { &flatten->m_input, &flatten->m_output, &flatten->m_pgain, }; *ports[port] = (float *)location; } void FlattenDynamics::activate(LADSPA_Handle handle) { FlattenDynamics *flatten = (FlattenDynamics *)handle; flatten->reset(); } void FlattenDynamics::run(LADSPA_Handle handle, unsigned long samples) { FlattenDynamics *flatten = (FlattenDynamics *)handle; flatten->runImpl(samples); } void FlattenDynamics::deactivate(LADSPA_Handle handle) { activate(handle); // both functions just reset the plugin } void FlattenDynamics::cleanup(LADSPA_Handle handle) { delete (FlattenDynamics *)handle; } void FlattenDynamics::reset() { delete[] m_history; m_histlen = int(round(m_sampleRate * historySeconds)); if (m_histlen < 1) m_histlen = 1; m_history = new float[m_histlen]; m_histwrite = 0; m_histread = 0; m_sumOfSquares = 0.0; m_rms = 0.0; m_gain = 1.f; } void FlattenDynamics::updateParameters() { if (m_pgain) *m_pgain = m_gain; } void FlattenDynamics::runImpl(unsigned long sampleCount) { if (!m_input || !m_output) return; updateParameters(); // Adjust gain so that // * RMS level of the past N seconds is some fixed R, but // * peak level does not clip // We aim to take M seconds to move to our target gain for (int i = 0; i < sampleCount; ++i) { m_output[i] = process(m_input[i]); } } float FlattenDynamics::process(float f) { updateRMS(f); if (m_rms == 0.f) { return f; } float targetGain = targetRMS / m_rms; if (targetGain > maxGain) { targetGain = maxGain; } float catchUpSamples = catchUpSeconds * m_sampleRate; // asymptotic, could improve? m_gain = m_gain + (targetGain - m_gain) / catchUpSamples; if (fabsf(f) * m_gain > 1.f) { m_gain = 1.f / fabsf(f); } // cerr << "target gain = " << targetGain << ", gain = " << m_gain << endl; return f * m_gain; } void FlattenDynamics::updateRMS(float f) { int nextWrite = (m_histwrite + 1) % m_histlen; float lose; if (nextWrite == m_histread) { // full lose = m_history[m_histread]; m_histread = (m_histread + 1) % m_histlen; } else { // not full lose = 0.f; } m_history[m_histwrite] = f; m_histwrite = nextWrite; int fill = (m_histwrite - m_histread + m_histlen) % m_histlen; m_sumOfSquares -= lose * lose; m_sumOfSquares += f * f; m_rms = sqrt(m_sumOfSquares / fill); // cerr << "rms = " << m_rms << " (from " << fill << " samples of " << m_histlen << ", latest " << f << ")" << endl; } const LADSPA_Descriptor * ladspa_descriptor(unsigned long ix) { return FlattenDynamics::getDescriptor(ix); }