Mercurial > hg > silvet
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 |