1 /* ------------------------------------------------------------
2 name: "harm_trem"
3 Code generated with Faust 2.20.2 (https://faust.grame.fr)
4 Compilation options: -lang cpp -scal -ftz 0
5 ------------------------------------------------------------ */
6
7 #ifndef __harm_trem_H__
8 #define __harm_trem_H__
9
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
~dsp_memory_managerdsp_memory_manager90 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
dsp()105 dsp() {}
~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 */
compute(double,int count,FAUSTFLOAT ** inputs,FAUSTFLOAT ** outputs)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
decorator_dsp(dsp * dsp=nullptr)203 decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
~decorator_dsp()204 virtual ~decorator_dsp() { delete fDSP; }
205
getNumInputs()206 virtual int getNumInputs() { return fDSP->getNumInputs(); }
getNumOutputs()207 virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
buildUserInterface(UI * ui_interface)208 virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
getSampleRate()209 virtual int getSampleRate() { return fDSP->getSampleRate(); }
init(int sample_rate)210 virtual void init(int sample_rate) { fDSP->init(sample_rate); }
instanceInit(int sample_rate)211 virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
instanceConstants(int sample_rate)212 virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
instanceResetUserInterface()213 virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
instanceClear()214 virtual void instanceClear() { fDSP->instanceClear(); }
clone()215 virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
metadata(Meta * m)216 virtual void metadata(Meta* m) { fDSP->metadata(m); }
217 // Beware: subclasses usually have to overload the two 'compute' methods
compute(int count,FAUSTFLOAT ** inputs,FAUSTFLOAT ** outputs)218 virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
compute(double date_usec,int count,FAUSTFLOAT ** inputs,FAUSTFLOAT ** 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);
~dsp_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
UIReal()314 UIReal() {}
~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
declare(REAL * zone,const char * key,const char * val)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
UI()351 UI() {}
~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 {
declareMeta364 void declare(const char *key, const char *value)
365 {
366 (*this)[key] = value;
367 }
getMeta368 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
addSoundfile(const char * label,const char * filename,Soundfile ** sf_zone)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
LV2UI(int maxvoices)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
~LV2UI()458 LV2UI::~LV2UI()
459 {
460 if (elems) free(elems);
461 }
462
declare(float * zone,const char * key,const char * value)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
add_elem(ui_elem_type_t type,const char * label)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
add_elem(ui_elem_type_t type,const char * label,float * zone)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
add_elem(ui_elem_type_t type,const char * label,float * zone,float init,float min,float max,float step)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
add_elem(ui_elem_type_t type,const char * label,float * zone,float min,float max)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
is_voice_ctrl(const char * label)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
addButton(const char * label,float * zone)566 void LV2UI::addButton(const char* label, float* zone)
567 { add_elem(UI_BUTTON, label, zone); }
addCheckButton(const char * label,float * zone)568 void LV2UI::addCheckButton(const char* label, float* zone)
569 { add_elem(UI_CHECK_BUTTON, label, zone); }
addVerticalSlider(const char * label,float * zone,float init,float min,float max,float step)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); }
addHorizontalSlider(const char * label,float * zone,float init,float min,float max,float 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); }
addNumEntry(const char * label,float * zone,float init,float min,float max,float 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
addHorizontalBargraph(const char * label,float * zone,float min,float max)577 void LV2UI::addHorizontalBargraph(const char* label, float* zone, float min, float max)
578 { add_elem(UI_H_BARGRAPH, label, zone, min, max); }
addVerticalBargraph(const char * label,float * zone,float min,float 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
openTabBox(const char * label)582 void LV2UI::openTabBox(const char* label)
583 { add_elem(UI_T_GROUP, label); }
openHorizontalBox(const char * label)584 void LV2UI::openHorizontalBox(const char* label)
585 { add_elem(UI_H_GROUP, label); }
openVerticalBox(const char * label)586 void LV2UI::openVerticalBox(const char* label)
587 { add_elem(UI_V_GROUP, label); }
closeBox()588 void LV2UI::closeBox()
589 { add_elem(UI_END_GROUP); }
590
run()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 class harm_tremSIG0 {
606
607 private:
608
609 int iRec4[2];
610
611 public:
612
getNumInputsharm_tremSIG0()613 int getNumInputsharm_tremSIG0() {
614 return 0;
615 }
getNumOutputsharm_tremSIG0()616 int getNumOutputsharm_tremSIG0() {
617 return 1;
618 }
getInputRateharm_tremSIG0(int channel)619 int getInputRateharm_tremSIG0(int channel) {
620 int rate;
621 switch ((channel)) {
622 default: {
623 rate = -1;
624 break;
625 }
626 }
627 return rate;
628 }
getOutputRateharm_tremSIG0(int channel)629 int getOutputRateharm_tremSIG0(int channel) {
630 int rate;
631 switch ((channel)) {
632 case 0: {
633 rate = 0;
634 break;
635 }
636 default: {
637 rate = -1;
638 break;
639 }
640 }
641 return rate;
642 }
643
instanceInitharm_tremSIG0(int sample_rate)644 void instanceInitharm_tremSIG0(int sample_rate) {
645 for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
646 iRec4[l5] = 0;
647 }
648 }
649
fillharm_tremSIG0(int count,float * table)650 void fillharm_tremSIG0(int count, float* table) {
651 for (int i = 0; (i < count); i = (i + 1)) {
652 iRec4[0] = (iRec4[1] + 1);
653 table[i] = std::sin((9.58738019e-05f * float((iRec4[0] + -1))));
654 iRec4[1] = iRec4[0];
655 }
656 }
657
658 };
659
newharm_tremSIG0()660 static harm_tremSIG0* newharm_tremSIG0() { return (harm_tremSIG0*)new harm_tremSIG0(); }
deleteharm_tremSIG0(harm_tremSIG0 * dsp)661 static void deleteharm_tremSIG0(harm_tremSIG0* dsp) { delete dsp; }
662
harm_trem_faustpower2_f(float value)663 static float harm_trem_faustpower2_f(float value) {
664 return (value * value);
665 }
666 static float ftbl0harm_tremSIG0[65536];
667
668 #ifndef FAUSTCLASS
669 #define FAUSTCLASS harm_trem
670 #endif
671
672 #ifdef __APPLE__
673 #define exp10f __exp10f
674 #define exp10 __exp10
675 #endif
676
677 class harm_trem : public dsp {
678
679 private:
680
681 float fVec0[2];
682 int fSampleRate;
683 float fConst0;
684 float fConst1;
685 FAUSTFLOAT fVslider0;
686 float fRec2[2];
687 float fRec1[2];
688 float fRec0[3];
689 FAUSTFLOAT fHslider0;
690 float fRec3[2];
691 float fConst2;
692 FAUSTFLOAT fVslider1;
693 float fRec6[2];
694 float fRec5[2];
695 float fRec8[2];
696 float fRec7[3];
697
698 public:
699
metadata(Meta * m)700 void metadata(Meta* m) {
701 m->declare("analyzers.lib/name", "Faust Analyzer Library");
702 m->declare("analyzers.lib/version", "0.0");
703 m->declare("basics.lib/name", "Faust Basic Element Library");
704 m->declare("basics.lib/version", "0.1");
705 m->declare("filename", "harm_trem.dsp");
706 m->declare("filters.lib/filterbank:author", "Julius O. Smith III");
707 m->declare("filters.lib/filterbank:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
708 m->declare("filters.lib/filterbank:license", "MIT-style STK-4.3 license");
709 m->declare("filters.lib/fir:author", "Julius O. Smith III");
710 m->declare("filters.lib/fir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
711 m->declare("filters.lib/fir:license", "MIT-style STK-4.3 license");
712 m->declare("filters.lib/highpass:author", "Julius O. Smith III");
713 m->declare("filters.lib/highpass:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
714 m->declare("filters.lib/iir:author", "Julius O. Smith III");
715 m->declare("filters.lib/iir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
716 m->declare("filters.lib/iir:license", "MIT-style STK-4.3 license");
717 m->declare("filters.lib/lowpass0_highpass1", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
718 m->declare("filters.lib/lowpass0_highpass1:author", "Julius O. Smith III");
719 m->declare("filters.lib/lowpass:author", "Julius O. Smith III");
720 m->declare("filters.lib/lowpass:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
721 m->declare("filters.lib/lowpass:license", "MIT-style STK-4.3 license");
722 m->declare("filters.lib/name", "Faust Filters Library");
723 m->declare("filters.lib/tf1:author", "Julius O. Smith III");
724 m->declare("filters.lib/tf1:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
725 m->declare("filters.lib/tf1:license", "MIT-style STK-4.3 license");
726 m->declare("filters.lib/tf1s:author", "Julius O. Smith III");
727 m->declare("filters.lib/tf1s:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
728 m->declare("filters.lib/tf1s:license", "MIT-style STK-4.3 license");
729 m->declare("filters.lib/tf2:author", "Julius O. Smith III");
730 m->declare("filters.lib/tf2:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
731 m->declare("filters.lib/tf2:license", "MIT-style STK-4.3 license");
732 m->declare("filters.lib/tf2s:author", "Julius O. Smith III");
733 m->declare("filters.lib/tf2s:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
734 m->declare("filters.lib/tf2s:license", "MIT-style STK-4.3 license");
735 m->declare("maths.lib/author", "GRAME");
736 m->declare("maths.lib/copyright", "GRAME");
737 m->declare("maths.lib/license", "LGPL with exception");
738 m->declare("maths.lib/name", "Faust Math Library");
739 m->declare("maths.lib/version", "2.1");
740 m->declare("name", "harm_trem");
741 m->declare("oscillators.lib/name", "Faust Oscillator Library");
742 m->declare("oscillators.lib/version", "0.0");
743 m->declare("signals.lib/name", "Faust Signal Routing Library");
744 m->declare("signals.lib/version", "0.0");
745 }
746
getNumInputs()747 virtual int getNumInputs() {
748 return 1;
749 }
getNumOutputs()750 virtual int getNumOutputs() {
751 return 1;
752 }
getInputRate(int channel)753 virtual int getInputRate(int channel) {
754 int rate;
755 switch ((channel)) {
756 case 0: {
757 rate = 1;
758 break;
759 }
760 default: {
761 rate = -1;
762 break;
763 }
764 }
765 return rate;
766 }
getOutputRate(int channel)767 virtual int getOutputRate(int channel) {
768 int rate;
769 switch ((channel)) {
770 case 0: {
771 rate = 1;
772 break;
773 }
774 default: {
775 rate = -1;
776 break;
777 }
778 }
779 return rate;
780 }
781
classInit(int sample_rate)782 static void classInit(int sample_rate) {
783 harm_tremSIG0* sig0 = newharm_tremSIG0();
784 sig0->instanceInitharm_tremSIG0(sample_rate);
785 sig0->fillharm_tremSIG0(65536, ftbl0harm_tremSIG0);
786 deleteharm_tremSIG0(sig0);
787 }
788
instanceConstants(int sample_rate)789 virtual void instanceConstants(int sample_rate) {
790 fSampleRate = sample_rate;
791 fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
792 fConst1 = (3.14159274f / fConst0);
793 fConst2 = (0.0166666675f / fConst0);
794 }
795
instanceResetUserInterface()796 virtual void instanceResetUserInterface() {
797 fVslider0 = FAUSTFLOAT(800.0f);
798 fHslider0 = FAUSTFLOAT(0.0f);
799 fVslider1 = FAUSTFLOAT(120.0f);
800 }
801
instanceClear()802 virtual void instanceClear() {
803 for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
804 fVec0[l0] = 0.0f;
805 }
806 for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
807 fRec2[l1] = 0.0f;
808 }
809 for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
810 fRec1[l2] = 0.0f;
811 }
812 for (int l3 = 0; (l3 < 3); l3 = (l3 + 1)) {
813 fRec0[l3] = 0.0f;
814 }
815 for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
816 fRec3[l4] = 0.0f;
817 }
818 for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) {
819 fRec6[l6] = 0.0f;
820 }
821 for (int l7 = 0; (l7 < 2); l7 = (l7 + 1)) {
822 fRec5[l7] = 0.0f;
823 }
824 for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
825 fRec8[l8] = 0.0f;
826 }
827 for (int l9 = 0; (l9 < 3); l9 = (l9 + 1)) {
828 fRec7[l9] = 0.0f;
829 }
830 }
831
init(int sample_rate)832 virtual void init(int sample_rate) {
833 classInit(sample_rate);
834 instanceInit(sample_rate);
835 }
instanceInit(int sample_rate)836 virtual void instanceInit(int sample_rate) {
837 instanceConstants(sample_rate);
838 instanceResetUserInterface();
839 instanceClear();
840 }
841
clone()842 virtual harm_trem* clone() {
843 return new harm_trem();
844 }
845
getSampleRate()846 virtual int getSampleRate() {
847 return fSampleRate;
848 }
849
buildUserInterface(UI * ui_interface)850 virtual void buildUserInterface(UI* ui_interface) {
851 ui_interface->openVerticalBox("harm_trem");
852 ui_interface->declare(&fVslider1, "0", "");
853 ui_interface->declare(&fVslider1, "midi", "ctrl 63");
854 ui_interface->declare(&fVslider1, "style", "knob");
855 ui_interface->addVerticalSlider("BPM", &fVslider1, 120.0f, 15.0f, 300.0f, 0.100000001f);
856 ui_interface->declare(&fVslider0, "1", "");
857 ui_interface->declare(&fVslider0, "midi", "ctrl 64");
858 ui_interface->declare(&fVslider0, "style", "knob");
859 ui_interface->addVerticalSlider("CrossoverFreq", &fVslider0, 800.0f, 20.0f, 10000.0f, 1.0f);
860 ui_interface->declare(&fHslider0, "2", "");
861 ui_interface->addHorizontalSlider("depth", &fHslider0, 0.0f, 0.0f, 1.0f, 0.00999999978f);
862 ui_interface->closeBox();
863 }
864
compute(int count,FAUSTFLOAT ** inputs,FAUSTFLOAT ** outputs)865 virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
866 FAUSTFLOAT* input0 = inputs[0];
867 FAUSTFLOAT* output0 = outputs[0];
868 float fSlow0 = (0.00100000005f * float(fVslider0));
869 float fSlow1 = (0.00100000005f * float(fHslider0));
870 float fSlow2 = (0.00100000005f * float(fVslider1));
871 for (int i = 0; (i < count); i = (i + 1)) {
872 float fTemp0 = float(input0[i]);
873 fVec0[0] = fTemp0;
874 fRec2[0] = (fSlow0 + (0.999000013f * fRec2[1]));
875 float fTemp1 = std::tan((fConst1 * fRec2[0]));
876 float fTemp2 = (1.0f / fTemp1);
877 float fTemp3 = (fTemp2 + 1.0f);
878 float fTemp4 = (1.0f - fTemp2);
879 fRec1[0] = ((fVec0[1] * (0.0f - (1.0f / (fTemp1 * fTemp3)))) - (((fRec1[1] * fTemp4) - (fTemp0 / fTemp1)) / fTemp3));
880 float fTemp5 = (((fTemp2 + -1.0f) / fTemp1) + 1.0f);
881 float fTemp6 = harm_trem_faustpower2_f(fTemp1);
882 float fTemp7 = (1.0f - (1.0f / fTemp6));
883 float fTemp8 = (((fTemp2 + 1.0f) / fTemp1) + 1.0f);
884 fRec0[0] = (fRec1[0] - (((fRec0[2] * fTemp5) + (2.0f * (fRec0[1] * fTemp7))) / fTemp8));
885 fRec3[0] = (fSlow1 + (0.999000013f * fRec3[1]));
886 fRec6[0] = (fSlow2 + (0.999000013f * fRec6[1]));
887 float fTemp9 = (fRec5[1] + (fConst2 * fRec6[0]));
888 fRec5[0] = (fTemp9 - std::floor(fTemp9));
889 float fTemp10 = ftbl0harm_tremSIG0[int((65536.0f * fRec5[0]))];
890 fRec8[0] = (0.0f - (((fTemp4 * fRec8[1]) - (fTemp0 + fVec0[1])) / fTemp3));
891 fRec7[0] = (fRec8[0] - (((fTemp5 * fRec7[2]) + (2.0f * (fTemp7 * fRec7[1]))) / fTemp8));
892 output0[i] = FAUSTFLOAT(((((((fRec0[1] * (0.0f - (2.0f / fTemp6))) + (fRec0[0] / fTemp6)) + (fRec0[2] / fTemp6)) * (1.0f - (0.5f * (fRec3[0] * (fTemp10 + 1.0f))))) + ((fRec7[2] + (fRec7[0] + (2.0f * fRec7[1]))) * (1.0f - (0.5f * (fRec3[0] * ((1.0f - fTemp10) + 1.0f)))))) / fTemp8));
893 fVec0[1] = fVec0[0];
894 fRec2[1] = fRec2[0];
895 fRec1[1] = fRec1[0];
896 fRec0[2] = fRec0[1];
897 fRec0[1] = fRec0[0];
898 fRec3[1] = fRec3[0];
899 fRec6[1] = fRec6[0];
900 fRec5[1] = fRec5[0];
901 fRec8[1] = fRec8[0];
902 fRec7[2] = fRec7[1];
903 fRec7[1] = fRec7[0];
904 }
905 }
906
907 };
908
909 //----------------------------------------------------------------------------
910 // LV2 interface
911 //----------------------------------------------------------------------------
912
913 #line 286 "lv2.cpp"
914
915 #include <assert.h>
916 #include <stdio.h>
917 #include <stdlib.h>
918
919 #include <bitset>
920 #include <boost/circular_buffer.hpp>
921
922 #include <lv2/lv2plug.in/ns/lv2core/lv2.h>
923 #include <lv2/lv2plug.in/ns/ext/dynmanifest/dynmanifest.h>
924 #include <lv2/lv2plug.in/ns/ext/atom/util.h>
925 #include <lv2/lv2plug.in/ns/ext/urid/urid.h>
926
927 // Set this to the proper shared library extension for your system
928 #ifndef DLLEXT
929 #define DLLEXT ".so"
930 #endif
931
932 #ifndef URI_PREFIX
933 #define URI_PREFIX "https://faustlv2.bitbucket.io"
934 #endif
935
936 #ifndef PLUGIN_URI
937 #define PLUGIN_URI URI_PREFIX "/harm_trem"
938 #endif
939
940 #define MIDI_EVENT_URI "http://lv2plug.in/ns/ext/midi#MidiEvent"
941
942 /* Setting NVOICES at compile time overrides meta data in the Faust source. If
943 set, this must be an integer value >= 0. A nonzero value indicates an
944 instrument (VSTi) plugin with the given maximum number of voices. Use 1 for
945 a monophonic synthesizer, and 0 for a simple effect plugin. If NVOICES
946 isn't defined at compile time then the number of voices of an instrument
947 plugin can also be set with the global "nvoices" meta data key in the Faust
948 source. This setting also adds a special "polyphony" control to the plugin
949 which can be used to dynamically adjust the actual number of voices in the
950 range 1..NVOICES. */
951 //#define NVOICES 16
952
953 /* This enables a special "tuning" control for instruments which lets you
954 select the MTS tuning to be used for the synth. In order to use this, you
955 just drop some sysex (.syx) files with MTS octave-based tunings in 1- or
956 2-byte format into the ~/.fautvst/tuning directory (these can be generated
957 with the author's sclsyx program, https://bitbucket.org/agraef/sclsyx).
958 The control will only be shown if any .syx files were found at startup. 0
959 selects the default tuning (standard 12-tone equal temperament), i>0 the
960 tuning in the ith sysex file (in alphabetic order). */
961 #ifndef FAUST_MTS
962 #define FAUST_MTS 1
963 #endif
964
965 /* This allows various manifest data to be generated from the corresponding
966 metadata (author, name, description, license) in the Faust source. */
967 #ifndef FAUST_META
968 #define FAUST_META 1
969 #endif
970
971 /* This enables automatic MIDI controller mapping based on the midi:ctrl
972 attributes in the Faust source. We have this enabled by default, but you
973 may have to disable it if the custom controller mapping gets in the way of
974 the automation facilities that the host provides. (But then again if the
975 host wants to do its own controller mapping then it probably won't, or at
976 least shouldn't, send us the MIDI controllers in the first place.) */
977 #ifndef FAUST_MIDICC
978 #define FAUST_MIDICC 1
979 #endif
980
981 /* This enables or disables the plugin's custom Qt GUI (cf. lv2ui.cpp). Note
982 that this only affects the plugin manifest, the GUI code itself is in a
983 separate module created with the lv2ui.cpp architecture. Also, you'll have
984 to use the alternative lv2ui manifest templates to tell the LV2 host about
985 the GUI. */
986 #ifndef FAUST_UI
987 #define FAUST_UI 0
988 #endif
989
990 // You can define these for various debugging output items.
991 //#define DEBUG_META 1 // recognized MIDI controller metadata
992 //#define DEBUG_VOICES 1 // triggering of synth voices
993 //#define DEBUG_VOICE_ALLOC 1 // voice allocation
994 //#define DEBUG_MIDI 1 // incoming MIDI messages
995 //#define DEBUG_NOTES 1 // note messages
996 //#define DEBUG_MIDICC 1 // controller messages
997 //#define DEBUG_RPN 1 // RPN messages (pitch bend range, master tuning)
998 //#define DEBUG_MTS 1 // MTS messages (octave/scale tuning)
999
1000 // Note and voice data structures.
1001
1002 struct NoteInfo {
1003 uint8_t ch;
1004 int8_t note;
1005 };
1006
1007 struct VoiceData {
1008 // Octave tunings (offsets in semitones) per MIDI channel.
1009 float tuning[16][12];
1010 // Allocated voices per MIDI channel and note.
1011 int8_t notes[16][128];
1012 // Free and used voices.
1013 int n_free, n_used;
1014 boost::circular_buffer<int> free_voices;
1015 boost::circular_buffer<int> used_voices;
1016 NoteInfo *note_info;
1017 // Voices queued for note-offs (zero-length notes).
1018 set<int> queued;
1019 // Last gate value during run() for each voice. We need to keep track of
1020 // these so that we can force the Faust synth to retrigger a note when
1021 // needed.
1022 float *lastgate;
1023 // Current pitch bend and pitch bend range on each MIDI channel, in semitones.
1024 float bend[16], range[16];
1025 // Current coarse, fine and total master tuning on each MIDI channel (tuning
1026 // offset relative to A4 = 440 Hz, in semitones).
1027 float coarse[16], fine[16], tune[16];
VoiceDataVoiceData1028 VoiceData(int n) : free_voices(n), used_voices(n) { }
1029 };
1030
1031 #if FAUST_MTS
1032
1033 // Helper classes to read and store MTS tunings.
1034
1035 #include <sys/types.h>
1036 #include <sys/stat.h>
1037 #include <dirent.h>
1038
1039 #include <string>
1040 #include <vector>
1041
1042 struct MTSTuning {
1043 char *name; // name of the tuning
1044 int len; // length of sysex data in bytes
1045 unsigned char *data; // sysex data
MTSTuningMTSTuning1046 MTSTuning() : name(0), len(0), data(0) {}
operator =MTSTuning1047 MTSTuning& operator=(const MTSTuning &t)
1048 {
1049 if (this == &t) return *this;
1050 if (name) free(name); if (data) free(data);
1051 name = 0; data = 0; len = t.len;
1052 if (t.name) {
1053 name = strdup(t.name); assert(name);
1054 }
1055 if (t.data) {
1056 data = (unsigned char*)malloc(len); assert(data);
1057 memcpy(data, t.data, len);
1058 }
1059 return *this;
1060 }
MTSTuningMTSTuning1061 MTSTuning(const MTSTuning& t) : name(0), len(0), data(0)
1062 { *this = t; }
1063 MTSTuning(const char *filename);
~MTSTuningMTSTuning1064 ~MTSTuning()
1065 { if (name) free(name); if (data) free(data); }
1066 };
1067
MTSTuning(const char * filename)1068 MTSTuning::MTSTuning(const char *filename)
1069 {
1070 FILE *fp = fopen(filename, "rb");
1071 name = 0; len = 0; data = 0;
1072 if (!fp) return;
1073 struct stat st;
1074 if (fstat(fileno(fp), &st)) return;
1075 len = st.st_size;
1076 data = (unsigned char*)calloc(len, 1);
1077 if (!data) {
1078 len = 0; fclose(fp);
1079 return;
1080 }
1081 assert(len > 0);
1082 if (fread(data, 1, len, fp) < len) {
1083 free(data); len = 0; data = 0; fclose(fp);
1084 return;
1085 }
1086 fclose(fp);
1087 // Do some basic sanity checks.
1088 if (data[0] != 0xf0 || data[len-1] != 0xf7 || // not a sysex message
1089 (data[1] != 0x7e && data[1] != 0x7f) || data[3] != 8 || // not MTS
1090 !((len == 21 && data[4] == 8) ||
1091 (len == 33 && data[4] == 9))) { // no 1- or 2-byte tuning
1092 free(data); len = 0; data = 0;
1093 return;
1094 }
1095 // Name of the tuning is the basename of the file, without the trailing .syx
1096 // suffix.
1097 string nm = filename;
1098 size_t p = nm.rfind(".syx");
1099 if (p != string::npos) nm.erase(p);
1100 p = nm.rfind('/');
1101 if (p != string::npos) nm.erase(0, p+1);
1102 name = strdup(nm.c_str());
1103 assert(name);
1104 }
1105
1106 struct MTSTunings {
1107 vector<MTSTuning> tuning;
MTSTuningsMTSTunings1108 MTSTunings() {}
1109 MTSTunings(const char *path);
1110 };
1111
compareByName(const MTSTuning & a,const MTSTuning & b)1112 static bool compareByName(const MTSTuning &a, const MTSTuning &b)
1113 {
1114 return strcmp(a.name, b.name) < 0;
1115 }
1116
MTSTunings(const char * path)1117 MTSTunings::MTSTunings(const char *path)
1118 {
1119 DIR *dp = opendir(path);
1120 if (!dp) return;
1121 struct dirent *d;
1122 while ((d = readdir(dp))) {
1123 string nm = d->d_name;
1124 if (nm.length() > 4 && nm.substr(nm.length()-4) == ".syx") {
1125 string pathname = path;
1126 pathname += "/";
1127 pathname += nm;
1128 MTSTuning t(pathname.c_str());
1129 if (t.data) tuning.push_back(t);
1130 }
1131 }
1132 closedir(dp);
1133 // sort found tunings by name
1134 sort(tuning.begin(), tuning.end(), compareByName);
1135 }
1136
1137 #endif
1138
1139 #if FAUST_MIDICC
ctrlval(const ui_elem_t & el,uint8_t v)1140 static float ctrlval(const ui_elem_t &el, uint8_t v)
1141 {
1142 // Translate the given MIDI controller value to the range and stepsize
1143 // indicated by the Faust control.
1144 switch (el.type) {
1145 case UI_BUTTON: case UI_CHECK_BUTTON:
1146 return (float)(v>=64);
1147 default:
1148 /* Continuous controllers. The problem here is that the range 0..127 is
1149 not symmetric. We'd like to map 64 to the center of the range
1150 (max-min)/2 and at the same time retain the full control range
1151 min..max. So let's just pretend that there are 128 controller values
1152 and map value 127 to the max value anyway. */
1153 if (v==127)
1154 return el.max;
1155 else
1156 // XXXFIXME: We might want to add proper quantization according to
1157 // el.step here.
1158 return el.min+(el.max-el.min)*v/128;
1159 }
1160 }
1161 #endif
1162
1163 /***************************************************************************/
1164
1165 /* Polyphonic Faust plugin data structure. XXXTODO: At present this is just a
1166 big struct which exposes all requisite data. Some more work is needed to
1167 make the interface a bit more abstract and properly encapsulate the
1168 internal data structures, so that implementation details can be changed
1169 more easily. */
1170
1171 struct LV2Plugin {
1172 const int maxvoices; // maximum number of voices (zero if not an instrument)
1173 const int ndsps; // number of dsp instances (1 if maxvoices==0)
1174 bool active; // activation status
1175 int rate; // sampling rate
1176 int nvoices; // current number of voices (<= maxvoices)
1177 int tuning_no; // current tuning number (<= n_tunings)
1178 harm_trem **dsp; // the dsps
1179 LV2UI **ui; // their Faust interface descriptions
1180 int n_in, n_out; // number of input and output control ports
1181 int *ctrls; // Faust ui elements (indices into ui->elems)
1182 float **ports; // corresponding LV2 data
1183 float *portvals; // cached port data from the last run
1184 float *midivals[16]; // per-midi channel data
1185 int *inctrls, *outctrls; // indices for active and passive controls
1186 float **inputs, **outputs; // audio buffers
1187 int freq, gain, gate; // indices of voice controls
1188 unsigned n_samples; // current block size
1189 float **outbuf; // audio buffers for mixing down the voices
1190 float **inbuf; // dummy input buffer
1191 LV2_Atom_Sequence* event_port; // midi input
1192 float *poly, *tuning; // polyphony and tuning ports
1193 std::map<uint8_t,int> ctrlmap; // MIDI controller map
1194 // Needed host features.
1195 LV2_URID_Map* map; // the urid extension
1196 LV2_URID midi_event; // midi event uri
1197 // Current RPN MSB and LSB numbers, as set with controllers 101 and 100.
1198 uint8_t rpn_msb[16], rpn_lsb[16];
1199 // Current data entry MSB and LSB numbers, as set with controllers 6 and 38.
1200 uint8_t data_msb[16], data_lsb[16];
1201 // Synth voice data (instruments only).
1202 VoiceData *vd;
1203
1204 // Static methods. These all use static data so they can be invoked before
1205 // instantiating a plugin.
1206
1207 // Global meta data (dsp name, author, etc.).
1208 static Meta *meta;
init_metaLV2Plugin1209 static void init_meta()
1210 {
1211 if (!meta && (meta = new Meta)) {
1212 // We allocate the temporary dsp object on the heap here, to prevent
1213 // large dsp objects from running out of stack in environments where
1214 // stack space is precious (e.g., Reaper). Note that if any of these
1215 // allocations fail then no meta data will be available, but at least we
1216 // won't make the host crash and burn.
1217 harm_trem* tmp_dsp = new harm_trem();
1218 if (tmp_dsp) {
1219 tmp_dsp->metadata(meta);
1220 delete tmp_dsp;
1221 }
1222 }
1223 }
meta_getLV2Plugin1224 static const char *meta_get(const char *key, const char *deflt)
1225 {
1226 init_meta();
1227 return meta?meta->get(key, deflt):deflt;
1228 }
1229
pluginNameLV2Plugin1230 static const char *pluginName()
1231 {
1232 return meta_get("name", "harm_trem");
1233 }
1234
pluginAuthorLV2Plugin1235 static const char *pluginAuthor()
1236 {
1237 return meta_get("author", "");
1238 }
1239
pluginDescriptionLV2Plugin1240 static const char *pluginDescription()
1241 {
1242 return meta_get("description", "");
1243 }
1244
pluginLicenseLV2Plugin1245 static const char *pluginLicense()
1246 {
1247 return meta_get("license", "");
1248 }
1249
pluginVersionLV2Plugin1250 static const char *pluginVersion()
1251 {
1252 return meta_get("version", "");
1253 }
1254
1255 // Load a collection of sysex files with MTS tunings in ~/.faust/tuning.
1256 static int n_tunings;
1257 #if FAUST_MTS
1258 static MTSTunings *mts;
1259
load_sysex_dataLV2Plugin1260 static MTSTunings *load_sysex_data()
1261 {
1262 if (!mts) {
1263 string mts_path;
1264 // Look for FAUST_HOME. If that isn't set, try $HOME/.faust. If HOME
1265 // isn't set either, just assume a .faust subdir of the cwd.
1266 const char *home = getenv("FAUST_HOME");
1267 if (home)
1268 mts_path = home;
1269 else {
1270 home = getenv("HOME");
1271 if (home) {
1272 mts_path = home;
1273 mts_path += "/.faust";
1274 } else
1275 mts_path = ".faust";
1276 }
1277 // MTS tunings are looked for in this subdir.
1278 mts_path += "/tuning";
1279 mts = new MTSTunings(mts_path.c_str());
1280 #ifdef __APPLE__
1281 if (!mts || mts->tuning.size() == 0) {
1282 // Also check ~/Library/Faust/Tuning on the Mac.
1283 home = getenv("HOME");
1284 if (home) {
1285 if (mts) delete mts;
1286 mts_path = home;
1287 mts_path += "/Library/Faust/Tuning";
1288 mts = new MTSTunings(mts_path.c_str());
1289 }
1290 }
1291 #endif
1292 n_tunings = mts->tuning.size();
1293 }
1294 return mts;
1295 }
1296 #endif
1297
1298 // The number of voices of an instrument plugin. We get this information
1299 // from the global meta data (nvoices key) of the dsp module if present, and
1300 // you can also override this setting at compile time by defining the
1301 // NVOICES macro. If neither is defined or the value is zero then the plugin
1302 // becomes a simple audio effect instead.
numVoicesLV2Plugin1303 static int numVoices()
1304 {
1305 #ifdef NVOICES
1306 return NVOICES;
1307 #else
1308 const char *numVoices = meta_get("nvoices", "0");
1309 int nvoices = atoi(numVoices);
1310 if (nvoices < 0 ) nvoices = 0;
1311 return nvoices;
1312 #endif
1313 }
1314
1315 // Instance methods.
1316
LV2PluginLV2Plugin1317 LV2Plugin(const int num_voices, const int sr)
1318 : maxvoices(num_voices), ndsps(num_voices<=0?1:num_voices),
1319 vd(num_voices>0?new VoiceData(num_voices):0)
1320 {
1321 // Initialize static data.
1322 init_meta();
1323 #if FAUST_MTS
1324 // Synth: load tuning sysex data if present.
1325 if (num_voices>0) load_sysex_data();
1326 #endif
1327 // Allocate data structures and set some reasonable defaults.
1328 dsp = (harm_trem**)calloc(ndsps, sizeof(harm_trem*));
1329 ui = (LV2UI**)calloc(ndsps, sizeof(LV2UI*));
1330 assert(dsp && ui);
1331 if (vd) {
1332 vd->note_info = (NoteInfo*)calloc(ndsps, sizeof(NoteInfo));
1333 vd->lastgate = (float*)calloc(ndsps, sizeof(float));
1334 assert(vd->note_info && vd->lastgate);
1335 }
1336 active = false;
1337 rate = sr;
1338 nvoices = maxvoices;
1339 tuning_no = 0;
1340 n_in = n_out = 0;
1341 map = NULL;
1342 midi_event = -1;
1343 event_port = NULL;
1344 poly = tuning = NULL;
1345 freq = gain = gate = -1;
1346 if (vd) {
1347 vd->n_free = maxvoices;
1348 for (int i = 0; i < maxvoices; i++) {
1349 vd->free_voices.push_back(i);
1350 vd->lastgate[i] = 0.0f;
1351 }
1352 for (int i = 0; i < 16; i++) {
1353 vd->bend[i] = 0.0f;
1354 vd->range[i] = 2.0f;
1355 vd->coarse[i] = vd->fine[i] = vd->tune[i] = 0.0f;
1356 for (int j = 0; j < 12; j++)
1357 vd->tuning[i][j] = 0.0f;
1358 }
1359 vd->n_used = 0;
1360 memset(vd->notes, 0xff, sizeof(vd->notes));
1361 }
1362 n_samples = 0;
1363 ctrls = inctrls = outctrls = NULL;
1364 ports = inputs = outputs = inbuf = outbuf = NULL;
1365 portvals = NULL;
1366 memset(midivals, 0, sizeof(midivals));
1367 // Initialize the Faust DSPs.
1368 for (int i = 0; i < ndsps; i++) {
1369 dsp[i] = new harm_trem();
1370 ui[i] = new LV2UI(num_voices);
1371 dsp[i]->init(rate);
1372 dsp[i]->buildUserInterface(ui[i]);
1373 }
1374 // The ports are numbered as follows: 0..k-1 are the control ports, then
1375 // come the n audio input ports, then the m audio output ports, and
1376 // finally the midi input port and the polyphony and tuning controls.
1377 int k = ui[0]->nports, p = 0, q = 0;
1378 int n = dsp[0]->getNumInputs(), m = dsp[0]->getNumOutputs();
1379 // Allocate tables for the built-in control elements and their ports.
1380 ctrls = (int*)calloc(k, sizeof(int));
1381 inctrls = (int*)calloc(k, sizeof(int));
1382 outctrls = (int*)calloc(k, sizeof(int));
1383 ports = (float**)calloc(k, sizeof(float*));
1384 portvals = (float*)calloc(k, sizeof(float));
1385 assert(k == 0 || (ctrls && inctrls && outctrls && ports && portvals));
1386 for (int ch = 0; ch < 16; ch++) {
1387 midivals[ch] = (float*)calloc(k, sizeof(float));
1388 assert(k == 0 || midivals[ch]);
1389 }
1390 // Scan the Faust UI for active and passive controls which become the
1391 // input and output control ports of the plugin, respectively.
1392 for (int i = 0, j = 0; i < ui[0]->nelems; i++) {
1393 switch (ui[0]->elems[i].type) {
1394 case UI_T_GROUP: case UI_H_GROUP: case UI_V_GROUP: case UI_END_GROUP:
1395 // control groups (ignored right now)
1396 break;
1397 case UI_H_BARGRAPH: case UI_V_BARGRAPH:
1398 // passive controls (output ports)
1399 ctrls[j++] = i;
1400 outctrls[q++] = i;
1401 break;
1402 default:
1403 // active controls (input ports)
1404 if (maxvoices == 0)
1405 goto noinstr;
1406 else if (freq == -1 &&
1407 !strcmp(ui[0]->elems[i].label, "freq"))
1408 freq = i;
1409 else if (gain == -1 &&
1410 !strcmp(ui[0]->elems[i].label, "gain"))
1411 gain = i;
1412 else if (gate == -1 &&
1413 !strcmp(ui[0]->elems[i].label, "gate"))
1414 gate = i;
1415 else {
1416 noinstr:
1417 #if FAUST_MIDICC
1418 std::map< int, list<strpair> >::iterator it =
1419 ui[0]->metadata.find(i);
1420 if (it != ui[0]->metadata.end()) {
1421 // Scan for controller mappings.
1422 for (std::list<strpair>::iterator jt = it->second.begin();
1423 jt != it->second.end(); jt++) {
1424 const char *key = jt->first, *val = jt->second;
1425 #if DEBUG_META
1426 fprintf(stderr, "ctrl '%s' meta: '%s' -> '%s'\n",
1427 ui[0]->elems[i].label, key, val);
1428 #endif
1429 if (strcmp(key, "midi") == 0) {
1430 unsigned num;
1431 if (sscanf(val, "ctrl %u", &num) < 1) continue;
1432 #if 0 // enable this to get feedback about controller assignments
1433 fprintf(stderr, "%s: cc %d -> %s\n", PLUGIN_URI, num,
1434 ui[0]->elems[i].label);
1435 #endif
1436 ctrlmap.insert(std::pair<uint8_t,int>(num, p));
1437 }
1438 }
1439 }
1440 #endif
1441 ctrls[j++] = i;
1442 inctrls[p++] = i;
1443 int p = ui[0]->elems[i].port;
1444 float val = ui[0]->elems[i].init;
1445 assert(p>=0);
1446 portvals[p] = val;
1447 for (int ch = 0; ch < 16; ch++)
1448 midivals[ch][p] = val;
1449 }
1450 break;
1451 }
1452 }
1453 // Realloc the inctrls and outctrls vectors to their appropriate sizes.
1454 inctrls = (int*)realloc(inctrls, p*sizeof(int));
1455 assert(p == 0 || inctrls);
1456 outctrls = (int*)realloc(outctrls, q*sizeof(int));
1457 assert(q == 0 || outctrls);
1458 n_in = p; n_out = q;
1459 // Allocate vectors for the audio input and output ports. Like
1460 // ports, these will be initialized in the connect_port callback.
1461 inputs = (float**)calloc(n, sizeof(float*));
1462 assert(n == 0 || inputs);
1463 outputs = (float**)calloc(m, sizeof(float*));
1464 assert(m == 0 || outputs);
1465 if (maxvoices > 0) {
1466 // Initialize the mixdown buffer.
1467 outbuf = (float**)calloc(m, sizeof(float*));
1468 assert(m == 0 || outbuf);
1469 // We start out with a blocksize of 512 samples here. Hopefully this is
1470 // enough for most realtime hosts so that we can avoid reallocations
1471 // later when we know what the actual blocksize is.
1472 n_samples = 512;
1473 for (int i = 0; i < m; i++) {
1474 outbuf[i] = (float*)malloc(n_samples*sizeof(float));
1475 assert(outbuf[i]);
1476 }
1477 // Initialize a 1-sample dummy input buffer used for retriggering notes.
1478 inbuf = (float**)calloc(n, sizeof(float*));
1479 assert(n == 0 || inbuf);
1480 for (int i = 0; i < m; i++) {
1481 inbuf[i] = (float*)malloc(sizeof(float));
1482 assert(inbuf[i]);
1483 *inbuf[i] = 0.0f;
1484 }
1485 }
1486 }
1487
~LV2PluginLV2Plugin1488 ~LV2Plugin()
1489 {
1490 const int n = dsp[0]->getNumInputs();
1491 const int m = dsp[0]->getNumOutputs();
1492 for (int i = 0; i < ndsps; i++) {
1493 delete dsp[i];
1494 delete ui[i];
1495 }
1496 free(ctrls); free(inctrls); free(outctrls);
1497 free(ports); free(portvals);
1498 free(inputs); free(outputs);
1499 for (int ch = 0; ch < 16; ch++)
1500 free(midivals[ch]);
1501 if (inbuf) {
1502 for (int i = 0; i < n; i++)
1503 free(inbuf[i]);
1504 free(inbuf);
1505 }
1506 if (outbuf) {
1507 for (int i = 0; i < m; i++)
1508 free(outbuf[i]);
1509 free(outbuf);
1510 }
1511 free(dsp); free(ui);
1512 if (vd) {
1513 free(vd->note_info);
1514 free(vd->lastgate);
1515 delete vd;
1516 }
1517 }
1518 // Voice allocation.
1519
1520 #if DEBUG_VOICE_ALLOC
print_voicesLV2Plugin1521 void print_voices(const char *msg)
1522 {
1523 fprintf(stderr, "%s: notes =", msg);
1524 for (uint8_t ch = 0; ch < 16; ch++)
1525 for (int note = 0; note < 128; note++)
1526 if (vd->notes[ch][note] >= 0)
1527 fprintf(stderr, " [%d] %d(#%d)", ch, note, vd->notes[ch][note]);
1528 fprintf(stderr, "\nqueued (%d):", vd->queued.size());
1529 for (int i = 0; i < nvoices; i++)
1530 if (vd->queued.find(i) != vd->queued.end()) fprintf(stderr, " #%d", i);
1531 fprintf(stderr, "\nused (%d):", vd->n_used);
1532 for (boost::circular_buffer<int>::iterator it = vd->used_voices.begin();
1533 it != vd->used_voices.end(); it++)
1534 fprintf(stderr, " #%d->%d", *it, vd->note_info[*it].note);
1535 fprintf(stderr, "\nfree (%d):", vd->n_free);
1536 for (boost::circular_buffer<int>::iterator it = vd->free_voices.begin();
1537 it != vd->free_voices.end(); it++)
1538 fprintf(stderr, " #%d", *it);
1539 fprintf(stderr, "\n");
1540 }
1541 #endif
1542
alloc_voiceLV2Plugin1543 int alloc_voice(uint8_t ch, int8_t note, int8_t vel)
1544 {
1545 int i = vd->notes[ch][note];
1546 if (i >= 0) {
1547 // note already playing on same channel, retrigger it
1548 voice_off(i);
1549 voice_on(i, note, vel, ch);
1550 // move this voice to the end of the used list
1551 for (boost::circular_buffer<int>::iterator it =
1552 vd->used_voices.begin();
1553 it != vd->used_voices.end(); it++) {
1554 if (*it == i) {
1555 vd->used_voices.erase(it);
1556 vd->used_voices.push_back(i);
1557 break;
1558 }
1559 }
1560 #if DEBUG_VOICE_ALLOC
1561 print_voices("retrigger");
1562 #endif
1563 return i;
1564 } else if (vd->n_free > 0) {
1565 // take voice from free list
1566 int i = vd->free_voices.front();
1567 vd->free_voices.pop_front();
1568 vd->n_free--;
1569 vd->used_voices.push_back(i);
1570 vd->note_info[i].ch = ch;
1571 vd->note_info[i].note = note;
1572 vd->n_used++;
1573 voice_on(i, note, vel, ch);
1574 vd->notes[ch][note] = i;
1575 #if DEBUG_VOICE_ALLOC
1576 print_voices("alloc");
1577 #endif
1578 return i;
1579 } else {
1580 // steal a voice
1581 assert(vd->n_used > 0);
1582 // FIXME: Maybe we should look for the oldest note on the *current*
1583 // channel here, but this is faster.
1584 int i = vd->used_voices.front();
1585 int oldch = vd->note_info[i].ch;
1586 int oldnote = vd->note_info[i].note;
1587 voice_off(i);
1588 vd->notes[oldch][oldnote] = -1;
1589 vd->queued.erase(i);
1590 vd->used_voices.pop_front();
1591 vd->used_voices.push_back(i);
1592 vd->note_info[i].ch = ch;
1593 vd->note_info[i].note = note;
1594 voice_on(i, note, vel, ch);
1595 vd->notes[ch][note] = i;
1596 #if DEBUG_VOICE_ALLOC
1597 print_voices("steal");
1598 #endif
1599 return i;
1600 }
1601 }
1602
dealloc_voiceLV2Plugin1603 int dealloc_voice(uint8_t ch, int8_t note, int8_t vel)
1604 {
1605 int i = vd->notes[ch][note];
1606 if (i >= 0) {
1607 if (vd->lastgate[i] == 0.0f && gate >= 0) {
1608 // zero-length note, queued for later
1609 vd->queued.insert(i);
1610 vd->notes[ch][note] = -1;
1611 #if DEBUG_VOICE_ALLOC
1612 print_voices("dealloc (queued)");
1613 #endif
1614 return i;
1615 }
1616 assert(vd->n_free < nvoices);
1617 vd->free_voices.push_back(i);
1618 vd->n_free++;
1619 voice_off(i);
1620 vd->notes[ch][note] = -1;
1621 // erase this voice from the used list
1622 for (boost::circular_buffer<int>::iterator it =
1623 vd->used_voices.begin();
1624 it != vd->used_voices.end(); it++) {
1625 if (*it == i) {
1626 vd->used_voices.erase(it);
1627 vd->n_used--;
1628 break;
1629 }
1630 }
1631 #if DEBUG_VOICE_ALLOC
1632 print_voices("dealloc");
1633 #endif
1634 return i;
1635 }
1636 return -1;
1637 }
1638
1639
midicpsLV2Plugin1640 float midicps(int8_t note, uint8_t chan)
1641 {
1642 float pitch = note + vd->tune[chan] +
1643 vd->tuning[chan][note%12] + vd->bend[chan];
1644 return 440.0*pow(2, (pitch-69.0)/12.0);
1645 }
1646
voice_onLV2Plugin1647 void voice_on(int i, int8_t note, int8_t vel, uint8_t ch)
1648 {
1649 if (vd->lastgate[i] == 1.0f && gate >= 0) {
1650 // Make sure that the synth sees the 0.0f gate so that the voice is
1651 // properly retriggered.
1652 *ui[i]->elems[gate].zone = 0.0f;
1653 dsp[i]->compute(1, inbuf, outbuf);
1654 }
1655 #if DEBUG_VOICES
1656 fprintf(stderr, "voice on: %d %d (%g Hz) %d (%g)\n", i,
1657 note, midicps(note, ch), vel, vel/127.0);
1658 #endif
1659 if (freq >= 0)
1660 *ui[i]->elems[freq].zone = midicps(note, ch);
1661 if (gate >= 0)
1662 *ui[i]->elems[gate].zone = 1.0f;
1663 if (gain >= 0)
1664 *ui[i]->elems[gain].zone = vel/127.0;
1665 // reinitialize the per-channel control data for this voice
1666 for (int idx = 0; idx < n_in; idx++) {
1667 int j = inctrls[idx], k = ui[0]->elems[j].port;
1668 *ui[i]->elems[j].zone = midivals[ch][k];
1669 }
1670 }
1671
voice_offLV2Plugin1672 void voice_off(int i)
1673 {
1674 #if DEBUG_VOICES
1675 fprintf(stderr, "voice off: %d\n", i);
1676 #endif
1677 if (gate >= 0)
1678 *ui[i]->elems[gate].zone = 0.0f;
1679 }
1680
update_voicesLV2Plugin1681 void update_voices(uint8_t chan)
1682 {
1683 // update running voices on the given channel after tuning or pitch bend
1684 // changes
1685 for (boost::circular_buffer<int>::iterator it =
1686 vd->used_voices.begin();
1687 it != vd->used_voices.end(); it++) {
1688 int i = *it;
1689 if (vd->note_info[i].ch == chan && freq >= 0) {
1690 int note = vd->note_info[i].note;
1691 *ui[i]->elems[freq].zone = midicps(note, chan);
1692 }
1693 }
1694 }
1695
all_notes_offLV2Plugin1696 void all_notes_off()
1697 {
1698 for (int i = 0; i < nvoices; i++)
1699 voice_off(i);
1700 for (int i = 0; i < 16; i++)
1701 vd->bend[i] = 0.0f;
1702 memset(vd->notes, 0xff, sizeof(vd->notes));
1703 vd->free_voices.clear();
1704 vd->n_free = nvoices;
1705 for (int i = 0; i < nvoices; i++)
1706 vd->free_voices.push_back(i);
1707 vd->queued.clear();
1708 vd->used_voices.clear();
1709 vd->n_used = 0;
1710 }
1711
all_notes_offLV2Plugin1712 void all_notes_off(uint8_t chan)
1713 {
1714 for (boost::circular_buffer<int>::iterator it =
1715 vd->used_voices.begin();
1716 it != vd->used_voices.end(); ) {
1717 int i = *it;
1718 if (vd->note_info[i].ch == chan) {
1719 assert(vd->n_free < nvoices);
1720 vd->free_voices.push_back(i);
1721 vd->n_free++;
1722 voice_off(i);
1723 vd->notes[vd->note_info[i].ch][vd->note_info[i].note] = -1;
1724 vd->queued.erase(i);
1725 // erase this voice from the used list
1726 it = vd->used_voices.erase(it);
1727 vd->n_used--;
1728 #if DEBUG_VOICE_ALLOC
1729 print_voices("dealloc (all-notes-off)");
1730 #endif
1731 } else
1732 it++;
1733 }
1734 vd->bend[chan] = 0.0f;
1735 }
1736
queued_notes_offLV2Plugin1737 void queued_notes_off()
1738 {
1739 if (vd->queued.empty()) return;
1740 for (int i = 0; i < nvoices; i++)
1741 if (vd->queued.find(i) != vd->queued.end()) {
1742 assert(vd->n_free < nvoices);
1743 vd->free_voices.push_back(i);
1744 vd->n_free++;
1745 voice_off(i);
1746 vd->notes[vd->note_info[i].ch][vd->note_info[i].note] = -1;
1747 vd->queued.erase(i);
1748 // erase this voice from the used list
1749 for (boost::circular_buffer<int>::iterator it =
1750 vd->used_voices.begin();
1751 it != vd->used_voices.end(); it++) {
1752 if (*it == i) {
1753 vd->used_voices.erase(it);
1754 vd->n_used--;
1755 break;
1756 }
1757 }
1758 #if DEBUG_VOICE_ALLOC
1759 print_voices("dealloc (unqueued)");
1760 #endif
1761 }
1762 }
1763
1764 // Plugin activation status. suspend() deactivates a plugin (disables audio
1765 // processing), resume() reactivates it. Also, set_rate() changes the sample
1766 // rate. Note that the audio and MIDI process functions (see below) can
1767 // still be called in deactivated state, but this is optional. The plugin
1768 // tries to do some reasonable processing in either case, no matter whether
1769 // the host plugin architecture actually executes callbacks in suspended
1770 // state or not.
1771
suspendLV2Plugin1772 void suspend()
1773 {
1774 active = false;
1775 if (maxvoices > 0) all_notes_off();
1776 }
1777
resumeLV2Plugin1778 void resume()
1779 {
1780 for (int i = 0; i < ndsps; i++)
1781 dsp[i]->init(rate);
1782 for (int i = 0, j = 0; i < ui[0]->nelems; i++) {
1783 int p = ui[0]->elems[i].port;
1784 if (p >= 0) {
1785 float val = ui[0]->elems[i].init;
1786 portvals[p] = val;
1787 }
1788 }
1789 active = true;
1790 }
1791
set_rateLV2Plugin1792 void set_rate(int sr)
1793 {
1794 rate = sr;
1795 for (int i = 0; i < ndsps; i++)
1796 dsp[i]->init(rate);
1797 }
1798
1799 // Audio and MIDI process functions. The plugin should run these in the
1800 // appropriate real-time callbacks.
1801
process_audioLV2Plugin1802 void process_audio(int blocksz, float **inputs, float **outputs)
1803 {
1804 int n = dsp[0]->getNumInputs(), m = dsp[0]->getNumOutputs();
1805 AVOIDDENORMALS;
1806 if (maxvoices > 0) queued_notes_off();
1807 if (!active) {
1808 // Depending on the plugin architecture and host, this code might never
1809 // be invoked, since the plugin is deactivitated at this point. But
1810 // let's do something reasonable here anyway.
1811 if (n == m) {
1812 // copy inputs to outputs
1813 for (int i = 0; i < m; i++)
1814 for (unsigned j = 0; j < blocksz; j++)
1815 outputs[i][j] = inputs[i][j];
1816 } else {
1817 // silence
1818 for (int i = 0; i < m; i++)
1819 for (unsigned j = 0; j < blocksz; j++)
1820 outputs[i][j] = 0.0f;
1821 }
1822 return;
1823 }
1824 // Handle changes in the polyphony and tuning controls.
1825 bool is_instr = maxvoices > 0;
1826 if (is_instr) {
1827 if (!poly)
1828 ; // this shouldn't happen but...
1829 else if (nvoices != (int)*poly &&
1830 (int)*poly > 0 && (int)*poly <= maxvoices) {
1831 for (int i = 0; i < nvoices; i++)
1832 voice_off(i);
1833 nvoices = (int)*poly;
1834 // Reset the voice allocation.
1835 memset(vd->notes, 0xff, sizeof(vd->notes));
1836 vd->free_voices.clear();
1837 vd->n_free = nvoices;
1838 for (int i = 0; i < nvoices; i++)
1839 vd->free_voices.push_back(i);
1840 vd->used_voices.clear();
1841 vd->n_used = 0;
1842 } else
1843 *poly = nvoices;
1844 #if FAUST_MTS
1845 if (tuning && tuning_no != (int)*tuning) change_tuning((int)*tuning);
1846 #endif
1847 }
1848 // Only update the controls (of all voices simultaneously) if a port value
1849 // actually changed. This is necessary to allow MIDI controllers to modify
1850 // the values for individual MIDI channels (see processEvents below). Also
1851 // note that this will be done *after* processing the MIDI controller data
1852 // for the current audio block, so manual inputs can still override these.
1853 for (int i = 0; i < n_in; i++) {
1854 int j = inctrls[i], k = ui[0]->elems[j].port;
1855 float &oldval = portvals[k], newval = *ports[k];
1856 if (newval != oldval) {
1857 if (is_instr) {
1858 // instrument: update running voices
1859 for (boost::circular_buffer<int>::iterator it =
1860 vd->used_voices.begin();
1861 it != vd->used_voices.end(); it++) {
1862 int i = *it;
1863 *ui[i]->elems[j].zone = newval;
1864 }
1865 } else {
1866 // simple effect: here we only have a single dsp instance
1867 *ui[0]->elems[j].zone = newval;
1868 }
1869 // also update the MIDI controller data for all channels (manual
1870 // control input is always omni)
1871 for (int ch = 0; ch < 16; ch++)
1872 midivals[ch][k] = newval;
1873 // record the new value
1874 oldval = newval;
1875 }
1876 }
1877 // Initialize the output buffers.
1878 if (n_samples < blocksz) {
1879 // We need to enlarge the buffers. We're not officially allowed to do
1880 // this here (presumably in the realtime thread), but since we usually
1881 // don't know the hosts's block size beforehand, there's really nothing
1882 // else that we can do. Let's just hope that doing this once suffices,
1883 // then hopefully noone will notice.
1884 if (outbuf) {
1885 for (int i = 0; i < m; i++) {
1886 outbuf[i] = (float*)realloc(outbuf[i],
1887 blocksz*sizeof(float));
1888 assert(outbuf[i]);
1889 }
1890 }
1891 n_samples = blocksz;
1892 }
1893 if (outbuf) {
1894 // Polyphonic instrument: Mix the voices down to one signal.
1895 for (int i = 0; i < m; i++)
1896 for (unsigned j = 0; j < blocksz; j++)
1897 outputs[i][j] = 0.0f;
1898 for (int l = 0; l < nvoices; l++) {
1899 // Let Faust do all the hard work.
1900 dsp[l]->compute(blocksz, inputs, outbuf);
1901 for (int i = 0; i < m; i++)
1902 for (unsigned j = 0; j < blocksz; j++)
1903 outputs[i][j] += outbuf[i][j];
1904 }
1905 } else {
1906 // Simple effect: We can write directly to the output buffer.
1907 dsp[0]->compute(blocksz, inputs, outputs);
1908 }
1909 // Finally grab the passive controls and write them back to the
1910 // corresponding control ports. NOTE: Depending on the plugin
1911 // architecture, this might require a host call to get the control GUI
1912 // updated in real-time (if the host supports this at all).
1913 // FIXME: It's not clear how to aggregate the data of the different
1914 // voices. We compute the maximum of each control for now.
1915 for (int i = 0; i < n_out; i++) {
1916 int j = outctrls[i], k = ui[0]->elems[j].port;
1917 float *z = ui[0]->elems[j].zone;
1918 *ports[k] = *z;
1919 for (int l = 1; l < nvoices; l++) {
1920 float *z = ui[l]->elems[j].zone;
1921 if (*ports[k] < *z)
1922 *ports[k] = *z;
1923 }
1924 }
1925 // Keep track of the last gates set for each voice, so that voices can be
1926 // forcibly retriggered if needed.
1927 if (gate >= 0)
1928 for (int i = 0; i < nvoices; i++)
1929 vd->lastgate[i] =
1930 *ui[i]->elems[gate].zone;
1931 }
1932
1933 // This processes just a single MIDI message, so to process an entire series
1934 // of MIDI events you'll have to loop over the event data in the plugin's
1935 // MIDI callback. XXXTODO: Sample-accurate processing of MIDI events.
1936
process_midiLV2Plugin1937 void process_midi(unsigned char *data, int sz)
1938 {
1939 #if DEBUG_MIDI
1940 fprintf(stderr, "midi ev (%d bytes):", sz);
1941 for (int i = 0; i < sz; i++)
1942 fprintf(stderr, " 0x%0x", data[i]);
1943 fprintf(stderr, "\n");
1944 #endif
1945 uint8_t status = data[0] & 0xf0, chan = data[0] & 0x0f;
1946 bool is_instr = maxvoices > 0;
1947 switch (status) {
1948 case 0x90: {
1949 if (!is_instr) break;
1950 // note on
1951 #if DEBUG_NOTES
1952 fprintf(stderr, "note-on chan %d, note %d, vel %d\n", chan+1,
1953 data[1], data[2]);
1954 #endif
1955 if (data[2] == 0) goto note_off;
1956 alloc_voice(chan, data[1], data[2]);
1957 break;
1958 }
1959 case 0x80: {
1960 if (!is_instr) break;
1961 // note off
1962 #if DEBUG_NOTES
1963 fprintf(stderr, "note-off chan %d, note %d, vel %d\n", chan+1,
1964 data[1], data[2]);
1965 #endif
1966 note_off:
1967 dealloc_voice(chan, data[1], data[2]);
1968 break;
1969 }
1970 case 0xe0: {
1971 if (!is_instr) break;
1972 // pitch bend
1973 // data[1] is LSB, data[2] MSB, range is 0..0x3fff (which maps to
1974 // -2..+2 semitones by default), center point is 0x2000 = 8192
1975 int val = data[1] | (data[2]<<7);
1976 vd->bend[chan] =
1977 (val-0x2000)/8192.0f*vd->range[chan];
1978 #if DEBUG_MIDICC
1979 fprintf(stderr, "pitch-bend (chan %d): %g cent\n", chan+1,
1980 vd->bend[chan]*100.0);
1981 #endif
1982 update_voices(chan);
1983 break;
1984 }
1985 case 0xb0: {
1986 // controller change
1987 switch (data[1]) {
1988 case 120: case 123:
1989 if (!is_instr) break;
1990 // all-sound-off and all-notes-off controllers (these are treated
1991 // the same in the current implementation)
1992 all_notes_off(chan);
1993 #if DEBUG_MIDICC
1994 fprintf(stderr, "all-notes-off (chan %d)\n", chan+1);
1995 #endif
1996 break;
1997 case 121:
1998 // all-controllers-off (in the current implementation, this just
1999 // resets the RPN-related controllers)
2000 data_msb[chan] = data_lsb[chan] = 0;
2001 rpn_msb[chan] = rpn_lsb[chan] = 0x7f;
2002 #if DEBUG_MIDICC
2003 fprintf(stderr, "all-controllers-off (chan %d)\n", chan+1);
2004 #endif
2005 break;
2006 case 101: case 100:
2007 // RPN MSB/LSB
2008 if (data[1] == 101)
2009 rpn_msb[chan] = data[2];
2010 else
2011 rpn_lsb[chan] = data[2];
2012 break;
2013 case 6: case 38:
2014 // data entry coarse/fine
2015 if (data[1] == 6)
2016 data_msb[chan] = data[2];
2017 else
2018 data_lsb[chan] = data[2];
2019 goto rpn;
2020 case 96: case 97:
2021 // data increment/decrement
2022 /* NOTE: The specification of these controllers is a complete
2023 mess. Originally, the MIDI specification didn't have anything
2024 to say about their exact behaviour at all. Nowadays, the
2025 behaviour depends on which RPN or NRPN is being modified, which
2026 is also rather confusing. Fortunately, as we only handle RPNs
2027 0..2 here anyway, it's sufficient to assume the MSB for RPN #2
2028 (channel coarse tuning) and the LSB otherwise. */
2029 if (rpn_msb[chan] == 0 && rpn_lsb[chan] == 2) {
2030 // modify the MSB
2031 if (data[1] == 96 && data_msb[chan] < 0x7f)
2032 data_msb[chan]++;
2033 else if (data[1] == 97 && data_msb[chan] > 0)
2034 data_msb[chan]--;
2035 } else {
2036 // modify the LSB
2037 if (data[1] == 96 && data_lsb[chan] < 0x7f)
2038 data_lsb[chan]++;
2039 else if (data[1] == 97 && data_lsb[chan] > 0)
2040 data_lsb[chan]--;
2041 }
2042 rpn:
2043 if (!is_instr) break;
2044 if (rpn_msb[chan] == 0) {
2045 switch (rpn_lsb[chan]) {
2046 case 0:
2047 // pitch bend range, coarse value is in semitones, fine value
2048 // in cents
2049 vd->range[chan] = data_msb[chan]+
2050 data_lsb[chan]/100.0;
2051 #if DEBUG_RPN
2052 fprintf(stderr, "pitch-bend-range (chan %d): %g cent\n", chan+1,
2053 vd->range[chan]*100.0);
2054 #endif
2055 break;
2056 case 1:
2057 {
2058 // channel fine tuning (14 bit value, range -100..+100 cents)
2059 int value = (data_msb[chan]<<7) |
2060 data_lsb[chan];
2061 vd->fine[chan] = (value-8192)/8192.0f;
2062 }
2063 goto master_tune;
2064 case 2:
2065 // channel coarse tuning (only msb is used, range -64..+63
2066 // semitones)
2067 vd->coarse[chan] = data_msb[chan]-64;
2068 master_tune:
2069 vd->tune[chan] = vd->coarse[chan]+
2070 vd->fine[chan];
2071 #if DEBUG_RPN
2072 fprintf(stderr, "master-tuning (chan %d): %g cent\n", chan+1,
2073 vd->tune[chan]*100.0);
2074 #endif
2075 update_voices(chan);
2076 break;
2077 default:
2078 break;
2079 }
2080 }
2081 break;
2082 default: {
2083 #if FAUST_MIDICC
2084 // interpret all other controller changes according to the MIDI
2085 // controller map defined in the Faust plugin itself
2086 std::map<uint8_t,int>::iterator it = ctrlmap.find(data[1]);
2087 if (it != ctrlmap.end()) {
2088 // defined MIDI controller
2089 int j = inctrls[it->second],
2090 k = ui[0]->elems[j].port;
2091 float val = ctrlval(ui[0]->elems[j], data[2]);
2092 midivals[chan][k] = val;
2093 if (is_instr) {
2094 // instrument: update running voices on this channel
2095 for (boost::circular_buffer<int>::iterator it =
2096 vd->used_voices.begin();
2097 it != vd->used_voices.end(); it++) {
2098 int i = *it;
2099 if (vd->note_info[i].ch == chan)
2100 *ui[i]->elems[j].zone = val;
2101 }
2102 } else {
2103 // simple effect: here we only have a single dsp instance and
2104 // we're operating in omni mode, so we just update the control no
2105 // matter what the midi channel is
2106 *ui[0]->elems[j].zone = val;
2107 }
2108 #if DEBUG_MIDICC
2109 fprintf(stderr, "ctrl-change chan %d, ctrl %d, val %d\n", chan+1,
2110 data[1], data[2]);
2111 #endif
2112 }
2113 #endif
2114 break;
2115 }
2116 }
2117 break;
2118 }
2119 default:
2120 break;
2121 }
2122 }
2123
2124 // Process an MTS sysex message and update the control values accordingly.
2125
process_sysexLV2Plugin2126 void process_sysex(uint8_t *data, int sz)
2127 {
2128 if (!data || sz < 2) return;
2129 #if DEBUG_MIDI
2130 fprintf(stderr, "midi sysex (%d bytes):", sz);
2131 for (int i = 0; i < sz; i++)
2132 fprintf(stderr, " 0x%0x", data[i]);
2133 fprintf(stderr, "\n");
2134 #endif
2135 if (data[0] == 0xf0) {
2136 // Skip over the f0 and f7 status bytes in case they are included in the
2137 // dump.
2138 data++; sz--;
2139 if (data[sz-1] == 0xf7) sz--;
2140 }
2141 if ((data[0] == 0x7e || data[0] == 0x7f) && data[2] == 8) {
2142 // MIDI tuning standard
2143 bool realtime = data[0] == 0x7f;
2144 if ((sz == 19 && data[3] == 8) ||
2145 (sz == 31 && data[3] == 9)) {
2146 // MTS scale/octave tuning 1- or 2-byte form
2147 bool onebyte = data[3] == 8;
2148 unsigned chanmsk = (data[4]<<14) | (data[5]<<7) | data[6];
2149 for (int i = 0; i < 12; i++) {
2150 float t;
2151 if (onebyte)
2152 t = (data[i+7]-64)/100.0;
2153 else
2154 t = (((data[2*i+7]<<7)|data[2*i+8])-8192)/8192.0;
2155 for (uint8_t ch = 0; ch < 16; ch++)
2156 if (chanmsk & (1<<ch))
2157 vd->tuning[ch][i] = t;
2158 }
2159 if (realtime) {
2160 for (uint8_t ch = 0; ch < 16; ch++)
2161 if (chanmsk & (1<<ch)) {
2162 // update running voices on this channel
2163 update_voices(ch);
2164 }
2165 }
2166 #if DEBUG_MTS
2167 fprintf(stderr, "octave-tuning-%s (chan ",
2168 realtime?"realtime":"non-realtime");
2169 bool first = true;
2170 for (uint8_t i = 0; i < 16; )
2171 if (chanmsk & (1<<i)) {
2172 uint8_t j;
2173 for (j = i+1; j < 16 && (chanmsk&(1<<j)); )
2174 j++;
2175 if (first)
2176 first = false;
2177 else
2178 fprintf(stderr, ",");
2179 if (j > i+1)
2180 fprintf(stderr, "%u-%u", i+1, j);
2181 else
2182 fprintf(stderr, "%u", i+1);
2183 i = j;
2184 } else
2185 i++;
2186 fprintf(stderr, "):");
2187 if (onebyte) {
2188 for (int i = 7; i < 19; i++) {
2189 int val = data[i];
2190 fprintf(stderr, " %d", val-64);
2191 }
2192 } else {
2193 for (int i = 7; i < 31; i++) {
2194 int val = data[i++] << 7;
2195 val |= data[i];
2196 fprintf(stderr, " %g", ((double)val-8192.0)/8192.0*100.0);
2197 }
2198 }
2199 fprintf(stderr, "\n");
2200 #endif
2201 }
2202 }
2203 }
2204
2205 // Change to a given preloaded tuning. The given tuning number may be in the
2206 // range 1..PFaustPlugin::n_tunings, zero denotes the default tuning (equal
2207 // temperament). This is only supported if FAUST_MTS is defined at compile
2208 // time.
2209
change_tuningLV2Plugin2210 void change_tuning(int num)
2211 {
2212 #if FAUST_MTS
2213 if (!mts || num == tuning_no) return;
2214 if (num < 0) num = 0;
2215 if (num > mts->tuning.size())
2216 num = mts->tuning.size();
2217 tuning_no = num;
2218 if (tuning_no > 0) {
2219 process_sysex(mts->tuning[tuning_no-1].data,
2220 mts->tuning[tuning_no-1].len);
2221 } else {
2222 memset(vd->tuning, 0, sizeof(vd->tuning));
2223 #if DEBUG_MTS
2224 fprintf(stderr,
2225 "octave-tuning-default (chan 1-16): equal temperament\n");
2226 #endif
2227 }
2228 #endif
2229 }
2230
2231 };
2232
2233 Meta *LV2Plugin::meta = 0;
2234 int LV2Plugin::n_tunings = 0;
2235 #if FAUST_MTS
2236 MTSTunings *LV2Plugin::mts = 0;
2237 #endif
2238
2239 /* LV2-specific part starts here. ********************************************/
2240
2241 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)2242 instantiate(const LV2_Descriptor* descriptor,
2243 double rate,
2244 const char* bundle_path,
2245 const LV2_Feature* const* features)
2246 {
2247 LV2Plugin* plugin =
2248 new LV2Plugin(LV2Plugin::numVoices(), (int)rate);
2249 // Scan host features for URID map.
2250 for (int i = 0; features[i]; i++) {
2251 if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
2252 plugin->map = (LV2_URID_Map*)features[i]->data;
2253 plugin->midi_event =
2254 plugin->map->map(plugin->map->handle, MIDI_EVENT_URI);
2255 }
2256 }
2257 if (!plugin->map) {
2258 fprintf
2259 (stderr, "%s: host doesn't support urid:map, giving up\n",
2260 PLUGIN_URI);
2261 delete plugin;
2262 return 0;
2263 }
2264 return (LV2_Handle)plugin;
2265 }
2266
2267 static void
cleanup(LV2_Handle instance)2268 cleanup(LV2_Handle instance)
2269 {
2270 LV2Plugin* plugin = (LV2Plugin*)instance;
2271 delete plugin;
2272 }
2273
2274 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)2275 connect_port(LV2_Handle instance,
2276 uint32_t port,
2277 void* data)
2278 {
2279 LV2Plugin* plugin = (LV2Plugin*)instance;
2280 int i = port, k = plugin->ui[0]->nports;
2281 int n = plugin->dsp[0]->getNumInputs(), m = plugin->dsp[0]->getNumOutputs();
2282 if (i < k)
2283 plugin->ports[i] = (float*)data;
2284 else {
2285 i -= k;
2286 if (i < n)
2287 plugin->inputs[i] = (float*)data;
2288 else {
2289 i -= n;
2290 if (i < m)
2291 plugin->outputs[i] = (float*)data;
2292 else if (i == m)
2293 plugin->event_port = (LV2_Atom_Sequence*)data;
2294 else if (i == m+1)
2295 plugin->poly = (float*)data;
2296 else if (i == m+2)
2297 plugin->tuning = (float*)data;
2298 else
2299 fprintf(stderr, "%s: bad port number %u\n", PLUGIN_URI, port);
2300 }
2301 }
2302 }
2303
2304 static void
run(LV2_Handle instance,uint32_t n_samples)2305 run(LV2_Handle instance, uint32_t n_samples)
2306 {
2307 LV2Plugin* plugin = (LV2Plugin*)instance;
2308 // Process incoming MIDI events.
2309 if (plugin->event_port) {
2310 LV2_ATOM_SEQUENCE_FOREACH(plugin->event_port, ev) {
2311 if (ev->body.type == plugin->midi_event) {
2312 uint8_t *data = (uint8_t*)(ev+1);
2313 #if 0
2314 // FIXME: Consider doing sample-accurate note onsets here. LV2 keeps
2315 // track of the exact onset in the frames and subframes fields
2316 // (http://lv2plug.in/ns/doc/html/structLV2__Atom__Event.html), but we
2317 // can't use that information at present, since our gate parameter is
2318 // a control variable which can only change at block boundaries. In
2319 // the future, the gate could be implemented as an audio signal to get
2320 // sample-accurate note onsets.
2321 uint32_t frames = ev->body.frames;
2322 #endif
2323 if (data[0] == 0xf0)
2324 plugin->process_sysex(data, ev->body.size);
2325 else
2326 plugin->process_midi(data, ev->body.size);
2327 }
2328 }
2329 }
2330 // Process audio.
2331 plugin->process_audio(n_samples, plugin->inputs, plugin->outputs);
2332 }
2333
2334 static void
activate(LV2_Handle instance)2335 activate(LV2_Handle instance)
2336 {
2337 LV2Plugin* plugin = (LV2Plugin*)instance;
2338 plugin->resume();
2339 }
2340
2341 static void
deactivate(LV2_Handle instance)2342 deactivate(LV2_Handle instance)
2343 {
2344 LV2Plugin* plugin = (LV2Plugin*)instance;
2345 plugin->suspend();
2346 }
2347
2348 const void*
extension_data(const char * uri)2349 extension_data(const char* uri)
2350 {
2351 return NULL;
2352 }
2353
2354 static const LV2_Descriptor descriptor = {
2355 PLUGIN_URI,
2356 instantiate,
2357 connect_port,
2358 activate,
2359 run,
2360 deactivate,
2361 cleanup,
2362 extension_data
2363 };
2364
2365 extern "C"
2366 LV2_SYMBOL_EXPORT
2367 const LV2_Descriptor*
lv2_descriptor(uint32_t index)2368 lv2_descriptor(uint32_t index)
2369 {
2370 switch (index) {
2371 case 0:
2372 return &descriptor;
2373 default:
2374 return NULL;
2375 }
2376 }
2377
2378 //----------------------------------------------------------------------------
2379 // Dynamic manifest
2380 //----------------------------------------------------------------------------
2381
2382 // NOTE: If your LV2 host doesn't offer this extension then you'll have to
2383 // create a static ttl file with the descriptions of the ports. You can do
2384 // this by compiling this code to a standalone executable. Running the
2385 // executable then prints the manifest on stdout.
2386
2387 extern "C"
2388 LV2_SYMBOL_EXPORT
lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle * handle,const LV2_Feature * const * features)2389 int lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle *handle,
2390 const LV2_Feature *const *features)
2391 {
2392 LV2Plugin* plugin =
2393 new LV2Plugin(LV2Plugin::numVoices(), 48000);
2394 *handle = (LV2_Dyn_Manifest_Handle)plugin;
2395 return 0;
2396 }
2397
2398 extern "C"
2399 LV2_SYMBOL_EXPORT
lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle,FILE * fp)2400 int lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle,
2401 FILE *fp)
2402 {
2403 fprintf(fp, "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
2404 <%s> a lv2:Plugin .\n", PLUGIN_URI);
2405 return 0;
2406 }
2407
2408 #include <string>
2409 #include <ctype.h>
2410
mangle(const string & s)2411 static string mangle(const string &s)
2412 {
2413 string t = s;
2414 size_t n = s.size();
2415 for (size_t i = 0; i < n; i++)
2416 if ((i == 0 && !isalpha(t[i]) && t[i] != '_') ||
2417 (!isalnum(t[i]) && t[i] != '_'))
2418 t[i] = '_';
2419 return t;
2420 }
2421
steps(float min,float max,float step)2422 static unsigned steps(float min, float max, float step)
2423 {
2424 if (step == 0.0) return 1;
2425 int n = (max-min)/step;
2426 if (n < 0) n = -n;
2427 if (n == 0) n = 1;
2428 return n;
2429 }
2430
2431 #if FAUST_META
is_xmlstring(const char * s)2432 static bool is_xmlstring(const char *s)
2433 {
2434 // This is just a basic sanity check. The string must not contain any
2435 // (unescaped) newlines, carriage returns or double quotes.
2436 return !strchr(s, '\n') && !strchr(s, '\r') && !strchr(s, '"');
2437 }
2438 #endif
2439
2440 extern "C"
2441 LV2_SYMBOL_EXPORT
lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle,FILE * fp,const char * uri)2442 int lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle,
2443 FILE *fp,
2444 const char *uri)
2445 {
2446 LV2Plugin* plugin = (LV2Plugin*)handle;
2447 int k = plugin->ui[0]->nports;
2448 int n = plugin->dsp[0]->getNumInputs(), m = plugin->dsp[0]->getNumOutputs();
2449 bool is_instr = plugin->maxvoices > 0, have_midi = is_instr;
2450 // Scan the global metadata for plugin name, description, license etc.
2451 const char *plugin_name = NULL, *plugin_author = NULL, *plugin_descr = NULL,
2452 *plugin_version = NULL, *plugin_license = NULL;
2453 #if FAUST_META
2454 plugin_name = plugin->pluginName();
2455 plugin_descr = plugin->pluginDescription();
2456 plugin_author = plugin->pluginAuthor();
2457 plugin_version = plugin->pluginVersion();
2458 plugin_license = plugin->pluginLicense();
2459 #endif
2460 if (!plugin_name || !*plugin_name) plugin_name = "harm_trem";
2461 fprintf(fp, "@prefix doap: <http://usefulinc.com/ns/doap#> .\n\
2462 @prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\
2463 @prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
2464 @prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n\
2465 @prefix epp: <http://lv2plug.in/ns/ext/port-props#> .\n\
2466 @prefix atom: <http://lv2plug.in/ns/ext/atom#> .\n\
2467 @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n\
2468 @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n\
2469 @prefix units: <http://lv2plug.in/ns/extensions/units#> .\n\
2470 <%s>\n\
2471 a lv2:Plugin%s ;\n\
2472 doap:name \"%s\" ;\n\
2473 lv2:binary <harm_trem%s> ;\n\
2474 lv2:optionalFeature epp:supportsStrictBounds ;\n\
2475 lv2:optionalFeature lv2:hardRtCapable ;\n", PLUGIN_URI,
2476 is_instr?", lv2:InstrumentPlugin":"",
2477 plugin_name, DLLEXT);
2478 if (plugin_author && *plugin_author)
2479 fprintf(fp, "\
2480 doap:maintainer [ foaf:name \"%s\" ] ;\n", plugin_author);
2481 // doap:description just seems to be ignored by all LV2 hosts anyway, so we
2482 // rather use rdfs:comment now which works with Ardour at least.
2483 if (plugin_descr && *plugin_descr)
2484 fprintf(fp, "\
2485 rdfs:comment \"%s\" ;\n", plugin_descr);
2486 if (plugin_version && *plugin_version)
2487 fprintf(fp, "\
2488 doap:revision \"%s\" ;\n", plugin_version);
2489 if (plugin_license && *plugin_license)
2490 fprintf(fp, "\
2491 doap:license \"%s\" ;\n", plugin_license);
2492 #if FAUST_UI
2493 fprintf(fp, "\
2494 ui:ui <%sui> ;\n", PLUGIN_URI);
2495 #endif
2496 int idx = 0;
2497 // control ports
2498 for (int i = 0; i < k; i++, idx++) {
2499 int j = plugin->ctrls[i];
2500 assert(idx == plugin->ui[0]->elems[j].port);
2501 fprintf(fp, "%s [\n", idx==0?" lv2:port":" ,");
2502 const char *label = plugin->ui[0]->elems[j].label;
2503 assert(label);
2504 string sym = mangle(plugin->ui[0]->elems[j].label);
2505 switch (plugin->ui[0]->elems[j].type) {
2506 // active controls (input ports)
2507 case UI_BUTTON: case UI_CHECK_BUTTON:
2508 fprintf(fp, "\
2509 a lv2:InputPort ;\n\
2510 a lv2:ControlPort ;\n\
2511 lv2:index %d ;\n\
2512 lv2:symbol \"%s_%d\" ;\n\
2513 lv2:name \"%s\" ;\n\
2514 lv2:portProperty epp:hasStrictBounds ;\n\
2515 lv2:portProperty lv2:toggled ;\n\
2516 lv2:default 0.00000 ;\n\
2517 lv2:minimum 0.00000 ;\n\
2518 lv2:maximum 1.00000 ;\n", idx, sym.c_str(), idx, label);
2519 break;
2520 case UI_NUM_ENTRY: case UI_H_SLIDER: case UI_V_SLIDER:
2521 fprintf(fp, "\
2522 a lv2:InputPort ;\n\
2523 a lv2:ControlPort ;\n\
2524 lv2:index %d ;\n\
2525 lv2:symbol \"%s_%d\" ;\n\
2526 lv2:name \"%s\" ;\n\
2527 lv2:portProperty epp:hasStrictBounds ;\n\
2528 epp:rangeSteps %u ;\n\
2529 lv2:default %g ;\n\
2530 lv2:minimum %g ;\n\
2531 lv2:maximum %g ;\n", idx, sym.c_str(), idx, label,
2532 steps(plugin->ui[0]->elems[j].min,
2533 plugin->ui[0]->elems[j].max,
2534 plugin->ui[0]->elems[j].step),
2535 plugin->ui[0]->elems[j].init,
2536 plugin->ui[0]->elems[j].min,
2537 plugin->ui[0]->elems[j].max);
2538 break;
2539 // passive controls (output ports)
2540 case UI_H_BARGRAPH: case UI_V_BARGRAPH:
2541 fprintf(fp, "\
2542 a lv2:OutputPort ;\n\
2543 a lv2:ControlPort ;\n\
2544 lv2:index %d ;\n\
2545 lv2:symbol \"%s_%d\" ;\n\
2546 lv2:name \"%s\" ;\n\
2547 lv2:default %g ;\n\
2548 lv2:minimum %g ;\n\
2549 lv2:maximum %g ;\n", idx, sym.c_str(), idx, label,
2550 plugin->ui[0]->elems[j].min,
2551 plugin->ui[0]->elems[j].min,
2552 plugin->ui[0]->elems[j].max);
2553 break;
2554 default:
2555 assert(0 && "this can't happen");
2556 break;
2557 }
2558 // Scan for Faust control metadata we understand and add corresponding
2559 // hints to the LV2 description of the port.
2560 std::map< int, list<strpair> >::iterator it =
2561 plugin->ui[0]->metadata.find(j);
2562 if (it != plugin->ui[0]->metadata.end()) {
2563 for (std::list<strpair>::iterator jt = it->second.begin();
2564 jt != it->second.end(); jt++) {
2565 const char *key = jt->first, *val = jt->second;
2566 #if FAUST_MIDICC
2567 unsigned num;
2568 if (!strcmp(key, "midi") && sscanf(val, "ctrl %u", &num) == 1)
2569 have_midi = true;
2570 #endif
2571 if (!strcmp(key, "unit"))
2572 fprintf(fp, "\
2573 units:unit [\n\
2574 a units:Unit ;\n\
2575 units:name \"%s\" ;\n\
2576 units:symbol \"%s\" ;\n\
2577 units:render \"%%f %s\"\n\
2578 ] ;\n", val, val, val);
2579 if (strcmp(key, "lv2")) continue;
2580 if (!strcmp(val, "integer"))
2581 fprintf(fp, "\
2582 lv2:portProperty lv2:integer ;\n");
2583 else if (!strcmp(val, "reportsLatency"))
2584 fprintf(fp, "\
2585 lv2:portProperty lv2:reportsLatency ;\n\
2586 lv2:designation lv2:latency ;\n");
2587 else if (!strcmp(val, "hidden") || !strcmp(val, "notOnGUI"))
2588 fprintf(fp, "\
2589 lv2:portProperty epp:notOnGUI ;\n");
2590 else if (!strncmp(val, "scalepoint", 10) ||
2591 !strncmp(val, "scalePoint", 10)) {
2592 val += 10;
2593 if (!isspace(*val)) continue;
2594 char *label = (char*)malloc(strlen(val)+1);
2595 float point;
2596 int pos;
2597 while (sscanf(val, "%s %g%n", label, &point, &pos) == 2) {
2598 fprintf(fp, "\
2599 lv2:scalePoint [ rdfs:label \"%s\"; rdf:value %g ] ;\n",
2600 label, point);
2601 val += pos;
2602 }
2603 free(label);
2604 } else
2605 fprintf(stderr, "%s: bad port property '%s:%s'\n", PLUGIN_URI,
2606 key, val);
2607 }
2608 }
2609 fprintf(fp, " ]");
2610 }
2611 // audio inputs
2612 for (int i = 0; i < n; i++, idx++)
2613 fprintf(fp, "%s [\n\
2614 a lv2:InputPort ;\n\
2615 a lv2:AudioPort ;\n\
2616 lv2:index %d ;\n\
2617 lv2:symbol \"in%d\" ;\n\
2618 lv2:name \"in%d\" ;\n\
2619 ]", idx==0?" lv2:port":" ,", idx, i, i);
2620 // audio outputs
2621 for (int i = 0; i < m; i++, idx++)
2622 fprintf(fp, "%s [\n\
2623 a lv2:OutputPort ;\n\
2624 a lv2:AudioPort ;\n\
2625 lv2:index %d ;\n\
2626 lv2:symbol \"out%d\" ;\n\
2627 lv2:name \"out%d\" ;\n\
2628 ]", idx==0?" lv2:port":" ,", idx, i, i);
2629 if (have_midi) {
2630 // midi input
2631 fprintf(fp, "%s [\n\
2632 a lv2:InputPort ;\n\
2633 a atom:AtomPort ;\n\
2634 atom:bufferType atom:Sequence ;\n\
2635 atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n\
2636 lv2:index %d ;\n\
2637 lv2:symbol \"midiin\" ;\n\
2638 lv2:name \"midiin\"\n\
2639 ]", idx==0?" lv2:port":" ,", idx);
2640 idx++;
2641 }
2642 if (is_instr) {
2643 // polyphony control
2644 fprintf(fp, "%s [\n\
2645 a lv2:InputPort ;\n\
2646 a lv2:ControlPort ;\n\
2647 lv2:index %d ;\n\
2648 lv2:symbol \"polyphony\" ;\n\
2649 lv2:name \"polyphony\" ;\n\
2650 lv2:portProperty epp:hasStrictBounds ;\n\
2651 # lv2:portProperty epp:expensive ;\n\
2652 lv2:portProperty lv2:integer ;\n\
2653 epp:rangeSteps %d ;\n\
2654 lv2:default %d ;\n\
2655 lv2:minimum 1 ;\n\
2656 lv2:maximum %d ;\n\
2657 ]", idx==0?" lv2:port":" ,", idx, plugin->maxvoices-1,
2658 plugin->maxvoices>1?plugin->maxvoices/2:1,
2659 plugin->maxvoices);
2660 idx++;
2661 #if FAUST_MTS
2662 if (plugin->n_tunings > 0) {
2663 // tuning control
2664 fprintf(fp, "%s [\n\
2665 a lv2:InputPort ;\n\
2666 a lv2:ControlPort ;\n\
2667 lv2:index %d ;\n\
2668 lv2:symbol \"tuning\" ;\n\
2669 lv2:name \"tuning\" ;\n\
2670 lv2:portProperty epp:hasStrictBounds ;\n\
2671 lv2:portProperty lv2:integer ;\n\
2672 epp:rangeSteps %d ;\n\
2673 lv2:default 0 ;\n\
2674 lv2:minimum 0 ;\n\
2675 lv2:maximum %d ;\n",
2676 idx==0?" lv2:port":" ,", idx, plugin->n_tunings, plugin->n_tunings);
2677 for (int i = 0; i <= plugin->n_tunings; i++)
2678 fprintf(fp, "\
2679 lv2:scalePoint [ rdfs:label \"%s\"; rdf:value %d ] ;\n",
2680 (i>0)?plugin->mts->tuning[i-1].name:"default", i);
2681 fprintf(fp, " ]");
2682 idx++;
2683 }
2684 #endif
2685 }
2686 fprintf(fp, "\n.\n");
2687 return 0;
2688 }
2689
2690 extern "C"
2691 LV2_SYMBOL_EXPORT
lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle)2692 void lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle)
2693 {
2694 LV2Plugin* plugin = (LV2Plugin*)handle;
2695 delete plugin;
2696 }
2697
main()2698 int main()
2699 {
2700 LV2_Dyn_Manifest_Handle handle;
2701 LV2_Feature **features = { NULL };
2702 int res = lv2_dyn_manifest_open(&handle, features);
2703 if (res) return res;
2704 res = lv2_dyn_manifest_get_data(handle, stdout, PLUGIN_URI);
2705 return res;
2706 }
2707
2708 #endif
2709