+ AUTHORS: updated
[calf.git] / src / modules_small.cpp
blobf9b2f770de371d9f358baa905a62370709ec2efc
1 /* Calf DSP Library
2 * Small modules for modular synthesizers
4 * Copyright (C) 2001-2008 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, USA.
21 #include <config.h>
22 #include <assert.h>
23 #include <memory.h>
24 #include <calf/primitives.h>
25 #include <calf/biquad.h>
26 #include <calf/inertia.h>
27 #include <calf/audio_fx.h>
28 #include <calf/plugininfo.h>
29 #include <calf/giface.h>
30 #include <calf/lv2wrap.h>
31 #include <calf/osc.h>
32 #include <calf/modules_small.h>
33 #include <calf/lv2helpers.h>
35 #ifdef ENABLE_EXPERIMENTAL
37 #if USE_LV2
38 #define LV2_SMALL_WRAPPER(mod, name) static calf_plugins::lv2_small_wrapper<small_plugins::mod##_audio_module> lv2_small_##mod(name);
39 #else
40 #define LV2_SMALL_WRAPPER(...)
41 #endif
43 #define SMALL_WRAPPERS(mod, name) LV2_SMALL_WRAPPER(mod, name)
45 #if USE_LV2
47 using namespace calf_plugins;
48 using namespace dsp;
49 using namespace std;
51 template<class Module> LV2_Descriptor lv2_small_wrapper<Module>::descriptor;
52 template<class Module> uint32_t lv2_small_wrapper<Module>::poly_port_types;
54 namespace small_plugins
57 class filter_base: public null_small_audio_module
59 public:
60 enum { in_signal, in_cutoff, in_resonance, in_count };
61 enum { out_signal, out_count};
62 float *ins[in_count];
63 float *outs[out_count];
64 static void port_info(plugin_info_iface *pii)
66 pii->audio_port("in", "In").input();
67 pii->control_port("cutoff", "Cutoff", 1000).input().log_range(20, 20000);
68 pii->control_port("res", "Resonance", 0.707).input().log_range(0.707, 20);
69 pii->audio_port("out", "Out").output();
71 dsp::biquad_d1<float> filter;
73 void activate() {
74 filter.reset();
76 inline void process_inner(uint32_t count) {
77 for (uint32_t i = 0; i < count; i++)
78 outs[out_signal][i] = filter.process(ins[in_signal][i]);
79 filter.sanitize();
83 class lp_filter_audio_module: public filter_base
85 public:
86 inline void process(uint32_t count) {
87 filter.set_lp_rbj(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), *ins[in_resonance], srate);
88 process_inner(count);
90 static void plugin_info(plugin_info_iface *pii)
92 pii->names("lowpass12", "12dB/oct RBJ Lowpass", "lv2:LowpassPlugin");
93 port_info(pii);
97 class hp_filter_audio_module: public filter_base
99 public:
100 inline void process(uint32_t count) {
101 filter.set_hp_rbj(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), *ins[in_resonance], srate);
102 process_inner(count);
104 static void plugin_info(plugin_info_iface *pii)
106 pii->names("highpass12", "12dB/oct RBJ Highpass", "lv2:HighpassPlugin");
107 port_info(pii);
111 class bp_filter_audio_module: public filter_base
113 public:
114 inline void process(uint32_t count) {
115 filter.set_bp_rbj(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), *ins[in_resonance], srate);
116 process_inner(count);
118 static void plugin_info(plugin_info_iface *pii)
120 pii->names("bandpass6", "6dB/oct RBJ Bandpass", "lv2:BandpassPlugin");
121 port_info(pii);
125 class br_filter_audio_module: public filter_base
127 public:
128 inline void process(uint32_t count) {
129 filter.set_br_rbj(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), *ins[in_resonance], srate);
130 process_inner(count);
132 static void plugin_info(plugin_info_iface *pii)
134 pii->names("notch6", "6dB/oct RBJ Bandpass", "lv2:FilterPlugin");
135 port_info(pii);
139 class onepole_filter_base: public null_small_audio_module
141 public:
142 enum { in_signal, in_cutoff, in_count };
143 enum { out_signal, out_count};
144 float *ins[in_count];
145 float *outs[out_count];
146 dsp::onepole<float> filter;
147 static parameter_properties param_props[];
149 static void port_info(plugin_info_iface *pii)
151 pii->audio_port("In", "in").input();
152 pii->control_port("Cutoff", "cutoff", 1000).input().log_range(20, 20000);
153 pii->audio_port("Out", "out").output();
155 /// do not export mode and inertia as CVs, as those are settings and not parameters
156 void activate() {
157 filter.reset();
161 class onepole_lp_filter_audio_module: public onepole_filter_base
163 public:
164 void process(uint32_t count) {
165 filter.set_lp(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), srate);
166 for (uint32_t i = 0; i < count; i++)
167 outs[0][i] = filter.process_lp(ins[0][i]);
168 filter.sanitize();
170 static void plugin_info(plugin_info_iface *pii)
172 pii->names("lowpass6", "6dB/oct Lowpass Filter", "lv2:LowpassPlugin");
173 port_info(pii);
177 class onepole_hp_filter_audio_module: public onepole_filter_base
179 public:
180 void process(uint32_t count) {
181 filter.set_hp(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), srate);
182 for (uint32_t i = 0; i < count; i++)
183 outs[0][i] = filter.process_hp(ins[0][i]);
184 filter.sanitize();
186 static void plugin_info(plugin_info_iface *pii)
188 pii->names("highpass6", "6dB/oct Highpass Filter", "lv2:HighpassPlugin");
189 port_info(pii);
193 class onepole_ap_filter_audio_module: public onepole_filter_base
195 public:
196 void process(uint32_t count) {
197 filter.set_ap(clip<float>(*ins[in_cutoff], 0.0001, 0.48 * srate), srate);
198 for (uint32_t i = 0; i < count; i++)
199 outs[0][i] = filter.process_ap(ins[0][i]);
200 filter.sanitize();
202 static void plugin_info(plugin_info_iface *pii)
204 pii->names("allpass", "1-pole 1-zero Allpass Filter", "lv2:AllpassPlugin");
205 port_info(pii);
209 /// This works for 1 or 2 operands only...
210 template<int Inputs>
211 class audio_operator_audio_module: public small_audio_module_base<Inputs, 1>
213 public:
214 static void port_info(plugin_info_iface *pii)
216 if (Inputs == 1)
217 pii->audio_port("in", "In", "").input();
218 else
220 pii->audio_port("in_1", "In 1", "").input();
221 pii->audio_port("in_2", "In 2", "").input();
223 pii->audio_port("out", "Out", "").output();
227 class min_audio_module: public audio_operator_audio_module<2>
229 public:
230 void process(uint32_t count) {
231 for (uint32_t i = 0; i < count; i++)
232 outs[0][i] = std::min(ins[0][i], ins[1][i]);
234 static void plugin_info(plugin_info_iface *pii)
236 pii->names("min", "Minimum (A)", "kf:MathOperatorPlugin", "min");
237 port_info(pii);
241 class max_audio_module: public audio_operator_audio_module<2>
243 public:
244 void process(uint32_t count) {
245 for (uint32_t i = 0; i < count; i++)
246 outs[0][i] = std::max(ins[0][i], ins[1][i]);
248 static void plugin_info(plugin_info_iface *pii)
250 pii->names("max", "Maximum (A)", "kf:MathOperatorPlugin", "max");
251 port_info(pii);
255 class minus_audio_module: public audio_operator_audio_module<2>
257 public:
258 void process(uint32_t count) {
259 for (uint32_t i = 0; i < count; i++)
260 outs[0][i] = ins[0][i] - ins[1][i];
262 static void plugin_info(plugin_info_iface *pii)
264 pii->names("minus", "Subtract (A)", "kf:MathOperatorPlugin", "-");
265 port_info(pii);
269 class mul_audio_module: public audio_operator_audio_module<2>
271 public:
272 void process(uint32_t count) {
273 for (uint32_t i = 0; i < count; i++)
274 outs[0][i] = ins[0][i] * ins[1][i];
276 static void plugin_info(plugin_info_iface *pii)
278 pii->names("mul", "Multiply (A)", "kf:MathOperatorPlugin", "*");
279 port_info(pii);
283 class neg_audio_module: public audio_operator_audio_module<1>
285 public:
286 void process(uint32_t count) {
287 for (uint32_t i = 0; i < count; i++)
288 outs[0][i] = -ins[0][i];
290 static void plugin_info(plugin_info_iface *pii)
292 pii->names("neg", "Negative (A)", "kf:MathOperatorPlugin", "-");
293 port_info(pii);
297 template<class T, int Inputs> struct polymorphic_process;
299 template<class T> struct polymorphic_process<T, 1>
301 static inline void run(float **ins, float **outs, uint32_t count, uint32_t poly_port_types) {
302 if (poly_port_types < 2) // control to control or audio to control
303 *outs[0] = T::process_single(*ins[0]);
304 else if (poly_port_types == 2) {
305 outs[0][0] = T::process_single(ins[0][0]); // same as above, but the index might not be 0 in later versions
306 for (uint32_t i = 1; i < count; i++)
307 outs[0][i] = outs[0][0];
309 else { // audio to audio
310 for (uint32_t i = 0; i < count; i++)
311 outs[0][i] = T::process_single(ins[0][i]);
316 template<class T> struct polymorphic_process<T, 2>
318 static inline void run(float **ins, float **outs, uint32_t count, uint32_t poly_port_types) {
319 poly_port_types &= ~1;
320 if (poly_port_types < 4) // any to control
321 *outs[0] = T::process_single(*ins[0], *ins[1]);
322 else if (poly_port_types == 4) { // control+control to audio
323 outs[0][0] = T::process_single(*ins[0], *ins[1]); // same as above, but the index might not be 0 in later versions
324 for (uint32_t i = 1; i < count; i++)
325 outs[0][i] = outs[0][0];
327 else { // {control+audio or audio+control or audio+audio} to audio
328 // use masks to force 0 for index for control ports
329 uint32_t mask1 = null_small_audio_module::port_audio_mask(0, poly_port_types);
330 uint32_t mask2 = null_small_audio_module::port_audio_mask(1, poly_port_types);
331 for (uint32_t i = 0; i < count; i++)
332 outs[0][i] = T::process_single(ins[0][i & mask1], ins[1][i & mask2]);
337 /// This works for 1 or 2 operands only...
338 template<int Inputs>
339 class control_operator_audio_module: public small_audio_module_base<Inputs, 1>
341 public:
342 using small_audio_module_base<Inputs, 1>::ins;
343 using small_audio_module_base<Inputs, 1>::outs;
344 using small_audio_module_base<Inputs, 1>::poly_port_types;
345 static void port_info(plugin_info_iface *pii, control_port_info_iface *cports[Inputs + 1], float in1 = 0, float in2 = 0)
347 int idx = 0;
348 if (Inputs == 1)
349 cports[idx++] = &pii->control_port("in", "In", in1, "").polymorphic().poly_audio().input();
350 else
352 cports[idx++] = &pii->control_port("in_1", "In 1", in1, "").polymorphic().poly_audio().input();
353 cports[idx++] = &pii->control_port("in_2", "In 2", in2, "").polymorphic().poly_audio().input();
355 cports[idx++] = &pii->control_port("out", "Out", 0, "").poly_audio().output();
358 template<class T> inline void do_process(uint32_t count) {
359 polymorphic_process<T, Inputs>::run(ins, outs, count, poly_port_types);
363 class minus_c_audio_module: public control_operator_audio_module<2>
365 public:
366 static inline float process_single(float x, float y) {
367 return x - y;
369 void process(uint32_t count) {
370 do_process<minus_c_audio_module>(count);
372 static void plugin_info(plugin_info_iface *pii)
374 pii->names("minus_c", "Subtract (C)", "kf:MathOperatorPlugin", "-");
375 control_port_info_iface *cports[3];
376 port_info(pii, cports);
380 class mul_c_audio_module: public control_operator_audio_module<2>
382 public:
383 static inline float process_single(float x, float y) {
384 return x * y;
386 void process(uint32_t count) {
387 do_process<mul_c_audio_module>(count);
389 static void plugin_info(plugin_info_iface *pii)
391 pii->names("mul_c", "Multiply (C)", "kf:MathOperatorPlugin", "*");
392 control_port_info_iface *cports[3];
393 port_info(pii, cports);
397 class neg_c_audio_module: public control_operator_audio_module<1>
399 public:
400 static inline float process_single(float x) {
401 return -x;
403 void process(uint32_t count) {
404 do_process<neg_c_audio_module>(count);
406 static void plugin_info(plugin_info_iface *pii)
408 pii->names("neg_c", "Negative (C)", "kf:MathOperatorPlugin", "-");
409 control_port_info_iface *cports[2];
410 port_info(pii, cports);
414 class min_c_audio_module: public control_operator_audio_module<2>
416 public:
417 static inline float process_single(float x, float y) {
418 return std::min(x, y);
420 void process(uint32_t count) {
421 do_process<min_c_audio_module>(count);
423 static void plugin_info(plugin_info_iface *pii)
425 pii->names("min_c", "Minimum (C)", "kf:MathOperatorPlugin", "min");
426 control_port_info_iface *cports[3];
427 port_info(pii, cports);
431 class max_c_audio_module: public control_operator_audio_module<2>
433 public:
434 static inline float process_single(float x, float y) {
435 return std::max(x, y);
437 void process(uint32_t count) {
438 do_process<max_c_audio_module>(count);
440 static void plugin_info(plugin_info_iface *pii)
442 pii->names("max_c", "Maximum (C)", "kf:MathOperatorPlugin", "max");
443 control_port_info_iface *cports[3];
444 port_info(pii, cports);
448 class less_c_audio_module: public control_operator_audio_module<2>
450 public:
451 static inline float process_single(float x, float y) {
452 return x < y;
454 void process(uint32_t count) {
455 do_process<less_c_audio_module>(count);
457 static void plugin_info(plugin_info_iface *pii)
459 pii->names("less_c", "Less than (C)", "kf:MathOperatorPlugin", "<");
460 control_port_info_iface *cports[2];
461 port_info(pii, cports);
462 cports[2]->toggle();
466 class level2edge_c_audio_module: public control_operator_audio_module<1>
468 public:
469 bool last_value;
470 void activate() {
471 last_value = false;
473 void process(uint32_t count) {
474 *outs[0] = (*ins[0] > 0 && !last_value) ? 1.f : 0.f;
475 last_value = *ins[0] > 0;
477 static void plugin_info(plugin_info_iface *pii)
479 pii->names("level2edge_c", "Level to edge (C)", "kf:BooleanPlugin");
480 control_port_info_iface *cports[2];
481 port_info(pii, cports);
482 cports[0]->toggle();
483 cports[1]->toggle().trigger();
487 class int_c_audio_module: public control_operator_audio_module<1>
489 public:
490 static inline float process_single(float x) {
491 return (int)x;
493 void process(uint32_t count) {
494 do_process<int_c_audio_module>(count);
496 static void plugin_info(plugin_info_iface *pii)
498 pii->names("int_c", "Integer value (C)", "kf:IntegerPlugin");
499 control_port_info_iface *cports[2];
500 port_info(pii, cports);
501 cports[0]->integer();
502 cports[1]->integer();
506 class bitwise_op_c_module_base: public control_operator_audio_module<2>
508 public:
509 static void port_info(plugin_info_iface *pii)
511 pii->control_port("in_1", "In 1", 0, "").polymorphic().poly_audio().integer().input();
512 pii->control_port("in_2", "In 2", 0, "").polymorphic().poly_audio().integer().input();
513 pii->control_port("out", "Out", 0, "").polymorphic().poly_audio().integer().output();
516 class bit_and_c_audio_module: public bitwise_op_c_module_base
518 public:
519 static inline float process_single(float x, float y) {
520 return ((int)x) & ((int)y);
522 void process(uint32_t count) {
523 do_process<bit_and_c_audio_module>(count);
525 static void plugin_info(plugin_info_iface *pii)
527 pii->names("bit_and_c", "Bitwise AND (C)", "kf:IntegerPlugin");
528 port_info(pii);
532 class bit_or_c_audio_module: public bitwise_op_c_module_base
534 public:
535 static inline float process_single(float x, float y) {
536 return ((int)x) | ((int)y);
538 void process(uint32_t count) {
539 do_process<bit_or_c_audio_module>(count);
541 static void plugin_info(plugin_info_iface *pii)
543 pii->names("bit_or_c", "Bitwise OR (C)", "kf:IntegerPlugin");
544 port_info(pii);
548 class bit_xor_c_audio_module: public bitwise_op_c_module_base
550 public:
551 static inline float process_single(float x, float y) {
552 return ((int)x) ^ ((int)y);
554 void process(uint32_t count) {
555 do_process<bit_xor_c_audio_module>(count);
557 static void plugin_info(plugin_info_iface *pii)
559 pii->names("bit_xor_c", "Bitwise XOR (C)", "kf:IntegerPlugin");
560 port_info(pii);
564 class flipflop_c_audio_module: public control_operator_audio_module<1>
566 public:
567 bool last_value, output;
568 void activate() {
569 last_value = false;
570 output = false;
572 void process(uint32_t count) {
573 if (*ins[0] > 0 && !last_value)
574 output = !output;
575 *outs[0] = output ? 1.f : 0.f;
576 last_value = *ins[0] > 0;
578 static void plugin_info(plugin_info_iface *pii)
580 pii->names("flipflop_c", "T Flip-Flop (C)", "kf:BooleanPlugin");
581 control_port_info_iface *cports[2];
582 port_info(pii, cports);
583 cports[0]->toggle().trigger();
584 cports[1]->toggle();
588 class logical_and_c_audio_module: public control_operator_audio_module<2>
590 public:
591 static inline float process_single(float x, float y) {
592 return (x > 0 && y > 0) ? 1.f : 0.f;
594 void process(uint32_t count) {
595 do_process<logical_and_c_audio_module>(count);
597 static void plugin_info(plugin_info_iface *pii)
599 pii->names("logical_and_c", "Logical AND (C)", "kf:BooleanPlugin", "&&");
600 control_port_info_iface *cports[3];
601 port_info(pii, cports);
602 cports[0]->toggle();
603 cports[1]->toggle();
604 cports[2]->toggle();
608 class logical_or_c_audio_module: public control_operator_audio_module<2>
610 public:
611 static inline float process_single(float x, float y) {
612 return (x > 0 || y > 0) ? 1.f : 0.f;
614 void process(uint32_t count) {
615 do_process<logical_or_c_audio_module>(count);
617 static void plugin_info(plugin_info_iface *pii)
619 pii->names("logical_or_c", "Logical OR (C)", "kf:BooleanPlugin", "||");
620 control_port_info_iface *cports[3];
621 port_info(pii, cports);
622 cports[0]->toggle();
623 cports[1]->toggle();
624 cports[2]->toggle();
628 class logical_xor_c_audio_module: public control_operator_audio_module<2>
630 public:
631 static inline float process_single(float x, float y) {
632 return ((x > 0) != (y > 0)) ? 1.f : 0.f;
634 void process(uint32_t count) {
635 do_process<logical_xor_c_audio_module>(count);
637 static void plugin_info(plugin_info_iface *pii)
639 pii->names("logical_xor_c", "Logical XOR (C)", "kf:BooleanPlugin", "xor");
640 control_port_info_iface *cports[3];
641 port_info(pii, cports);
642 cports[0]->toggle();
643 cports[1]->toggle();
644 cports[2]->toggle();
648 class logical_not_c_audio_module: public control_operator_audio_module<1>
650 public:
651 static inline float process_single(float x) {
652 return (x <= 0) ? 1.f : 0.f;
654 void process(uint32_t count) {
655 do_process<logical_not_c_audio_module>(count);
657 static void plugin_info(plugin_info_iface *pii)
659 pii->names("logical_not_c", "Logical NOT (C)", "kf:BooleanPlugin", "!");
660 control_port_info_iface *cports[2];
661 port_info(pii, cports);
662 cports[0]->toggle();
663 cports[1]->toggle();
667 /// converter of trigger signals from audio to control rate
668 class trigger_a2c_audio_module: public null_small_audio_module
670 public:
671 enum { in_count = 1, out_count = 1 };
672 float *ins[in_count];
673 float *outs[out_count];
674 void process(uint32_t count) {
675 for (uint32_t i = 0; i < count; i++)
677 if (ins[0][i] > 0)
679 *outs[0] = 1.f;
680 return;
683 *outs[0] = 0.f;
685 static void plugin_info(plugin_info_iface *pii)
687 pii->names("trigger_a2c", "Audio-to-control OR", "kf:BooleanPlugin", "ta2c");
688 pii->audio_port("in", "In").input();
689 pii->control_port("out", "Out", 0.f).output().toggle();
693 /// Monostable multivibrator like 74121 or 74123, with reset input, progress output (0 to 1), "finished" signal, configurable to allow or forbid retriggering.
694 class timer_c_audio_module: public null_small_audio_module
696 public:
697 enum { in_trigger, in_time, in_reset, in_allow_retrig, in_count };
698 enum { out_running, out_finished, out_progress, out_count };
699 float *ins[in_count];
700 float *outs[out_count];
701 bool running, finished, old_trigger;
702 double state;
704 void activate()
706 state = 0.f;
707 running = false;
708 finished = false;
709 old_trigger = false;
711 static void plugin_info(plugin_info_iface *pii)
713 pii->names("timer_c", "Timer (C)", "lv2:UtilityPlugin");
714 pii->control_port("trigger", "Trigger", 0.f).input().toggle().trigger();
715 pii->control_port("time", "Time", 0.f).input();
716 pii->control_port("reset", "Reset", 0).input().toggle();
717 pii->control_port("allow_retrig", "Allow retrig", 0).input().toggle();
718 pii->control_port("running", "Running", 0.f).output().toggle();
719 pii->control_port("finished", "Finished", 0.f).output().toggle();
720 pii->control_port("progress", "Progress", 0.f).output().lin_range(0, 1);
722 void process(uint32_t count)
724 // This is a branch city, which is definitely a bad thing.
725 // Perhaps I'll add a bunch of __builtin_expect hints some day, but somebody would have to start using it first.
726 if (*ins[in_reset] > 0)
728 state = 0.0;
729 running = finished = false;
731 else
732 if (!old_trigger && *ins[in_trigger] > 0 && (!running || *ins[in_allow_retrig] > 0))
734 state = 0.0;
735 running = true;
736 finished = false;
738 else
739 if (running)
741 float rate = (1.0 / std::max(0.0000001f, *ins[in_time]));
742 state += rate * odsr * count;
743 if (state >= 1.0)
745 running = false;
746 finished = true;
747 state = 1.0;
750 old_trigger = *ins[in_trigger] > 0;
751 *outs[out_running] = running ? 1.f : 0.f;
752 *outs[out_finished] = finished ? 1.f : 0.f;
753 *outs[out_progress] = state;
757 /// 4-input priority multiplexer - without inertia. Outputs the first input if gate_1 is TRUE, else second input if gate_2 is TRUE, else... else "Else" input
758 class prio_mux_c_audio_module: public null_small_audio_module
760 public:
761 enum { in_in1, in_gate1, in_in2, in_gate2, in_in3, in_gate3, in_in4, in_gate4, in_else, in_count };
762 enum { out_value, out_count };
763 float *ins[in_count];
764 float *outs[out_count];
766 static void plugin_info(plugin_info_iface *pii)
768 pii->names("prio_mux_c", "Priority Multiplexer (C)", "kf:BooleanPlugin");
769 for (int i = 1; i <= 4; i++)
771 stringstream numb;
772 numb << i;
773 string num = numb.str();
774 pii->control_port("in_"+num, "In "+num, 0.f).input();
775 pii->control_port("gate_"+num, "Gate "+num, 0.f).input().toggle();
777 pii->control_port("in_else", "Else", 0.f).input();
778 pii->control_port("out", "Out", 0.f).output();
780 void process(uint32_t count)
782 for (int i = 0; i < 4; i++)
784 if (*ins[i * 2 + in_gate1] > 0)
786 *outs[out_value] = *ins[i * 2 + in_in1];
787 return;
790 *outs[out_value] = *ins[in_else];
794 /// 8-input priority encoder - outputs the index of the first port whose value is >0. 'Any' output is set whenever any of gates is set (which tells
795 /// apart no inputs set and 0th input set).
796 template<int N>
797 class prio_enc_c_audio_module: public null_small_audio_module
799 public:
800 enum { in_gate1, in_count = in_gate1 + N};
801 enum { out_value, out_any, out_count };
802 float *ins[in_count];
803 float *outs[out_count];
805 static void plugin_info(plugin_info_iface *pii)
807 char buf[32], buf2[64];
808 sprintf(buf, "prio_enc%d_c", N);
809 sprintf(buf2, "%d-input Priority Encoder (C)", N);
810 pii->names(buf, buf2, "kf:IntegerPlugin");
811 for (int i = 0; i < N; i++)
813 stringstream numb;
814 numb << i;
815 string num = numb.str();
816 pii->control_port("gate_"+num, "Gate "+num, 0.f).input().toggle();
818 pii->control_port("out", "Out", -1).output().integer();
819 pii->control_port("any", "Any", -1).output().toggle();
821 void process(uint32_t count)
823 for (int i = 0; i < N; i++)
825 if (*ins[in_gate1 + i] > 0)
827 *outs[out_value] = i;
828 *outs[out_any] = 1;
829 return;
832 *outs[out_value] = 0;
833 *outs[out_any] = 0;
837 typedef prio_enc_c_audio_module<8> prio_enc8_c_audio_module;
839 /// 8-input integer multiplexer, outputs the input selected by ((int)select input & 7)
840 template<int N>
841 class mux_c_audio_module: public null_small_audio_module
843 public:
844 enum { in_select, in_in1, in_count = in_in1 + N};
845 enum { out_value, out_count };
846 float *ins[in_count];
847 float *outs[out_count];
849 static void plugin_info(plugin_info_iface *pii)
851 char buf[32], buf2[64];
852 sprintf(buf, "mux%d_c", N);
853 sprintf(buf2, "%d-input Multiplexer (C)", N);
854 pii->names(buf, buf2, "kf:IntegerPlugin");
855 pii->control_port("select", "Select", 0.f).input().integer().lin_range(0, N - 1);
856 for (int i = 0; i < N; i++)
858 stringstream numb;
859 numb << i;
860 string num = numb.str();
861 pii->control_port("in_"+num, "In "+num, 0.f).input();
863 pii->control_port("out", "Out", -1).output();
865 void process(uint32_t count)
867 *outs[out_value] = *ins[in_in1 + ((N - 1) & (int)*ins[in_select])];
871 typedef mux_c_audio_module<4> mux4_c_audio_module;
872 typedef mux_c_audio_module<8> mux8_c_audio_module;
873 typedef mux_c_audio_module<16> mux16_c_audio_module;
875 /// Linear-to-exponential mapper
876 class map_lin2exp_audio_module: public null_small_audio_module
878 public:
879 enum { in_signal, in_from_min, in_from_max, in_to_min, in_to_max, in_count };
880 enum { out_signal, out_count };
881 float *ins[in_count];
882 float *outs[out_count];
884 static void plugin_info(plugin_info_iface *pii)
886 pii->names("lin2exp", "Lin-Exp Mapper", "lv2:UtilityPlugin");
887 pii->control_port("in", "In", 0.f).input();
888 pii->control_port("from_min", "Min (from)", 0).input();
889 pii->control_port("from_max", "Max (from)", 1).input();
890 pii->control_port("to_min", "Min (to)", 20).input();
891 pii->control_port("to_max", "Max (to)", 20000).input();
892 pii->control_port("out", "Out", 0.f).output();
894 void process(uint32_t count)
896 float normalized = (*ins[in_signal] - *ins[in_from_min]) / (*ins[in_from_max] - *ins[in_from_min]);
897 *outs[out_signal] = *ins[in_to_min] * pow(*ins[in_to_max] / *ins[in_to_min], normalized);
901 /// Schmitt trigger - http://en.wikipedia.org/wiki/Schmitt_trigger - also outputs a change signal (positive spike whenever output value is changed)
902 class schmitt_c_audio_module: public null_small_audio_module
904 public:
905 enum { in_signal, in_low, in_high, in_count };
906 enum { out_signal, out_change, out_count };
907 float *ins[in_count];
908 float *outs[out_count];
909 bool state;
911 void activate()
913 state = false;
915 static void plugin_info(plugin_info_iface *pii)
917 pii->names("schmitt_c", "Schmitt Trigger (C)", "kf:BooleanPlugin");
918 pii->control_port("in", "In", 0.f).input();
919 pii->control_port("low", "Low threshold", 0).input();
920 pii->control_port("high", "High threshold", 0.5).input();
921 pii->control_port("out", "Out", 0.f).output();
922 pii->control_port("change", "Change", 0.f).output();
924 void process(uint32_t count)
926 float value = *ins[in_signal];
927 bool new_state = state;
928 if (value <= *ins[in_low])
929 new_state = false;
930 if (value >= *ins[in_high])
931 new_state = true;
932 *outs[out_signal] = new_state ? 1.f : 0.f;
933 *outs[out_change] = (new_state != state) ? 1.f : 0.f;
934 state = new_state;
938 /// Stateless 'between' operator (lo <= in <= hi)
939 class between_c_audio_module: public null_small_audio_module
941 public:
942 enum { in_signal, in_low, in_high, in_count };
943 enum { out_signal, out_count };
944 float *ins[in_count];
945 float *outs[out_count];
947 static void plugin_info(plugin_info_iface *pii)
949 pii->names("between_c", "Between (C)", "kf:MathOperatorPlugin");
950 pii->control_port("in", "In", 0.f).input();
951 pii->control_port("low", "Low threshold", 0).input();
952 pii->control_port("high", "High threshold", 1).input();
953 pii->control_port("out", "Out", 0.f).output();
955 void process(uint32_t count)
957 float value = *ins[in_signal];
958 *outs[out_signal] = (value >= *ins[in_low] && value <= *ins[in_high]) ? 1.f : 0.f;
962 /// Clip to range
963 class clip_c_audio_module: public null_small_audio_module
965 public:
966 enum { in_signal, in_min, in_max, in_count };
967 enum { out_signal, out_count };
968 float *ins[in_count];
969 float *outs[out_count];
971 static void plugin_info(plugin_info_iface *pii)
973 pii->names("clip_c", "Clip (C)", "kf:MathOperatorPlugin", "clip");
974 pii->control_port("in", "In", 0.f).input();
975 pii->control_port("min", "Min", 0).input();
976 pii->control_port("max", "Max", 1).input();
977 pii->control_port("out", "Out", 0.f).output();
979 void process(uint32_t count)
981 float value = *ins[in_signal];
982 *outs[out_signal] = std::min(*ins[in_max], std::max(value, *ins[in_min]));
986 /// Two input control crossfader
987 class crossfader2_c_audio_module: public null_small_audio_module
989 public:
990 enum { in_a, in_b, in_ctl, in_count };
991 enum { out_value, out_count };
992 float *ins[in_count];
993 float *outs[out_count];
995 static void plugin_info(plugin_info_iface *pii)
997 pii->names("crossfader2_c", "2-in crossfader (C)", "kf:MathOperatorPlugin", "xfC");
998 pii->control_port("in_a", "In A", 0.f).input();
999 pii->control_port("in_b", "In B", 0).input();
1000 pii->control_port("mix", "B in mix", 0.5).input();
1001 pii->control_port("out", "Out", 0.f).output();
1003 void process(uint32_t count)
1005 *outs[out_value] = *ins[in_a] + (*ins[in_b] - *ins[in_a]) * dsp::clip(*ins[in_ctl], 0.f, 1.f);
1009 /// 2-input multiplexer (if-then-else)
1010 class ifthenelse_c_audio_module: public null_small_audio_module
1012 public:
1013 enum { in_if, in_then, in_else, in_count };
1014 enum { out_value, out_count };
1015 float *ins[in_count];
1016 float *outs[out_count];
1018 static void plugin_info(plugin_info_iface *pii)
1020 pii->names("ifthenelse_c", "If-Then-Else (C)", "kf:BooleanPlugin", "if");
1021 pii->control_port("if", "If", 0.f).input().toggle();
1022 pii->control_port("then", "Then", 0).input();
1023 pii->control_port("else", "Else", 0).input();
1024 pii->control_port("out", "Out", 0.f).output();
1026 void process(uint32_t count)
1028 *outs[out_value] = *ins[in_if] > 0 ? *ins[in_then] : *ins[in_else];
1032 /// Integer counter with definable ranges
1033 class counter_c_audio_module: public null_small_audio_module
1035 public:
1036 enum { in_clock, in_min, in_max, in_steps, in_reset, in_count };
1037 enum { out_value, out_carry, out_count };
1038 float *ins[in_count];
1039 float *outs[out_count];
1040 bool state;
1041 int value;
1043 void activate()
1045 state = false;
1046 value = 0;
1049 static void plugin_info(plugin_info_iface *pii)
1051 pii->names("counter_c", "Counter (C)", "kf:IntegerPlugin", "cnt");
1052 pii->control_port("clock", "Clock", 0.f).input().toggle().trigger();
1053 pii->control_port("min", "Min", 0).input();
1054 pii->control_port("max", "Max", 15).input();
1055 pii->control_port("steps", "Steps", 16).input().integer();
1056 pii->control_port("reset", "Reset", 0).input().toggle();
1057 pii->control_port("out", "Out", 0.f).output();
1058 pii->control_port("carry", "Carry", 0.f).output().toggle().trigger();
1060 void process(uint32_t count)
1062 // Yes, this is slower than it should be. I will bother optimizing it when someone starts actually using it.
1063 if (*ins[in_reset] > 0 || *ins[in_steps] < 2.0)
1065 state = false;
1066 value = 0;
1067 *outs[out_value] = *ins[in_min];
1068 *outs[out_carry] = 0.f;
1069 return;
1071 *outs[out_carry] = 0;
1072 if (!state && *ins[in_clock] > 0)
1074 value++;
1075 state = true;
1076 if (value >= (int)*ins[in_steps])
1078 value = 0;
1079 *outs[out_carry] = 1;
1082 else
1083 state = *ins[in_clock] > 0;
1084 *outs[out_value] = *ins[in_min] + (*ins[in_max] - *ins[in_min]) * value / (int)(*ins[in_steps] - 1);
1088 /// Two input audio crossfader
1089 class crossfader2_a_audio_module: public null_small_audio_module
1091 public:
1092 enum { in_a, in_b, in_ctl, in_count };
1093 enum { out_value, out_count };
1094 float *ins[in_count];
1095 float *outs[out_count];
1097 static void plugin_info(plugin_info_iface *pii)
1099 pii->names("crossfader2_a", "2-in crossfader (A)", "kf:MathOperatorPlugin", "xfA");
1100 pii->audio_port("in_a", "In A").input();
1101 pii->audio_port("in_b", "In B").input();
1102 pii->audio_port("mix", "B in mix").input();
1103 pii->audio_port("out", "Out").output();
1105 void process(uint32_t count)
1107 for (uint32_t i = 0; i < count; i++)
1108 outs[out_value][i] = ins[in_a][i] + (ins[in_b][i] - ins[in_a][i]) * dsp::clip(ins[in_ctl][i], 0.f, 1.f);
1112 /// Base class for LFOs with frequency and reset inputs
1113 class freq_phase_lfo_base: public small_audio_module_base<2, 1>
1115 public:
1116 enum { in_freq, in_reset };
1117 double phase;
1118 inline void activate()
1120 phase = 0;
1122 static void port_info(plugin_info_iface *pii)
1124 pii->control_port("freq", "Frequency", 1).input().log_range(0.02, 100);
1125 pii->control_port("reset", "Reset", 0).input().toggle();
1126 pii->control_port("out", "Out", 0).output();
1128 inline void check_inputs()
1130 if (*ins[in_reset])
1131 phase = 0;
1133 inline void advance(uint32_t count)
1135 phase += count * *ins[in_freq] * odsr;
1136 if (phase >= 1.0)
1137 phase = fmod(phase, 1.0);
1141 class square_lfo_audio_module: public freq_phase_lfo_base
1143 public:
1144 void process(uint32_t count)
1146 check_inputs();
1147 *outs[0] = (phase < 0.5) ? -1 : +1;
1148 advance(count);
1150 static void plugin_info(plugin_info_iface *pii)
1152 pii->names("square_lfo", "Square LFO", "lv2:OscillatorPlugin");
1153 port_info(pii);
1157 class saw_lfo_audio_module: public freq_phase_lfo_base
1159 public:
1160 void process(uint32_t count)
1162 check_inputs();
1163 *outs[0] = -1 + 2 * phase;
1164 advance(count);
1166 static void plugin_info(plugin_info_iface *pii)
1168 pii->names("saw_lfo", "Saw LFO", "lv2:OscillatorPlugin");
1169 port_info(pii);
1173 class pulse_lfo_audio_module: public freq_phase_lfo_base
1175 public:
1176 inline void activate()
1178 phase = 1.0;
1180 void process(uint32_t count)
1182 check_inputs();
1183 double oldphase = phase;
1184 advance(count);
1185 *outs[0] = (phase < oldphase) ? 1.f : 0.f;
1187 static void plugin_info(plugin_info_iface *pii)
1189 pii->names("pulse_lfo", "Pulse LFO", "lv2:OscillatorPlugin");
1190 port_info(pii);
1194 #define SMALL_OSC_TABLE_BITS 12
1196 class freq_only_osc_base_common: public null_small_audio_module
1198 public:
1199 typedef waveform_family<SMALL_OSC_TABLE_BITS> waves_type;
1200 enum { in_freq, in_count };
1201 enum { out_signal, out_count};
1202 enum { wave_size = 1 << SMALL_OSC_TABLE_BITS };
1203 float *ins[in_count];
1204 float *outs[out_count];
1205 waves_type *waves;
1206 waveform_oscillator<SMALL_OSC_TABLE_BITS> osc;
1208 /// Fill the array with the original, non-bandlimited, waveform
1209 virtual void get_original_waveform(float data[wave_size]) = 0;
1210 /// This function needs to be virtual to ensure a separate wave family for each class (but not each instance)
1211 virtual waves_type *get_waves() = 0;
1212 void activate() {
1213 waves = get_waves();
1215 void process(uint32_t count)
1217 osc.set_freq_odsr(*ins[in_freq], odsr);
1218 osc.waveform = waves->get_level(osc.phasedelta);
1219 if (osc.waveform)
1221 for (uint32_t i = 0; i < count; i++)
1222 outs[out_signal][i] = osc.get();
1224 else
1225 dsp::zero(outs[out_signal], count);
1227 static void port_info(plugin_info_iface *pii)
1229 pii->control_port("freq", "Frequency", 440).input().log_range(20, 20000);
1230 pii->audio_port("out", "Out").output();
1232 /// Generate a wave family (bandlimit levels) from the original wave
1233 waves_type *create_waves() {
1234 waves_type *ptr = new waves_type;
1235 float source[wave_size];
1236 get_original_waveform(source);
1237 bandlimiter<SMALL_OSC_TABLE_BITS> bl;
1238 ptr->make(bl, source);
1239 return ptr;
1243 template<class T>
1244 class freq_only_osc_base: public freq_only_osc_base_common
1246 virtual waves_type *get_waves() {
1247 static waves_type *waves = NULL;
1248 if (!waves)
1249 waves = create_waves();
1250 return waves;
1254 class square_osc_audio_module: public freq_only_osc_base<square_osc_audio_module>
1256 public:
1257 virtual void get_original_waveform(float data[wave_size]) {
1258 for (int i = 0; i < wave_size; i++)
1259 data[i] = (i < wave_size / 2) ? +1 : -1;
1261 static void plugin_info(plugin_info_iface *pii)
1263 pii->names("squareosc", "Square Oscillator", "lv2:OscillatorPlugin");
1264 port_info(pii);
1268 class saw_osc_audio_module: public freq_only_osc_base<saw_osc_audio_module>
1270 public:
1271 virtual void get_original_waveform(float data[wave_size]) {
1272 for (int i = 0; i < wave_size; i++)
1273 data[i] = (i * 2.0 / wave_size) - 1;
1275 static void plugin_info(plugin_info_iface *pii)
1277 pii->names("sawosc", "Saw Oscillator", "lv2:OscillatorPlugin");
1278 port_info(pii);
1282 class print_c_audio_module: public small_audio_module_base<1, 0>
1284 public:
1285 static void plugin_info(plugin_info_iface *pii)
1287 pii->names("print_c", "Print To Console (C)", "lv2:UtilityPlugin");
1288 pii->control_port("in", "In", 0).input();
1290 void process(uint32_t)
1292 printf("%f\n", *ins[0]);
1296 class print_e_audio_module: public small_audio_module_base<1, 0>
1298 public:
1299 static void plugin_info(plugin_info_iface *pii)
1301 pii->names("print_e", "Print To Console (E)", "lv2:UtilityPlugin");
1302 pii->event_port("in", "In").input();
1304 void dump(LV2_Event_Buffer *event_data)
1306 event_port_read_iterator ei(event_data);
1307 while(ei)
1309 const lv2_event &event = *ei++;
1310 printf("Event at %d.%d, type %d, size %d:", event.frames, event.subframes, (int)event.type, (int)event.size);
1311 uint32_t size = std::min((uint16_t)16, event.size);
1313 for (uint32_t j = 0; j < size; j++)
1314 printf(" %02X", (uint32_t)event.data[j]);
1315 if (event.size > size)
1316 printf("...\n");
1317 else
1318 printf("\n");
1321 void process(uint32_t)
1323 LV2_Event_Buffer *event_data = (LV2_Event_Buffer *)ins[0];
1324 dump(event_data);
1328 class print_em_audio_module: public print_e_audio_module
1330 public:
1331 LV2_Event_Buffer *events;
1332 static void plugin_info(plugin_info_iface *pii)
1334 pii->names("print_em", "Print To Console (EM)", "lv2:UtilityPlugin");
1335 pii->lv2_ttl("lv2:requiredFeature <http://lv2plug.in/ns/dev/contexts> ;");
1336 pii->lv2_ttl("lv2:requiredFeature lv2ctx:MessageContext ;");
1337 pii->lv2_ttl("lv2ctx:requiredContext lv2ctx:MessageContext ;");
1338 pii->event_port("in", "In").input().lv2_ttl("lv2ctx:context lv2ctx:MessageContext ;");
1340 void process(uint32_t)
1343 static uint32_t message_run(LV2_Handle instance, const void *valid_inputs, void *outputs_written)
1345 print_em_audio_module *self = (print_em_audio_module *)instance;
1346 if (lv2_contexts_port_is_valid(valid_inputs, 0))
1348 printf("message_run (events = %p, count = %d)\n", self->events, self->events->event_count);
1349 self->dump(self->events);
1351 return 0;
1353 static void message_connect_port(LV2_Handle instance, uint32_t port, void* data)
1355 print_em_audio_module *self = (print_em_audio_module *)instance;
1356 printf("message_connect_port %d -> %p\n", port, data);
1357 assert(!port);
1358 self->events = (LV2_Event_Buffer *)data;
1360 static inline const void *ext_data(const char *URI) {
1361 static LV2MessageContext ctx_ext_data = { message_run, message_connect_port };
1362 printf("URI=%s\n", URI);
1363 if (!strcmp(URI, LV2_CONTEXT_MESSAGE))
1365 return &ctx_ext_data;
1367 return NULL;
1371 class copy_em_audio_module: public small_audio_module_base<0, 0>
1373 public:
1374 LV2_Event_Buffer *events_in, *events_out;
1375 static void plugin_info(plugin_info_iface *pii)
1377 pii->names("copy_em", "Message pass-through (EM)", "lv2:UtilityPlugin");
1378 pii->lv2_ttl("lv2:requiredFeature lv2ctx:MessageContext ;");
1379 pii->lv2_ttl("lv2:requiredFeature <http://lv2plug.in/ns/dev/contexts> ;");
1380 pii->lv2_ttl("lv2:requiredContext lv2ctx:MessageContext ;");
1381 pii->event_port("in", "In").input().lv2_ttl("lv2ctx:context lv2ctx:MessageContext ;");
1382 pii->event_port("out", "Out").output().lv2_ttl("lv2ctx:context lv2ctx:MessageContext ;");
1384 void process(uint32_t)
1387 static uint32_t message_run(LV2_Handle instance, const void *valid_inputs, void *outputs_written)
1389 copy_em_audio_module *self = (copy_em_audio_module *)instance;
1390 return self->message_run(valid_inputs, outputs_written);
1392 uint32_t message_run(const void *inputs_written, void *outputs_written)
1394 if (lv2_contexts_port_is_valid(inputs_written, 0))
1396 event_port_read_iterator ri(events_in);
1397 event_port_write_iterator wi(events_out);
1398 if (events_in->size > events_out->capacity)
1400 printf("Buffer capacity exceeded!\n");
1401 return false;
1403 while(ri)
1405 const lv2_event &event = *ri++;
1406 *wi++ = event;
1408 if (events_in->event_count != 0)
1410 lv2_contexts_set_port_valid(outputs_written, 1);
1411 return 1;
1414 lv2_contexts_unset_port_valid(outputs_written, 1);
1415 return 0;
1417 static void message_connect_port(LV2_Handle instance, uint32_t port, void* data)
1419 copy_em_audio_module *self = (copy_em_audio_module *)instance;
1420 printf("message_connect_port %d -> %p\n", port, data);
1421 if (port == 0) self->events_in = (LV2_Event_Buffer *)data;
1422 if (port == 1) self->events_out = (LV2_Event_Buffer *)data;
1424 static inline const void *ext_data(const char *URI) {
1425 static LV2MessageContext ctx_ext_data = { message_run, message_connect_port };
1426 if (!strcmp(URI, LV2_CONTEXT_MESSAGE))
1428 printf("URI=%s\n", URI);
1429 return &ctx_ext_data;
1431 return NULL;
1435 template<class Range, int Inputs = 1>
1436 class miditypefilter_m_audio_module: public midi_mixin<small_audio_module_base<Inputs, 2> >
1438 public:
1439 static inline void extra_inputs(plugin_info_iface *pii)
1442 static inline const char *plugin_symbol() { return Range::strings()[0]; }
1443 static inline const char *plugin_name() { return Range::strings()[1]; }
1444 static inline const char *port_symbol() { return Range::strings()[2]; }
1445 static inline const char *port_name() { return Range::strings()[3]; }
1446 static void plugin_info(plugin_info_iface *pii)
1448 pii->names(Range::plugin_symbol(), Range::plugin_name(), "kf:MIDIPlugin");
1449 pii->event_port("in", "In").input();
1450 Range::extra_inputs(pii);
1451 pii->event_port(Range::port_symbol(), Range::port_name()).output();
1452 pii->event_port("others", "Others").output();
1454 void process(uint32_t)
1456 event_port_read_iterator ri((LV2_Event_Buffer *)this->ins[0]);
1457 event_port_write_iterator wi((LV2_Event_Buffer *)this->outs[0]);
1458 event_port_write_iterator wi2((LV2_Event_Buffer *)this->outs[1]);
1459 while(ri)
1461 const lv2_event &event = *ri++;
1462 if (event.type == this->midi_event_type && event.size && Range::is_in_range(event.data, this->ins))
1463 *wi++ = event;
1464 else
1465 *wi2++ = event;
1470 class notefilter_m_audio_module: public miditypefilter_m_audio_module<notefilter_m_audio_module>
1472 public:
1473 static inline bool is_in_range(const uint8_t *data, float **) { return data[0] >= 0x80 && data[0] <= 0x9F; }
1474 static inline const char **strings() { static const char *s[] = { "notefilter_m", "Note Filter", "note", "Note" }; return s;}
1477 class pcfilter_m_audio_module: public miditypefilter_m_audio_module<pcfilter_m_audio_module>
1479 public:
1480 static inline bool is_in_range(const uint8_t *data, float **) { return data[0] >= 0xA0 && data[0] <= 0xAF; }
1481 static inline const char **strings() { static const char *s[] = { "pcfilter_m", "Program Change Filter", "pc", "PC" }; return s;}
1484 class ccfilter_m_audio_module: public miditypefilter_m_audio_module<ccfilter_m_audio_module>
1486 public:
1487 static inline bool is_in_range(const uint8_t *data, float **) { return data[0] >= 0xB0 && data[0] <= 0xBF; }
1488 static inline const char **strings() { static const char *s[] = { "ccfilter_m", "Control Change Filter", "cc", "CC" }; return s;}
1491 class pressurefilter_m_audio_module: public miditypefilter_m_audio_module<pressurefilter_m_audio_module>
1493 public:
1494 static inline bool is_in_range(const uint8_t *data, float **) { return data[0] >= 0xC0 && data[0] <= 0xDF; }
1495 static inline const char **strings() { static const char *s[] = { "pressurefilter_m", "Pressure Filter", "pressure", "Pressure" }; return s;}
1498 class pitchbendfilter_m_audio_module: public miditypefilter_m_audio_module<pitchbendfilter_m_audio_module>
1500 public:
1501 static inline bool is_in_range(const uint8_t *data, float **) { return data[0] >= 0xE0 && data[0] <= 0xEF; }
1502 static inline const char **strings() { static const char *s[] = { "pitchbendfilter_m", "Pitch Bend Filter", "pbend", "Pitch Bend" }; return s;}
1505 class systemfilter_m_audio_module: public miditypefilter_m_audio_module<systemfilter_m_audio_module>
1507 public:
1508 static inline bool is_in_range(const uint8_t *data, float **) { return data[0] >= 0xF0; }
1509 static inline const char **strings() { static const char *s[] = { "systemfilter_m", "System Msg Filter", "system", "System" }; return s;}
1512 class channelfilter_m_audio_module: public miditypefilter_m_audio_module<channelfilter_m_audio_module, 3>
1514 public:
1515 static inline void extra_inputs(plugin_info_iface *pii)
1517 pii->control_port("min", "Min Channel", 1).input().integer().lin_range(1, 16);
1518 pii->control_port("max", "Max Channel", 16).input().integer().lin_range(1, 16);
1520 static inline bool is_in_range(const uint8_t *data, float **ins) {
1521 int chnl = 1 + (data[0] & 0xF);
1522 return data[0] < 0xF0 && chnl >= *ins[1] && chnl <= *ins[2];
1524 static inline const char **strings() { static const char *s[] = { "channelfilter_m", "Channel Range Filter", "range", "Range" }; return s;}
1527 class keyfilter_m_audio_module: public miditypefilter_m_audio_module<keyfilter_m_audio_module, 3>
1529 public:
1530 static inline void extra_inputs(plugin_info_iface *pii)
1532 pii->control_port("min", "Min Note", 0).input().integer().lin_range(0, 127);
1533 pii->control_port("max", "Max Note", 127).input().integer().lin_range(0, 127);
1535 static inline bool is_in_range(const uint8_t *data, float **ins) {
1536 // XXXKF doesn't handle polyphonic aftertouch
1537 return (data[0] >= 0x80 && data[0] <= 0x9F) && data[0] >= *ins[1] && data[1] <= *ins[2];
1539 static inline const char **strings() { static const char *s[] = { "keyfilter_m", "Key Range Filter", "range", "Range" }; return s;}
1542 class key_less_than_m_audio_module: public miditypefilter_m_audio_module<key_less_than_m_audio_module, 2>
1544 public:
1545 static inline void extra_inputs(plugin_info_iface *pii)
1547 pii->control_port("threshold", "Threshold", 60).input().integer().lin_range(0, 128);
1549 static inline bool is_in_range(const uint8_t *data, float **ins) {
1550 // XXXKF doesn't handle polyphonic aftertouch
1551 return (data[0] >= 0x80 && data[0] <= 0x9F) && data[1] < *ins[1];
1553 static inline const char **strings() { static const char *s[] = { "key_less_than_m", "Key Less-Than Filter", "less", "Less" }; return s;}
1556 class channel_less_than_m_audio_module: public miditypefilter_m_audio_module<channel_less_than_m_audio_module, 2>
1558 public:
1559 static inline void extra_inputs(plugin_info_iface *pii)
1561 pii->control_port("threshold", "Threshold", 10).input().integer().lin_range(1, 16);
1563 static inline bool is_in_range(const uint8_t *data, float **ins) {
1564 // XXXKF doesn't handle polyphonic aftertouch
1565 return (data[0] < 0xF0) && (1 + (data[0] & 0xF)) < *ins[1];
1567 static inline const char **strings() { static const char *s[] = { "channel_less_than_m", "Channel Less-Than Filter", "less", "Less" }; return s;}
1570 class transpose_m_audio_module: public midi_mixin<small_audio_module_base<2, 1> >
1572 public:
1573 static void plugin_info(plugin_info_iface *pii)
1575 pii->names("transpose_m", "Transpose", "kf:MIDIPlugin");
1576 pii->event_port("in", "In").input();
1577 pii->control_port("transpose", "Transpose", 12).input().integer();
1578 pii->event_port("out", "Out").output();
1580 void process(uint32_t)
1582 event_port_read_iterator ri((LV2_Event_Buffer *)ins[0]);
1583 event_port_write_iterator wi((LV2_Event_Buffer *)outs[0]);
1584 while(ri)
1586 const lv2_event &event = *ri++;
1587 if (event.type == this->midi_event_type && event.size == 3 && (event.data[0] >= 0x80 && event.data[0] <= 0x9F))
1589 int new_note = event.data[1] + (int)*ins[1];
1590 // ignore out-of-range notes
1591 if (new_note >= 0 && new_note <= 127)
1593 // it is not possible to create copies here because they are variable length and would "nicely" overwrite the stack
1594 // so write the original event instead, and then modify the pitch
1595 *wi = event;
1596 wi->data[1] = new_note;
1597 wi++;
1600 else
1601 *wi++ = event;
1606 class setchannel_m_audio_module: public midi_mixin<small_audio_module_base<2, 1> >
1608 public:
1609 static void plugin_info(plugin_info_iface *pii)
1611 pii->names("setchannel_m", "Set Channel", "kf:MIDIPlugin");
1612 pii->event_port("in", "In").input();
1613 pii->control_port("channel", "Channel", 1).input().integer().lin_range(1, 16);
1614 pii->event_port("out", "Out").output();
1616 void process(uint32_t)
1618 event_port_read_iterator ri((LV2_Event_Buffer *)ins[0]);
1619 event_port_write_iterator wi((LV2_Event_Buffer *)outs[0]);
1620 while(ri)
1622 const lv2_event &event = *ri++;
1623 if (event.type == this->midi_event_type && (event.data[0] >= 0x80 && event.data[0] <= 0xEF))
1625 *wi = event;
1626 // modify channel number in the first byte
1627 wi->data[0] = (wi->data[0] & 0xF0) | (((int)*ins[1] - 1) & 0xF);
1628 wi++;
1630 else
1631 *wi++ = event;
1636 class eventmerge_e_audio_module: public event_mixin<small_audio_module_base<2, 1> >
1638 public:
1639 static void plugin_info(plugin_info_iface *pii)
1641 pii->names("eventmerge_e", "Event Merge (E)", "lv2:UtilityPlugin");
1642 pii->event_port("in_1", "In 1").input();
1643 pii->event_port("in_2", "In 2").input();
1644 pii->event_port("out", "Out").output();
1646 void process(uint32_t)
1648 event_port_merge_iterator<event_port_read_iterator, event_port_read_iterator> ri((const LV2_Event_Buffer *)ins[0], (const LV2_Event_Buffer *)ins[1]);
1649 event_port_write_iterator wi((LV2_Event_Buffer *)outs[0]);
1650 while(ri)
1651 *wi++ = *ri++;
1655 class print_a_audio_module: public small_audio_module_base<1, 0>
1657 public:
1658 static void plugin_info(plugin_info_iface *pii)
1660 pii->names("print_a", "Print To Console (A)", "lv2:UtilityPlugin");
1661 pii->audio_port("in", "In").input();
1663 void process(uint32_t)
1665 printf("%f\n", *ins[0]);
1669 template<bool audio>
1670 class quadpower_base: public null_small_audio_module
1672 public:
1673 enum { in_value, in_factor, in_count , out_count = 4 };
1674 float *ins[in_count];
1675 float *outs[out_count];
1677 static void plugin_info(plugin_info_iface *pii)
1679 const char *names[8] = {"xa", "x*a^1", "xaa", "x*a^2", "xaaa", "x*a^3", "xaaaa", "x*a^4" };
1680 if (audio)
1681 pii->names("quadpower_a", "Quad Power (A)", "kf:MathOperatorPlugin");
1682 else
1683 pii->names("quadpower_c", "Quad Power (C)", "kf:MathOperatorPlugin");
1684 if (audio)
1685 pii->audio_port("x", "x").input();
1686 else
1687 pii->control_port("x", "x", 1).input();
1688 pii->control_port("a", "a", 1).input();
1689 for (int i = 0; i < 8; i += 2)
1690 if (audio)
1691 pii->audio_port(names[i], names[i+1]).output();
1692 else
1693 pii->control_port(names[i], names[i+1], 0).output();
1697 class quadpower_a_audio_module: public quadpower_base<true>
1699 public:
1700 void process(uint32_t count)
1702 float a = *ins[in_factor];
1703 for (uint32_t i = 0; i < count; i++)
1705 float x = ins[in_value][i];
1706 outs[0][i] = x * a;
1707 outs[1][i] = x * a * a;
1708 outs[2][i] = x * a * a * a;
1709 outs[3][i] = x * a * a * a * a;
1714 class quadpower_c_audio_module: public quadpower_base<false>
1716 public:
1717 void process(uint32_t)
1719 float x = *ins[in_value];
1720 float a = *ins[in_factor];
1721 *outs[0] = x * a;
1722 *outs[1] = x * a * a;
1723 *outs[2] = x * a * a * a;
1724 *outs[3] = x * a * a * a * a;
1728 template<class Ramp>
1729 class inertia_c_module_base: public small_audio_module_base<3, 1>
1731 public:
1732 enum { in_value, in_inertia, in_immediate };
1733 bool reset;
1734 inertia<Ramp> state;
1735 inertia_c_module_base()
1736 : state(Ramp(1))
1738 void activate()
1740 reset = true;
1742 static void port_info(plugin_info_iface *pii)
1744 pii->control_port("in", "In", 0).input();
1745 pii->control_port("time", "Inertia time", 100).input();
1746 pii->control_port("reset", "Reset", 0).input().toggle().trigger();
1747 pii->control_port("out", "Out", 0).output();
1749 void process(uint32_t count)
1751 float value = *ins[in_value];
1752 if (reset || *ins[in_immediate] > 0)
1754 *outs[0] = value;
1755 state.set_now(value);
1756 reset = false;
1758 else
1760 if (value != state.get_last())
1762 state.ramp.set_length(dsp::clip((int)(srate * 0.001 * *ins[in_inertia]), 1, 10000000));
1764 state.set_inertia(value);
1765 *outs[0] = state.get_last();
1766 if (count)
1767 state.step_many(count);
1772 class linear_inertia_c_audio_module: public inertia_c_module_base<linear_ramp>
1774 public:
1775 static void plugin_info(plugin_info_iface *pii)
1777 pii->names("linear_inertia_c", "Linear Inertia (C)", "lv2:FilterPlugin");
1778 port_info(pii);
1782 class exp_inertia_c_audio_module: public inertia_c_module_base<exponential_ramp>
1784 public:
1785 static void plugin_info(plugin_info_iface *pii)
1787 pii->names("exp_inertia_c", "Exponential Inertia (C)", "lv2:FilterPlugin");
1788 port_info(pii);
1792 class sample_hold_base: public small_audio_module_base<2, 1>
1794 public:
1795 enum { in_value, in_gate };
1796 static void port_info(plugin_info_iface *pii, const char *clock_symbol, const char *clock_name)
1798 pii->control_port("in", "In", 0).input();
1799 pii->control_port(clock_symbol, clock_name, 0).input().toggle().trigger();
1800 pii->control_port("out", "Out", 0).output();
1804 class sample_hold_edge_c_audio_module: public sample_hold_base
1806 public:
1807 bool prev_clock;
1808 float value;
1809 void activate()
1811 prev_clock = false;
1812 value = 0;
1814 void process(uint32_t count)
1816 if (!prev_clock && *ins[in_gate] > 0)
1817 value = *ins[in_value];
1818 prev_clock = *ins[in_gate] > 0;
1819 *outs[0] = value;
1821 static void plugin_info(plugin_info_iface *pii)
1823 pii->names("sample_hold_edge", "Sample&Hold (Edge, C)", "lv2:UtilityPlugin");
1824 port_info(pii, "clock", "Clock");
1828 class sample_hold_level_c_audio_module: public sample_hold_base
1830 public:
1831 float value;
1832 void activate()
1834 value = 0;
1836 void process(uint32_t count)
1838 if (*ins[in_gate] > 0)
1839 value = *ins[in_value];
1840 *outs[0] = value;
1842 static void plugin_info(plugin_info_iface *pii)
1844 pii->names("sample_hold_level", "Sample&Hold (Level, C)", "lv2:UtilityPlugin");
1845 port_info(pii, "gate", "Gate");
1849 class msgread_e_audio_module: public message_mixin<small_audio_module_base<1, 1> >
1851 public:
1852 uint32_t set_float_msg, float_type;
1853 static void plugin_info(plugin_info_iface *pii)
1855 pii->names("msgread_e", "Msg Read", "lv2:UtilityPlugin");
1856 pii->has_gui();
1857 pii->event_port("in", "In").input();
1858 pii->control_port("out", "Out", 0).output();
1860 virtual void map_uris()
1862 message_mixin<small_audio_module_base<1, 1> >::map_uris();
1863 set_float_msg = map_uri("http://lv2plug.in/ns/dev/msg", "http://foltman.com/garbage/setFloat");
1864 float_type = map_uri("http://lv2plug.in/ns/dev/types", "http://lv2plug.in/ns/dev/types#float");
1866 void process(uint32_t count)
1868 event_port_read_iterator ri((const LV2_Event_Buffer *)ins[0]);
1869 while(ri)
1871 const lv2_event *event = &*ri++;
1872 if (event->type == message_event_type)
1874 struct payload {
1875 uint32_t selector;
1876 uint32_t serial_no;
1877 uint32_t data_size;
1878 uint32_t parg_count;
1879 uint32_t data_type;
1880 float data_value;
1881 uint32_t narg_count;
1883 const payload *p = (const payload *)event->data;
1884 if (p->selector == set_float_msg) {
1885 assert(p->parg_count == 1);
1886 assert(p->data_size == 16);
1887 assert(p->data_type == float_type);
1888 *outs[0] = p->data_value;
1889 assert(p->narg_count == 0); // this is just for testing - passing
1898 #define PER_SMALL_MODULE_ITEM(name, id) SMALL_WRAPPERS(name, id)
1899 #include <calf/modulelist.h>
1901 const LV2_Descriptor *calf_plugins::lv2_small_descriptor(uint32_t index)
1903 #define PER_SMALL_MODULE_ITEM(name, id) if (!(index--)) return &::lv2_small_##name.descriptor;
1904 #include <calf/modulelist.h>
1905 return NULL;
1907 #endif
1908 #endif
1910 void calf_plugins::get_all_small_plugins(plugin_list_info_iface *iface)
1912 #if USE_LV2
1913 #define PER_SMALL_MODULE_ITEM(name, id) { plugin_info_iface *pii = &iface->plugin(id); small_plugins::name##_audio_module::plugin_info(pii); pii->finalize(); }
1914 #include <calf/modulelist.h>
1915 #endif