1 /* ------------------------------------------------------------
2 name: "vibrato_ext"
3 Code generated with Faust 2.20.2 (https://faust.grame.fr)
4 Compilation options: -lang cpp -scal -ftz 0
5 ------------------------------------------------------------ */
6
7 #ifndef __vibrato_ext_H__
8 #define __vibrato_ext_H__
9
main(int argc,char * argv[])10 /************************************************************************
11 ************************************************************************
12 FAUST Architecture File
13 Copyright (C) 2009-2016 Albert Graef <aggraef@gmail.com>
14 ---------------------------------------------------------------------
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU Lesser General Public License as
17 published by the Free Software Foundation; either version 3 of the
18 License, or (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU Lesser General Public License for more details.
24
25 You should have received a copy of the GNU Lesser General Public
26 License along with the GNU C Library; if not, write to the Free
27 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28 02111-1307 USA.
29 ************************************************************************
30 ************************************************************************/
31
32 /* LV2 architecture for Faust synths. */
33
34 /* NOTE: This requires one of the Boost headers (boost/circular_buffer.hpp),
35 so to compile Faust programs created with this architecture you need to
36 have at least the Boost headers installed somewhere on your include path
37 (the Boost libraries aren't needed). */
38
39 #include <stdlib.h>
40 #include <string.h>
41 #include <math.h>
42 #include <list>
43 #include <map>
44 #include <set>
45
46 // generic Faust dsp and UI classes
47 /************************** BEGIN dsp.h **************************/
48 /************************************************************************
49 FAUST Architecture File
50 Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
51 ---------------------------------------------------------------------
52 This Architecture section is free software; you can redistribute it
53 and/or modify it under the terms of the GNU General Public License
54 as published by the Free Software Foundation; either version 3 of
55 the License, or (at your option) any later version.
56
57 This program is distributed in the hope that it will be useful,
58 but WITHOUT ANY WARRANTY; without even the implied warranty of
59 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60 GNU General Public License for more details.
61
62 You should have received a copy of the GNU General Public License
63 along with this program; If not, see <http://www.gnu.org/licenses/>.
64
65 EXCEPTION : As a special exception, you may create a larger work
66 that contains this FAUST architecture section and distribute
67 that work under terms of your choice, so long as this FAUST
68 architecture section is not modified.
69 ************************************************************************/
70
71 #ifndef __dsp__
72 #define __dsp__
73
74 #include <string>
75 #include <vector>
76
77 #ifndef FAUSTFLOAT
78 #define FAUSTFLOAT float
79 #endif
80
81 class UI;
82 struct Meta;
83
84 /**
85 * DSP memory manager.
86 */
87
88 struct dsp_memory_manager {
89
90 virtual ~dsp_memory_manager() {}
91
92 virtual void* allocate(size_t size) = 0;
93 virtual void destroy(void* ptr) = 0;
94
95 };
96
97 /**
98 * Signal processor definition.
99 */
100
101 class dsp {
102
103 public:
104
105 dsp() {}
106 virtual ~dsp() {}
107
108 /* Return instance number of audio inputs */
109 virtual int getNumInputs() = 0;
110
111 /* Return instance number of audio outputs */
112 virtual int getNumOutputs() = 0;
113
114 /**
115 * Trigger the ui_interface parameter with instance specific calls
116 * to 'addBtton', 'addVerticalSlider'... in order to build the UI.
117 *
118 * @param ui_interface - the user interface builder
119 */
120 virtual void buildUserInterface(UI* ui_interface) = 0;
121
122 /* Returns the sample rate currently used by the instance */
123 virtual int getSampleRate() = 0;
124
125 /**
126 * Global init, calls the following methods:
127 * - static class 'classInit': static tables initialization
128 * - 'instanceInit': constants and instance state initialization
129 *
130 * @param sample_rate - the sampling rate in Hertz
131 */
132 virtual void init(int sample_rate) = 0;
133
134 /**
135 * Init instance state
136 *
137 * @param sample_rate - the sampling rate in Hertz
138 */
139 virtual void instanceInit(int sample_rate) = 0;
140
141 /**
142 * Init instance constant state
143 *
144 * @param sample_rate - the sampling rate in Hertz
145 */
146 virtual void instanceConstants(int sample_rate) = 0;
147
148 /* Init default control parameters values */
149 virtual void instanceResetUserInterface() = 0;
150
151 /* Init instance state (delay lines...) */
152 virtual void instanceClear() = 0;
153
154 /**
155 * Return a clone of the instance.
156 *
157 * @return a copy of the instance on success, otherwise a null pointer.
158 */
159 virtual dsp* clone() = 0;
160
161 /**
162 * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
163 *
164 * @param m - the Meta* meta user
165 */
166 virtual void metadata(Meta* m) = 0;
167
168 /**
169 * DSP instance computation, to be called with successive in/out audio buffers.
170 *
171 * @param count - the number of frames to compute
172 * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
173 * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
174 *
175 */
176 virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
177
178 /**
179 * DSP instance computation: alternative method to be used by subclasses.
180 *
181 * @param date_usec - the timestamp in microsec given by audio driver.
182 * @param count - the number of frames to compute
183 * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
184 * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
185 *
186 */
187 virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
188
189 };
190
191 /**
192 * Generic DSP decorator.
193 */
194
195 class decorator_dsp : public dsp {
196
197 protected:
198
199 dsp* fDSP;
200
201 public:
202
203 decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
204 virtual ~decorator_dsp() { delete fDSP; }
205
206 virtual int getNumInputs() { return fDSP->getNumInputs(); }
207 virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
208 virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
209 virtual int getSampleRate() { return fDSP->getSampleRate(); }
210 virtual void init(int sample_rate) { fDSP->init(sample_rate); }
211 virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
212 virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
213 virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
214 virtual void instanceClear() { fDSP->instanceClear(); }
215 virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
216 virtual void metadata(Meta* m) { fDSP->metadata(m); }
217 // Beware: subclasses usually have to overload the two 'compute' methods
218 virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
219 virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
220
221 };
222
223 /**
224 * DSP factory class.
225 */
226
227 class dsp_factory {
228
229 protected:
230
231 // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
232 virtual ~dsp_factory() {}
233
234 public:
235
236 virtual std::string getName() = 0;
237 virtual std::string getSHAKey() = 0;
238 virtual std::string getDSPCode() = 0;
239 virtual std::string getCompileOptions() = 0;
240 virtual std::vector<std::string> getLibraryList() = 0;
241 virtual std::vector<std::string> getIncludePathnames() = 0;
242
243 virtual dsp* createDSPInstance() = 0;
244
245 virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
246 virtual dsp_memory_manager* getMemoryManager() = 0;
247
248 };
249
250 /**
251 * On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
252 * flags to avoid costly denormals.
253 */
254
255 #ifdef __SSE__
256 #include <xmmintrin.h>
257 #ifdef __SSE2__
258 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
259 #else
260 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
261 #endif
262 #else
263 #define AVOIDDENORMALS
264 #endif
265
266 #endif
267 /************************** END dsp.h **************************/
268 /************************** BEGIN UI.h **************************/
269 /************************************************************************
270 FAUST Architecture File
271 Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
272 ---------------------------------------------------------------------
273 This Architecture section is free software; you can redistribute it
274 and/or modify it under the terms of the GNU General Public License
275 as published by the Free Software Foundation; either version 3 of
276 the License, or (at your option) any later version.
277
278 This program is distributed in the hope that it will be useful,
279 but WITHOUT ANY WARRANTY; without even the implied warranty of
280 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
281 GNU General Public License for more details.
282
283 You should have received a copy of the GNU General Public License
284 along with this program; If not, see <http://www.gnu.org/licenses/>.
285
286 EXCEPTION : As a special exception, you may create a larger work
287 that contains this FAUST architecture section and distribute
288 that work under terms of your choice, so long as this FAUST
289 architecture section is not modified.
290 ************************************************************************/
291
292 #ifndef __UI_H__
293 #define __UI_H__
294
295 #ifndef FAUSTFLOAT
296 #define FAUSTFLOAT float
297 #endif
298
299 /*******************************************************************************
300 * UI : Faust DSP User Interface
301 * User Interface as expected by the buildUserInterface() method of a DSP.
302 * This abstract class contains only the method that the Faust compiler can
303 * generate to describe a DSP user interface.
304 ******************************************************************************/
305
306 struct Soundfile;
307
308 template <typename REAL>
309 class UIReal
310 {
311
312 public:
313
314 UIReal() {}
315 virtual ~UIReal() {}
316
317 // -- widget's layouts
318
319 virtual void openTabBox(const char* label) = 0;
320 virtual void openHorizontalBox(const char* label) = 0;
321 virtual void openVerticalBox(const char* label) = 0;
322 virtual void closeBox() = 0;
323
324 // -- active widgets
325
326 virtual void addButton(const char* label, REAL* zone) = 0;
327 virtual void addCheckButton(const char* label, REAL* zone) = 0;
328 virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
329 virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
330 virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
331
332 // -- passive widgets
333
334 virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
335 virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
336
337 // -- soundfiles
338
339 virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
340
341 // -- metadata declarations
342
343 virtual void declare(REAL* zone, const char* key, const char* val) {}
344 };
345
346 class UI : public UIReal<FAUSTFLOAT>
347 {
348
349 public:
350
351 UI() {}
352 virtual ~UI() {}
353 };
354
355 #endif
356 /************************** END UI.h **************************/
357
358 using namespace std;
359
360 typedef pair<const char*,const char*> strpair;
361
362 struct Meta : std::map<const char*, const char*>
363 {
364 void declare(const char *key, const char *value)
365 {
366 (*this)[key] = value;
367 }
368 const char* get(const char *key, const char *def)
369 {
370 if (this->find(key) != this->end())
371 return (*this)[key];
372 else
373 return def;
374 }
375 };
376
377 /******************************************************************************
378 *******************************************************************************
379
380 VECTOR INTRINSICS
381
382 *******************************************************************************
383 *******************************************************************************/
384
385
386 /***************************************************************************
387 LV2 UI interface
388 ***************************************************************************/
389
390 enum ui_elem_type_t {
391 UI_BUTTON, UI_CHECK_BUTTON,
392 UI_V_SLIDER, UI_H_SLIDER, UI_NUM_ENTRY,
393 UI_V_BARGRAPH, UI_H_BARGRAPH,
394 UI_END_GROUP, UI_V_GROUP, UI_H_GROUP, UI_T_GROUP
395 };
396
397 struct ui_elem_t {
398 ui_elem_type_t type;
399 const char *label;
400 int port;
401 float *zone;
402 void *ref;
403 float init, min, max, step;
404 };
405
406 class LV2UI : public UI
407 {
408 public:
409 bool is_instr;
410 int nelems, nports;
411 ui_elem_t *elems;
412 map< int, list<strpair> > metadata;
413
414 LV2UI(int maxvoices = 0);
415 virtual ~LV2UI();
416
417 protected:
418 void add_elem(ui_elem_type_t type, const char *label = NULL);
419 void add_elem(ui_elem_type_t type, const char *label, float *zone);
420 void add_elem(ui_elem_type_t type, const char *label, float *zone,
421 float init, float min, float max, float step);
422 void add_elem(ui_elem_type_t type, const char *label, float *zone,
423 float min, float max);
424
425 bool have_freq, have_gain, have_gate;
426 bool is_voice_ctrl(const char *label);
427
428 public:
429 virtual void addButton(const char* label, float* zone);
430 virtual void addCheckButton(const char* label, float* zone);
431 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step);
432 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step);
433 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step);
434
435 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max);
436 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max);
437
438 virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
439
440 virtual void openTabBox(const char* label);
441 virtual void openHorizontalBox(const char* label);
442 virtual void openVerticalBox(const char* label);
443 virtual void closeBox();
444
445 virtual void run();
446
447 virtual void declare(float* zone, const char* key, const char* value);
448 };
449
450 LV2UI::LV2UI(int maxvoices)
451 {
452 is_instr = maxvoices>0;
453 have_freq = have_gain = have_gate = false;
454 nelems = nports = 0;
455 elems = NULL;
456 }
457
458 LV2UI::~LV2UI()
459 {
460 if (elems) free(elems);
461 }
462
463 void LV2UI::declare(float* zone, const char* key, const char* value)
464 {
465 map< int, list<strpair> >::iterator it = metadata.find(nelems);
466 if (it != metadata.end())
467 it->second.push_back(strpair(key, value));
468 else
469 metadata[nelems] = list<strpair>(1, strpair(key, value));
470 }
471
472 inline void LV2UI::add_elem(ui_elem_type_t type, const char *label)
473 {
474 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
475 if (elems1)
476 elems = elems1;
477 else
478 return;
479 elems[nelems].type = type;
480 elems[nelems].label = label;
481 elems[nelems].port = -1;
482 elems[nelems].zone = NULL;
483 elems[nelems].ref = NULL;
484 elems[nelems].init = 0.0;
485 elems[nelems].min = 0.0;
486 elems[nelems].max = 0.0;
487 elems[nelems].step = 0.0;
488 nelems++;
489 }
490
491 #define portno(label) (is_voice_ctrl(label)?-1:nports++)
492
493 inline void LV2UI::add_elem(ui_elem_type_t type, const char *label, float *zone)
494 {
495 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
496 if (elems1)
497 elems = elems1;
498 else
499 return;
500 elems[nelems].type = type;
501 elems[nelems].label = label;
502 elems[nelems].port = portno(label);
503 elems[nelems].zone = zone;
504 elems[nelems].ref = NULL;
505 elems[nelems].init = 0.0;
506 elems[nelems].min = 0.0;
507 elems[nelems].max = 0.0;
508 elems[nelems].step = 0.0;
509 nelems++;
510 }
511
512 inline void LV2UI::add_elem(ui_elem_type_t type, const char *label, float *zone,
513 float init, float min, float max, float step)
514 {
515 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
516 if (elems1)
517 elems = elems1;
518 else
519 return;
520 elems[nelems].type = type;
521 elems[nelems].label = label;
522 elems[nelems].port = portno(label);
523 elems[nelems].zone = zone;
524 elems[nelems].ref = NULL;
525 elems[nelems].init = init;
526 elems[nelems].min = min;
527 elems[nelems].max = max;
528 elems[nelems].step = step;
529 nelems++;
530 }
531
532 inline void LV2UI::add_elem(ui_elem_type_t type, const char *label, float *zone,
533 float min, float max)
534 {
535 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
536 if (elems1)
537 elems = elems1;
538 else
539 return;
540 elems[nelems].type = type;
541 elems[nelems].label = label;
542 elems[nelems].port = portno(label);
543 elems[nelems].zone = zone;
544 elems[nelems].ref = NULL;
545 elems[nelems].init = 0.0;
546 elems[nelems].min = min;
547 elems[nelems].max = max;
548 elems[nelems].step = 0.0;
549 nelems++;
550 }
551
552 inline bool LV2UI::is_voice_ctrl(const char *label)
553 {
554 if (!is_instr)
555 return false;
556 else if (!have_freq && !strcmp(label, "freq"))
557 return (have_freq = true);
558 else if (!have_gain && !strcmp(label, "gain"))
559 return (have_gain = true);
560 else if (!have_gate && !strcmp(label, "gate"))
561 return (have_gate = true);
562 else
563 return false;
564 }
565
566 void LV2UI::addButton(const char* label, float* zone)
567 { add_elem(UI_BUTTON, label, zone); }
568 void LV2UI::addCheckButton(const char* label, float* zone)
569 { add_elem(UI_CHECK_BUTTON, label, zone); }
570 void LV2UI::addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
571 { add_elem(UI_V_SLIDER, label, zone, init, min, max, step); }
572 void LV2UI::addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
573 { add_elem(UI_H_SLIDER, label, zone, init, min, max, step); }
574 void LV2UI::addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
575 { add_elem(UI_NUM_ENTRY, label, zone, init, min, max, step); }
576
577 void LV2UI::addHorizontalBargraph(const char* label, float* zone, float min, float max)
578 { add_elem(UI_H_BARGRAPH, label, zone, min, max); }
579 void LV2UI::addVerticalBargraph(const char* label, float* zone, float min, float max)
580 { add_elem(UI_V_BARGRAPH, label, zone, min, max); }
581
582 void LV2UI::openTabBox(const char* label)
583 { add_elem(UI_T_GROUP, label); }
584 void LV2UI::openHorizontalBox(const char* label)
585 { add_elem(UI_H_GROUP, label); }
586 void LV2UI::openVerticalBox(const char* label)
587 { add_elem(UI_V_GROUP, label); }
588 void LV2UI::closeBox()
589 { add_elem(UI_END_GROUP); }
590
591 void LV2UI::run() {}
592
593 //----------------------------------------------------------------------------
594 // FAUST generated signal processor
595 //----------------------------------------------------------------------------
596
597 #ifndef FAUSTFLOAT
598 #define FAUSTFLOAT float
599 #endif
600
601 #include <algorithm>
602 #include <cmath>
603 #include <math.h>
604
605 static float vibrato_ext_faustpower2_f(float value) {
606 return (value * value);
607 }
608 static float vibrato_ext_faustpower3_f(float value) {
609 return ((value * value) * value);
610 }
611 static float vibrato_ext_faustpower4_f(float value) {
612 return (((value * value) * value) * value);
613 }
614 static float vibrato_ext_faustpower5_f(float value) {
615 return ((((value * value) * value) * value) * value);
616 }
617 static float vibrato_ext_faustpower6_f(float value) {
618 return (((((value * value) * value) * value) * value) * value);
619 }
620
621 #ifndef FAUSTCLASS
622 #define FAUSTCLASS vibrato_ext
623 #endif
624
625 #ifdef __APPLE__
626 #define exp10f __exp10f
627 #define exp10 __exp10
628 #endif
629
630 class vibrato_ext : public dsp {
631
632 private:
633
634 FAUSTFLOAT fCheckbox0;
635 FAUSTFLOAT fHslider0;
636 int fSampleRate;
637 float fConst0;
638 float fConst1;
639 FAUSTFLOAT fHslider1;
640 FAUSTFLOAT fHslider2;
641 FAUSTFLOAT fHslider3;
642 float fConst2;
643 FAUSTFLOAT fHslider4;
644 FAUSTFLOAT fHslider5;
645 float fRec6[3];
646 float fRec5[3];
647 float fRec4[3];
648 float fRec3[3];
649 float fRec2[3];
650 float fRec1[3];
651 float fRec0[2];
652 FAUSTFLOAT fCheckbox1;
653
654 public:
655
656 void metadata(Meta* m) {
657 m->declare("filename", "vibrato_ext.dsp");
658 m->declare("filters.lib/fir:author", "Julius O. Smith III");
659 m->declare("filters.lib/fir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
660 m->declare("filters.lib/fir:license", "MIT-style STK-4.3 license");
661 m->declare("filters.lib/iir:author", "Julius O. Smith III");
662 m->declare("filters.lib/iir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
663 m->declare("filters.lib/iir:license", "MIT-style STK-4.3 license");
664 m->declare("filters.lib/lowpass0_highpass1", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
665 m->declare("filters.lib/name", "Faust Filters Library");
666 m->declare("filters.lib/tf2:author", "Julius O. Smith III");
667 m->declare("filters.lib/tf2:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
668 m->declare("filters.lib/tf2:license", "MIT-style STK-4.3 license");
669 m->declare("maths.lib/author", "GRAME");
670 m->declare("maths.lib/copyright", "GRAME");
671 m->declare("maths.lib/license", "LGPL with exception");
672 m->declare("maths.lib/name", "Faust Math Library");
673 m->declare("maths.lib/version", "2.1");
674 m->declare("name", "vibrato_ext");
675 }
676
677 virtual int getNumInputs() {
678 return 2;
679 }
680 virtual int getNumOutputs() {
681 return 1;
682 }
683 virtual int getInputRate(int channel) {
684 int rate;
685 switch ((channel)) {
686 case 0: {
687 rate = 1;
688 break;
689 }
690 case 1: {
691 rate = 1;
692 break;
693 }
694 default: {
695 rate = -1;
696 break;
697 }
698 }
699 return rate;
700 }
701 virtual int getOutputRate(int channel) {
702 int rate;
703 switch ((channel)) {
704 case 0: {
705 rate = 1;
706 break;
707 }
708 default: {
709 rate = -1;
710 break;
711 }
712 }
713 return rate;
714 }
715
716 static void classInit(int sample_rate) {
717 }
718
719 virtual void instanceConstants(int sample_rate) {
720 fSampleRate = sample_rate;
721 fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
722 fConst1 = (1.0f / fConst0);
723 fConst2 = (6.28318548f / fConst0);
724 }
725
726 virtual void instanceResetUserInterface() {
727 fCheckbox0 = FAUSTFLOAT(0.0f);
728 fHslider0 = FAUSTFLOAT(1.0f);
729 fHslider1 = FAUSTFLOAT(1000.0f);
730 fHslider2 = FAUSTFLOAT(0.0f);
731 fHslider3 = FAUSTFLOAT(1.5f);
732 fHslider4 = FAUSTFLOAT(100.0f);
733 fHslider5 = FAUSTFLOAT(800.0f);
734 fCheckbox1 = FAUSTFLOAT(0.0f);
735 }
736
737 virtual void instanceClear() {
738 for (int l0 = 0; (l0 < 3); l0 = (l0 + 1)) {
739 fRec6[l0] = 0.0f;
740 }
741 for (int l1 = 0; (l1 < 3); l1 = (l1 + 1)) {
742 fRec5[l1] = 0.0f;
743 }
744 for (int l2 = 0; (l2 < 3); l2 = (l2 + 1)) {
745 fRec4[l2] = 0.0f;
746 }
747 for (int l3 = 0; (l3 < 3); l3 = (l3 + 1)) {
748 fRec3[l3] = 0.0f;
749 }
750 for (int l4 = 0; (l4 < 3); l4 = (l4 + 1)) {
751 fRec2[l4] = 0.0f;
752 }
753 for (int l5 = 0; (l5 < 3); l5 = (l5 + 1)) {
754 fRec1[l5] = 0.0f;
755 }
756 for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) {
757 fRec0[l6] = 0.0f;
758 }
759 }
760
761 virtual void init(int sample_rate) {
762 classInit(sample_rate);
763 instanceInit(sample_rate);
764 }
765 virtual void instanceInit(int sample_rate) {
766 instanceConstants(sample_rate);
767 instanceResetUserInterface();
768 instanceClear();
769 }
770
771 virtual vibrato_ext* clone() {
772 return new vibrato_ext();
773 }
774
775 virtual int getSampleRate() {
776 return fSampleRate;
777 }
778
779 virtual void buildUserInterface(UI* ui_interface) {
780 ui_interface->declare(0, "tooltip", "Reference: https://ccrma.stanford.edu/~jos/pasp/Flanging.html");
781 ui_interface->openVerticalBox("PHASER2");
782 ui_interface->declare(0, "0", "");
783 ui_interface->openHorizontalBox("0x00");
784 ui_interface->declare(&fCheckbox1, "1", "");
785 ui_interface->addCheckButton("Invert Internal Phaser Sum", &fCheckbox1);
786 ui_interface->declare(&fCheckbox0, "2", "");
787 ui_interface->addCheckButton("Vibrato Mode", &fCheckbox0);
788 ui_interface->closeBox();
789 ui_interface->declare(0, "1", "");
790 ui_interface->openHorizontalBox("0x00");
791 ui_interface->declare(&fHslider0, "2", "");
792 ui_interface->declare(&fHslider0, "style", "knob");
793 ui_interface->addHorizontalSlider("Notch Depth (Intensity)", &fHslider0, 1.0f, 0.0f, 1.0f, 0.00100000005f);
794 ui_interface->declare(&fHslider2, "3", "");
795 ui_interface->declare(&fHslider2, "style", "knob");
796 ui_interface->addHorizontalSlider("Feedback Gain", &fHslider2, 0.0f, -0.999000013f, 0.999000013f, 0.00100000005f);
797 ui_interface->closeBox();
798 ui_interface->declare(0, "2", "");
799 ui_interface->openHorizontalBox("0x00");
800 ui_interface->declare(&fHslider1, "1", "");
801 ui_interface->declare(&fHslider1, "scale", "log");
802 ui_interface->declare(&fHslider1, "style", "knob");
803 ui_interface->declare(&fHslider1, "unit", "Hz");
804 ui_interface->addHorizontalSlider("Notch width", &fHslider1, 1000.0f, 10.0f, 5000.0f, 1.0f);
805 ui_interface->declare(&fHslider4, "2", "");
806 ui_interface->declare(&fHslider4, "scale", "log");
807 ui_interface->declare(&fHslider4, "style", "knob");
808 ui_interface->declare(&fHslider4, "unit", "Hz");
809 ui_interface->addHorizontalSlider("Min Notch1 Freq", &fHslider4, 100.0f, 20.0f, 5000.0f, 1.0f);
810 ui_interface->declare(&fHslider5, "3", "");
811 ui_interface->declare(&fHslider5, "scale", "log");
812 ui_interface->declare(&fHslider5, "style", "knob");
813 ui_interface->declare(&fHslider5, "unit", "Hz");
814 ui_interface->addHorizontalSlider("Max Notch1 Freq", &fHslider5, 800.0f, 20.0f, 10000.0f, 1.0f);
815 ui_interface->declare(&fHslider3, "4", "");
816 ui_interface->declare(&fHslider3, "style", "knob");
817 ui_interface->addHorizontalSlider("Notch Freq Ratio", &fHslider3, 1.5f, 1.10000002f, 4.0f, 0.00100000005f);
818 ui_interface->closeBox();
819 ui_interface->closeBox();
820 }
821
822 virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
823 FAUSTFLOAT* input0 = inputs[0];
824 FAUSTFLOAT* input1 = inputs[1];
825 FAUSTFLOAT* output0 = outputs[0];
826 float fSlow0 = (0.5f * (int(float(fCheckbox0)) ? 2.0f : float(fHslider0)));
827 float fSlow1 = (1.0f - fSlow0);
828 float fSlow2 = std::exp((fConst1 * (0.0f - (3.14159274f * float(fHslider1)))));
829 float fSlow3 = vibrato_ext_faustpower2_f(fSlow2);
830 float fSlow4 = (0.0f - (2.0f * fSlow2));
831 float fSlow5 = float(fHslider2);
832 float fSlow6 = float(fHslider3);
833 float fSlow7 = float(fHslider4);
834 float fSlow8 = (fConst2 * fSlow7);
835 float fSlow9 = (0.0f - (fConst2 * (fSlow7 - std::max<float>(fSlow7, float(fHslider5)))));
836 float fSlow10 = vibrato_ext_faustpower2_f(fSlow6);
837 float fSlow11 = vibrato_ext_faustpower3_f(fSlow6);
838 float fSlow12 = vibrato_ext_faustpower4_f(fSlow6);
839 float fSlow13 = vibrato_ext_faustpower5_f(fSlow6);
840 float fSlow14 = vibrato_ext_faustpower6_f(fSlow6);
841 float fSlow15 = (int(float(fCheckbox1)) ? (-1.0f * fSlow0) : fSlow0);
842 for (int i = 0; (i < count); i = (i + 1)) {
843 float fTemp0 = float(input1[i]);
844 float fTemp1 = (fSlow8 + (fSlow9 * float(input0[i])));
845 float fTemp2 = (fRec6[1] * std::cos((fSlow6 * fTemp1)));
846 fRec6[0] = ((fTemp0 + (fSlow5 * fRec0[1])) - ((fSlow4 * fTemp2) + (fSlow3 * fRec6[2])));
847 float fTemp3 = (fRec5[1] * std::cos((fSlow10 * fTemp1)));
848 fRec5[0] = ((fSlow4 * (fTemp2 - fTemp3)) + (fRec6[2] + (fSlow3 * (fRec6[0] - fRec5[2]))));
849 float fTemp4 = (fRec4[1] * std::cos((fSlow11 * fTemp1)));
850 fRec4[0] = ((fSlow4 * (fTemp3 - fTemp4)) + (fRec5[2] + (fSlow3 * (fRec5[0] - fRec4[2]))));
851 float fTemp5 = (fRec3[1] * std::cos((fSlow12 * fTemp1)));
852 fRec3[0] = ((fSlow4 * (fTemp4 - fTemp5)) + (fRec4[2] + (fSlow3 * (fRec4[0] - fRec3[2]))));
853 float fTemp6 = (fRec2[1] * std::cos((fSlow13 * fTemp1)));
854 fRec2[0] = ((fSlow3 * (fRec3[0] - fRec2[2])) + (fRec3[2] + (fSlow4 * (fTemp5 - fTemp6))));
855 float fTemp7 = (fRec1[1] * std::cos((fSlow14 * fTemp1)));
856 fRec1[0] = ((fSlow4 * (fTemp6 - fTemp7)) + (fRec2[2] + (fSlow3 * (fRec2[0] - fRec1[2]))));
857 fRec0[0] = ((fSlow3 * fRec1[0]) + ((fSlow4 * fTemp7) + fRec1[2]));
858 output0[i] = FAUSTFLOAT(((fTemp0 * fSlow1) + (fRec0[0] * fSlow15)));
859 fRec6[2] = fRec6[1];
860 fRec6[1] = fRec6[0];
861 fRec5[2] = fRec5[1];
862 fRec5[1] = fRec5[0];
863 fRec4[2] = fRec4[1];
864 fRec4[1] = fRec4[0];
865 fRec3[2] = fRec3[1];
866 fRec3[1] = fRec3[0];
867 fRec2[2] = fRec2[1];
868 fRec2[1] = fRec2[0];
869 fRec1[2] = fRec1[1];
870 fRec1[1] = fRec1[0];
871 fRec0[1] = fRec0[0];
872 }
873 }
874
875 };
876
877 //----------------------------------------------------------------------------
878 // LV2 interface
879 //----------------------------------------------------------------------------
880
881 #line 286 "lv2.cpp"
882
883 #include <assert.h>
884 #include <stdio.h>
885 #include <stdlib.h>
886
887 #include <bitset>
888 #include <boost/circular_buffer.hpp>
889
890 #include <lv2/lv2plug.in/ns/lv2core/lv2.h>
891 #include <lv2/lv2plug.in/ns/ext/dynmanifest/dynmanifest.h>
892 #include <lv2/lv2plug.in/ns/ext/atom/util.h>
893 #include <lv2/lv2plug.in/ns/ext/urid/urid.h>
894
895 // Set this to the proper shared library extension for your system
896 #ifndef DLLEXT
897 #define DLLEXT ".so"
898 #endif
899
900 #ifndef URI_PREFIX
901 #define URI_PREFIX "https://faustlv2.bitbucket.io"
902 #endif
903
904 #ifndef PLUGIN_URI
905 #define PLUGIN_URI URI_PREFIX "/vibrato_ext"
906 #endif
907
908 #define MIDI_EVENT_URI "http://lv2plug.in/ns/ext/midi#MidiEvent"
909
910 /* Setting NVOICES at compile time overrides meta data in the Faust source. If
911 set, this must be an integer value >= 0. A nonzero value indicates an
912 instrument (VSTi) plugin with the given maximum number of voices. Use 1 for
913 a monophonic synthesizer, and 0 for a simple effect plugin. If NVOICES
914 isn't defined at compile time then the number of voices of an instrument
915 plugin can also be set with the global "nvoices" meta data key in the Faust
916 source. This setting also adds a special "polyphony" control to the plugin
917 which can be used to dynamically adjust the actual number of voices in the
918 range 1..NVOICES. */
919 //#define NVOICES 16
920
921 /* This enables a special "tuning" control for instruments which lets you
922 select the MTS tuning to be used for the synth. In order to use this, you
923 just drop some sysex (.syx) files with MTS octave-based tunings in 1- or
924 2-byte format into the ~/.fautvst/tuning directory (these can be generated
925 with the author's sclsyx program, https://bitbucket.org/agraef/sclsyx).
926 The control will only be shown if any .syx files were found at startup. 0
927 selects the default tuning (standard 12-tone equal temperament), i>0 the
928 tuning in the ith sysex file (in alphabetic order). */
929 #ifndef FAUST_MTS
930 #define FAUST_MTS 1
931 #endif
932
933 /* This allows various manifest data to be generated from the corresponding
934 metadata (author, name, description, license) in the Faust source. */
935 #ifndef FAUST_META
936 #define FAUST_META 1
937 #endif
938
939 /* This enables automatic MIDI controller mapping based on the midi:ctrl
940 attributes in the Faust source. We have this enabled by default, but you
941 may have to disable it if the custom controller mapping gets in the way of
942 the automation facilities that the host provides. (But then again if the
943 host wants to do its own controller mapping then it probably won't, or at
944 least shouldn't, send us the MIDI controllers in the first place.) */
945 #ifndef FAUST_MIDICC
946 #define FAUST_MIDICC 1
947 #endif
948
949 /* This enables or disables the plugin's custom Qt GUI (cf. lv2ui.cpp). Note
950 that this only affects the plugin manifest, the GUI code itself is in a
951 separate module created with the lv2ui.cpp architecture. Also, you'll have
952 to use the alternative lv2ui manifest templates to tell the LV2 host about
953 the GUI. */
954 #ifndef FAUST_UI
955 #define FAUST_UI 0
956 #endif
957
958 // You can define these for various debugging output items.
959 //#define DEBUG_META 1 // recognized MIDI controller metadata
960 //#define DEBUG_VOICES 1 // triggering of synth voices
961 //#define DEBUG_VOICE_ALLOC 1 // voice allocation
962 //#define DEBUG_MIDI 1 // incoming MIDI messages
963 //#define DEBUG_NOTES 1 // note messages
964 //#define DEBUG_MIDICC 1 // controller messages
965 //#define DEBUG_RPN 1 // RPN messages (pitch bend range, master tuning)
966 //#define DEBUG_MTS 1 // MTS messages (octave/scale tuning)
967
968 // Note and voice data structures.
969
970 struct NoteInfo {
971 uint8_t ch;
972 int8_t note;
973 };
974
975 struct VoiceData {
976 // Octave tunings (offsets in semitones) per MIDI channel.
977 float tuning[16][12];
978 // Allocated voices per MIDI channel and note.
979 int8_t notes[16][128];
980 // Free and used voices.
981 int n_free, n_used;
982 boost::circular_buffer<int> free_voices;
983 boost::circular_buffer<int> used_voices;
984 NoteInfo *note_info;
985 // Voices queued for note-offs (zero-length notes).
986 set<int> queued;
987 // Last gate value during run() for each voice. We need to keep track of
988 // these so that we can force the Faust synth to retrigger a note when
989 // needed.
990 float *lastgate;
991 // Current pitch bend and pitch bend range on each MIDI channel, in semitones.
992 float bend[16], range[16];
993 // Current coarse, fine and total master tuning on each MIDI channel (tuning
994 // offset relative to A4 = 440 Hz, in semitones).
995 float coarse[16], fine[16], tune[16];
996 VoiceData(int n) : free_voices(n), used_voices(n) { }
997 };
998
999 #if FAUST_MTS
1000
1001 // Helper classes to read and store MTS tunings.
1002
1003 #include <sys/types.h>
1004 #include <sys/stat.h>
1005 #include <dirent.h>
1006
1007 #include <string>
1008 #include <vector>
1009
1010 struct MTSTuning {
1011 char *name; // name of the tuning
1012 int len; // length of sysex data in bytes
1013 unsigned char *data; // sysex data
1014 MTSTuning() : name(0), len(0), data(0) {}
1015 MTSTuning& operator=(const MTSTuning &t)
1016 {
1017 if (this == &t) return *this;
1018 if (name) free(name); if (data) free(data);
1019 name = 0; data = 0; len = t.len;
1020 if (t.name) {
1021 name = strdup(t.name); assert(name);
1022 }
1023 if (t.data) {
1024 data = (unsigned char*)malloc(len); assert(data);
1025 memcpy(data, t.data, len);
1026 }
1027 return *this;
1028 }
1029 MTSTuning(const MTSTuning& t) : name(0), len(0), data(0)
1030 { *this = t; }
1031 MTSTuning(const char *filename);
1032 ~MTSTuning()
1033 { if (name) free(name); if (data) free(data); }
1034 };
1035
1036 MTSTuning::MTSTuning(const char *filename)
1037 {
1038 FILE *fp = fopen(filename, "rb");
1039 name = 0; len = 0; data = 0;
1040 if (!fp) return;
1041 struct stat st;
1042 if (fstat(fileno(fp), &st)) return;
1043 len = st.st_size;
1044 data = (unsigned char*)calloc(len, 1);
1045 if (!data) {
1046 len = 0; fclose(fp);
1047 return;
1048 }
1049 assert(len > 0);
1050 if (fread(data, 1, len, fp) < len) {
1051 free(data); len = 0; data = 0; fclose(fp);
1052 return;
1053 }
1054 fclose(fp);
1055 // Do some basic sanity checks.
1056 if (data[0] != 0xf0 || data[len-1] != 0xf7 || // not a sysex message
1057 (data[1] != 0x7e && data[1] != 0x7f) || data[3] != 8 || // not MTS
1058 !((len == 21 && data[4] == 8) ||
1059 (len == 33 && data[4] == 9))) { // no 1- or 2-byte tuning
1060 free(data); len = 0; data = 0;
1061 return;
1062 }
1063 // Name of the tuning is the basename of the file, without the trailing .syx
1064 // suffix.
1065 string nm = filename;
1066 size_t p = nm.rfind(".syx");
1067 if (p != string::npos) nm.erase(p);
1068 p = nm.rfind('/');
1069 if (p != string::npos) nm.erase(0, p+1);
1070 name = strdup(nm.c_str());
1071 assert(name);
1072 }
1073
1074 struct MTSTunings {
1075 vector<MTSTuning> tuning;
1076 MTSTunings() {}
1077 MTSTunings(const char *path);
1078 };
1079
1080 static bool compareByName(const MTSTuning &a, const MTSTuning &b)
1081 {
1082 return strcmp(a.name, b.name) < 0;
1083 }
1084
1085 MTSTunings::MTSTunings(const char *path)
1086 {
1087 DIR *dp = opendir(path);
1088 if (!dp) return;
1089 struct dirent *d;
1090 while ((d = readdir(dp))) {
1091 string nm = d->d_name;
1092 if (nm.length() > 4 && nm.substr(nm.length()-4) == ".syx") {
1093 string pathname = path;
1094 pathname += "/";
1095 pathname += nm;
1096 MTSTuning t(pathname.c_str());
1097 if (t.data) tuning.push_back(t);
1098 }
1099 }
1100 closedir(dp);
1101 // sort found tunings by name
1102 sort(tuning.begin(), tuning.end(), compareByName);
1103 }
1104
1105 #endif
1106
1107 #if FAUST_MIDICC
1108 static float ctrlval(const ui_elem_t &el, uint8_t v)
1109 {
1110 // Translate the given MIDI controller value to the range and stepsize
1111 // indicated by the Faust control.
1112 switch (el.type) {
1113 case UI_BUTTON: case UI_CHECK_BUTTON:
1114 return (float)(v>=64);
1115 default:
1116 /* Continuous controllers. The problem here is that the range 0..127 is
1117 not symmetric. We'd like to map 64 to the center of the range
1118 (max-min)/2 and at the same time retain the full control range
1119 min..max. So let's just pretend that there are 128 controller values
1120 and map value 127 to the max value anyway. */
1121 if (v==127)
1122 return el.max;
1123 else
1124 // XXXFIXME: We might want to add proper quantization according to
1125 // el.step here.
1126 return el.min+(el.max-el.min)*v/128;
1127 }
1128 }
1129 #endif
1130
1131 /***************************************************************************/
1132
1133 /* Polyphonic Faust plugin data structure. XXXTODO: At present this is just a
1134 big struct which exposes all requisite data. Some more work is needed to
1135 make the interface a bit more abstract and properly encapsulate the
1136 internal data structures, so that implementation details can be changed
1137 more easily. */
1138
1139 struct LV2Plugin {
1140 const int maxvoices; // maximum number of voices (zero if not an instrument)
1141 const int ndsps; // number of dsp instances (1 if maxvoices==0)
1142 bool active; // activation status
1143 int rate; // sampling rate
1144 int nvoices; // current number of voices (<= maxvoices)
1145 int tuning_no; // current tuning number (<= n_tunings)
1146 vibrato_ext **dsp; // the dsps
1147 LV2UI **ui; // their Faust interface descriptions
1148 int n_in, n_out; // number of input and output control ports
1149 int *ctrls; // Faust ui elements (indices into ui->elems)
1150 float **ports; // corresponding LV2 data
1151 float *portvals; // cached port data from the last run
1152 float *midivals[16]; // per-midi channel data
1153 int *inctrls, *outctrls; // indices for active and passive controls
1154 float **inputs, **outputs; // audio buffers
1155 int freq, gain, gate; // indices of voice controls
1156 unsigned n_samples; // current block size
1157 float **outbuf; // audio buffers for mixing down the voices
1158 float **inbuf; // dummy input buffer
1159 LV2_Atom_Sequence* event_port; // midi input
1160 float *poly, *tuning; // polyphony and tuning ports
1161 std::map<uint8_t,int> ctrlmap; // MIDI controller map
1162 // Needed host features.
1163 LV2_URID_Map* map; // the urid extension
1164 LV2_URID midi_event; // midi event uri
1165 // Current RPN MSB and LSB numbers, as set with controllers 101 and 100.
1166 uint8_t rpn_msb[16], rpn_lsb[16];
1167 // Current data entry MSB and LSB numbers, as set with controllers 6 and 38.
1168 uint8_t data_msb[16], data_lsb[16];
1169 // Synth voice data (instruments only).
1170 VoiceData *vd;
1171
1172 // Static methods. These all use static data so they can be invoked before
1173 // instantiating a plugin.
1174
1175 // Global meta data (dsp name, author, etc.).
1176 static Meta *meta;
1177 static void init_meta()
1178 {
1179 if (!meta && (meta = new Meta)) {
1180 // We allocate the temporary dsp object on the heap here, to prevent
1181 // large dsp objects from running out of stack in environments where
1182 // stack space is precious (e.g., Reaper). Note that if any of these
1183 // allocations fail then no meta data will be available, but at least we
1184 // won't make the host crash and burn.
1185 vibrato_ext* tmp_dsp = new vibrato_ext();
1186 if (tmp_dsp) {
1187 tmp_dsp->metadata(meta);
1188 delete tmp_dsp;
1189 }
1190 }
1191 }
1192 static const char *meta_get(const char *key, const char *deflt)
1193 {
1194 init_meta();
1195 return meta?meta->get(key, deflt):deflt;
1196 }
1197
1198 static const char *pluginName()
1199 {
1200 return meta_get("name", "vibrato_ext");
1201 }
1202
1203 static const char *pluginAuthor()
1204 {
1205 return meta_get("author", "");
1206 }
1207
1208 static const char *pluginDescription()
1209 {
1210 return meta_get("description", "");
1211 }
1212
1213 static const char *pluginLicense()
1214 {
1215 return meta_get("license", "");
1216 }
1217
1218 static const char *pluginVersion()
1219 {
1220 return meta_get("version", "");
1221 }
1222
1223 // Load a collection of sysex files with MTS tunings in ~/.faust/tuning.
1224 static int n_tunings;
1225 #if FAUST_MTS
1226 static MTSTunings *mts;
1227
1228 static MTSTunings *load_sysex_data()
1229 {
1230 if (!mts) {
1231 string mts_path;
1232 // Look for FAUST_HOME. If that isn't set, try $HOME/.faust. If HOME
1233 // isn't set either, just assume a .faust subdir of the cwd.
1234 const char *home = getenv("FAUST_HOME");
1235 if (home)
1236 mts_path = home;
1237 else {
1238 home = getenv("HOME");
1239 if (home) {
1240 mts_path = home;
1241 mts_path += "/.faust";
1242 } else
1243 mts_path = ".faust";
1244 }
1245 // MTS tunings are looked for in this subdir.
1246 mts_path += "/tuning";
1247 mts = new MTSTunings(mts_path.c_str());
1248 #ifdef __APPLE__
1249 if (!mts || mts->tuning.size() == 0) {
1250 // Also check ~/Library/Faust/Tuning on the Mac.
1251 home = getenv("HOME");
1252 if (home) {
1253 if (mts) delete mts;
1254 mts_path = home;
1255 mts_path += "/Library/Faust/Tuning";
1256 mts = new MTSTunings(mts_path.c_str());
1257 }
1258 }
1259 #endif
1260 n_tunings = mts->tuning.size();
1261 }
1262 return mts;
1263 }
1264 #endif
1265
1266 // The number of voices of an instrument plugin. We get this information
1267 // from the global meta data (nvoices key) of the dsp module if present, and
1268 // you can also override this setting at compile time by defining the
1269 // NVOICES macro. If neither is defined or the value is zero then the plugin
1270 // becomes a simple audio effect instead.
1271 static int numVoices()
1272 {
1273 #ifdef NVOICES
1274 return NVOICES;
1275 #else
1276 const char *numVoices = meta_get("nvoices", "0");
1277 int nvoices = atoi(numVoices);
1278 if (nvoices < 0 ) nvoices = 0;
1279 return nvoices;
1280 #endif
1281 }
1282
1283 // Instance methods.
1284
1285 LV2Plugin(const int num_voices, const int sr)
1286 : maxvoices(num_voices), ndsps(num_voices<=0?1:num_voices),
1287 vd(num_voices>0?new VoiceData(num_voices):0)
1288 {
1289 // Initialize static data.
1290 init_meta();
1291 #if FAUST_MTS
1292 // Synth: load tuning sysex data if present.
1293 if (num_voices>0) load_sysex_data();
1294 #endif
1295 // Allocate data structures and set some reasonable defaults.
1296 dsp = (vibrato_ext**)calloc(ndsps, sizeof(vibrato_ext*));
1297 ui = (LV2UI**)calloc(ndsps, sizeof(LV2UI*));
1298 assert(dsp && ui);
1299 if (vd) {
1300 vd->note_info = (NoteInfo*)calloc(ndsps, sizeof(NoteInfo));
1301 vd->lastgate = (float*)calloc(ndsps, sizeof(float));
1302 assert(vd->note_info && vd->lastgate);
1303 }
1304 active = false;
1305 rate = sr;
1306 nvoices = maxvoices;
1307 tuning_no = 0;
1308 n_in = n_out = 0;
1309 map = NULL;
1310 midi_event = -1;
1311 event_port = NULL;
1312 poly = tuning = NULL;
1313 freq = gain = gate = -1;
1314 if (vd) {
1315 vd->n_free = maxvoices;
1316 for (int i = 0; i < maxvoices; i++) {
1317 vd->free_voices.push_back(i);
1318 vd->lastgate[i] = 0.0f;
1319 }
1320 for (int i = 0; i < 16; i++) {
1321 vd->bend[i] = 0.0f;
1322 vd->range[i] = 2.0f;
1323 vd->coarse[i] = vd->fine[i] = vd->tune[i] = 0.0f;
1324 for (int j = 0; j < 12; j++)
1325 vd->tuning[i][j] = 0.0f;
1326 }
1327 vd->n_used = 0;
1328 memset(vd->notes, 0xff, sizeof(vd->notes));
1329 }
1330 n_samples = 0;
1331 ctrls = inctrls = outctrls = NULL;
1332 ports = inputs = outputs = inbuf = outbuf = NULL;
1333 portvals = NULL;
1334 memset(midivals, 0, sizeof(midivals));
1335 // Initialize the Faust DSPs.
1336 for (int i = 0; i < ndsps; i++) {
1337 dsp[i] = new vibrato_ext();
1338 ui[i] = new LV2UI(num_voices);
1339 dsp[i]->init(rate);
1340 dsp[i]->buildUserInterface(ui[i]);
1341 }
1342 // The ports are numbered as follows: 0..k-1 are the control ports, then
1343 // come the n audio input ports, then the m audio output ports, and
1344 // finally the midi input port and the polyphony and tuning controls.
1345 int k = ui[0]->nports, p = 0, q = 0;
1346 int n = dsp[0]->getNumInputs(), m = dsp[0]->getNumOutputs();
1347 // Allocate tables for the built-in control elements and their ports.
1348 ctrls = (int*)calloc(k, sizeof(int));
1349 inctrls = (int*)calloc(k, sizeof(int));
1350 outctrls = (int*)calloc(k, sizeof(int));
1351 ports = (float**)calloc(k, sizeof(float*));
1352 portvals = (float*)calloc(k, sizeof(float));
1353 assert(k == 0 || (ctrls && inctrls && outctrls && ports && portvals));
1354 for (int ch = 0; ch < 16; ch++) {
1355 midivals[ch] = (float*)calloc(k, sizeof(float));
1356 assert(k == 0 || midivals[ch]);
1357 }
1358 // Scan the Faust UI for active and passive controls which become the
1359 // input and output control ports of the plugin, respectively.
1360 for (int i = 0, j = 0; i < ui[0]->nelems; i++) {
1361 switch (ui[0]->elems[i].type) {
1362 case UI_T_GROUP: case UI_H_GROUP: case UI_V_GROUP: case UI_END_GROUP:
1363 // control groups (ignored right now)
1364 break;
1365 case UI_H_BARGRAPH: case UI_V_BARGRAPH:
1366 // passive controls (output ports)
1367 ctrls[j++] = i;
1368 outctrls[q++] = i;
1369 break;
1370 default:
1371 // active controls (input ports)
1372 if (maxvoices == 0)
1373 goto noinstr;
1374 else if (freq == -1 &&
1375 !strcmp(ui[0]->elems[i].label, "freq"))
1376 freq = i;
1377 else if (gain == -1 &&
1378 !strcmp(ui[0]->elems[i].label, "gain"))
1379 gain = i;
1380 else if (gate == -1 &&
1381 !strcmp(ui[0]->elems[i].label, "gate"))
1382 gate = i;
1383 else {
1384 noinstr:
1385 #if FAUST_MIDICC
1386 std::map< int, list<strpair> >::iterator it =
1387 ui[0]->metadata.find(i);
1388 if (it != ui[0]->metadata.end()) {
1389 // Scan for controller mappings.
1390 for (std::list<strpair>::iterator jt = it->second.begin();
1391 jt != it->second.end(); jt++) {
1392 const char *key = jt->first, *val = jt->second;
1393 #if DEBUG_META
1394 fprintf(stderr, "ctrl '%s' meta: '%s' -> '%s'\n",
1395 ui[0]->elems[i].label, key, val);
1396 #endif
1397 if (strcmp(key, "midi") == 0) {
1398 unsigned num;
1399 if (sscanf(val, "ctrl %u", &num) < 1) continue;
1400 #if 0 // enable this to get feedback about controller assignments
1401 fprintf(stderr, "%s: cc %d -> %s\n", PLUGIN_URI, num,
1402 ui[0]->elems[i].label);
1403 #endif
1404 ctrlmap.insert(std::pair<uint8_t,int>(num, p));
1405 }
1406 }
1407 }
1408 #endif
1409 ctrls[j++] = i;
1410 inctrls[p++] = i;
1411 int p = ui[0]->elems[i].port;
1412 float val = ui[0]->elems[i].init;
1413 assert(p>=0);
1414 portvals[p] = val;
1415 for (int ch = 0; ch < 16; ch++)
1416 midivals[ch][p] = val;
1417 }
1418 break;
1419 }
1420 }
1421 // Realloc the inctrls and outctrls vectors to their appropriate sizes.
1422 inctrls = (int*)realloc(inctrls, p*sizeof(int));
1423 assert(p == 0 || inctrls);
1424 outctrls = (int*)realloc(outctrls, q*sizeof(int));
1425 assert(q == 0 || outctrls);
1426 n_in = p; n_out = q;
1427 // Allocate vectors for the audio input and output ports. Like
1428 // ports, these will be initialized in the connect_port callback.
1429 inputs = (float**)calloc(n, sizeof(float*));
1430 assert(n == 0 || inputs);
1431 outputs = (float**)calloc(m, sizeof(float*));
1432 assert(m == 0 || outputs);
1433 if (maxvoices > 0) {
1434 // Initialize the mixdown buffer.
1435 outbuf = (float**)calloc(m, sizeof(float*));
1436 assert(m == 0 || outbuf);
1437 // We start out with a blocksize of 512 samples here. Hopefully this is
1438 // enough for most realtime hosts so that we can avoid reallocations
1439 // later when we know what the actual blocksize is.
1440 n_samples = 512;
1441 for (int i = 0; i < m; i++) {
1442 outbuf[i] = (float*)malloc(n_samples*sizeof(float));
1443 assert(outbuf[i]);
1444 }
1445 // Initialize a 1-sample dummy input buffer used for retriggering notes.
1446 inbuf = (float**)calloc(n, sizeof(float*));
1447 assert(n == 0 || inbuf);
1448 for (int i = 0; i < m; i++) {
1449 inbuf[i] = (float*)malloc(sizeof(float));
1450 assert(inbuf[i]);
1451 *inbuf[i] = 0.0f;
1452 }
1453 }
1454 }
1455
1456 ~LV2Plugin()
1457 {
1458 const int n = dsp[0]->getNumInputs();
1459 const int m = dsp[0]->getNumOutputs();
1460 for (int i = 0; i < ndsps; i++) {
1461 delete dsp[i];
1462 delete ui[i];
1463 }
1464 free(ctrls); free(inctrls); free(outctrls);
1465 free(ports); free(portvals);
1466 free(inputs); free(outputs);
1467 for (int ch = 0; ch < 16; ch++)
1468 free(midivals[ch]);
1469 if (inbuf) {
1470 for (int i = 0; i < n; i++)
1471 free(inbuf[i]);
1472 free(inbuf);
1473 }
1474 if (outbuf) {
1475 for (int i = 0; i < m; i++)
1476 free(outbuf[i]);
1477 free(outbuf);
1478 }
1479 free(dsp); free(ui);
1480 if (vd) {
1481 free(vd->note_info);
1482 free(vd->lastgate);
1483 delete vd;
1484 }
1485 }
1486 // Voice allocation.
1487
1488 #if DEBUG_VOICE_ALLOC
1489 void print_voices(const char *msg)
1490 {
1491 fprintf(stderr, "%s: notes =", msg);
1492 for (uint8_t ch = 0; ch < 16; ch++)
1493 for (int note = 0; note < 128; note++)
1494 if (vd->notes[ch][note] >= 0)
1495 fprintf(stderr, " [%d] %d(#%d)", ch, note, vd->notes[ch][note]);
1496 fprintf(stderr, "\nqueued (%d):", vd->queued.size());
1497 for (int i = 0; i < nvoices; i++)
1498 if (vd->queued.find(i) != vd->queued.end()) fprintf(stderr, " #%d", i);
1499 fprintf(stderr, "\nused (%d):", vd->n_used);
1500 for (boost::circular_buffer<int>::iterator it = vd->used_voices.begin();
1501 it != vd->used_voices.end(); it++)
1502 fprintf(stderr, " #%d->%d", *it, vd->note_info[*it].note);
1503 fprintf(stderr, "\nfree (%d):", vd->n_free);
1504 for (boost::circular_buffer<int>::iterator it = vd->free_voices.begin();
1505 it != vd->free_voices.end(); it++)
1506 fprintf(stderr, " #%d", *it);
1507 fprintf(stderr, "\n");
1508 }
1509 #endif
1510
1511 int alloc_voice(uint8_t ch, int8_t note, int8_t vel)
1512 {
1513 int i = vd->notes[ch][note];
1514 if (i >= 0) {
1515 // note already playing on same channel, retrigger it
1516 voice_off(i);
1517 voice_on(i, note, vel, ch);
1518 // move this voice to the end of the used list
1519 for (boost::circular_buffer<int>::iterator it =
1520 vd->used_voices.begin();
1521 it != vd->used_voices.end(); it++) {
1522 if (*it == i) {
1523 vd->used_voices.erase(it);
1524 vd->used_voices.push_back(i);
1525 break;
1526 }
1527 }
1528 #if DEBUG_VOICE_ALLOC
1529 print_voices("retrigger");
1530 #endif
1531 return i;
1532 } else if (vd->n_free > 0) {
1533 // take voice from free list
1534 int i = vd->free_voices.front();
1535 vd->free_voices.pop_front();
1536 vd->n_free--;
1537 vd->used_voices.push_back(i);
1538 vd->note_info[i].ch = ch;
1539 vd->note_info[i].note = note;
1540 vd->n_used++;
1541 voice_on(i, note, vel, ch);
1542 vd->notes[ch][note] = i;
1543 #if DEBUG_VOICE_ALLOC
1544 print_voices("alloc");
1545 #endif
1546 return i;
1547 } else {
1548 // steal a voice
1549 assert(vd->n_used > 0);
1550 // FIXME: Maybe we should look for the oldest note on the *current*
1551 // channel here, but this is faster.
1552 int i = vd->used_voices.front();
1553 int oldch = vd->note_info[i].ch;
1554 int oldnote = vd->note_info[i].note;
1555 voice_off(i);
1556 vd->notes[oldch][oldnote] = -1;
1557 vd->queued.erase(i);
1558 vd->used_voices.pop_front();
1559 vd->used_voices.push_back(i);
1560 vd->note_info[i].ch = ch;
1561 vd->note_info[i].note = note;
1562 voice_on(i, note, vel, ch);
1563 vd->notes[ch][note] = i;
1564 #if DEBUG_VOICE_ALLOC
1565 print_voices("steal");
1566 #endif
1567 return i;
1568 }
1569 }
1570
1571 int dealloc_voice(uint8_t ch, int8_t note, int8_t vel)
1572 {
1573 int i = vd->notes[ch][note];
1574 if (i >= 0) {
1575 if (vd->lastgate[i] == 0.0f && gate >= 0) {
1576 // zero-length note, queued for later
1577 vd->queued.insert(i);
1578 vd->notes[ch][note] = -1;
1579 #if DEBUG_VOICE_ALLOC
1580 print_voices("dealloc (queued)");
1581 #endif
1582 return i;
1583 }
1584 assert(vd->n_free < nvoices);
1585 vd->free_voices.push_back(i);
1586 vd->n_free++;
1587 voice_off(i);
1588 vd->notes[ch][note] = -1;
1589 // erase this voice from the used list
1590 for (boost::circular_buffer<int>::iterator it =
1591 vd->used_voices.begin();
1592 it != vd->used_voices.end(); it++) {
1593 if (*it == i) {
1594 vd->used_voices.erase(it);
1595 vd->n_used--;
1596 break;
1597 }
1598 }
1599 #if DEBUG_VOICE_ALLOC
1600 print_voices("dealloc");
1601 #endif
1602 return i;
1603 }
1604 return -1;
1605 }
1606
1607
1608 float midicps(int8_t note, uint8_t chan)
1609 {
1610 float pitch = note + vd->tune[chan] +
1611 vd->tuning[chan][note%12] + vd->bend[chan];
1612 return 440.0*pow(2, (pitch-69.0)/12.0);
1613 }
1614
1615 void voice_on(int i, int8_t note, int8_t vel, uint8_t ch)
1616 {
1617 if (vd->lastgate[i] == 1.0f && gate >= 0) {
1618 // Make sure that the synth sees the 0.0f gate so that the voice is
1619 // properly retriggered.
1620 *ui[i]->elems[gate].zone = 0.0f;
1621 dsp[i]->compute(1, inbuf, outbuf);
1622 }
1623 #if DEBUG_VOICES
1624 fprintf(stderr, "voice on: %d %d (%g Hz) %d (%g)\n", i,
1625 note, midicps(note, ch), vel, vel/127.0);
1626 #endif
1627 if (freq >= 0)
1628 *ui[i]->elems[freq].zone = midicps(note, ch);
1629 if (gate >= 0)
1630 *ui[i]->elems[gate].zone = 1.0f;
1631 if (gain >= 0)
1632 *ui[i]->elems[gain].zone = vel/127.0;
1633 // reinitialize the per-channel control data for this voice
1634 for (int idx = 0; idx < n_in; idx++) {
1635 int j = inctrls[idx], k = ui[0]->elems[j].port;
1636 *ui[i]->elems[j].zone = midivals[ch][k];
1637 }
1638 }
1639
1640 void voice_off(int i)
1641 {
1642 #if DEBUG_VOICES
1643 fprintf(stderr, "voice off: %d\n", i);
1644 #endif
1645 if (gate >= 0)
1646 *ui[i]->elems[gate].zone = 0.0f;
1647 }
1648
1649 void update_voices(uint8_t chan)
1650 {
1651 // update running voices on the given channel after tuning or pitch bend
1652 // changes
1653 for (boost::circular_buffer<int>::iterator it =
1654 vd->used_voices.begin();
1655 it != vd->used_voices.end(); it++) {
1656 int i = *it;
1657 if (vd->note_info[i].ch == chan && freq >= 0) {
1658 int note = vd->note_info[i].note;
1659 *ui[i]->elems[freq].zone = midicps(note, chan);
1660 }
1661 }
1662 }
1663
1664 void all_notes_off()
1665 {
1666 for (int i = 0; i < nvoices; i++)
1667 voice_off(i);
1668 for (int i = 0; i < 16; i++)
1669 vd->bend[i] = 0.0f;
1670 memset(vd->notes, 0xff, sizeof(vd->notes));
1671 vd->free_voices.clear();
1672 vd->n_free = nvoices;
1673 for (int i = 0; i < nvoices; i++)
1674 vd->free_voices.push_back(i);
1675 vd->queued.clear();
1676 vd->used_voices.clear();
1677 vd->n_used = 0;
1678 }
1679
1680 void all_notes_off(uint8_t chan)
1681 {
1682 for (boost::circular_buffer<int>::iterator it =
1683 vd->used_voices.begin();
1684 it != vd->used_voices.end(); ) {
1685 int i = *it;
1686 if (vd->note_info[i].ch == chan) {
1687 assert(vd->n_free < nvoices);
1688 vd->free_voices.push_back(i);
1689 vd->n_free++;
1690 voice_off(i);
1691 vd->notes[vd->note_info[i].ch][vd->note_info[i].note] = -1;
1692 vd->queued.erase(i);
1693 // erase this voice from the used list
1694 it = vd->used_voices.erase(it);
1695 vd->n_used--;
1696 #if DEBUG_VOICE_ALLOC
1697 print_voices("dealloc (all-notes-off)");
1698 #endif
1699 } else
1700 it++;
1701 }
1702 vd->bend[chan] = 0.0f;
1703 }
1704
1705 void queued_notes_off()
1706 {
1707 if (vd->queued.empty()) return;
1708 for (int i = 0; i < nvoices; i++)
1709 if (vd->queued.find(i) != vd->queued.end()) {
1710 assert(vd->n_free < nvoices);
1711 vd->free_voices.push_back(i);
1712 vd->n_free++;
1713 voice_off(i);
1714 vd->notes[vd->note_info[i].ch][vd->note_info[i].note] = -1;
1715 vd->queued.erase(i);
1716 // erase this voice from the used list
1717 for (boost::circular_buffer<int>::iterator it =
1718 vd->used_voices.begin();
1719 it != vd->used_voices.end(); it++) {
1720 if (*it == i) {
1721 vd->used_voices.erase(it);
1722 vd->n_used--;
1723 break;
1724 }
1725 }
1726 #if DEBUG_VOICE_ALLOC
1727 print_voices("dealloc (unqueued)");
1728 #endif
1729 }
1730 }
1731
1732 // Plugin activation status. suspend() deactivates a plugin (disables audio
1733 // processing), resume() reactivates it. Also, set_rate() changes the sample
1734 // rate. Note that the audio and MIDI process functions (see below) can
1735 // still be called in deactivated state, but this is optional. The plugin
1736 // tries to do some reasonable processing in either case, no matter whether
1737 // the host plugin architecture actually executes callbacks in suspended
1738 // state or not.
1739
1740 void suspend()
1741 {
1742 active = false;
1743 if (maxvoices > 0) all_notes_off();
1744 }
1745
1746 void resume()
1747 {
1748 for (int i = 0; i < ndsps; i++)
1749 dsp[i]->init(rate);
1750 for (int i = 0, j = 0; i < ui[0]->nelems; i++) {
1751 int p = ui[0]->elems[i].port;
1752 if (p >= 0) {
1753 float val = ui[0]->elems[i].init;
1754 portvals[p] = val;
1755 }
1756 }
1757 active = true;
1758 }
1759
1760 void set_rate(int sr)
1761 {
1762 rate = sr;
1763 for (int i = 0; i < ndsps; i++)
1764 dsp[i]->init(rate);
1765 }
1766
1767 // Audio and MIDI process functions. The plugin should run these in the
1768 // appropriate real-time callbacks.
1769
1770 void process_audio(int blocksz, float **inputs, float **outputs)
1771 {
1772 int n = dsp[0]->getNumInputs(), m = dsp[0]->getNumOutputs();
1773 AVOIDDENORMALS;
1774 if (maxvoices > 0) queued_notes_off();
1775 if (!active) {
1776 // Depending on the plugin architecture and host, this code might never
1777 // be invoked, since the plugin is deactivitated at this point. But
1778 // let's do something reasonable here anyway.
1779 if (n == m) {
1780 // copy inputs to outputs
1781 for (int i = 0; i < m; i++)
1782 for (unsigned j = 0; j < blocksz; j++)
1783 outputs[i][j] = inputs[i][j];
1784 } else {
1785 // silence
1786 for (int i = 0; i < m; i++)
1787 for (unsigned j = 0; j < blocksz; j++)
1788 outputs[i][j] = 0.0f;
1789 }
1790 return;
1791 }
1792 // Handle changes in the polyphony and tuning controls.
1793 bool is_instr = maxvoices > 0;
1794 if (is_instr) {
1795 if (!poly)
1796 ; // this shouldn't happen but...
1797 else if (nvoices != (int)*poly &&
1798 (int)*poly > 0 && (int)*poly <= maxvoices) {
1799 for (int i = 0; i < nvoices; i++)
1800 voice_off(i);
1801 nvoices = (int)*poly;
1802 // Reset the voice allocation.
1803 memset(vd->notes, 0xff, sizeof(vd->notes));
1804 vd->free_voices.clear();
1805 vd->n_free = nvoices;
1806 for (int i = 0; i < nvoices; i++)
1807 vd->free_voices.push_back(i);
1808 vd->used_voices.clear();
1809 vd->n_used = 0;
1810 } else
1811 *poly = nvoices;
1812 #if FAUST_MTS
1813 if (tuning && tuning_no != (int)*tuning) change_tuning((int)*tuning);
1814 #endif
1815 }
1816 // Only update the controls (of all voices simultaneously) if a port value
1817 // actually changed. This is necessary to allow MIDI controllers to modify
1818 // the values for individual MIDI channels (see processEvents below). Also
1819 // note that this will be done *after* processing the MIDI controller data
1820 // for the current audio block, so manual inputs can still override these.
1821 for (int i = 0; i < n_in; i++) {
1822 int j = inctrls[i], k = ui[0]->elems[j].port;
1823 float &oldval = portvals[k], newval = *ports[k];
1824 if (newval != oldval) {
1825 if (is_instr) {
1826 // instrument: update running voices
1827 for (boost::circular_buffer<int>::iterator it =
1828 vd->used_voices.begin();
1829 it != vd->used_voices.end(); it++) {
1830 int i = *it;
1831 *ui[i]->elems[j].zone = newval;
1832 }
1833 } else {
1834 // simple effect: here we only have a single dsp instance
1835 *ui[0]->elems[j].zone = newval;
1836 }
1837 // also update the MIDI controller data for all channels (manual
1838 // control input is always omni)
1839 for (int ch = 0; ch < 16; ch++)
1840 midivals[ch][k] = newval;
1841 // record the new value
1842 oldval = newval;
1843 }
1844 }
1845 // Initialize the output buffers.
1846 if (n_samples < blocksz) {
1847 // We need to enlarge the buffers. We're not officially allowed to do
1848 // this here (presumably in the realtime thread), but since we usually
1849 // don't know the hosts's block size beforehand, there's really nothing
1850 // else that we can do. Let's just hope that doing this once suffices,
1851 // then hopefully noone will notice.
1852 if (outbuf) {
1853 for (int i = 0; i < m; i++) {
1854 outbuf[i] = (float*)realloc(outbuf[i],
1855 blocksz*sizeof(float));
1856 assert(outbuf[i]);
1857 }
1858 }
1859 n_samples = blocksz;
1860 }
1861 if (outbuf) {
1862 // Polyphonic instrument: Mix the voices down to one signal.
1863 for (int i = 0; i < m; i++)
1864 for (unsigned j = 0; j < blocksz; j++)
1865 outputs[i][j] = 0.0f;
1866 for (int l = 0; l < nvoices; l++) {
1867 // Let Faust do all the hard work.
1868 dsp[l]->compute(blocksz, inputs, outbuf);
1869 for (int i = 0; i < m; i++)
1870 for (unsigned j = 0; j < blocksz; j++)
1871 outputs[i][j] += outbuf[i][j];
1872 }
1873 } else {
1874 // Simple effect: We can write directly to the output buffer.
1875 dsp[0]->compute(blocksz, inputs, outputs);
1876 }
1877 // Finally grab the passive controls and write them back to the
1878 // corresponding control ports. NOTE: Depending on the plugin
1879 // architecture, this might require a host call to get the control GUI
1880 // updated in real-time (if the host supports this at all).
1881 // FIXME: It's not clear how to aggregate the data of the different
1882 // voices. We compute the maximum of each control for now.
1883 for (int i = 0; i < n_out; i++) {
1884 int j = outctrls[i], k = ui[0]->elems[j].port;
1885 float *z = ui[0]->elems[j].zone;
1886 *ports[k] = *z;
1887 for (int l = 1; l < nvoices; l++) {
1888 float *z = ui[l]->elems[j].zone;
1889 if (*ports[k] < *z)
1890 *ports[k] = *z;
1891 }
1892 }
1893 // Keep track of the last gates set for each voice, so that voices can be
1894 // forcibly retriggered if needed.
1895 if (gate >= 0)
1896 for (int i = 0; i < nvoices; i++)
1897 vd->lastgate[i] =
1898 *ui[i]->elems[gate].zone;
1899 }
1900
1901 // This processes just a single MIDI message, so to process an entire series
1902 // of MIDI events you'll have to loop over the event data in the plugin's
1903 // MIDI callback. XXXTODO: Sample-accurate processing of MIDI events.
1904
1905 void process_midi(unsigned char *data, int sz)
1906 {
1907 #if DEBUG_MIDI
1908 fprintf(stderr, "midi ev (%d bytes):", sz);
1909 for (int i = 0; i < sz; i++)
1910 fprintf(stderr, " 0x%0x", data[i]);
1911 fprintf(stderr, "\n");
1912 #endif
1913 uint8_t status = data[0] & 0xf0, chan = data[0] & 0x0f;
1914 bool is_instr = maxvoices > 0;
1915 switch (status) {
1916 case 0x90: {
1917 if (!is_instr) break;
1918 // note on
1919 #if DEBUG_NOTES
1920 fprintf(stderr, "note-on chan %d, note %d, vel %d\n", chan+1,
1921 data[1], data[2]);
1922 #endif
1923 if (data[2] == 0) goto note_off;
1924 alloc_voice(chan, data[1], data[2]);
1925 break;
1926 }
1927 case 0x80: {
1928 if (!is_instr) break;
1929 // note off
1930 #if DEBUG_NOTES
1931 fprintf(stderr, "note-off chan %d, note %d, vel %d\n", chan+1,
1932 data[1], data[2]);
1933 #endif
1934 note_off:
1935 dealloc_voice(chan, data[1], data[2]);
1936 break;
1937 }
1938 case 0xe0: {
1939 if (!is_instr) break;
1940 // pitch bend
1941 // data[1] is LSB, data[2] MSB, range is 0..0x3fff (which maps to
1942 // -2..+2 semitones by default), center point is 0x2000 = 8192
1943 int val = data[1] | (data[2]<<7);
1944 vd->bend[chan] =
1945 (val-0x2000)/8192.0f*vd->range[chan];
1946 #if DEBUG_MIDICC
1947 fprintf(stderr, "pitch-bend (chan %d): %g cent\n", chan+1,
1948 vd->bend[chan]*100.0);
1949 #endif
1950 update_voices(chan);
1951 break;
1952 }
1953 case 0xb0: {
1954 // controller change
1955 switch (data[1]) {
1956 case 120: case 123:
1957 if (!is_instr) break;
1958 // all-sound-off and all-notes-off controllers (these are treated
1959 // the same in the current implementation)
1960 all_notes_off(chan);
1961 #if DEBUG_MIDICC
1962 fprintf(stderr, "all-notes-off (chan %d)\n", chan+1);
1963 #endif
1964 break;
1965 case 121:
1966 // all-controllers-off (in the current implementation, this just
1967 // resets the RPN-related controllers)
1968 data_msb[chan] = data_lsb[chan] = 0;
1969 rpn_msb[chan] = rpn_lsb[chan] = 0x7f;
1970 #if DEBUG_MIDICC
1971 fprintf(stderr, "all-controllers-off (chan %d)\n", chan+1);
1972 #endif
1973 break;
1974 case 101: case 100:
1975 // RPN MSB/LSB
1976 if (data[1] == 101)
1977 rpn_msb[chan] = data[2];
1978 else
1979 rpn_lsb[chan] = data[2];
1980 break;
1981 case 6: case 38:
1982 // data entry coarse/fine
1983 if (data[1] == 6)
1984 data_msb[chan] = data[2];
1985 else
1986 data_lsb[chan] = data[2];
1987 goto rpn;
1988 case 96: case 97:
1989 // data increment/decrement
1990 /* NOTE: The specification of these controllers is a complete
1991 mess. Originally, the MIDI specification didn't have anything
1992 to say about their exact behaviour at all. Nowadays, the
1993 behaviour depends on which RPN or NRPN is being modified, which
1994 is also rather confusing. Fortunately, as we only handle RPNs
1995 0..2 here anyway, it's sufficient to assume the MSB for RPN #2
1996 (channel coarse tuning) and the LSB otherwise. */
1997 if (rpn_msb[chan] == 0 && rpn_lsb[chan] == 2) {
1998 // modify the MSB
1999 if (data[1] == 96 && data_msb[chan] < 0x7f)
2000 data_msb[chan]++;
2001 else if (data[1] == 97 && data_msb[chan] > 0)
2002 data_msb[chan]--;
2003 } else {
2004 // modify the LSB
2005 if (data[1] == 96 && data_lsb[chan] < 0x7f)
2006 data_lsb[chan]++;
2007 else if (data[1] == 97 && data_lsb[chan] > 0)
2008 data_lsb[chan]--;
2009 }
2010 rpn:
2011 if (!is_instr) break;
2012 if (rpn_msb[chan] == 0) {
2013 switch (rpn_lsb[chan]) {
2014 case 0:
2015 // pitch bend range, coarse value is in semitones, fine value
2016 // in cents
2017 vd->range[chan] = data_msb[chan]+
2018 data_lsb[chan]/100.0;
2019 #if DEBUG_RPN
2020 fprintf(stderr, "pitch-bend-range (chan %d): %g cent\n", chan+1,
2021 vd->range[chan]*100.0);
2022 #endif
2023 break;
2024 case 1:
2025 {
2026 // channel fine tuning (14 bit value, range -100..+100 cents)
2027 int value = (data_msb[chan]<<7) |
2028 data_lsb[chan];
2029 vd->fine[chan] = (value-8192)/8192.0f;
2030 }
2031 goto master_tune;
2032 case 2:
2033 // channel coarse tuning (only msb is used, range -64..+63
2034 // semitones)
2035 vd->coarse[chan] = data_msb[chan]-64;
2036 master_tune:
2037 vd->tune[chan] = vd->coarse[chan]+
2038 vd->fine[chan];
2039 #if DEBUG_RPN
2040 fprintf(stderr, "master-tuning (chan %d): %g cent\n", chan+1,
2041 vd->tune[chan]*100.0);
2042 #endif
2043 update_voices(chan);
2044 break;
2045 default:
2046 break;
2047 }
2048 }
2049 break;
2050 default: {
2051 #if FAUST_MIDICC
2052 // interpret all other controller changes according to the MIDI
2053 // controller map defined in the Faust plugin itself
2054 std::map<uint8_t,int>::iterator it = ctrlmap.find(data[1]);
2055 if (it != ctrlmap.end()) {
2056 // defined MIDI controller
2057 int j = inctrls[it->second],
2058 k = ui[0]->elems[j].port;
2059 float val = ctrlval(ui[0]->elems[j], data[2]);
2060 midivals[chan][k] = val;
2061 if (is_instr) {
2062 // instrument: update running voices on this channel
2063 for (boost::circular_buffer<int>::iterator it =
2064 vd->used_voices.begin();
2065 it != vd->used_voices.end(); it++) {
2066 int i = *it;
2067 if (vd->note_info[i].ch == chan)
2068 *ui[i]->elems[j].zone = val;
2069 }
2070 } else {
2071 // simple effect: here we only have a single dsp instance and
2072 // we're operating in omni mode, so we just update the control no
2073 // matter what the midi channel is
2074 *ui[0]->elems[j].zone = val;
2075 }
2076 #if DEBUG_MIDICC
2077 fprintf(stderr, "ctrl-change chan %d, ctrl %d, val %d\n", chan+1,
2078 data[1], data[2]);
2079 #endif
2080 }
2081 #endif
2082 break;
2083 }
2084 }
2085 break;
2086 }
2087 default:
2088 break;
2089 }
2090 }
2091
2092 // Process an MTS sysex message and update the control values accordingly.
2093
2094 void process_sysex(uint8_t *data, int sz)
2095 {
2096 if (!data || sz < 2) return;
2097 #if DEBUG_MIDI
2098 fprintf(stderr, "midi sysex (%d bytes):", sz);
2099 for (int i = 0; i < sz; i++)
2100 fprintf(stderr, " 0x%0x", data[i]);
2101 fprintf(stderr, "\n");
2102 #endif
2103 if (data[0] == 0xf0) {
2104 // Skip over the f0 and f7 status bytes in case they are included in the
2105 // dump.
2106 data++; sz--;
2107 if (data[sz-1] == 0xf7) sz--;
2108 }
2109 if ((data[0] == 0x7e || data[0] == 0x7f) && data[2] == 8) {
2110 // MIDI tuning standard
2111 bool realtime = data[0] == 0x7f;
2112 if ((sz == 19 && data[3] == 8) ||
2113 (sz == 31 && data[3] == 9)) {
2114 // MTS scale/octave tuning 1- or 2-byte form
2115 bool onebyte = data[3] == 8;
2116 unsigned chanmsk = (data[4]<<14) | (data[5]<<7) | data[6];
2117 for (int i = 0; i < 12; i++) {
2118 float t;
2119 if (onebyte)
2120 t = (data[i+7]-64)/100.0;
2121 else
2122 t = (((data[2*i+7]<<7)|data[2*i+8])-8192)/8192.0;
2123 for (uint8_t ch = 0; ch < 16; ch++)
2124 if (chanmsk & (1<<ch))
2125 vd->tuning[ch][i] = t;
2126 }
2127 if (realtime) {
2128 for (uint8_t ch = 0; ch < 16; ch++)
2129 if (chanmsk & (1<<ch)) {
2130 // update running voices on this channel
2131 update_voices(ch);
2132 }
2133 }
2134 #if DEBUG_MTS
2135 fprintf(stderr, "octave-tuning-%s (chan ",
2136 realtime?"realtime":"non-realtime");
2137 bool first = true;
2138 for (uint8_t i = 0; i < 16; )
2139 if (chanmsk & (1<<i)) {
2140 uint8_t j;
2141 for (j = i+1; j < 16 && (chanmsk&(1<<j)); )
2142 j++;
2143 if (first)
2144 first = false;
2145 else
2146 fprintf(stderr, ",");
2147 if (j > i+1)
2148 fprintf(stderr, "%u-%u", i+1, j);
2149 else
2150 fprintf(stderr, "%u", i+1);
2151 i = j;
2152 } else
2153 i++;
2154 fprintf(stderr, "):");
2155 if (onebyte) {
2156 for (int i = 7; i < 19; i++) {
2157 int val = data[i];
2158 fprintf(stderr, " %d", val-64);
2159 }
2160 } else {
2161 for (int i = 7; i < 31; i++) {
2162 int val = data[i++] << 7;
2163 val |= data[i];
2164 fprintf(stderr, " %g", ((double)val-8192.0)/8192.0*100.0);
2165 }
2166 }
2167 fprintf(stderr, "\n");
2168 #endif
2169 }
2170 }
2171 }
2172
2173 // Change to a given preloaded tuning. The given tuning number may be in the
2174 // range 1..PFaustPlugin::n_tunings, zero denotes the default tuning (equal
2175 // temperament). This is only supported if FAUST_MTS is defined at compile
2176 // time.
2177
2178 void change_tuning(int num)
2179 {
2180 #if FAUST_MTS
2181 if (!mts || num == tuning_no) return;
2182 if (num < 0) num = 0;
2183 if (num > mts->tuning.size())
2184 num = mts->tuning.size();
2185 tuning_no = num;
2186 if (tuning_no > 0) {
2187 process_sysex(mts->tuning[tuning_no-1].data,
2188 mts->tuning[tuning_no-1].len);
2189 } else {
2190 memset(vd->tuning, 0, sizeof(vd->tuning));
2191 #if DEBUG_MTS
2192 fprintf(stderr,
2193 "octave-tuning-default (chan 1-16): equal temperament\n");
2194 #endif
2195 }
2196 #endif
2197 }
2198
2199 };
2200
2201 Meta *LV2Plugin::meta = 0;
2202 int LV2Plugin::n_tunings = 0;
2203 #if FAUST_MTS
2204 MTSTunings *LV2Plugin::mts = 0;
2205 #endif
2206
2207 /* LV2-specific part starts here. ********************************************/
2208
2209 static LV2_Handle
2210 instantiate(const LV2_Descriptor* descriptor,
2211 double rate,
2212 const char* bundle_path,
2213 const LV2_Feature* const* features)
2214 {
2215 LV2Plugin* plugin =
2216 new LV2Plugin(LV2Plugin::numVoices(), (int)rate);
2217 // Scan host features for URID map.
2218 for (int i = 0; features[i]; i++) {
2219 if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
2220 plugin->map = (LV2_URID_Map*)features[i]->data;
2221 plugin->midi_event =
2222 plugin->map->map(plugin->map->handle, MIDI_EVENT_URI);
2223 }
2224 }
2225 if (!plugin->map) {
2226 fprintf
2227 (stderr, "%s: host doesn't support urid:map, giving up\n",
2228 PLUGIN_URI);
2229 delete plugin;
2230 return 0;
2231 }
2232 return (LV2_Handle)plugin;
2233 }
2234
2235 static void
2236 cleanup(LV2_Handle instance)
2237 {
2238 LV2Plugin* plugin = (LV2Plugin*)instance;
2239 delete plugin;
2240 }
2241
2242 static void
2243 connect_port(LV2_Handle instance,
2244 uint32_t port,
2245 void* data)
2246 {
2247 LV2Plugin* plugin = (LV2Plugin*)instance;
2248 int i = port, k = plugin->ui[0]->nports;
2249 int n = plugin->dsp[0]->getNumInputs(), m = plugin->dsp[0]->getNumOutputs();
2250 if (i < k)
2251 plugin->ports[i] = (float*)data;
2252 else {
2253 i -= k;
2254 if (i < n)
2255 plugin->inputs[i] = (float*)data;
2256 else {
2257 i -= n;
2258 if (i < m)
2259 plugin->outputs[i] = (float*)data;
2260 else if (i == m)
2261 plugin->event_port = (LV2_Atom_Sequence*)data;
2262 else if (i == m+1)
2263 plugin->poly = (float*)data;
2264 else if (i == m+2)
2265 plugin->tuning = (float*)data;
2266 else
2267 fprintf(stderr, "%s: bad port number %u\n", PLUGIN_URI, port);
2268 }
2269 }
2270 }
2271
2272 static void
2273 run(LV2_Handle instance, uint32_t n_samples)
2274 {
2275 LV2Plugin* plugin = (LV2Plugin*)instance;
2276 // Process incoming MIDI events.
2277 if (plugin->event_port) {
2278 LV2_ATOM_SEQUENCE_FOREACH(plugin->event_port, ev) {
2279 if (ev->body.type == plugin->midi_event) {
2280 uint8_t *data = (uint8_t*)(ev+1);
2281 #if 0
2282 // FIXME: Consider doing sample-accurate note onsets here. LV2 keeps
2283 // track of the exact onset in the frames and subframes fields
2284 // (http://lv2plug.in/ns/doc/html/structLV2__Atom__Event.html), but we
2285 // can't use that information at present, since our gate parameter is
2286 // a control variable which can only change at block boundaries. In
2287 // the future, the gate could be implemented as an audio signal to get
2288 // sample-accurate note onsets.
2289 uint32_t frames = ev->body.frames;
2290 #endif
2291 if (data[0] == 0xf0)
2292 plugin->process_sysex(data, ev->body.size);
2293 else
2294 plugin->process_midi(data, ev->body.size);
2295 }
2296 }
2297 }
2298 // Process audio.
2299 plugin->process_audio(n_samples, plugin->inputs, plugin->outputs);
2300 }
2301
2302 static void
2303 activate(LV2_Handle instance)
2304 {
2305 LV2Plugin* plugin = (LV2Plugin*)instance;
2306 plugin->resume();
2307 }
2308
2309 static void
2310 deactivate(LV2_Handle instance)
2311 {
2312 LV2Plugin* plugin = (LV2Plugin*)instance;
2313 plugin->suspend();
2314 }
2315
2316 const void*
2317 extension_data(const char* uri)
2318 {
2319 return NULL;
2320 }
2321
2322 static const LV2_Descriptor descriptor = {
2323 PLUGIN_URI,
2324 instantiate,
2325 connect_port,
2326 activate,
2327 run,
2328 deactivate,
2329 cleanup,
2330 extension_data
2331 };
2332
2333 extern "C"
2334 LV2_SYMBOL_EXPORT
2335 const LV2_Descriptor*
2336 lv2_descriptor(uint32_t index)
2337 {
2338 switch (index) {
2339 case 0:
2340 return &descriptor;
2341 default:
2342 return NULL;
2343 }
2344 }
2345
2346 //----------------------------------------------------------------------------
2347 // Dynamic manifest
2348 //----------------------------------------------------------------------------
2349
2350 // NOTE: If your LV2 host doesn't offer this extension then you'll have to
2351 // create a static ttl file with the descriptions of the ports. You can do
2352 // this by compiling this code to a standalone executable. Running the
2353 // executable then prints the manifest on stdout.
2354
2355 extern "C"
2356 LV2_SYMBOL_EXPORT
2357 int lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle *handle,
2358 const LV2_Feature *const *features)
2359 {
2360 LV2Plugin* plugin =
2361 new LV2Plugin(LV2Plugin::numVoices(), 48000);
2362 *handle = (LV2_Dyn_Manifest_Handle)plugin;
2363 return 0;
2364 }
2365
2366 extern "C"
2367 LV2_SYMBOL_EXPORT
2368 int lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle,
2369 FILE *fp)
2370 {
2371 fprintf(fp, "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
2372 <%s> a lv2:Plugin .\n", PLUGIN_URI);
2373 return 0;
2374 }
2375
2376 #include <string>
2377 #include <ctype.h>
2378
2379 static string mangle(const string &s)
2380 {
2381 string t = s;
2382 size_t n = s.size();
2383 for (size_t i = 0; i < n; i++)
2384 if ((i == 0 && !isalpha(t[i]) && t[i] != '_') ||
2385 (!isalnum(t[i]) && t[i] != '_'))
2386 t[i] = '_';
2387 return t;
2388 }
2389
2390 static unsigned steps(float min, float max, float step)
2391 {
2392 if (step == 0.0) return 1;
2393 int n = (max-min)/step;
2394 if (n < 0) n = -n;
2395 if (n == 0) n = 1;
2396 return n;
2397 }
2398
2399 #if FAUST_META
2400 static bool is_xmlstring(const char *s)
2401 {
2402 // This is just a basic sanity check. The string must not contain any
2403 // (unescaped) newlines, carriage returns or double quotes.
2404 return !strchr(s, '\n') && !strchr(s, '\r') && !strchr(s, '"');
2405 }
2406 #endif
2407
2408 extern "C"
2409 LV2_SYMBOL_EXPORT
2410 int lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle,
2411 FILE *fp,
2412 const char *uri)
2413 {
2414 LV2Plugin* plugin = (LV2Plugin*)handle;
2415 int k = plugin->ui[0]->nports;
2416 int n = plugin->dsp[0]->getNumInputs(), m = plugin->dsp[0]->getNumOutputs();
2417 bool is_instr = plugin->maxvoices > 0, have_midi = is_instr;
2418 // Scan the global metadata for plugin name, description, license etc.
2419 const char *plugin_name = NULL, *plugin_author = NULL, *plugin_descr = NULL,
2420 *plugin_version = NULL, *plugin_license = NULL;
2421 #if FAUST_META
2422 plugin_name = plugin->pluginName();
2423 plugin_descr = plugin->pluginDescription();
2424 plugin_author = plugin->pluginAuthor();
2425 plugin_version = plugin->pluginVersion();
2426 plugin_license = plugin->pluginLicense();
2427 #endif
2428 if (!plugin_name || !*plugin_name) plugin_name = "vibrato_ext";
2429 fprintf(fp, "@prefix doap: <http://usefulinc.com/ns/doap#> .\n\
2430 @prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\
2431 @prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
2432 @prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n\
2433 @prefix epp: <http://lv2plug.in/ns/ext/port-props#> .\n\
2434 @prefix atom: <http://lv2plug.in/ns/ext/atom#> .\n\
2435 @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n\
2436 @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n\
2437 @prefix units: <http://lv2plug.in/ns/extensions/units#> .\n\
2438 <%s>\n\
2439 a lv2:Plugin%s ;\n\
2440 doap:name \"%s\" ;\n\
2441 lv2:binary <vibrato_ext%s> ;\n\
2442 lv2:optionalFeature epp:supportsStrictBounds ;\n\
2443 lv2:optionalFeature lv2:hardRtCapable ;\n", PLUGIN_URI,
2444 is_instr?", lv2:InstrumentPlugin":"",
2445 plugin_name, DLLEXT);
2446 if (plugin_author && *plugin_author)
2447 fprintf(fp, "\
2448 doap:maintainer [ foaf:name \"%s\" ] ;\n", plugin_author);
2449 // doap:description just seems to be ignored by all LV2 hosts anyway, so we
2450 // rather use rdfs:comment now which works with Ardour at least.
2451 if (plugin_descr && *plugin_descr)
2452 fprintf(fp, "\
2453 rdfs:comment \"%s\" ;\n", plugin_descr);
2454 if (plugin_version && *plugin_version)
2455 fprintf(fp, "\
2456 doap:revision \"%s\" ;\n", plugin_version);
2457 if (plugin_license && *plugin_license)
2458 fprintf(fp, "\
2459 doap:license \"%s\" ;\n", plugin_license);
2460 #if FAUST_UI
2461 fprintf(fp, "\
2462 ui:ui <%sui> ;\n", PLUGIN_URI);
2463 #endif
2464 int idx = 0;
2465 // control ports
2466 for (int i = 0; i < k; i++, idx++) {
2467 int j = plugin->ctrls[i];
2468 assert(idx == plugin->ui[0]->elems[j].port);
2469 fprintf(fp, "%s [\n", idx==0?" lv2:port":" ,");
2470 const char *label = plugin->ui[0]->elems[j].label;
2471 assert(label);
2472 string sym = mangle(plugin->ui[0]->elems[j].label);
2473 switch (plugin->ui[0]->elems[j].type) {
2474 // active controls (input ports)
2475 case UI_BUTTON: case UI_CHECK_BUTTON:
2476 fprintf(fp, "\
2477 a lv2:InputPort ;\n\
2478 a lv2:ControlPort ;\n\
2479 lv2:index %d ;\n\
2480 lv2:symbol \"%s_%d\" ;\n\
2481 lv2:name \"%s\" ;\n\
2482 lv2:portProperty epp:hasStrictBounds ;\n\
2483 lv2:portProperty lv2:toggled ;\n\
2484 lv2:default 0.00000 ;\n\
2485 lv2:minimum 0.00000 ;\n\
2486 lv2:maximum 1.00000 ;\n", idx, sym.c_str(), idx, label);
2487 break;
2488 case UI_NUM_ENTRY: case UI_H_SLIDER: case UI_V_SLIDER:
2489 fprintf(fp, "\
2490 a lv2:InputPort ;\n\
2491 a lv2:ControlPort ;\n\
2492 lv2:index %d ;\n\
2493 lv2:symbol \"%s_%d\" ;\n\
2494 lv2:name \"%s\" ;\n\
2495 lv2:portProperty epp:hasStrictBounds ;\n\
2496 epp:rangeSteps %u ;\n\
2497 lv2:default %g ;\n\
2498 lv2:minimum %g ;\n\
2499 lv2:maximum %g ;\n", idx, sym.c_str(), idx, label,
2500 steps(plugin->ui[0]->elems[j].min,
2501 plugin->ui[0]->elems[j].max,
2502 plugin->ui[0]->elems[j].step),
2503 plugin->ui[0]->elems[j].init,
2504 plugin->ui[0]->elems[j].min,
2505 plugin->ui[0]->elems[j].max);
2506 break;
2507 // passive controls (output ports)
2508 case UI_H_BARGRAPH: case UI_V_BARGRAPH:
2509 fprintf(fp, "\
2510 a lv2:OutputPort ;\n\
2511 a lv2:ControlPort ;\n\
2512 lv2:index %d ;\n\
2513 lv2:symbol \"%s_%d\" ;\n\
2514 lv2:name \"%s\" ;\n\
2515 lv2:default %g ;\n\
2516 lv2:minimum %g ;\n\
2517 lv2:maximum %g ;\n", idx, sym.c_str(), idx, label,
2518 plugin->ui[0]->elems[j].min,
2519 plugin->ui[0]->elems[j].min,
2520 plugin->ui[0]->elems[j].max);
2521 break;
2522 default:
2523 assert(0 && "this can't happen");
2524 break;
2525 }
2526 // Scan for Faust control metadata we understand and add corresponding
2527 // hints to the LV2 description of the port.
2528 std::map< int, list<strpair> >::iterator it =
2529 plugin->ui[0]->metadata.find(j);
2530 if (it != plugin->ui[0]->metadata.end()) {
2531 for (std::list<strpair>::iterator jt = it->second.begin();
2532 jt != it->second.end(); jt++) {
2533 const char *key = jt->first, *val = jt->second;
2534 #if FAUST_MIDICC
2535 unsigned num;
2536 if (!strcmp(key, "midi") && sscanf(val, "ctrl %u", &num) == 1)
2537 have_midi = true;
2538 #endif
2539 if (!strcmp(key, "unit"))
2540 fprintf(fp, "\
2541 units:unit [\n\
2542 a units:Unit ;\n\
2543 units:name \"%s\" ;\n\
2544 units:symbol \"%s\" ;\n\
2545 units:render \"%%f %s\"\n\
2546 ] ;\n", val, val, val);
2547 if (strcmp(key, "lv2")) continue;
2548 if (!strcmp(val, "integer"))
2549 fprintf(fp, "\
2550 lv2:portProperty lv2:integer ;\n");
2551 else if (!strcmp(val, "reportsLatency"))
2552 fprintf(fp, "\
2553 lv2:portProperty lv2:reportsLatency ;\n\
2554 lv2:designation lv2:latency ;\n");
2555 else if (!strcmp(val, "hidden") || !strcmp(val, "notOnGUI"))
2556 fprintf(fp, "\
2557 lv2:portProperty epp:notOnGUI ;\n");
2558 else if (!strncmp(val, "scalepoint", 10) ||
2559 !strncmp(val, "scalePoint", 10)) {
2560 val += 10;
2561 if (!isspace(*val)) continue;
2562 char *label = (char*)malloc(strlen(val)+1);
2563 float point;
2564 int pos;
2565 while (sscanf(val, "%s %g%n", label, &point, &pos) == 2) {
2566 fprintf(fp, "\
2567 lv2:scalePoint [ rdfs:label \"%s\"; rdf:value %g ] ;\n",
2568 label, point);
2569 val += pos;
2570 }
2571 free(label);
2572 } else
2573 fprintf(stderr, "%s: bad port property '%s:%s'\n", PLUGIN_URI,
2574 key, val);
2575 }
2576 }
2577 fprintf(fp, " ]");
2578 }
2579 // audio inputs
2580 for (int i = 0; i < n; i++, idx++)
2581 fprintf(fp, "%s [\n\
2582 a lv2:InputPort ;\n\
2583 a lv2:AudioPort ;\n\
2584 lv2:index %d ;\n\
2585 lv2:symbol \"in%d\" ;\n\
2586 lv2:name \"in%d\" ;\n\
2587 ]", idx==0?" lv2:port":" ,", idx, i, i);
2588 // audio outputs
2589 for (int i = 0; i < m; i++, idx++)
2590 fprintf(fp, "%s [\n\
2591 a lv2:OutputPort ;\n\
2592 a lv2:AudioPort ;\n\
2593 lv2:index %d ;\n\
2594 lv2:symbol \"out%d\" ;\n\
2595 lv2:name \"out%d\" ;\n\
2596 ]", idx==0?" lv2:port":" ,", idx, i, i);
2597 if (have_midi) {
2598 // midi input
2599 fprintf(fp, "%s [\n\
2600 a lv2:InputPort ;\n\
2601 a atom:AtomPort ;\n\
2602 atom:bufferType atom:Sequence ;\n\
2603 atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n\
2604 lv2:index %d ;\n\
2605 lv2:symbol \"midiin\" ;\n\
2606 lv2:name \"midiin\"\n\
2607 ]", idx==0?" lv2:port":" ,", idx);
2608 idx++;
2609 }
2610 if (is_instr) {
2611 // polyphony control
2612 fprintf(fp, "%s [\n\
2613 a lv2:InputPort ;\n\
2614 a lv2:ControlPort ;\n\
2615 lv2:index %d ;\n\
2616 lv2:symbol \"polyphony\" ;\n\
2617 lv2:name \"polyphony\" ;\n\
2618 lv2:portProperty epp:hasStrictBounds ;\n\
2619 # lv2:portProperty epp:expensive ;\n\
2620 lv2:portProperty lv2:integer ;\n\
2621 epp:rangeSteps %d ;\n\
2622 lv2:default %d ;\n\
2623 lv2:minimum 1 ;\n\
2624 lv2:maximum %d ;\n\
2625 ]", idx==0?" lv2:port":" ,", idx, plugin->maxvoices-1,
2626 plugin->maxvoices>1?plugin->maxvoices/2:1,
2627 plugin->maxvoices);
2628 idx++;
2629 #if FAUST_MTS
2630 if (plugin->n_tunings > 0) {
2631 // tuning control
2632 fprintf(fp, "%s [\n\
2633 a lv2:InputPort ;\n\
2634 a lv2:ControlPort ;\n\
2635 lv2:index %d ;\n\
2636 lv2:symbol \"tuning\" ;\n\
2637 lv2:name \"tuning\" ;\n\
2638 lv2:portProperty epp:hasStrictBounds ;\n\
2639 lv2:portProperty lv2:integer ;\n\
2640 epp:rangeSteps %d ;\n\
2641 lv2:default 0 ;\n\
2642 lv2:minimum 0 ;\n\
2643 lv2:maximum %d ;\n",
2644 idx==0?" lv2:port":" ,", idx, plugin->n_tunings, plugin->n_tunings);
2645 for (int i = 0; i <= plugin->n_tunings; i++)
2646 fprintf(fp, "\
2647 lv2:scalePoint [ rdfs:label \"%s\"; rdf:value %d ] ;\n",
2648 (i>0)?plugin->mts->tuning[i-1].name:"default", i);
2649 fprintf(fp, " ]");
2650 idx++;
2651 }
2652 #endif
2653 }
2654 fprintf(fp, "\n.\n");
2655 return 0;
2656 }
2657
2658 extern "C"
2659 LV2_SYMBOL_EXPORT
2660 void lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle)
2661 {
2662 LV2Plugin* plugin = (LV2Plugin*)handle;
2663 delete plugin;
2664 }
2665
2666 int main()
2667 {
2668 LV2_Dyn_Manifest_Handle handle;
2669 LV2_Feature **features = { NULL };
2670 int res = lv2_dyn_manifest_open(&handle, features);
2671 if (res) return res;
2672 res = lv2_dyn_manifest_get_data(handle, stdout, PLUGIN_URI);
2673 return res;
2674 }
2675
2676 #endif
2677