annotate flattendynamics/flattendynamics-ladspa.cpp @ 372:af71cbdab621 tip

Update bqvec code
author Chris Cannam
date Tue, 19 Nov 2019 10:13:32 +0000
parents 5d0a2ebb4d17
children
rev   line source
Chris@366 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@366 2
Chris@366 3 #include "flattendynamics-ladspa.h"
Chris@366 4
Chris@366 5 #include <iostream>
Chris@366 6 #include <cmath>
Chris@366 7
Chris@366 8 using std::cerr;
Chris@366 9 using std::endl;
Chris@366 10
Chris@366 11 const float historySeconds = 4.f;
Chris@366 12 const float catchUpSeconds = 0.2f;
Chris@366 13 const float targetMaxRMS = 0.05f;
Chris@366 14 const float rmsMaxDecay = 0.999f; // per sample
Chris@366 15 const float maxGain = 10.f;
Chris@366 16
Chris@366 17 const char *const
Chris@366 18 FlattenDynamics::portNames[PortCount] =
Chris@366 19 {
Chris@366 20 "Input",
Chris@366 21 "Output",
Chris@366 22 "Gain",
Chris@366 23 };
Chris@366 24
Chris@366 25 const LADSPA_PortDescriptor
Chris@366 26 FlattenDynamics::ports[PortCount] =
Chris@366 27 {
Chris@366 28 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
Chris@366 29 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
Chris@366 30 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
Chris@366 31 };
Chris@366 32
Chris@366 33 const LADSPA_PortRangeHint
Chris@366 34 FlattenDynamics::hints[PortCount] =
Chris@366 35 {
Chris@366 36 { 0, 0, 0 },
Chris@366 37 { 0, 0, 0 },
Chris@366 38 { 0, 0, 0 },
Chris@366 39 };
Chris@366 40
Chris@366 41 const LADSPA_Properties
Chris@366 42 FlattenDynamics::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
Chris@366 43
Chris@366 44 const LADSPA_Descriptor
Chris@366 45 FlattenDynamics::ladspaDescriptor =
Chris@366 46 {
Chris@366 47 0xf0b375, // "Unique" ID
Chris@366 48 "flattendynamics", // Label
Chris@366 49 properties,
Chris@366 50 "Flatten Dynamics", // Name
Chris@366 51 "Queen Mary, University of London", // Maker
Chris@366 52 "BSD", // Copyright
Chris@366 53 PortCount,
Chris@366 54 ports,
Chris@366 55 portNames,
Chris@366 56 hints,
Chris@366 57 0, // Implementation data
Chris@366 58 ladspaInstantiate,
Chris@366 59 ladspaConnectPort,
Chris@366 60 ladspaActivate,
Chris@366 61 ladspaRun,
Chris@366 62 0, // Run adding
Chris@366 63 0, // Set run adding gain
Chris@366 64 ladspaDeactivate,
Chris@366 65 ladspaCleanup
Chris@366 66 };
Chris@366 67
Chris@366 68 const LADSPA_Descriptor *
Chris@366 69 FlattenDynamics::getDescriptor(unsigned long index)
Chris@366 70 {
Chris@366 71 if (index == 0) return &ladspaDescriptor;
Chris@366 72 return 0;
Chris@366 73 }
Chris@366 74
Chris@366 75 FlattenDynamics::FlattenDynamics(int sampleRate) :
Chris@366 76 m_sampleRate(sampleRate),
Chris@366 77 m_input(0),
Chris@366 78 m_output(0),
Chris@366 79 m_pgain(0),
Chris@366 80 m_history(0),
Chris@366 81 m_histlen(0),
Chris@366 82 m_histwrite(0),
Chris@366 83 m_histread(0),
Chris@366 84 m_sumOfSquares(0.f),
Chris@366 85 m_rms(0.f),
Chris@366 86 m_maxRms(0.f),
Chris@366 87 m_gain(1.f)
Chris@366 88 {
Chris@366 89 reset();
Chris@366 90 }
Chris@366 91
Chris@366 92 FlattenDynamics::~FlattenDynamics()
Chris@366 93 {
Chris@366 94 delete[] m_history;
Chris@366 95 }
Chris@366 96
Chris@366 97 LADSPA_Handle
Chris@366 98 FlattenDynamics::ladspaInstantiate(const LADSPA_Descriptor *, unsigned long rate)
Chris@366 99 {
Chris@366 100 FlattenDynamics *flatten = new FlattenDynamics(rate);
Chris@366 101 return flatten;
Chris@366 102 }
Chris@366 103
Chris@366 104 void
Chris@366 105 FlattenDynamics::ladspaConnectPort(LADSPA_Handle handle,
Chris@366 106 unsigned long port,
Chris@366 107 LADSPA_Data *location)
Chris@366 108 {
Chris@366 109 FlattenDynamics *flatten = (FlattenDynamics *)handle;
Chris@366 110 if (ports[port] & LADSPA_PORT_INPUT) {
Chris@366 111 flatten->connectInputPort(Port(port), location);
Chris@366 112 } else {
Chris@366 113 flatten->connectOutputPort(Port(port), location);
Chris@366 114 }
Chris@366 115 }
Chris@366 116
Chris@366 117 void
Chris@366 118 FlattenDynamics::ladspaActivate(LADSPA_Handle handle)
Chris@366 119 {
Chris@366 120 FlattenDynamics *flatten = (FlattenDynamics *)handle;
Chris@366 121 flatten->reset();
Chris@366 122 }
Chris@366 123
Chris@366 124 void
Chris@366 125 FlattenDynamics::ladspaRun(LADSPA_Handle handle, unsigned long samples)
Chris@366 126 {
Chris@366 127 FlattenDynamics *flatten = (FlattenDynamics *)handle;
Chris@366 128 flatten->process(samples);
Chris@366 129 }
Chris@366 130
Chris@366 131 void
Chris@366 132 FlattenDynamics::ladspaDeactivate(LADSPA_Handle handle)
Chris@366 133 {
Chris@366 134 ladspaActivate(handle); // both functions just reset the plugin
Chris@366 135 }
Chris@366 136
Chris@366 137 void
Chris@366 138 FlattenDynamics::ladspaCleanup(LADSPA_Handle handle)
Chris@366 139 {
Chris@366 140 delete (FlattenDynamics *)handle;
Chris@366 141 }
Chris@366 142
Chris@366 143 void
Chris@366 144 FlattenDynamics::connectInputPort(Port p, const float *location)
Chris@366 145 {
Chris@366 146 const float **ports[PortCount] = {
Chris@366 147 &m_input, 0, 0,
Chris@366 148 };
Chris@366 149
Chris@366 150 *ports[int(p)] = location;
Chris@366 151 }
Chris@366 152
Chris@366 153 void
Chris@366 154 FlattenDynamics::connectOutputPort(Port p, float *location)
Chris@366 155 {
Chris@366 156 float **ports[PortCount] = {
Chris@366 157 0, &m_output, &m_pgain,
Chris@366 158 };
Chris@366 159
Chris@366 160 *ports[int(p)] = location;
Chris@366 161 }
Chris@366 162
Chris@366 163 void
Chris@366 164 FlattenDynamics::reset()
Chris@366 165 {
Chris@366 166 delete[] m_history;
Chris@366 167 m_histlen = int(round(m_sampleRate * historySeconds));
Chris@366 168 if (m_histlen < 1) m_histlen = 1;
Chris@366 169 m_history = new float[m_histlen];
Chris@366 170 for (int i = 0; i < m_histlen; ++i) {
Chris@366 171 m_history[i] = 0.f;
Chris@366 172 }
Chris@366 173 m_histwrite = 0;
Chris@366 174 m_histread = 0;
Chris@366 175
Chris@366 176 m_sumOfSquares = 0.0;
Chris@366 177 m_rms = 0.f;
Chris@366 178 m_maxRms = 0.f;
Chris@366 179 m_gain = 1.f;
Chris@366 180 }
Chris@366 181
Chris@366 182 void
Chris@366 183 FlattenDynamics::updateParameters()
Chris@366 184 {
Chris@366 185 if (m_pgain) *m_pgain = m_gain;
Chris@366 186 }
Chris@366 187
Chris@366 188 void
Chris@366 189 FlattenDynamics::process(int sampleCount)
Chris@366 190 {
Chris@366 191 if (!m_input || !m_output) return;
Chris@366 192
Chris@366 193 updateParameters();
Chris@366 194
Chris@366 195 for (int i = 0; i < sampleCount; ++i) {
Chris@366 196 m_output[i] = processSingle(m_input[i]);
Chris@366 197 }
Chris@366 198 }
Chris@366 199
Chris@366 200 float
Chris@366 201 FlattenDynamics::processSingle(float f)
Chris@366 202 {
Chris@366 203 updateRMS(f);
Chris@366 204
Chris@366 205 if (m_rms == 0.f) {
Chris@366 206 return f;
Chris@366 207 }
Chris@366 208
Chris@366 209 if (m_rms >= m_maxRms) {
Chris@366 210 m_maxRms = m_rms;
Chris@366 211 } else {
Chris@366 212 m_maxRms = m_rms + (m_maxRms - m_rms) * rmsMaxDecay;
Chris@366 213 }
Chris@366 214
Chris@366 215 float targetGain = targetMaxRMS / m_maxRms;
Chris@366 216
Chris@366 217 if (targetGain > maxGain) {
Chris@366 218 targetGain = maxGain;
Chris@366 219 }
Chris@366 220
Chris@366 221 float catchUpSamples = catchUpSeconds * m_sampleRate;
Chris@366 222 // asymptotic, could improve?
Chris@366 223 m_gain = m_gain + (targetGain - m_gain) / catchUpSamples;
Chris@366 224
Chris@366 225 if (fabsf(f) * m_gain > 1.f) {
Chris@366 226 m_gain = 1.f / fabsf(f);
Chris@366 227 }
Chris@366 228
Chris@366 229 // cerr << "target gain = " << targetGain << ", gain = " << m_gain << endl;
Chris@366 230 return f * m_gain;
Chris@366 231 }
Chris@366 232
Chris@366 233 void
Chris@366 234 FlattenDynamics::updateRMS(float f)
Chris@366 235 {
Chris@366 236 // We update the RMS values by maintaining a sum-of-last-n-squares
Chris@366 237 // total (which the RMS is the square root of 1/n of) and
Chris@366 238 // recording the last n samples of history in a circular
Chris@366 239 // buffer. When a sample drops off the start of the history, we
Chris@366 240 // remove the square of it from the sum-of-squares total; then we
Chris@366 241 // add the square of the new sample.
Chris@366 242
Chris@366 243 int nextWrite = (m_histwrite + 1) % m_histlen;
Chris@366 244
Chris@366 245 float lose = 0.f;
Chris@366 246
Chris@366 247 if (nextWrite == m_histread) {
Chris@366 248 // full
Chris@366 249 lose = m_history[m_histread];
Chris@366 250 m_histread = (m_histread + 1) % m_histlen;
Chris@366 251 }
Chris@366 252
Chris@366 253 m_history[m_histwrite] = f;
Chris@366 254 m_histwrite = nextWrite;
Chris@366 255
Chris@366 256 int fill = (m_histwrite - m_histread + m_histlen) % m_histlen;
Chris@366 257
Chris@366 258 m_sumOfSquares -= lose * lose;
Chris@366 259 m_sumOfSquares += f * f;
Chris@366 260
Chris@366 261 m_rms = sqrt(m_sumOfSquares / fill);
Chris@366 262 // cerr << "rms = " << m_rms << " (from " << fill << " samples of " << m_histlen << ", latest " << f << ")" << endl;
Chris@366 263 }
Chris@366 264
Chris@366 265 const LADSPA_Descriptor *
Chris@366 266 ladspa_descriptor(unsigned long ix)
Chris@366 267 {
Chris@366 268 return FlattenDynamics::getDescriptor(ix);
Chris@366 269 }
Chris@366 270