1 /* meter.lv2
2 *
3 * Copyright (C) 2013 Robin Gareus <robin@gareus.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 /* static functions to be included in meters.cc
21 *
22 * broken out spectrum analyzer related LV2 functions
23 */
24
25 /******************************************************************************
26 * LV2 spec
27 */
28
29 #if defined __cplusplus && !defined isfinite
30 #define isfinite std::isfinite
31 #endif
32
33 #define FILTER_COUNT (30)
34
35 typedef enum {
36 SA_SPEED = 60,
37 SA_RESET = 61,
38 SA_AMP = 62,
39 SA_STATE = 63,
40 SA_INPUT0 = 64,
41 SA_OUTPUT0 = 65,
42 SA_INPUT1 = 66,
43 SA_OUTPUT1 = 67,
44 } SAPortIndex;
45
46 typedef struct {
47 float* input[2];
48 float* output[2];
49
50 float* spec[FILTER_COUNT];
51 float* maxf[FILTER_COUNT];
52 float* rst_p;
53 float* spd_p;
54 float* amp_p;
55
56 float rst_h;
57 float spd_h;
58
59 uint32_t nchannels;
60 double rate;
61
62 float omega;
63 float val_f[FILTER_COUNT];
64 float max_f[FILTER_COUNT];
65 struct FilterBank flt[FILTER_COUNT];
66
67 } LV2spec;
68
69 /******************************************************************************
70 * LV2 callbacks
71 */
72
73 static LV2_Handle
spectrum_instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)74 spectrum_instantiate(
75 const LV2_Descriptor* descriptor,
76 double rate,
77 const char* bundle_path,
78 const LV2_Feature* const* features)
79 {
80 uint32_t nchannels;
81 if (!strcmp(descriptor->URI, MTR_URI "spectr30stereo")) {
82 nchannels = 2;
83 }
84 else if (!strcmp(descriptor->URI, MTR_URI "spectr30mono")) {
85 nchannels = 1;
86 }
87 else { return NULL; }
88
89 LV2spec* self = (LV2spec*)calloc(1, sizeof(LV2spec));
90 if (!self) return NULL;
91
92 self->nchannels = nchannels;
93 self->rate = rate;
94
95 self->rst_h = -4;
96 self->spd_h = 1.0;
97 // 1.0 - e^(-2.0 * π * v / 48000)
98 self->omega = 1.0f - expf(-2.0 * M_PI * self->spd_h / rate);
99
100 /* filter-frequencies */
101 const double f_r = 1000;
102 const double b = 3;
103 const double f1f = pow(2, -1. / (2. * b));
104 const double f2f = pow(2, 1. / (2. * b));
105
106 for (uint32_t i=0; i < FILTER_COUNT; ++i) {
107 const int x = i - 16;
108 const double f_m = pow(2, x / b) * f_r;
109 const double f_1 = f_m * f1f;
110 const double f_2 = f_m * f2f;
111 const double bw = f_2 - f_1;
112 #ifdef DEBUG_SPECTR
113 printf("--F %2d (%3d): f:%9.2fHz b:%9.2fHz (%9.2fHz -> %9.2fHz)\n",i, x, f_m, bw, f_1, f_2);
114 #endif
115 self->val_f[i] = 0;
116 self->max_f[i] = 0;
117 bandpass_setup(&self->flt[i], self->rate, f_m, bw, 6);
118 }
119
120 return (LV2_Handle)self;
121 }
122
123 static void
spectrum_connect_port(LV2_Handle instance,uint32_t port,void * data)124 spectrum_connect_port(LV2_Handle instance, uint32_t port, void* data)
125 {
126 LV2spec* self = (LV2spec*)instance;
127 switch (port) {
128 case SA_INPUT0:
129 self->input[0] = (float*) data;
130 break;
131 case SA_OUTPUT0:
132 self->output[0] = (float*) data;
133 break;
134 case SA_INPUT1:
135 self->input[1] = (float*) data;
136 break;
137 case SA_OUTPUT1:
138 self->output[1] = (float*) data;
139 break;
140 case SA_RESET:
141 self->rst_p = (float*) data;
142 break;
143 case SA_SPEED:
144 self->spd_p = (float*) data;
145 break;
146 case SA_AMP:
147 break;
148 default:
149 if (port < 30) {
150 self->spec[port] = (float*) data;
151 }
152 if (port >= 30 && port < 60) {
153 self->maxf[port-30] = (float*) data;
154 }
155 break;
156 }
157 }
158
159 static void
spectrum_run(LV2_Handle instance,uint32_t n_samples)160 spectrum_run(LV2_Handle instance, uint32_t n_samples)
161 {
162 LV2spec* self = (LV2spec*)instance;
163 float* inL = self->input[0];
164 float* inR = self->input[1];
165 bool reinit_gui = false;
166
167 /* calculate time-constant when it is changed,
168 * (no-need to smoothen transition for the visual display)
169 */
170 if (self->spd_h != *self->spd_p) {
171 self->spd_h = *self->spd_p;
172 float v = self->spd_h;
173 if (v < 0.01) v = 0.01;
174 if (v > 15.0) v = 15.0;
175 self->omega = 1.0f - expf(-2.0 * M_PI * v / self->rate);
176 self->rst_h = 0; // reset peak-hold on change
177 }
178
179 /* localize variables */
180 float val_f[FILTER_COUNT];
181 float max_f[FILTER_COUNT];
182 const float omega = self->omega;
183 struct FilterBank *flt[FILTER_COUNT];
184
185 for(int i=0; i < FILTER_COUNT; ++i) {
186 val_f[i] = self->val_f[i];
187 max_f[i] = self->max_f[i];
188 flt[i] = &self->flt[i];
189 }
190
191 if (self->rst_h != *self->rst_p) {
192 /* reset peak-hold */
193 if (fabsf(*self->rst_p) < 3 || self->rst_h == 0) {
194 reinit_gui = true;
195 for(int i = 0; i < FILTER_COUNT; ++i) {
196 max_f[i] = 0;
197 }
198 }
199 if (fabsf(*self->rst_p) != 3) {
200 self->rst_h = *self->rst_p;
201 }
202 }
203 if (fabsf(*self->rst_p) == 3) {
204 reinit_gui = true;
205 }
206
207 const bool stereo = self->nchannels == 2;
208
209 /* .. and go */
210 for (uint32_t j = 0 ; j < n_samples; ++j) {
211 float in;
212 // TODO separate loop implementation for mono+stereo for efficiency
213 if (stereo) {
214 const float L = *(inL++);
215 const float R = *(inR++);
216 in = (L + R) / 2.0f;
217 } else {
218 in = *(inL++);
219 }
220
221 for(int i = 0; i < FILTER_COUNT; ++i) {
222 const float v = bandpass_process(flt[i], in);
223 const float s = v * v;
224 val_f[i] += omega * (s - val_f[i]);
225 if (val_f[i] > max_f[i]) max_f[i] = val_f[i];
226 }
227 }
228
229 /* copy back variables and assign value */
230 for(int i=0; i < FILTER_COUNT; ++i) {
231 if (!isfinite(val_f[i])) val_f[i] = 0;
232 if (!isfinite(max_f[i])) max_f[i] = 0;
233 for (uint32_t j=0; j < flt[i]->filter_stages; ++j) {
234 if (!isfinite(flt[i]->f[j].z[0])) flt[i]->f[j].z[0] = 0;
235 if (!isfinite(flt[i]->f[j].z[1])) flt[i]->f[j].z[1] = 0;
236 }
237 self->val_f[i] = val_f[i] + 1e-20f;
238 self->max_f[i] = max_f[i];
239
240 const float vs = sqrtf(2. * val_f[i]);
241 const float mx = sqrtf(2. * max_f[i]);
242 *(self->spec[i]) = vs > .00001f ? 20.0 * log10f(vs) : -100.0;
243 if (reinit_gui) {
244 /* force parameter change */
245 *(self->maxf[i]) = -500 - (rand() & 0xffff);
246 } else {
247 *(self->maxf[i]) = mx > .00001f ? 20.0 * log10f(mx) : -100.0;
248 }
249 }
250
251 if (self->input[0] != self->output[0]) {
252 memcpy(self->output[0], self->input[0], sizeof(float) * n_samples);
253 }
254 if (self->input[1] != self->output[1]) {
255 memcpy(self->output[1], self->input[1], sizeof(float) * n_samples);
256 }
257 }
258
259 static void
spectrum_cleanup(LV2_Handle instance)260 spectrum_cleanup(LV2_Handle instance)
261 {
262 free(instance);
263 }
264
265 #define SPECTRDESC(ID, NAME) \
266 static const LV2_Descriptor descriptor ## ID = { \
267 MTR_URI NAME, \
268 spectrum_instantiate, \
269 spectrum_connect_port, \
270 NULL, \
271 spectrum_run, \
272 NULL, \
273 spectrum_cleanup, \
274 extension_data \
275 };
276
277 SPECTRDESC(Spectrum1, "spectr30mono");
278 SPECTRDESC(Spectrum2, "spectr30stereo");
279