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