comparison flattendynamics/flattendynamics-ladspa.cpp @ 366:5d0a2ebb4d17

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