1 /* fil4.lv2
2  *
3  * Copyright (C) 2004-2009 Fons Adriaensen <fons@kokkinizita.net>
4  * Copyright (C) 2015,2016 Robin Gareus <robin@gareus.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "filters.h"
24 #include "uris.h"
25 #include "iir.h"
26 #include "hip.h"
27 #include "lop.h"
28 
29 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
30 #include "lv2/lv2plug.in/ns/ext/state/state.h"
31 #include "lv2/lv2plug.in/ns/ext/options/options.h"
32 
33 #ifdef DISPLAY_INTERFACE
34 #include <cairo/cairo.h>
35 #include <pango/pangocairo.h>
36 #include "lv2_rgext.h"
37 #endif
38 
39 static bool printed_capacity_warning = false;
40 
41 typedef struct {
42 	Fil4Paramsect _sect [NSECT];
43 	HighPass      hip;
44 	LowPass       lop;
45 
46 	IIRProc       iir_lowshelf;
47 	IIRProc       iir_highshelf;
48 
49 	int           _fade;
50 	float         _gain;
51 } FilterChannel;
52 
53 typedef struct {
54 	float        *_port [FIL_LAST];
55 	float         rate;
56 	float         below_nyquist;
57 
58 	FilterChannel fc[2];
59 	uint32_t n_channels;
60 
61 	/* atom-forge & fft related */
62 	const LV2_Atom_Sequence *control;
63 	LV2_Atom_Sequence       *notify;
64 	LV2_URID_Map            *map;
65 	Fil4LV2URIs              uris;
66 	LV2_Atom_Forge           forge;
67 	LV2_Atom_Forge_Frame     frame;
68 
69 	/* peak hold */
70 	int                      peak_reset;
71 	float                    peak_signal;
72 
73 	/* GUI state */
74 	bool                     ui_active;
75 	bool                     send_state_to_ui;
76 	uint32_t                 resend_peak;
77 
78 	int32_t                  fft_mode;
79 	int32_t                  fft_chan;
80 	float                    fft_gain;
81 	float                    db_scale;
82 	float                    ui_scale;
83 	float                    kb_tuning;
84 
85 	bool                     need_expose;
86 	bool                     enabled;
87 #ifdef DISPLAY_INTERFACE
88 	LV2_Inline_Display_Image_Surface surf;
89 	cairo_surface_t*         display;
90 	LV2_Inline_Display*      queue_draw;
91 	uint32_t                 w, h;
92 #endif
93 } Fil4;
94 
init_filter_channel(FilterChannel * fc,double rate)95 static void init_filter_channel (FilterChannel *fc, double rate) {
96 	fc->_fade = 0;
97 	fc->_gain = 1.f;
98 	for (int j = 0; j < NSECT; ++j) {
99 		fc->_sect [j].init ();
100 	}
101 
102 	iir_init (&fc->iir_lowshelf, rate);
103 	iir_init (&fc->iir_highshelf, rate);
104 
105 	fc->iir_lowshelf.freq = 50;
106 	fc->iir_highshelf.freq = 8000;
107 
108 	iir_calc_lowshelf (&fc->iir_lowshelf);
109 	iir_calc_highshelf (&fc->iir_highshelf);
110 
111 	hip_setup (&fc->hip, rate, 20, .7);
112 	lop_setup (&fc->lop, rate, 10000, .7);
113 }
114 
115 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)116 instantiate(const LV2_Descriptor*     descriptor,
117             double                    rate,
118             const char*               bundle_path,
119             const LV2_Feature* const* features)
120 {
121 	Fil4* self = (Fil4*)calloc(1, sizeof(Fil4));
122 
123 	if (!strcmp (descriptor->URI, FIL4_URI "mono")) {
124 		self->n_channels = 1;
125 	} else if (!strcmp (descriptor->URI, FIL4_URI "stereo")) {
126 		self->n_channels = 2;
127 	} else {
128 		free (self);
129 		return NULL;
130 	}
131 
132 	const LV2_Options_Option* options = NULL;
133 
134 	for (int i=0; features[i]; ++i) {
135 		if (!strcmp(features[i]->URI, LV2_URID__map)) {
136 			self->map = (LV2_URID_Map*)features[i]->data;
137 		} else if (!strcmp(features[i]->URI, LV2_OPTIONS__options)) {
138 			options = (LV2_Options_Option*)features[i]->data;
139 		}
140 #ifdef DISPLAY_INTERFACE
141 		else if (!strcmp(features[i]->URI, LV2_INLINEDISPLAY__queue_draw)) {
142 			self->queue_draw = (LV2_Inline_Display*) features[i]->data;
143 		}
144 #endif
145 	}
146 
147 	if (!self->map) {
148 		fprintf (stderr, "fil4.lv2 error: Host does not support urid:map\n");
149 		free (self);
150 		return NULL;
151 	}
152 
153 	self->rate = rate;
154 	self->below_nyquist = rate * 0.4998;
155 	lv2_atom_forge_init (&self->forge, self->map);
156 	map_fil4_uris (self->map, &self->uris);
157 
158 	for (uint32_t c = 0; c < self->n_channels; ++c) {
159 		init_filter_channel (&self->fc[c], rate);
160 	}
161 
162 	self->ui_active = false;
163 	self->fft_mode = 0x1201;
164 	self->fft_gain = 0;
165 	self->fft_chan = -1;
166 	self->resend_peak = 0;
167 	self->db_scale = DEFAULT_YZOOM;
168 	self->ui_scale = 1.0;
169 	self->kb_tuning = 440.0;
170 
171 	if (options) {
172 		LV2_URID atom_Float = self->map->map (self->map->handle, LV2_ATOM__Float);
173 		LV2_URID ui_scale   = self->map->map (self->map->handle, "http://lv2plug.in/ns/extensions/ui#scaleFactor");
174 		for (const LV2_Options_Option* o = options; o->key; ++o) {
175 			if (o->context == LV2_OPTIONS_INSTANCE && o->key == ui_scale && o->type == atom_Float) {
176 				float ui_scale = *(const float*)o->value;
177 				if (ui_scale < 1.0) { ui_scale = 1.0; }
178 				if (ui_scale > 2.0) { ui_scale = 2.0; }
179 				self->ui_scale = ui_scale;
180 			}
181 		}
182 	}
183 
184 	return (LV2_Handle)self;
185 }
186 
187 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)188 connect_port(LV2_Handle instance,
189              uint32_t   port,
190              void*      data)
191 {
192 	Fil4* self = (Fil4*)instance;
193 	if (port == FIL_ATOM_CONTROL) {
194 		self->control = (const LV2_Atom_Sequence*) data;
195 	} else if (port == FIL_ATOM_NOTIFY) {
196 		self->notify = (LV2_Atom_Sequence*) data;
197 	} else if (port <= FIL_OUTPUT1) {
198 		self->_port[port] = (float*) data;
199 	}
200 }
201 
exp2ap(float x)202 static float exp2ap (float x) {
203 	int i;
204 
205 	i = (int)(floorf (x));
206 	x -= i;
207 	return ldexpf (1 + x * (0.6930f + x * (0.2416f + x * (0.0517f + x * 0.0137f))), i);
208 }
209 
210 /** forge atom-vector of raw data */
tx_rawaudio(LV2_Atom_Forge * forge,Fil4LV2URIs * uris,const float sr,const uint32_t chn,const size_t n_samples,void * data)211 static void tx_rawaudio (LV2_Atom_Forge *forge, Fil4LV2URIs *uris,
212                          const float sr, const uint32_t chn,
213                          const size_t n_samples, void *data)
214 {
215 	LV2_Atom_Forge_Frame frame;
216 	/* forge container object of type 'rawaudio' */
217 	lv2_atom_forge_frame_time(forge, 0);
218 	x_forge_object(forge, &frame, 1, uris->rawaudio);
219 
220 	/* add float attribute 'samplerate' */
221 	lv2_atom_forge_property_head(forge, uris->samplerate, 0);
222 	lv2_atom_forge_float(forge, sr);
223 
224 	/* add integer attribute 'channelid' */
225 	lv2_atom_forge_property_head(forge, uris->channelid, 0);
226 	lv2_atom_forge_int(forge, chn);
227 
228 	/* add vector of floats raw 'audiodata' */
229 	lv2_atom_forge_property_head(forge, uris->audiodata, 0);
230 	lv2_atom_forge_vector(forge, sizeof(float), uris->atom_Float, n_samples, data);
231 
232 	/* close off atom-object */
233 	lv2_atom_forge_pop(forge, &frame);
234 }
235 
tx_state(Fil4 * self)236 static void tx_state (Fil4* self)
237 {
238 	LV2_Atom_Forge_Frame frame;
239 	lv2_atom_forge_frame_time(&self->forge, 0);
240 	x_forge_object(&self->forge, &frame, 1, self->uris.state);
241 
242 	lv2_atom_forge_property_head(&self->forge, self->uris.samplerate, 0);
243 	lv2_atom_forge_float(&self->forge, self->rate);
244 
245 	lv2_atom_forge_property_head(&self->forge, self->uris.s_dbscale, 0);
246 	lv2_atom_forge_float(&self->forge, self->db_scale);
247 
248 	lv2_atom_forge_property_head(&self->forge, self->uris.s_fftgain, 0);
249 	lv2_atom_forge_float(&self->forge, self->fft_gain);
250 
251 	lv2_atom_forge_property_head(&self->forge, self->uris.s_fftmode, 0);
252 	lv2_atom_forge_int(&self->forge, self->fft_mode);
253 
254 	lv2_atom_forge_property_head(&self->forge, self->uris.s_fftchan, 0);
255 	lv2_atom_forge_int(&self->forge, self->fft_chan);
256 
257 	lv2_atom_forge_property_head(&self->forge, self->uris.s_uiscale, 0);
258 	lv2_atom_forge_float(&self->forge, self->ui_scale);
259 
260 	lv2_atom_forge_property_head(&self->forge, self->uris.s_kbtuning, 0);
261 	lv2_atom_forge_float(&self->forge, self->kb_tuning);
262 
263 	lv2_atom_forge_pop(&self->forge, &frame);
264 }
265 
process_channel(Fil4 * self,FilterChannel * fc,uint32_t p_samples,uint32_t chn)266 static void process_channel(Fil4* self, FilterChannel *fc, uint32_t p_samples, uint32_t chn) {
267 
268 	/* localize variables */
269 	const float ls_gain = *self->_port[IIR_LS_EN] > 0 ? powf (10.f, .05f * self->_port[IIR_LS_GAIN][0]) : 1.f;
270 	const float hs_gain = *self->_port[IIR_HS_EN] > 0 ? powf (10.f, .05f * self->_port[IIR_HS_GAIN][0]) : 1.f;
271 	const float ls_freq = *self->_port[IIR_LS_FREQ];
272 	const float hs_freq = *self->_port[IIR_HS_FREQ];
273 	// map [2^-4 .. 4] to [2^(-3/2) .. 2]
274 	const float ls_q    = .2129f + self->_port[IIR_LS_Q][0] / 2.25f;
275 	const float hs_q    = .2129f + self->_port[IIR_HS_Q][0] / 2.25f;
276 	const bool  hipass  = *self->_port[FIL_HIPASS] > 0 ? true : false;
277 	const bool  lopass  = *self->_port[FIL_LOPASS] > 0 ? true : false;
278 	float hifreq  = *self->_port[FIL_HIFREQ];
279 	float hi_q    = *self->_port[FIL_HIQ];
280 	float lofreq  = *self->_port[FIL_LOFREQ];
281 	float lo_q    = *self->_port[FIL_LOQ];
282 
283 	float *aip = self->_port [FIL_INPUT0 + (chn<<1)];
284 	float *aop = self->_port [FIL_OUTPUT0 + (chn<<1)];
285 
286 	float sfreq [NSECT];
287 	float sband [NSECT];
288 	float sgain [NSECT];
289 
290 
291 	/* clamp inputs to legal range - see lv2ttl/fil4.ports.ttl.in */
292 	if (lofreq > self->below_nyquist) lofreq = self->below_nyquist;
293 	if (lofreq < 630) lofreq = 630;
294 	if (lofreq > 20000) lofreq = 20000;
295 	if (lo_q < 0.0625) lo_q = 0.0625;
296 	if (lo_q > 4.0)    lo_q = 4.0;
297 
298 	if (hifreq > self->below_nyquist) hifreq = self->below_nyquist;
299 	if (hifreq < 10) hifreq = 10;
300 	if (hifreq > 1000) hifreq = 1000;
301 	if (hi_q < 0.0625) hi_q = 0.0625;
302 	if (hi_q > 4.0)    hi_q = 4.0;
303 
304 	// shelf-filter freq,q is clamped in src/iir.h
305 
306 
307 	/* calculate target values, parameter smoothing */
308 	const float fgain = exp2ap (0.1661 * self->_port [FIL_GAIN][0]);
309 
310 	for (int j = 0; j < NSECT; ++j) {
311 		float t = self->_port [FIL_SEC1 + 4 * j + Fil4Paramsect::FREQ][0] / self->rate;
312 		if (t < 0.0002) t = 0.0002;
313 		if (t > 0.4998) t = 0.4998;
314 
315 		sfreq [j] = t;
316 		sband [j] = self->_port [FIL_SEC1 + 4 * j + Fil4Paramsect::BAND][0];
317 
318 		if (self->_port [FIL_SEC1 + 4 * j + Fil4Paramsect::SECT][0] > 0) {
319 			sgain [j] = exp2ap (0.1661 * self->_port [FIL_SEC1 + 4 * j + Fil4Paramsect::GAIN][0]);
320 		} else {
321 			sgain [j] = 1.0;
322 		}
323 	}
324 
325 	while (p_samples) {
326 		uint32_t i;
327 		float sig [48];
328 		const uint32_t k = (p_samples > 48) ? 32 : p_samples;
329 
330 		float t = fgain;
331 		float g = fc->_gain;
332 		if      (t > 1.25 * g) t = 1.25 * g;
333 		else if (t < 0.80 * g) t = 0.80 * g;
334 		fc->_gain = t;
335 		float d = (t - g) / k;
336 
337 		/* apply gain */
338 		for (i = 0; i < k; i++) {
339 			g += d;
340 			sig [i] = g * aip [i];
341 		}
342 
343 		/* update IIR */
344 		if (iir_interpolate (&fc->iir_lowshelf,  ls_gain, ls_freq, ls_q)) {
345 			iir_calc_lowshelf (&fc->iir_lowshelf);
346 			self->need_expose = true;
347 		}
348 		if (iir_interpolate (&fc->iir_highshelf, hs_gain, hs_freq, hs_q)) {
349 			iir_calc_highshelf (&fc->iir_highshelf);
350 			self->need_expose = true;
351 		}
352 
353 		if (hip_interpolate (&fc->hip, hipass, hifreq, hi_q)) {
354 			self->need_expose = true;
355 		}
356 		if (lop_interpolate (&fc->lop, lopass, lofreq, lo_q)) {
357 			self->need_expose = true;
358 		}
359 
360 		/* run filters */
361 
362 		hip_compute (&fc->hip, k, sig);
363 		lop_compute (&fc->lop, k, sig);
364 
365 		for (int j = 0; j < NSECT; ++j) {
366 			if (fc->_sect [j].proc (k, sig, sfreq [j], sband [j], sgain [j])) {
367 				self->need_expose = true;
368 			}
369 		}
370 
371 		iir_compute (&fc->iir_lowshelf, k, sig);
372 		iir_compute (&fc->iir_highshelf, k, sig);
373 
374 		/* fade 16 * 32 samples when enable changes */
375 		int j = fc->_fade;
376 		g = j / 16.0;
377 
378 		float *p = NULL;
379 
380 		if (self->_port [FIL_ENABLE][0] > 0) {
381 			if (j == 16) p = sig;
382 			else ++j;
383 		}
384 		else
385 		{
386 			if (j == 0) p = aip;
387 			else --j;
388 		}
389 		fc->_fade = j;
390 
391 		if (p) {
392 			/* active or bypassed */
393 			if (aop != p) { // no in-place bypass
394 				memcpy (aop, p, k * sizeof (float));
395 			}
396 		} else {
397 			/* fade in/out */
398 			self->need_expose = true;
399 			d = (j / 16.0 - g) / k;
400 			for (uint32_t i = 0; i < k; ++i) {
401 				g += d;
402 				aop [i] = g * sig [i] + (1 - g) * aip [i];
403 			}
404 		}
405 
406 		aip += k;
407 		aop += k;
408 		p_samples -= k;
409 	}
410 }
411 
412 static void
run(LV2_Handle instance,uint32_t n_samples)413 run(LV2_Handle instance, uint32_t n_samples)
414 {
415 	Fil4* self = (Fil4*)instance;
416 
417 	/* check atom buffer size */
418 	const size_t size = (sizeof(float) * self->n_channels * n_samples + 64);
419 	const uint32_t capacity = self->notify->atom.size;
420 	bool capacity_ok = true;
421 	if (capacity < size + 128) {
422 		capacity_ok = false;
423 		if (!printed_capacity_warning) {
424 #ifdef _WIN32
425 			fprintf (stderr, "fil4.lv2 error: LV2 comm-buffersize is insufficient %d/%d bytes.\n",
426 					capacity, (int)size + 160);
427 #else
428 			fprintf (stderr, "fil4.lv2 error: LV2 comm-buffersize is insufficient %d/%zu bytes.\n",
429 					capacity, size + 160);
430 #endif
431 			printed_capacity_warning = true;
432 		}
433 	}
434 
435 	/* prepare forge buffer and initialize atom-sequence */
436 	lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, capacity);
437 	lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0);
438 
439 	// process messages from GUI;
440 	if (self->control) {
441 		LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(self->control)->body);
442 		while(!lv2_atom_sequence_is_end(&(self->control)->body, (self->control)->atom.size, ev)) {
443 			if (ev->body.type == self->uris.atom_Blank || ev->body.type == self->uris.atom_Object) {
444 				const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body;
445 				if (obj->body.otype == self->uris.ui_off) {
446 					self->ui_active = false;
447 				}
448 				else if (obj->body.otype == self->uris.ui_on) {
449 					self->ui_active = true;
450 					self->send_state_to_ui = true;
451 				}
452 				else if (obj->body.otype == self->uris.state) {
453 					const LV2_Atom* v = NULL;
454 					lv2_atom_object_get(obj, self->uris.s_fftmode, &v, 0);
455 					if (v) { self->fft_mode = ((LV2_Atom_Int*)v)->body; }
456 
457 					v = NULL;
458 					lv2_atom_object_get(obj, self->uris.s_fftgain, &v, 0);
459 					if (v) { self->fft_gain = ((LV2_Atom_Float*)v)->body; }
460 
461 					v = NULL;
462 					lv2_atom_object_get(obj, self->uris.s_fftchan, &v, 0);
463 					if (v) { self->fft_chan = ((LV2_Atom_Int*)v)->body; }
464 
465 					v = NULL;
466 					lv2_atom_object_get(obj, self->uris.s_dbscale, &v, 0);
467 					if (v) { self->db_scale = ((LV2_Atom_Float*)v)->body; }
468 
469 					v = NULL;
470 					lv2_atom_object_get(obj, self->uris.s_uiscale, &v, 0);
471 					if (v) { self->ui_scale = ((LV2_Atom_Float*)v)->body; }
472 
473 					v = NULL;
474 					lv2_atom_object_get(obj, self->uris.s_kbtuning, &v, 0);
475 					if (v) { self->kb_tuning = ((LV2_Atom_Float*)v)->body; }
476 				}
477 			}
478 			ev = lv2_atom_sequence_next(ev);
479 		}
480 	}
481 
482 	if (self->ui_active && self->send_state_to_ui) {
483 		self->send_state_to_ui = false;
484 		self->resend_peak = self->rate / n_samples;
485 		tx_state (self);
486 	}
487 
488 	const int32_t fft_mode = self->ui_active ? (self->fft_mode & 0xf) : 0;
489 
490 	// send raw input to GUI (for spectrum analysis)
491 	if (fft_mode > 0 && (fft_mode & 1) == 0 && capacity_ok) {
492 		for (uint32_t c = 0; c < self->n_channels; ++c) {
493 			tx_rawaudio (&self->forge, &self->uris, self->rate, c, n_samples, self->_port [FIL_INPUT0 + (c<<1)]);
494 		}
495 	}
496 
497 	if (self->peak_reset != (int)(floorf (self->_port [FIL_PEAK_RESET][0]))) {
498 		self->peak_signal = 0;
499 		self->peak_reset = (int)(floorf (self->_port [FIL_PEAK_RESET][0]));
500 	}
501 
502 	// audio processing & peak calc.
503 	float peak = self->peak_signal;
504 	for (uint32_t c = 0; c < self->n_channels; ++c) {
505 		process_channel (self, &self->fc[c], n_samples, c);
506 
507 		const float * const d = self->_port [FIL_OUTPUT0 + (c<<1)];
508 		for (uint32_t i = 0; i < n_samples; ++i) {
509 			const float pk = fabsf (d[i]);
510 			if (pk > peak) {
511 				peak = pk;
512 			}
513 		}
514 	}
515 
516 	self->enabled = self->_port [FIL_ENABLE][0] > 0;
517 
518 	self->peak_signal = peak;
519 	if (self->resend_peak > 0) {
520 		--self->resend_peak;
521 		*self->_port [FIL_PEAK_DB] = -120 - self->resend_peak / 100.f;
522 	} else {
523 		*self->_port [FIL_PEAK_DB] = (peak > 1e-6) ? 20.f * log10f (peak) : -120;
524 	}
525 
526 	// send processed output to GUI (for analysis)
527 	if ((fft_mode & 1) == 1 && capacity_ok) {
528 		for (uint32_t c = 0; c < self->n_channels; ++c) {
529 			tx_rawaudio (&self->forge, &self->uris, self->rate, c, n_samples, self->_port [FIL_OUTPUT0 + (c<<1)]);
530 		}
531 	}
532 
533 	/* close off atom-sequence */
534 	lv2_atom_forge_pop(&self->forge, &self->frame);
535 
536 #ifdef DISPLAY_INTERFACE
537 	if (self->need_expose && self->queue_draw) {
538 		self->need_expose = false;
539 		self->queue_draw->queue_draw (self->queue_draw->handle);
540 	}
541 #endif
542 }
543 
544 #define STATESTORE(URI, TYPE, VALUE) \
545 	store(handle, self->uris.URI, \
546 			(void*) &(VALUE), sizeof(uint32_t), \
547 			self->uris.atom_ ## TYPE, \
548 			LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); \
549 
550 static LV2_State_Status
fil4_save(LV2_Handle instance,LV2_State_Store_Function store,LV2_State_Handle handle,uint32_t flags,const LV2_Feature * const * features)551 fil4_save(LV2_Handle                instance,
552           LV2_State_Store_Function  store,
553           LV2_State_Handle          handle,
554           uint32_t                  flags,
555           const LV2_Feature* const* features)
556 {
557 	Fil4* self = (Fil4*)instance;
558 
559 	STATESTORE(s_dbscale, Float, self->db_scale)
560 	STATESTORE(s_fftgain, Float, self->fft_gain)
561 	STATESTORE(s_uiscale, Float, self->ui_scale)
562 	STATESTORE(s_kbtuning, Float, self->kb_tuning)
563 	STATESTORE(s_fftmode, Int, self->fft_mode)
564 	STATESTORE(s_fftchan, Int, self->fft_chan)
565 
566 	return LV2_STATE_SUCCESS;
567 }
568 
569 #define STATEREAD(URI, TYPE, CAST, PARAM) \
570 	value = retrieve(handle, self->uris.URI, &size, &type, &valflags); \
571 	if (value && size == sizeof(uint32_t) && type == self->uris.atom_ ## TYPE) { \
572 		PARAM = *((const CAST *)value); \
573 	}
574 
575 
576 static LV2_State_Status
fil4_restore(LV2_Handle instance,LV2_State_Retrieve_Function retrieve,LV2_State_Handle handle,uint32_t flags,const LV2_Feature * const * features)577 fil4_restore(LV2_Handle                  instance,
578              LV2_State_Retrieve_Function retrieve,
579              LV2_State_Handle            handle,
580              uint32_t                    flags,
581              const LV2_Feature* const*   features)
582 {
583 	Fil4* self = (Fil4*)instance;
584 	const void* value;
585 	size_t   size;
586 	uint32_t type;
587 	uint32_t valflags;
588 
589 	STATEREAD(s_dbscale, Float, float,   self->db_scale)
590 	STATEREAD(s_fftgain, Float, float,   self->fft_gain)
591 	STATEREAD(s_uiscale, Float, float,   self->ui_scale)
592 	STATEREAD(s_kbtuning, Float, float,   self->kb_tuning)
593 	STATEREAD(s_fftmode, Int,   int32_t, self->fft_mode)
594 	STATEREAD(s_fftchan, Int,   int32_t, self->fft_chan)
595 
596 	self->send_state_to_ui = true;
597 	return LV2_STATE_SUCCESS;
598 }
599 
600 static void
cleanup(LV2_Handle instance)601 cleanup(LV2_Handle instance)
602 {
603 #ifdef DISPLAY_INTERFACE
604 	Fil4* self = (Fil4*)instance;
605 	if (self->display) {
606 		cairo_surface_destroy (self->display);
607 	}
608 #endif
609 	free(instance);
610 }
611 #ifdef WITH_SIGNATURE
612 #define RTK_URI FIL4_URI
613 #include "gpg_init.c"
614 #include WITH_SIGNATURE
615 struct license_info license_infos = {
616 	"x42-Equalizer",
617 	"http://x42-plugins.com/x42/x42-eq"
618 };
619 #include "gpg_lv2ext.c"
620 #endif
621 
622 #include "idpy.c"
623 
624 const void*
extension_data(const char * uri)625 extension_data(const char* uri)
626 {
627 	static const LV2_State_Interface  state  = { fil4_save, fil4_restore };
628 	if (!strcmp(uri, LV2_STATE__interface)) {
629 		return &state;
630 	}
631 #ifdef DISPLAY_INTERFACE
632 	static const LV2_Inline_Display_Interface display  = { fil4_render };
633 	if (!strcmp(uri, LV2_INLINEDISPLAY__interface)) {
634 #if (defined _WIN32 && defined RTK_STATIC_INIT)
635 		static int once = 0;
636 		if (!once) {once = 1; gobject_init_ctor();}
637 #endif
638 		return &display;
639 	}
640 #endif
641 #ifdef WITH_SIGNATURE
642 	LV2_LICENSE_EXT_C
643 #endif
644 	return NULL;
645 }
646 
647 static const LV2_Descriptor descriptor_mono = {
648 	FIL4_URI "mono",
649 	instantiate,
650 	connect_port,
651 	NULL,
652 	run,
653 	NULL,
654 	cleanup,
655 	extension_data
656 };
657 
658 static const LV2_Descriptor descriptor_stereo = {
659 	FIL4_URI "stereo",
660 	instantiate,
661 	connect_port,
662 	NULL,
663 	run,
664 	NULL,
665 	cleanup,
666 	extension_data
667 };
668 
669 #undef LV2_SYMBOL_EXPORT
670 #ifdef _WIN32
671 #    define LV2_SYMBOL_EXPORT __declspec(dllexport)
672 #else
673 #    define LV2_SYMBOL_EXPORT  __attribute__ ((visibility ("default")))
674 #endif
675 LV2_SYMBOL_EXPORT
676 const LV2_Descriptor*
lv2_descriptor(uint32_t index)677 lv2_descriptor(uint32_t index)
678 {
679 	switch (index) {
680 	case 0:
681 		return &descriptor_mono;
682 	case 1:
683 		return &descriptor_stereo;
684 	default:
685 		return NULL;
686 	}
687 }
688