annotate 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
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 #include "flattendynamics-ladspa.h"
Chris@0 4
Chris@0 5 #include <iostream>
Chris@0 6 #include <cmath>
Chris@0 7
Chris@2 8 using std::cerr;
Chris@2 9 using std::endl;
Chris@2 10
Chris@1 11 const float historySeconds = 4.f;
Chris@2 12 const float catchUpSeconds = 0.5f;
Chris@2 13 const float targetRMS = 0.1f;
Chris@3 14 const float maxGain = 20.f;
Chris@1 15
Chris@0 16 const char *const
Chris@0 17 FlattenDynamics::portNames[PortCount] =
Chris@0 18 {
Chris@0 19 "Input",
Chris@0 20 "Output",
Chris@1 21 "Gain",
Chris@0 22 };
Chris@0 23
Chris@0 24 const LADSPA_PortDescriptor
Chris@0 25 FlattenDynamics::ports[PortCount] =
Chris@0 26 {
Chris@0 27 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
Chris@0 28 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
Chris@1 29 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
Chris@0 30 };
Chris@0 31
Chris@0 32 const LADSPA_PortRangeHint
Chris@0 33 FlattenDynamics::hints[PortCount] =
Chris@0 34 {
Chris@0 35 { 0, 0, 0 },
Chris@0 36 { 0, 0, 0 },
Chris@1 37 { 0, 0, 0 },
Chris@0 38 };
Chris@0 39
Chris@0 40 const LADSPA_Properties
Chris@0 41 FlattenDynamics::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
Chris@0 42
Chris@0 43 const LADSPA_Descriptor
Chris@0 44 FlattenDynamics::ladspaDescriptor =
Chris@0 45 {
Chris@0 46 0xf0b375, // "Unique" ID
Chris@0 47 "flattendynamics", // Label
Chris@0 48 properties,
Chris@2 49 "Flatten Dynamics", // Name
Chris@0 50 "Queen Mary, University of London", // Maker
Chris@0 51 "BSD", // Copyright
Chris@0 52 PortCount,
Chris@0 53 ports,
Chris@0 54 portNames,
Chris@0 55 hints,
Chris@0 56 0, // Implementation data
Chris@0 57 instantiate,
Chris@0 58 connectPort,
Chris@0 59 activate,
Chris@0 60 run,
Chris@0 61 0, // Run adding
Chris@0 62 0, // Set run adding gain
Chris@0 63 deactivate,
Chris@0 64 cleanup
Chris@0 65 };
Chris@0 66
Chris@0 67 const LADSPA_Descriptor *
Chris@0 68 FlattenDynamics::getDescriptor(unsigned long index)
Chris@0 69 {
Chris@0 70 if (index == 0) return &ladspaDescriptor;
Chris@0 71 return 0;
Chris@0 72 }
Chris@0 73
Chris@0 74 FlattenDynamics::FlattenDynamics(int sampleRate) :
Chris@0 75 m_sampleRate(sampleRate),
Chris@0 76 m_input(0),
Chris@1 77 m_output(0),
Chris@1 78 m_pgain(0),
Chris@1 79 m_history(0),
Chris@1 80 m_histlen(0),
Chris@1 81 m_histwrite(0),
Chris@1 82 m_histread(0),
Chris@1 83 m_sumOfSquares(0),
Chris@1 84 m_rms(0),
Chris@1 85 m_gain(1.f)
Chris@0 86 {
Chris@0 87 reset();
Chris@0 88 }
Chris@0 89
Chris@0 90 FlattenDynamics::~FlattenDynamics()
Chris@0 91 {
Chris@3 92 delete[] m_history;
Chris@0 93 }
Chris@0 94
Chris@0 95 LADSPA_Handle
Chris@0 96 FlattenDynamics::instantiate(const LADSPA_Descriptor *, unsigned long rate)
Chris@0 97 {
Chris@0 98 FlattenDynamics *flatten = new FlattenDynamics(rate);
Chris@0 99 return flatten;
Chris@0 100 }
Chris@0 101
Chris@0 102 void
Chris@0 103 FlattenDynamics::connectPort(LADSPA_Handle handle,
Chris@2 104 unsigned long port, LADSPA_Data *location)
Chris@0 105 {
Chris@0 106 FlattenDynamics *flatten = (FlattenDynamics *)handle;
Chris@0 107
Chris@0 108 float **ports[PortCount] = {
Chris@0 109 &flatten->m_input,
Chris@0 110 &flatten->m_output,
Chris@1 111 &flatten->m_pgain,
Chris@0 112 };
Chris@0 113
Chris@0 114 *ports[port] = (float *)location;
Chris@0 115 }
Chris@0 116
Chris@0 117 void
Chris@0 118 FlattenDynamics::activate(LADSPA_Handle handle)
Chris@0 119 {
Chris@0 120 FlattenDynamics *flatten = (FlattenDynamics *)handle;
Chris@0 121 flatten->reset();
Chris@0 122 }
Chris@0 123
Chris@0 124 void
Chris@0 125 FlattenDynamics::run(LADSPA_Handle handle, unsigned long samples)
Chris@0 126 {
Chris@0 127 FlattenDynamics *flatten = (FlattenDynamics *)handle;
Chris@0 128 flatten->runImpl(samples);
Chris@0 129 }
Chris@0 130
Chris@0 131 void
Chris@0 132 FlattenDynamics::deactivate(LADSPA_Handle handle)
Chris@0 133 {
Chris@0 134 activate(handle); // both functions just reset the plugin
Chris@0 135 }
Chris@0 136
Chris@0 137 void
Chris@0 138 FlattenDynamics::cleanup(LADSPA_Handle handle)
Chris@0 139 {
Chris@0 140 delete (FlattenDynamics *)handle;
Chris@0 141 }
Chris@0 142
Chris@0 143 void
Chris@0 144 FlattenDynamics::reset()
Chris@0 145 {
Chris@3 146 delete[] m_history;
Chris@1 147 m_histlen = int(round(m_sampleRate * historySeconds));
Chris@2 148 if (m_histlen < 1) m_histlen = 1;
Chris@2 149 m_history = new float[m_histlen];
Chris@1 150 m_histwrite = 0;
Chris@1 151 m_histread = 0;
Chris@1 152
Chris@1 153 m_sumOfSquares = 0.0;
Chris@1 154 m_rms = 0.0;
Chris@1 155 m_gain = 1.f;
Chris@0 156 }
Chris@0 157
Chris@0 158 void
Chris@0 159 FlattenDynamics::updateParameters()
Chris@0 160 {
Chris@1 161 if (m_pgain) *m_pgain = m_gain;
Chris@0 162 }
Chris@0 163
Chris@0 164 void
Chris@0 165 FlattenDynamics::runImpl(unsigned long sampleCount)
Chris@0 166 {
Chris@0 167 if (!m_input || !m_output) return;
Chris@0 168 updateParameters();
Chris@0 169
Chris@1 170 // Adjust gain so that
Chris@1 171 // * RMS level of the past N seconds is some fixed R, but
Chris@1 172 // * peak level does not clip
Chris@1 173 // We aim to take M seconds to move to our target gain
Chris@1 174
Chris@2 175 for (int i = 0; i < sampleCount; ++i) {
Chris@1 176 m_output[i] = process(m_input[i]);
Chris@0 177 }
Chris@0 178 }
Chris@0 179
Chris@1 180 float
Chris@1 181 FlattenDynamics::process(float f)
Chris@1 182 {
Chris@1 183 updateRMS(f);
Chris@2 184
Chris@2 185 if (m_rms == 0.f) {
Chris@2 186 return f;
Chris@2 187 }
Chris@2 188
Chris@2 189 float targetGain = targetRMS / m_rms;
Chris@3 190 if (targetGain > maxGain) {
Chris@3 191 targetGain = maxGain;
Chris@3 192 }
Chris@2 193 float catchUpSamples = catchUpSeconds * m_sampleRate;
Chris@2 194 // asymptotic, could improve?
Chris@2 195 m_gain = m_gain + (targetGain - m_gain) / catchUpSamples;
Chris@2 196 if (fabsf(f) * m_gain > 1.f) {
Chris@2 197 m_gain = 1.f / fabsf(f);
Chris@2 198 }
Chris@2 199 // cerr << "target gain = " << targetGain << ", gain = " << m_gain << endl;
Chris@2 200 return f * m_gain;
Chris@1 201 }
Chris@1 202
Chris@1 203 void
Chris@1 204 FlattenDynamics::updateRMS(float f)
Chris@1 205 {
Chris@1 206 int nextWrite = (m_histwrite + 1) % m_histlen;
Chris@1 207
Chris@1 208 float lose;
Chris@1 209
Chris@1 210 if (nextWrite == m_histread) {
Chris@1 211 // full
Chris@1 212 lose = m_history[m_histread];
Chris@1 213 m_histread = (m_histread + 1) % m_histlen;
Chris@1 214 } else {
Chris@1 215 // not full
Chris@1 216 lose = 0.f;
Chris@1 217 }
Chris@1 218
Chris@1 219 m_history[m_histwrite] = f;
Chris@1 220 m_histwrite = nextWrite;
Chris@1 221
Chris@2 222 int fill = (m_histwrite - m_histread + m_histlen) % m_histlen;
Chris@2 223
Chris@1 224 m_sumOfSquares -= lose * lose;
Chris@1 225 m_sumOfSquares += f * f;
Chris@1 226
Chris@1 227 m_rms = sqrt(m_sumOfSquares / fill);
Chris@2 228 // cerr << "rms = " << m_rms << " (from " << fill << " samples of " << m_histlen << ", latest " << f << ")" << endl;
Chris@1 229 }
Chris@1 230
Chris@0 231 const LADSPA_Descriptor *
Chris@0 232 ladspa_descriptor(unsigned long ix)
Chris@0 233 {
Chris@0 234 return FlattenDynamics::getDescriptor(ix);
Chris@0 235 }
Chris@0 236