1 /************************************************************************
2 ************************************************************************
3 FAUST Architecture File
4 Copyright (C) 2009-2016 Albert Graef <aggraef@gmail.com>
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 3 of the
9 License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20 ************************************************************************
21 ************************************************************************/
22
23 /* LV2 architecture for Faust synths. */
24
25 /* NOTE: This requires one of the Boost headers (boost/circular_buffer.hpp),
26 so to compile Faust programs created with this architecture you need to
27 have at least the Boost headers installed somewhere on your include path
28 (the Boost libraries aren't needed). */
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33 #include <list>
34 #include <map>
35 #include <set>
36
37 // generic Faust dsp and UI classes
38 #include <faust/dsp/dsp.h>
39 #include <faust/gui/UI.h>
40
41 using namespace std;
42
43 typedef pair<const char*,const char*> strpair;
44
45 struct Meta : std::map<const char*, const char*>
46 {
declareMeta47 void declare(const char *key, const char *value)
48 {
49 (*this)[key] = value;
50 }
getMeta51 const char* get(const char *key, const char *def)
52 {
53 if (this->find(key) != this->end())
54 return (*this)[key];
55 else
56 return def;
57 }
58 };
59
60 /******************************************************************************
61 *******************************************************************************
62
63 VECTOR INTRINSICS
64
65 *******************************************************************************
66 *******************************************************************************/
67
68 <<includeIntrinsic>>
69
70 /***************************************************************************
71 LV2 UI interface
72 ***************************************************************************/
73
74 enum ui_elem_type_t {
75 UI_BUTTON, UI_CHECK_BUTTON,
76 UI_V_SLIDER, UI_H_SLIDER, UI_NUM_ENTRY,
77 UI_V_BARGRAPH, UI_H_BARGRAPH,
78 UI_END_GROUP, UI_V_GROUP, UI_H_GROUP, UI_T_GROUP
79 };
80
81 struct ui_elem_t {
82 ui_elem_type_t type;
83 const char *label;
84 int port;
85 float *zone;
86 void *ref;
87 float init, min, max, step;
88 };
89
90 class LV2UI : public UI
91 {
92 public:
93 bool is_instr;
94 int nelems, nports;
95 ui_elem_t *elems;
96 map< int, list<strpair> > metadata;
97
98 LV2UI(int maxvoices = 0);
99 virtual ~LV2UI();
100
101 protected:
102 void add_elem(ui_elem_type_t type, const char *label = NULL);
103 void add_elem(ui_elem_type_t type, const char *label, float *zone);
104 void add_elem(ui_elem_type_t type, const char *label, float *zone,
105 float init, float min, float max, float step);
106 void add_elem(ui_elem_type_t type, const char *label, float *zone,
107 float min, float max);
108
109 bool have_freq, have_gain, have_gate;
110 bool is_voice_ctrl(const char *label);
111
112 public:
113 virtual void addButton(const char* label, float* zone);
114 virtual void addCheckButton(const char* label, float* zone);
115 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step);
116 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step);
117 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step);
118
119 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max);
120 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max);
121
addSoundfile(const char * label,const char * filename,Soundfile ** sf_zone)122 virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
123
124 virtual void openTabBox(const char* label);
125 virtual void openHorizontalBox(const char* label);
126 virtual void openVerticalBox(const char* label);
127 virtual void closeBox();
128
129 virtual void run();
130
131 virtual void declare(float* zone, const char* key, const char* value);
132 };
133
LV2UI(int maxvoices)134 LV2UI::LV2UI(int maxvoices)
135 {
136 is_instr = maxvoices>0;
137 have_freq = have_gain = have_gate = false;
138 nelems = nports = 0;
139 elems = NULL;
140 }
141
~LV2UI()142 LV2UI::~LV2UI()
143 {
144 if (elems) free(elems);
145 }
146
declare(float * zone,const char * key,const char * value)147 void LV2UI::declare(float* zone, const char* key, const char* value)
148 {
149 map< int, list<strpair> >::iterator it = metadata.find(nelems);
150 if (it != metadata.end())
151 it->second.push_back(strpair(key, value));
152 else
153 metadata[nelems] = list<strpair>(1, strpair(key, value));
154 }
155
add_elem(ui_elem_type_t type,const char * label)156 inline void LV2UI::add_elem(ui_elem_type_t type, const char *label)
157 {
158 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
159 if (elems1)
160 elems = elems1;
161 else
162 return;
163 elems[nelems].type = type;
164 elems[nelems].label = label;
165 elems[nelems].port = -1;
166 elems[nelems].zone = NULL;
167 elems[nelems].ref = NULL;
168 elems[nelems].init = 0.0;
169 elems[nelems].min = 0.0;
170 elems[nelems].max = 0.0;
171 elems[nelems].step = 0.0;
172 nelems++;
173 }
174
175 #define portno(label) (is_voice_ctrl(label)?-1:nports++)
176
add_elem(ui_elem_type_t type,const char * label,float * zone)177 inline void LV2UI::add_elem(ui_elem_type_t type, const char *label, float *zone)
178 {
179 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
180 if (elems1)
181 elems = elems1;
182 else
183 return;
184 elems[nelems].type = type;
185 elems[nelems].label = label;
186 elems[nelems].port = portno(label);
187 elems[nelems].zone = zone;
188 elems[nelems].ref = NULL;
189 elems[nelems].init = 0.0;
190 elems[nelems].min = 0.0;
191 elems[nelems].max = 0.0;
192 elems[nelems].step = 0.0;
193 nelems++;
194 }
195
add_elem(ui_elem_type_t type,const char * label,float * zone,float init,float min,float max,float step)196 inline void LV2UI::add_elem(ui_elem_type_t type, const char *label, float *zone,
197 float init, float min, float max, float step)
198 {
199 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
200 if (elems1)
201 elems = elems1;
202 else
203 return;
204 elems[nelems].type = type;
205 elems[nelems].label = label;
206 elems[nelems].port = portno(label);
207 elems[nelems].zone = zone;
208 elems[nelems].ref = NULL;
209 elems[nelems].init = init;
210 elems[nelems].min = min;
211 elems[nelems].max = max;
212 elems[nelems].step = step;
213 nelems++;
214 }
215
add_elem(ui_elem_type_t type,const char * label,float * zone,float min,float max)216 inline void LV2UI::add_elem(ui_elem_type_t type, const char *label, float *zone,
217 float min, float max)
218 {
219 ui_elem_t *elems1 = (ui_elem_t*)realloc(elems, (nelems+1)*sizeof(ui_elem_t));
220 if (elems1)
221 elems = elems1;
222 else
223 return;
224 elems[nelems].type = type;
225 elems[nelems].label = label;
226 elems[nelems].port = portno(label);
227 elems[nelems].zone = zone;
228 elems[nelems].ref = NULL;
229 elems[nelems].init = 0.0;
230 elems[nelems].min = min;
231 elems[nelems].max = max;
232 elems[nelems].step = 0.0;
233 nelems++;
234 }
235
is_voice_ctrl(const char * label)236 inline bool LV2UI::is_voice_ctrl(const char *label)
237 {
238 if (!is_instr)
239 return false;
240 else if (!have_freq && !strcmp(label, "freq"))
241 return (have_freq = true);
242 else if (!have_gain && !strcmp(label, "gain"))
243 return (have_gain = true);
244 else if (!have_gate && !strcmp(label, "gate"))
245 return (have_gate = true);
246 else
247 return false;
248 }
249
addButton(const char * label,float * zone)250 void LV2UI::addButton(const char* label, float* zone)
251 { add_elem(UI_BUTTON, label, zone); }
addCheckButton(const char * label,float * zone)252 void LV2UI::addCheckButton(const char* label, float* zone)
253 { add_elem(UI_CHECK_BUTTON, label, zone); }
addVerticalSlider(const char * label,float * zone,float init,float min,float max,float step)254 void LV2UI::addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
255 { 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)256 void LV2UI::addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
257 { 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)258 void LV2UI::addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
259 { add_elem(UI_NUM_ENTRY, label, zone, init, min, max, step); }
260
addHorizontalBargraph(const char * label,float * zone,float min,float max)261 void LV2UI::addHorizontalBargraph(const char* label, float* zone, float min, float max)
262 { add_elem(UI_H_BARGRAPH, label, zone, min, max); }
addVerticalBargraph(const char * label,float * zone,float min,float max)263 void LV2UI::addVerticalBargraph(const char* label, float* zone, float min, float max)
264 { add_elem(UI_V_BARGRAPH, label, zone, min, max); }
265
openTabBox(const char * label)266 void LV2UI::openTabBox(const char* label)
267 { add_elem(UI_T_GROUP, label); }
openHorizontalBox(const char * label)268 void LV2UI::openHorizontalBox(const char* label)
269 { add_elem(UI_H_GROUP, label); }
openVerticalBox(const char * label)270 void LV2UI::openVerticalBox(const char* label)
271 { add_elem(UI_V_GROUP, label); }
closeBox()272 void LV2UI::closeBox()
273 { add_elem(UI_END_GROUP); }
274
run()275 void LV2UI::run() {}
276
277 //----------------------------------------------------------------------------
278 // FAUST generated signal processor
279 //----------------------------------------------------------------------------
280
281 <<includeclass>>
282
283 //----------------------------------------------------------------------------
284 // LV2 interface
285 //----------------------------------------------------------------------------
286
287 #line 286 "lv2.cpp"
288
289 #include <assert.h>
290 #include <stdio.h>
291 #include <stdlib.h>
292
293 #include <bitset>
294 #include <boost/circular_buffer.hpp>
295
296 #include <lv2/lv2plug.in/ns/lv2core/lv2.h>
297 #include <lv2/lv2plug.in/ns/ext/dynmanifest/dynmanifest.h>
298 #include <lv2/lv2plug.in/ns/ext/atom/util.h>
299 #include <lv2/lv2plug.in/ns/ext/urid/urid.h>
300
301 // Set this to the proper shared library extension for your system
302 #ifndef DLLEXT
303 #define DLLEXT ".so"
304 #endif
305
306 #ifndef URI_PREFIX
307 #define URI_PREFIX "https://faustlv2.bitbucket.io"
308 #endif
309
310 #ifndef PLUGIN_URI
311 #define PLUGIN_URI URI_PREFIX "/mydsp"
312 #endif
313
314 #define MIDI_EVENT_URI "http://lv2plug.in/ns/ext/midi#MidiEvent"
315
316 /* Setting NVOICES at compile time overrides meta data in the Faust source. If
317 set, this must be an integer value >= 0. A nonzero value indicates an
318 instrument (VSTi) plugin with the given maximum number of voices. Use 1 for
319 a monophonic synthesizer, and 0 for a simple effect plugin. If NVOICES
320 isn't defined at compile time then the number of voices of an instrument
321 plugin can also be set with the global "nvoices" meta data key in the Faust
322 source. This setting also adds a special "polyphony" control to the plugin
323 which can be used to dynamically adjust the actual number of voices in the
324 range 1..NVOICES. */
325 //#define NVOICES 16
326
327 /* This enables a special "tuning" control for instruments which lets you
328 select the MTS tuning to be used for the synth. In order to use this, you
329 just drop some sysex (.syx) files with MTS octave-based tunings in 1- or
330 2-byte format into the ~/.fautvst/tuning directory (these can be generated
331 with the author's sclsyx program, https://bitbucket.org/agraef/sclsyx).
332 The control will only be shown if any .syx files were found at startup. 0
333 selects the default tuning (standard 12-tone equal temperament), i>0 the
334 tuning in the ith sysex file (in alphabetic order). */
335 #ifndef FAUST_MTS
336 #define FAUST_MTS 1
337 #endif
338
339 /* This allows various manifest data to be generated from the corresponding
340 metadata (author, name, description, license) in the Faust source. */
341 #ifndef FAUST_META
342 #define FAUST_META 1
343 #endif
344
345 /* This enables automatic MIDI controller mapping based on the midi:ctrl
346 attributes in the Faust source. We have this enabled by default, but you
347 may have to disable it if the custom controller mapping gets in the way of
348 the automation facilities that the host provides. (But then again if the
349 host wants to do its own controller mapping then it probably won't, or at
350 least shouldn't, send us the MIDI controllers in the first place.) */
351 #ifndef FAUST_MIDICC
352 #define FAUST_MIDICC 1
353 #endif
354
355 /* This enables or disables the plugin's custom Qt GUI (cf. lv2ui.cpp). Note
356 that this only affects the plugin manifest, the GUI code itself is in a
357 separate module created with the lv2ui.cpp architecture. Also, you'll have
358 to use the alternative lv2ui manifest templates to tell the LV2 host about
359 the GUI. */
360 #ifndef FAUST_UI
361 #define FAUST_UI 0
362 #endif
363
364 // You can define these for various debugging output items.
365 //#define DEBUG_META 1 // recognized MIDI controller metadata
366 //#define DEBUG_VOICES 1 // triggering of synth voices
367 //#define DEBUG_VOICE_ALLOC 1 // voice allocation
368 //#define DEBUG_MIDI 1 // incoming MIDI messages
369 //#define DEBUG_NOTES 1 // note messages
370 //#define DEBUG_MIDICC 1 // controller messages
371 //#define DEBUG_RPN 1 // RPN messages (pitch bend range, master tuning)
372 //#define DEBUG_MTS 1 // MTS messages (octave/scale tuning)
373
374 // Note and voice data structures.
375
376 struct NoteInfo {
377 uint8_t ch;
378 int8_t note;
379 };
380
381 struct VoiceData {
382 // Octave tunings (offsets in semitones) per MIDI channel.
383 float tuning[16][12];
384 // Allocated voices per MIDI channel and note.
385 int8_t notes[16][128];
386 // Free and used voices.
387 int n_free, n_used;
388 boost::circular_buffer<int> free_voices;
389 boost::circular_buffer<int> used_voices;
390 NoteInfo *note_info;
391 // Voices queued for note-offs (zero-length notes).
392 set<int> queued;
393 // Last gate value during run() for each voice. We need to keep track of
394 // these so that we can force the Faust synth to retrigger a note when
395 // needed.
396 float *lastgate;
397 // Current pitch bend and pitch bend range on each MIDI channel, in semitones.
398 float bend[16], range[16];
399 // Current coarse, fine and total master tuning on each MIDI channel (tuning
400 // offset relative to A4 = 440 Hz, in semitones).
401 float coarse[16], fine[16], tune[16];
VoiceDataVoiceData402 VoiceData(int n) : free_voices(n), used_voices(n) { }
403 };
404
405 #if FAUST_MTS
406
407 // Helper classes to read and store MTS tunings.
408
409 #include <sys/types.h>
410 #include <sys/stat.h>
411 #include <dirent.h>
412
413 #include <string>
414 #include <vector>
415
416 struct MTSTuning {
417 char *name; // name of the tuning
418 int len; // length of sysex data in bytes
419 unsigned char *data; // sysex data
MTSTuningMTSTuning420 MTSTuning() : name(0), len(0), data(0) {}
operator =MTSTuning421 MTSTuning& operator=(const MTSTuning &t)
422 {
423 if (this == &t) return *this;
424 if (name) free(name); if (data) free(data);
425 name = 0; data = 0; len = t.len;
426 if (t.name) {
427 name = strdup(t.name); assert(name);
428 }
429 if (t.data) {
430 data = (unsigned char*)malloc(len); assert(data);
431 memcpy(data, t.data, len);
432 }
433 return *this;
434 }
MTSTuningMTSTuning435 MTSTuning(const MTSTuning& t) : name(0), len(0), data(0)
436 { *this = t; }
437 MTSTuning(const char *filename);
~MTSTuningMTSTuning438 ~MTSTuning()
439 { if (name) free(name); if (data) free(data); }
440 };
441
MTSTuning(const char * filename)442 MTSTuning::MTSTuning(const char *filename)
443 {
444 FILE *fp = fopen(filename, "rb");
445 name = 0; len = 0; data = 0;
446 if (!fp) return;
447 struct stat st;
448 if (fstat(fileno(fp), &st)) return;
449 len = st.st_size;
450 data = (unsigned char*)calloc(len, 1);
451 if (!data) {
452 len = 0; fclose(fp);
453 return;
454 }
455 assert(len > 0);
456 if (fread(data, 1, len, fp) < len) {
457 free(data); len = 0; data = 0; fclose(fp);
458 return;
459 }
460 fclose(fp);
461 // Do some basic sanity checks.
462 if (data[0] != 0xf0 || data[len-1] != 0xf7 || // not a sysex message
463 (data[1] != 0x7e && data[1] != 0x7f) || data[3] != 8 || // not MTS
464 !((len == 21 && data[4] == 8) ||
465 (len == 33 && data[4] == 9))) { // no 1- or 2-byte tuning
466 free(data); len = 0; data = 0;
467 return;
468 }
469 // Name of the tuning is the basename of the file, without the trailing .syx
470 // suffix.
471 string nm = filename;
472 size_t p = nm.rfind(".syx");
473 if (p != string::npos) nm.erase(p);
474 p = nm.rfind('/');
475 if (p != string::npos) nm.erase(0, p+1);
476 name = strdup(nm.c_str());
477 assert(name);
478 }
479
480 struct MTSTunings {
481 vector<MTSTuning> tuning;
MTSTuningsMTSTunings482 MTSTunings() {}
483 MTSTunings(const char *path);
484 };
485
compareByName(const MTSTuning & a,const MTSTuning & b)486 static bool compareByName(const MTSTuning &a, const MTSTuning &b)
487 {
488 return strcmp(a.name, b.name) < 0;
489 }
490
MTSTunings(const char * path)491 MTSTunings::MTSTunings(const char *path)
492 {
493 DIR *dp = opendir(path);
494 if (!dp) return;
495 struct dirent *d;
496 while ((d = readdir(dp))) {
497 string nm = d->d_name;
498 if (nm.length() > 4 && nm.substr(nm.length()-4) == ".syx") {
499 string pathname = path;
500 pathname += "/";
501 pathname += nm;
502 MTSTuning t(pathname.c_str());
503 if (t.data) tuning.push_back(t);
504 }
505 }
506 closedir(dp);
507 // sort found tunings by name
508 sort(tuning.begin(), tuning.end(), compareByName);
509 }
510
511 #endif
512
513 #if FAUST_MIDICC
ctrlval(const ui_elem_t & el,uint8_t v)514 static float ctrlval(const ui_elem_t &el, uint8_t v)
515 {
516 // Translate the given MIDI controller value to the range and stepsize
517 // indicated by the Faust control.
518 switch (el.type) {
519 case UI_BUTTON: case UI_CHECK_BUTTON:
520 return (float)(v>=64);
521 default:
522 /* Continuous controllers. The problem here is that the range 0..127 is
523 not symmetric. We'd like to map 64 to the center of the range
524 (max-min)/2 and at the same time retain the full control range
525 min..max. So let's just pretend that there are 128 controller values
526 and map value 127 to the max value anyway. */
527 if (v==127)
528 return el.max;
529 else
530 // XXXFIXME: We might want to add proper quantization according to
531 // el.step here.
532 return el.min+(el.max-el.min)*v/128;
533 }
534 }
535 #endif
536
537 /***************************************************************************/
538
539 /* Polyphonic Faust plugin data structure. XXXTODO: At present this is just a
540 big struct which exposes all requisite data. Some more work is needed to
541 make the interface a bit more abstract and properly encapsulate the
542 internal data structures, so that implementation details can be changed
543 more easily. */
544
545 struct LV2Plugin {
546 const int maxvoices; // maximum number of voices (zero if not an instrument)
547 const int ndsps; // number of dsp instances (1 if maxvoices==0)
548 bool active; // activation status
549 int rate; // sampling rate
550 int nvoices; // current number of voices (<= maxvoices)
551 int tuning_no; // current tuning number (<= n_tunings)
552 mydsp **dsp; // the dsps
553 LV2UI **ui; // their Faust interface descriptions
554 int n_in, n_out; // number of input and output control ports
555 int *ctrls; // Faust ui elements (indices into ui->elems)
556 float **ports; // corresponding LV2 data
557 float *portvals; // cached port data from the last run
558 float *midivals[16]; // per-midi channel data
559 int *inctrls, *outctrls; // indices for active and passive controls
560 float **inputs, **outputs; // audio buffers
561 int freq, gain, gate; // indices of voice controls
562 unsigned n_samples; // current block size
563 float **outbuf; // audio buffers for mixing down the voices
564 float **inbuf; // dummy input buffer
565 LV2_Atom_Sequence* event_port; // midi input
566 float *poly, *tuning; // polyphony and tuning ports
567 std::map<uint8_t,int> ctrlmap; // MIDI controller map
568 // Needed host features.
569 LV2_URID_Map* map; // the urid extension
570 LV2_URID midi_event; // midi event uri
571 // Current RPN MSB and LSB numbers, as set with controllers 101 and 100.
572 uint8_t rpn_msb[16], rpn_lsb[16];
573 // Current data entry MSB and LSB numbers, as set with controllers 6 and 38.
574 uint8_t data_msb[16], data_lsb[16];
575 // Synth voice data (instruments only).
576 VoiceData *vd;
577
578 // Static methods. These all use static data so they can be invoked before
579 // instantiating a plugin.
580
581 // Global meta data (dsp name, author, etc.).
582 static Meta *meta;
init_metaLV2Plugin583 static void init_meta()
584 {
585 if (!meta && (meta = new Meta)) {
586 // We allocate the temporary dsp object on the heap here, to prevent
587 // large dsp objects from running out of stack in environments where
588 // stack space is precious (e.g., Reaper). Note that if any of these
589 // allocations fail then no meta data will be available, but at least we
590 // won't make the host crash and burn.
591 mydsp* tmp_dsp = new mydsp();
592 if (tmp_dsp) {
593 tmp_dsp->metadata(meta);
594 delete tmp_dsp;
595 }
596 }
597 }
meta_getLV2Plugin598 static const char *meta_get(const char *key, const char *deflt)
599 {
600 init_meta();
601 return meta?meta->get(key, deflt):deflt;
602 }
603
pluginNameLV2Plugin604 static const char *pluginName()
605 {
606 return meta_get("name", "mydsp");
607 }
608
pluginAuthorLV2Plugin609 static const char *pluginAuthor()
610 {
611 return meta_get("author", "");
612 }
613
pluginDescriptionLV2Plugin614 static const char *pluginDescription()
615 {
616 return meta_get("description", "");
617 }
618
pluginLicenseLV2Plugin619 static const char *pluginLicense()
620 {
621 return meta_get("license", "");
622 }
623
pluginVersionLV2Plugin624 static const char *pluginVersion()
625 {
626 return meta_get("version", "");
627 }
628
629 // Load a collection of sysex files with MTS tunings in ~/.faust/tuning.
630 static int n_tunings;
631 #if FAUST_MTS
632 static MTSTunings *mts;
633
load_sysex_dataLV2Plugin634 static MTSTunings *load_sysex_data()
635 {
636 if (!mts) {
637 string mts_path;
638 // Look for FAUST_HOME. If that isn't set, try $HOME/.faust. If HOME
639 // isn't set either, just assume a .faust subdir of the cwd.
640 const char *home = getenv("FAUST_HOME");
641 if (home)
642 mts_path = home;
643 else {
644 home = getenv("HOME");
645 if (home) {
646 mts_path = home;
647 mts_path += "/.faust";
648 } else
649 mts_path = ".faust";
650 }
651 // MTS tunings are looked for in this subdir.
652 mts_path += "/tuning";
653 mts = new MTSTunings(mts_path.c_str());
654 #ifdef __APPLE__
655 if (!mts || mts->tuning.size() == 0) {
656 // Also check ~/Library/Faust/Tuning on the Mac.
657 home = getenv("HOME");
658 if (home) {
659 if (mts) delete mts;
660 mts_path = home;
661 mts_path += "/Library/Faust/Tuning";
662 mts = new MTSTunings(mts_path.c_str());
663 }
664 }
665 #endif
666 n_tunings = mts->tuning.size();
667 }
668 return mts;
669 }
670 #endif
671
672 // The number of voices of an instrument plugin. We get this information
673 // from the global meta data (nvoices key) of the dsp module if present, and
674 // you can also override this setting at compile time by defining the
675 // NVOICES macro. If neither is defined or the value is zero then the plugin
676 // becomes a simple audio effect instead.
numVoicesLV2Plugin677 static int numVoices()
678 {
679 #ifdef NVOICES
680 return NVOICES;
681 #else
682 const char *numVoices = meta_get("nvoices", "0");
683 int nvoices = atoi(numVoices);
684 if (nvoices < 0 ) nvoices = 0;
685 return nvoices;
686 #endif
687 }
688
689 // Instance methods.
690
LV2PluginLV2Plugin691 LV2Plugin(const int num_voices, const int sr)
692 : maxvoices(num_voices), ndsps(num_voices<=0?1:num_voices),
693 vd(num_voices>0?new VoiceData(num_voices):0)
694 {
695 // Initialize static data.
696 init_meta();
697 #if FAUST_MTS
698 // Synth: load tuning sysex data if present.
699 if (num_voices>0) load_sysex_data();
700 #endif
701 // Allocate data structures and set some reasonable defaults.
702 dsp = (mydsp**)calloc(ndsps, sizeof(mydsp*));
703 ui = (LV2UI**)calloc(ndsps, sizeof(LV2UI*));
704 assert(dsp && ui);
705 if (vd) {
706 vd->note_info = (NoteInfo*)calloc(ndsps, sizeof(NoteInfo));
707 vd->lastgate = (float*)calloc(ndsps, sizeof(float));
708 assert(vd->note_info && vd->lastgate);
709 }
710 active = false;
711 rate = sr;
712 nvoices = maxvoices;
713 tuning_no = 0;
714 n_in = n_out = 0;
715 map = NULL;
716 midi_event = -1;
717 event_port = NULL;
718 poly = tuning = NULL;
719 freq = gain = gate = -1;
720 if (vd) {
721 vd->n_free = maxvoices;
722 for (int i = 0; i < maxvoices; i++) {
723 vd->free_voices.push_back(i);
724 vd->lastgate[i] = 0.0f;
725 }
726 for (int i = 0; i < 16; i++) {
727 vd->bend[i] = 0.0f;
728 vd->range[i] = 2.0f;
729 vd->coarse[i] = vd->fine[i] = vd->tune[i] = 0.0f;
730 for (int j = 0; j < 12; j++)
731 vd->tuning[i][j] = 0.0f;
732 }
733 vd->n_used = 0;
734 memset(vd->notes, 0xff, sizeof(vd->notes));
735 }
736 n_samples = 0;
737 ctrls = inctrls = outctrls = NULL;
738 ports = inputs = outputs = inbuf = outbuf = NULL;
739 portvals = NULL;
740 memset(midivals, 0, sizeof(midivals));
741 // Initialize the Faust DSPs.
742 for (int i = 0; i < ndsps; i++) {
743 dsp[i] = new mydsp();
744 ui[i] = new LV2UI(num_voices);
745 dsp[i]->init(rate);
746 dsp[i]->buildUserInterface(ui[i]);
747 }
748 // The ports are numbered as follows: 0..k-1 are the control ports, then
749 // come the n audio input ports, then the m audio output ports, and
750 // finally the midi input port and the polyphony and tuning controls.
751 int k = ui[0]->nports, p = 0, q = 0;
752 int n = dsp[0]->getNumInputs(), m = dsp[0]->getNumOutputs();
753 // Allocate tables for the built-in control elements and their ports.
754 ctrls = (int*)calloc(k, sizeof(int));
755 inctrls = (int*)calloc(k, sizeof(int));
756 outctrls = (int*)calloc(k, sizeof(int));
757 ports = (float**)calloc(k, sizeof(float*));
758 portvals = (float*)calloc(k, sizeof(float));
759 assert(k == 0 || (ctrls && inctrls && outctrls && ports && portvals));
760 for (int ch = 0; ch < 16; ch++) {
761 midivals[ch] = (float*)calloc(k, sizeof(float));
762 assert(k == 0 || midivals[ch]);
763 }
764 // Scan the Faust UI for active and passive controls which become the
765 // input and output control ports of the plugin, respectively.
766 for (int i = 0, j = 0; i < ui[0]->nelems; i++) {
767 switch (ui[0]->elems[i].type) {
768 case UI_T_GROUP: case UI_H_GROUP: case UI_V_GROUP: case UI_END_GROUP:
769 // control groups (ignored right now)
770 break;
771 case UI_H_BARGRAPH: case UI_V_BARGRAPH:
772 // passive controls (output ports)
773 ctrls[j++] = i;
774 outctrls[q++] = i;
775 break;
776 default:
777 // active controls (input ports)
778 if (maxvoices == 0)
779 goto noinstr;
780 else if (freq == -1 &&
781 !strcmp(ui[0]->elems[i].label, "freq"))
782 freq = i;
783 else if (gain == -1 &&
784 !strcmp(ui[0]->elems[i].label, "gain"))
785 gain = i;
786 else if (gate == -1 &&
787 !strcmp(ui[0]->elems[i].label, "gate"))
788 gate = i;
789 else {
790 noinstr:
791 #if FAUST_MIDICC
792 std::map< int, list<strpair> >::iterator it =
793 ui[0]->metadata.find(i);
794 if (it != ui[0]->metadata.end()) {
795 // Scan for controller mappings.
796 for (std::list<strpair>::iterator jt = it->second.begin();
797 jt != it->second.end(); jt++) {
798 const char *key = jt->first, *val = jt->second;
799 #if DEBUG_META
800 fprintf(stderr, "ctrl '%s' meta: '%s' -> '%s'\n",
801 ui[0]->elems[i].label, key, val);
802 #endif
803 if (strcmp(key, "midi") == 0) {
804 unsigned num;
805 if (sscanf(val, "ctrl %u", &num) < 1) continue;
806 #if 0 // enable this to get feedback about controller assignments
807 fprintf(stderr, "%s: cc %d -> %s\n", PLUGIN_URI, num,
808 ui[0]->elems[i].label);
809 #endif
810 ctrlmap.insert(std::pair<uint8_t,int>(num, p));
811 }
812 }
813 }
814 #endif
815 ctrls[j++] = i;
816 inctrls[p++] = i;
817 int p = ui[0]->elems[i].port;
818 float val = ui[0]->elems[i].init;
819 assert(p>=0);
820 portvals[p] = val;
821 for (int ch = 0; ch < 16; ch++)
822 midivals[ch][p] = val;
823 }
824 break;
825 }
826 }
827 // Realloc the inctrls and outctrls vectors to their appropriate sizes.
828 inctrls = (int*)realloc(inctrls, p*sizeof(int));
829 assert(p == 0 || inctrls);
830 outctrls = (int*)realloc(outctrls, q*sizeof(int));
831 assert(q == 0 || outctrls);
832 n_in = p; n_out = q;
833 // Allocate vectors for the audio input and output ports. Like
834 // ports, these will be initialized in the connect_port callback.
835 inputs = (float**)calloc(n, sizeof(float*));
836 assert(n == 0 || inputs);
837 outputs = (float**)calloc(m, sizeof(float*));
838 assert(m == 0 || outputs);
839 if (maxvoices > 0) {
840 // Initialize the mixdown buffer.
841 outbuf = (float**)calloc(m, sizeof(float*));
842 assert(m == 0 || outbuf);
843 // We start out with a blocksize of 512 samples here. Hopefully this is
844 // enough for most realtime hosts so that we can avoid reallocations
845 // later when we know what the actual blocksize is.
846 n_samples = 512;
847 for (int i = 0; i < m; i++) {
848 outbuf[i] = (float*)malloc(n_samples*sizeof(float));
849 assert(outbuf[i]);
850 }
851 // Initialize a 1-sample dummy input buffer used for retriggering notes.
852 inbuf = (float**)calloc(n, sizeof(float*));
853 assert(n == 0 || inbuf);
854 for (int i = 0; i < m; i++) {
855 inbuf[i] = (float*)malloc(sizeof(float));
856 assert(inbuf[i]);
857 *inbuf[i] = 0.0f;
858 }
859 }
860 }
861
~LV2PluginLV2Plugin862 ~LV2Plugin()
863 {
864 const int n = dsp[0]->getNumInputs();
865 const int m = dsp[0]->getNumOutputs();
866 for (int i = 0; i < ndsps; i++) {
867 delete dsp[i];
868 delete ui[i];
869 }
870 free(ctrls); free(inctrls); free(outctrls);
871 free(ports); free(portvals);
872 free(inputs); free(outputs);
873 for (int ch = 0; ch < 16; ch++)
874 free(midivals[ch]);
875 if (inbuf) {
876 for (int i = 0; i < n; i++)
877 free(inbuf[i]);
878 free(inbuf);
879 }
880 if (outbuf) {
881 for (int i = 0; i < m; i++)
882 free(outbuf[i]);
883 free(outbuf);
884 }
885 free(dsp); free(ui);
886 if (vd) {
887 free(vd->note_info);
888 free(vd->lastgate);
889 delete vd;
890 }
891 }
892 // Voice allocation.
893
894 #if DEBUG_VOICE_ALLOC
print_voicesLV2Plugin895 void print_voices(const char *msg)
896 {
897 fprintf(stderr, "%s: notes =", msg);
898 for (uint8_t ch = 0; ch < 16; ch++)
899 for (int note = 0; note < 128; note++)
900 if (vd->notes[ch][note] >= 0)
901 fprintf(stderr, " [%d] %d(#%d)", ch, note, vd->notes[ch][note]);
902 fprintf(stderr, "\nqueued (%d):", vd->queued.size());
903 for (int i = 0; i < nvoices; i++)
904 if (vd->queued.find(i) != vd->queued.end()) fprintf(stderr, " #%d", i);
905 fprintf(stderr, "\nused (%d):", vd->n_used);
906 for (boost::circular_buffer<int>::iterator it = vd->used_voices.begin();
907 it != vd->used_voices.end(); it++)
908 fprintf(stderr, " #%d->%d", *it, vd->note_info[*it].note);
909 fprintf(stderr, "\nfree (%d):", vd->n_free);
910 for (boost::circular_buffer<int>::iterator it = vd->free_voices.begin();
911 it != vd->free_voices.end(); it++)
912 fprintf(stderr, " #%d", *it);
913 fprintf(stderr, "\n");
914 }
915 #endif
916
alloc_voiceLV2Plugin917 int alloc_voice(uint8_t ch, int8_t note, int8_t vel)
918 {
919 int i = vd->notes[ch][note];
920 if (i >= 0) {
921 // note already playing on same channel, retrigger it
922 voice_off(i);
923 voice_on(i, note, vel, ch);
924 // move this voice to the end of the used list
925 for (boost::circular_buffer<int>::iterator it =
926 vd->used_voices.begin();
927 it != vd->used_voices.end(); it++) {
928 if (*it == i) {
929 vd->used_voices.erase(it);
930 vd->used_voices.push_back(i);
931 break;
932 }
933 }
934 #if DEBUG_VOICE_ALLOC
935 print_voices("retrigger");
936 #endif
937 return i;
938 } else if (vd->n_free > 0) {
939 // take voice from free list
940 int i = vd->free_voices.front();
941 vd->free_voices.pop_front();
942 vd->n_free--;
943 vd->used_voices.push_back(i);
944 vd->note_info[i].ch = ch;
945 vd->note_info[i].note = note;
946 vd->n_used++;
947 voice_on(i, note, vel, ch);
948 vd->notes[ch][note] = i;
949 #if DEBUG_VOICE_ALLOC
950 print_voices("alloc");
951 #endif
952 return i;
953 } else {
954 // steal a voice
955 assert(vd->n_used > 0);
956 // FIXME: Maybe we should look for the oldest note on the *current*
957 // channel here, but this is faster.
958 int i = vd->used_voices.front();
959 int oldch = vd->note_info[i].ch;
960 int oldnote = vd->note_info[i].note;
961 voice_off(i);
962 vd->notes[oldch][oldnote] = -1;
963 vd->queued.erase(i);
964 vd->used_voices.pop_front();
965 vd->used_voices.push_back(i);
966 vd->note_info[i].ch = ch;
967 vd->note_info[i].note = note;
968 voice_on(i, note, vel, ch);
969 vd->notes[ch][note] = i;
970 #if DEBUG_VOICE_ALLOC
971 print_voices("steal");
972 #endif
973 return i;
974 }
975 }
976
dealloc_voiceLV2Plugin977 int dealloc_voice(uint8_t ch, int8_t note, int8_t vel)
978 {
979 int i = vd->notes[ch][note];
980 if (i >= 0) {
981 if (vd->lastgate[i] == 0.0f && gate >= 0) {
982 // zero-length note, queued for later
983 vd->queued.insert(i);
984 vd->notes[ch][note] = -1;
985 #if DEBUG_VOICE_ALLOC
986 print_voices("dealloc (queued)");
987 #endif
988 return i;
989 }
990 assert(vd->n_free < nvoices);
991 vd->free_voices.push_back(i);
992 vd->n_free++;
993 voice_off(i);
994 vd->notes[ch][note] = -1;
995 // erase this voice from the used list
996 for (boost::circular_buffer<int>::iterator it =
997 vd->used_voices.begin();
998 it != vd->used_voices.end(); it++) {
999 if (*it == i) {
1000 vd->used_voices.erase(it);
1001 vd->n_used--;
1002 break;
1003 }
1004 }
1005 #if DEBUG_VOICE_ALLOC
1006 print_voices("dealloc");
1007 #endif
1008 return i;
1009 }
1010 return -1;
1011 }
1012
1013
midicpsLV2Plugin1014 float midicps(int8_t note, uint8_t chan)
1015 {
1016 float pitch = note + vd->tune[chan] +
1017 vd->tuning[chan][note%12] + vd->bend[chan];
1018 return 440.0*pow(2, (pitch-69.0)/12.0);
1019 }
1020
voice_onLV2Plugin1021 void voice_on(int i, int8_t note, int8_t vel, uint8_t ch)
1022 {
1023 if (vd->lastgate[i] == 1.0f && gate >= 0) {
1024 // Make sure that the synth sees the 0.0f gate so that the voice is
1025 // properly retriggered.
1026 *ui[i]->elems[gate].zone = 0.0f;
1027 dsp[i]->compute(1, inbuf, outbuf);
1028 }
1029 #if DEBUG_VOICES
1030 fprintf(stderr, "voice on: %d %d (%g Hz) %d (%g)\n", i,
1031 note, midicps(note, ch), vel, vel/127.0);
1032 #endif
1033 if (freq >= 0)
1034 *ui[i]->elems[freq].zone = midicps(note, ch);
1035 if (gate >= 0)
1036 *ui[i]->elems[gate].zone = 1.0f;
1037 if (gain >= 0)
1038 *ui[i]->elems[gain].zone = vel/127.0;
1039 // reinitialize the per-channel control data for this voice
1040 for (int idx = 0; idx < n_in; idx++) {
1041 int j = inctrls[idx], k = ui[0]->elems[j].port;
1042 *ui[i]->elems[j].zone = midivals[ch][k];
1043 }
1044 }
1045
voice_offLV2Plugin1046 void voice_off(int i)
1047 {
1048 #if DEBUG_VOICES
1049 fprintf(stderr, "voice off: %d\n", i);
1050 #endif
1051 if (gate >= 0)
1052 *ui[i]->elems[gate].zone = 0.0f;
1053 }
1054
update_voicesLV2Plugin1055 void update_voices(uint8_t chan)
1056 {
1057 // update running voices on the given channel after tuning or pitch bend
1058 // changes
1059 for (boost::circular_buffer<int>::iterator it =
1060 vd->used_voices.begin();
1061 it != vd->used_voices.end(); it++) {
1062 int i = *it;
1063 if (vd->note_info[i].ch == chan && freq >= 0) {
1064 int note = vd->note_info[i].note;
1065 *ui[i]->elems[freq].zone = midicps(note, chan);
1066 }
1067 }
1068 }
1069
all_notes_offLV2Plugin1070 void all_notes_off()
1071 {
1072 for (int i = 0; i < nvoices; i++)
1073 voice_off(i);
1074 for (int i = 0; i < 16; i++)
1075 vd->bend[i] = 0.0f;
1076 memset(vd->notes, 0xff, sizeof(vd->notes));
1077 vd->free_voices.clear();
1078 vd->n_free = nvoices;
1079 for (int i = 0; i < nvoices; i++)
1080 vd->free_voices.push_back(i);
1081 vd->queued.clear();
1082 vd->used_voices.clear();
1083 vd->n_used = 0;
1084 }
1085
all_notes_offLV2Plugin1086 void all_notes_off(uint8_t chan)
1087 {
1088 for (boost::circular_buffer<int>::iterator it =
1089 vd->used_voices.begin();
1090 it != vd->used_voices.end(); ) {
1091 int i = *it;
1092 if (vd->note_info[i].ch == chan) {
1093 assert(vd->n_free < nvoices);
1094 vd->free_voices.push_back(i);
1095 vd->n_free++;
1096 voice_off(i);
1097 vd->notes[vd->note_info[i].ch][vd->note_info[i].note] = -1;
1098 vd->queued.erase(i);
1099 // erase this voice from the used list
1100 it = vd->used_voices.erase(it);
1101 vd->n_used--;
1102 #if DEBUG_VOICE_ALLOC
1103 print_voices("dealloc (all-notes-off)");
1104 #endif
1105 } else
1106 it++;
1107 }
1108 vd->bend[chan] = 0.0f;
1109 }
1110
queued_notes_offLV2Plugin1111 void queued_notes_off()
1112 {
1113 if (vd->queued.empty()) return;
1114 for (int i = 0; i < nvoices; i++)
1115 if (vd->queued.find(i) != vd->queued.end()) {
1116 assert(vd->n_free < nvoices);
1117 vd->free_voices.push_back(i);
1118 vd->n_free++;
1119 voice_off(i);
1120 vd->notes[vd->note_info[i].ch][vd->note_info[i].note] = -1;
1121 vd->queued.erase(i);
1122 // erase this voice from the used list
1123 for (boost::circular_buffer<int>::iterator it =
1124 vd->used_voices.begin();
1125 it != vd->used_voices.end(); it++) {
1126 if (*it == i) {
1127 vd->used_voices.erase(it);
1128 vd->n_used--;
1129 break;
1130 }
1131 }
1132 #if DEBUG_VOICE_ALLOC
1133 print_voices("dealloc (unqueued)");
1134 #endif
1135 }
1136 }
1137
1138 // Plugin activation status. suspend() deactivates a plugin (disables audio
1139 // processing), resume() reactivates it. Also, set_rate() changes the sample
1140 // rate. Note that the audio and MIDI process functions (see below) can
1141 // still be called in deactivated state, but this is optional. The plugin
1142 // tries to do some reasonable processing in either case, no matter whether
1143 // the host plugin architecture actually executes callbacks in suspended
1144 // state or not.
1145
suspendLV2Plugin1146 void suspend()
1147 {
1148 active = false;
1149 if (maxvoices > 0) all_notes_off();
1150 }
1151
resumeLV2Plugin1152 void resume()
1153 {
1154 for (int i = 0; i < ndsps; i++)
1155 dsp[i]->init(rate);
1156 for (int i = 0, j = 0; i < ui[0]->nelems; i++) {
1157 int p = ui[0]->elems[i].port;
1158 if (p >= 0) {
1159 float val = ui[0]->elems[i].init;
1160 portvals[p] = val;
1161 }
1162 }
1163 active = true;
1164 }
1165
set_rateLV2Plugin1166 void set_rate(int sr)
1167 {
1168 rate = sr;
1169 for (int i = 0; i < ndsps; i++)
1170 dsp[i]->init(rate);
1171 }
1172
1173 // Audio and MIDI process functions. The plugin should run these in the
1174 // appropriate real-time callbacks.
1175
process_audioLV2Plugin1176 void process_audio(int blocksz, float **inputs, float **outputs)
1177 {
1178 int n = dsp[0]->getNumInputs(), m = dsp[0]->getNumOutputs();
1179 AVOIDDENORMALS;
1180 if (maxvoices > 0) queued_notes_off();
1181 if (!active) {
1182 // Depending on the plugin architecture and host, this code might never
1183 // be invoked, since the plugin is deactivitated at this point. But
1184 // let's do something reasonable here anyway.
1185 if (n == m) {
1186 // copy inputs to outputs
1187 for (int i = 0; i < m; i++)
1188 for (unsigned j = 0; j < blocksz; j++)
1189 outputs[i][j] = inputs[i][j];
1190 } else {
1191 // silence
1192 for (int i = 0; i < m; i++)
1193 for (unsigned j = 0; j < blocksz; j++)
1194 outputs[i][j] = 0.0f;
1195 }
1196 return;
1197 }
1198 // Handle changes in the polyphony and tuning controls.
1199 bool is_instr = maxvoices > 0;
1200 if (is_instr) {
1201 if (!poly)
1202 ; // this shouldn't happen but...
1203 else if (nvoices != (int)*poly &&
1204 (int)*poly > 0 && (int)*poly <= maxvoices) {
1205 for (int i = 0; i < nvoices; i++)
1206 voice_off(i);
1207 nvoices = (int)*poly;
1208 // Reset the voice allocation.
1209 memset(vd->notes, 0xff, sizeof(vd->notes));
1210 vd->free_voices.clear();
1211 vd->n_free = nvoices;
1212 for (int i = 0; i < nvoices; i++)
1213 vd->free_voices.push_back(i);
1214 vd->used_voices.clear();
1215 vd->n_used = 0;
1216 } else
1217 *poly = nvoices;
1218 #if FAUST_MTS
1219 if (tuning && tuning_no != (int)*tuning) change_tuning((int)*tuning);
1220 #endif
1221 }
1222 // Only update the controls (of all voices simultaneously) if a port value
1223 // actually changed. This is necessary to allow MIDI controllers to modify
1224 // the values for individual MIDI channels (see processEvents below). Also
1225 // note that this will be done *after* processing the MIDI controller data
1226 // for the current audio block, so manual inputs can still override these.
1227 for (int i = 0; i < n_in; i++) {
1228 int j = inctrls[i], k = ui[0]->elems[j].port;
1229 float &oldval = portvals[k], newval = *ports[k];
1230 if (newval != oldval) {
1231 if (is_instr) {
1232 // instrument: update running voices
1233 for (boost::circular_buffer<int>::iterator it =
1234 vd->used_voices.begin();
1235 it != vd->used_voices.end(); it++) {
1236 int i = *it;
1237 *ui[i]->elems[j].zone = newval;
1238 }
1239 } else {
1240 // simple effect: here we only have a single dsp instance
1241 *ui[0]->elems[j].zone = newval;
1242 }
1243 // also update the MIDI controller data for all channels (manual
1244 // control input is always omni)
1245 for (int ch = 0; ch < 16; ch++)
1246 midivals[ch][k] = newval;
1247 // record the new value
1248 oldval = newval;
1249 }
1250 }
1251 // Initialize the output buffers.
1252 if (n_samples < blocksz) {
1253 // We need to enlarge the buffers. We're not officially allowed to do
1254 // this here (presumably in the realtime thread), but since we usually
1255 // don't know the hosts's block size beforehand, there's really nothing
1256 // else that we can do. Let's just hope that doing this once suffices,
1257 // then hopefully noone will notice.
1258 if (outbuf) {
1259 for (int i = 0; i < m; i++) {
1260 outbuf[i] = (float*)realloc(outbuf[i],
1261 blocksz*sizeof(float));
1262 assert(outbuf[i]);
1263 }
1264 }
1265 n_samples = blocksz;
1266 }
1267 if (outbuf) {
1268 // Polyphonic instrument: Mix the voices down to one signal.
1269 for (int i = 0; i < m; i++)
1270 for (unsigned j = 0; j < blocksz; j++)
1271 outputs[i][j] = 0.0f;
1272 for (int l = 0; l < nvoices; l++) {
1273 // Let Faust do all the hard work.
1274 dsp[l]->compute(blocksz, inputs, outbuf);
1275 for (int i = 0; i < m; i++)
1276 for (unsigned j = 0; j < blocksz; j++)
1277 outputs[i][j] += outbuf[i][j];
1278 }
1279 } else {
1280 // Simple effect: We can write directly to the output buffer.
1281 dsp[0]->compute(blocksz, inputs, outputs);
1282 }
1283 // Finally grab the passive controls and write them back to the
1284 // corresponding control ports. NOTE: Depending on the plugin
1285 // architecture, this might require a host call to get the control GUI
1286 // updated in real-time (if the host supports this at all).
1287 // FIXME: It's not clear how to aggregate the data of the different
1288 // voices. We compute the maximum of each control for now.
1289 for (int i = 0; i < n_out; i++) {
1290 int j = outctrls[i], k = ui[0]->elems[j].port;
1291 float *z = ui[0]->elems[j].zone;
1292 *ports[k] = *z;
1293 for (int l = 1; l < nvoices; l++) {
1294 float *z = ui[l]->elems[j].zone;
1295 if (*ports[k] < *z)
1296 *ports[k] = *z;
1297 }
1298 }
1299 // Keep track of the last gates set for each voice, so that voices can be
1300 // forcibly retriggered if needed.
1301 if (gate >= 0)
1302 for (int i = 0; i < nvoices; i++)
1303 vd->lastgate[i] =
1304 *ui[i]->elems[gate].zone;
1305 }
1306
1307 // This processes just a single MIDI message, so to process an entire series
1308 // of MIDI events you'll have to loop over the event data in the plugin's
1309 // MIDI callback. XXXTODO: Sample-accurate processing of MIDI events.
1310
process_midiLV2Plugin1311 void process_midi(unsigned char *data, int sz)
1312 {
1313 #if DEBUG_MIDI
1314 fprintf(stderr, "midi ev (%d bytes):", sz);
1315 for (int i = 0; i < sz; i++)
1316 fprintf(stderr, " 0x%0x", data[i]);
1317 fprintf(stderr, "\n");
1318 #endif
1319 uint8_t status = data[0] & 0xf0, chan = data[0] & 0x0f;
1320 bool is_instr = maxvoices > 0;
1321 switch (status) {
1322 case 0x90: {
1323 if (!is_instr) break;
1324 // note on
1325 #if DEBUG_NOTES
1326 fprintf(stderr, "note-on chan %d, note %d, vel %d\n", chan+1,
1327 data[1], data[2]);
1328 #endif
1329 if (data[2] == 0) goto note_off;
1330 alloc_voice(chan, data[1], data[2]);
1331 break;
1332 }
1333 case 0x80: {
1334 if (!is_instr) break;
1335 // note off
1336 #if DEBUG_NOTES
1337 fprintf(stderr, "note-off chan %d, note %d, vel %d\n", chan+1,
1338 data[1], data[2]);
1339 #endif
1340 note_off:
1341 dealloc_voice(chan, data[1], data[2]);
1342 break;
1343 }
1344 case 0xe0: {
1345 if (!is_instr) break;
1346 // pitch bend
1347 // data[1] is LSB, data[2] MSB, range is 0..0x3fff (which maps to
1348 // -2..+2 semitones by default), center point is 0x2000 = 8192
1349 int val = data[1] | (data[2]<<7);
1350 vd->bend[chan] =
1351 (val-0x2000)/8192.0f*vd->range[chan];
1352 #if DEBUG_MIDICC
1353 fprintf(stderr, "pitch-bend (chan %d): %g cent\n", chan+1,
1354 vd->bend[chan]*100.0);
1355 #endif
1356 update_voices(chan);
1357 break;
1358 }
1359 case 0xb0: {
1360 // controller change
1361 switch (data[1]) {
1362 case 120: case 123:
1363 if (!is_instr) break;
1364 // all-sound-off and all-notes-off controllers (these are treated
1365 // the same in the current implementation)
1366 all_notes_off(chan);
1367 #if DEBUG_MIDICC
1368 fprintf(stderr, "all-notes-off (chan %d)\n", chan+1);
1369 #endif
1370 break;
1371 case 121:
1372 // all-controllers-off (in the current implementation, this just
1373 // resets the RPN-related controllers)
1374 data_msb[chan] = data_lsb[chan] = 0;
1375 rpn_msb[chan] = rpn_lsb[chan] = 0x7f;
1376 #if DEBUG_MIDICC
1377 fprintf(stderr, "all-controllers-off (chan %d)\n", chan+1);
1378 #endif
1379 break;
1380 case 101: case 100:
1381 // RPN MSB/LSB
1382 if (data[1] == 101)
1383 rpn_msb[chan] = data[2];
1384 else
1385 rpn_lsb[chan] = data[2];
1386 break;
1387 case 6: case 38:
1388 // data entry coarse/fine
1389 if (data[1] == 6)
1390 data_msb[chan] = data[2];
1391 else
1392 data_lsb[chan] = data[2];
1393 goto rpn;
1394 case 96: case 97:
1395 // data increment/decrement
1396 /* NOTE: The specification of these controllers is a complete
1397 mess. Originally, the MIDI specification didn't have anything
1398 to say about their exact behaviour at all. Nowadays, the
1399 behaviour depends on which RPN or NRPN is being modified, which
1400 is also rather confusing. Fortunately, as we only handle RPNs
1401 0..2 here anyway, it's sufficient to assume the MSB for RPN #2
1402 (channel coarse tuning) and the LSB otherwise. */
1403 if (rpn_msb[chan] == 0 && rpn_lsb[chan] == 2) {
1404 // modify the MSB
1405 if (data[1] == 96 && data_msb[chan] < 0x7f)
1406 data_msb[chan]++;
1407 else if (data[1] == 97 && data_msb[chan] > 0)
1408 data_msb[chan]--;
1409 } else {
1410 // modify the LSB
1411 if (data[1] == 96 && data_lsb[chan] < 0x7f)
1412 data_lsb[chan]++;
1413 else if (data[1] == 97 && data_lsb[chan] > 0)
1414 data_lsb[chan]--;
1415 }
1416 rpn:
1417 if (!is_instr) break;
1418 if (rpn_msb[chan] == 0) {
1419 switch (rpn_lsb[chan]) {
1420 case 0:
1421 // pitch bend range, coarse value is in semitones, fine value
1422 // in cents
1423 vd->range[chan] = data_msb[chan]+
1424 data_lsb[chan]/100.0;
1425 #if DEBUG_RPN
1426 fprintf(stderr, "pitch-bend-range (chan %d): %g cent\n", chan+1,
1427 vd->range[chan]*100.0);
1428 #endif
1429 break;
1430 case 1:
1431 {
1432 // channel fine tuning (14 bit value, range -100..+100 cents)
1433 int value = (data_msb[chan]<<7) |
1434 data_lsb[chan];
1435 vd->fine[chan] = (value-8192)/8192.0f;
1436 }
1437 goto master_tune;
1438 case 2:
1439 // channel coarse tuning (only msb is used, range -64..+63
1440 // semitones)
1441 vd->coarse[chan] = data_msb[chan]-64;
1442 master_tune:
1443 vd->tune[chan] = vd->coarse[chan]+
1444 vd->fine[chan];
1445 #if DEBUG_RPN
1446 fprintf(stderr, "master-tuning (chan %d): %g cent\n", chan+1,
1447 vd->tune[chan]*100.0);
1448 #endif
1449 update_voices(chan);
1450 break;
1451 default:
1452 break;
1453 }
1454 }
1455 break;
1456 default: {
1457 #if FAUST_MIDICC
1458 // interpret all other controller changes according to the MIDI
1459 // controller map defined in the Faust plugin itself
1460 std::map<uint8_t,int>::iterator it = ctrlmap.find(data[1]);
1461 if (it != ctrlmap.end()) {
1462 // defined MIDI controller
1463 int j = inctrls[it->second],
1464 k = ui[0]->elems[j].port;
1465 float val = ctrlval(ui[0]->elems[j], data[2]);
1466 midivals[chan][k] = val;
1467 if (is_instr) {
1468 // instrument: update running voices on this channel
1469 for (boost::circular_buffer<int>::iterator it =
1470 vd->used_voices.begin();
1471 it != vd->used_voices.end(); it++) {
1472 int i = *it;
1473 if (vd->note_info[i].ch == chan)
1474 *ui[i]->elems[j].zone = val;
1475 }
1476 } else {
1477 // simple effect: here we only have a single dsp instance and
1478 // we're operating in omni mode, so we just update the control no
1479 // matter what the midi channel is
1480 *ui[0]->elems[j].zone = val;
1481 }
1482 #if DEBUG_MIDICC
1483 fprintf(stderr, "ctrl-change chan %d, ctrl %d, val %d\n", chan+1,
1484 data[1], data[2]);
1485 #endif
1486 }
1487 #endif
1488 break;
1489 }
1490 }
1491 break;
1492 }
1493 default:
1494 break;
1495 }
1496 }
1497
1498 // Process an MTS sysex message and update the control values accordingly.
1499
process_sysexLV2Plugin1500 void process_sysex(uint8_t *data, int sz)
1501 {
1502 if (!data || sz < 2) return;
1503 #if DEBUG_MIDI
1504 fprintf(stderr, "midi sysex (%d bytes):", sz);
1505 for (int i = 0; i < sz; i++)
1506 fprintf(stderr, " 0x%0x", data[i]);
1507 fprintf(stderr, "\n");
1508 #endif
1509 if (data[0] == 0xf0) {
1510 // Skip over the f0 and f7 status bytes in case they are included in the
1511 // dump.
1512 data++; sz--;
1513 if (data[sz-1] == 0xf7) sz--;
1514 }
1515 if ((data[0] == 0x7e || data[0] == 0x7f) && data[2] == 8) {
1516 // MIDI tuning standard
1517 bool realtime = data[0] == 0x7f;
1518 if ((sz == 19 && data[3] == 8) ||
1519 (sz == 31 && data[3] == 9)) {
1520 // MTS scale/octave tuning 1- or 2-byte form
1521 bool onebyte = data[3] == 8;
1522 unsigned chanmsk = (data[4]<<14) | (data[5]<<7) | data[6];
1523 for (int i = 0; i < 12; i++) {
1524 float t;
1525 if (onebyte)
1526 t = (data[i+7]-64)/100.0;
1527 else
1528 t = (((data[2*i+7]<<7)|data[2*i+8])-8192)/8192.0;
1529 for (uint8_t ch = 0; ch < 16; ch++)
1530 if (chanmsk & (1<<ch))
1531 vd->tuning[ch][i] = t;
1532 }
1533 if (realtime) {
1534 for (uint8_t ch = 0; ch < 16; ch++)
1535 if (chanmsk & (1<<ch)) {
1536 // update running voices on this channel
1537 update_voices(ch);
1538 }
1539 }
1540 #if DEBUG_MTS
1541 fprintf(stderr, "octave-tuning-%s (chan ",
1542 realtime?"realtime":"non-realtime");
1543 bool first = true;
1544 for (uint8_t i = 0; i < 16; )
1545 if (chanmsk & (1<<i)) {
1546 uint8_t j;
1547 for (j = i+1; j < 16 && (chanmsk&(1<<j)); )
1548 j++;
1549 if (first)
1550 first = false;
1551 else
1552 fprintf(stderr, ",");
1553 if (j > i+1)
1554 fprintf(stderr, "%u-%u", i+1, j);
1555 else
1556 fprintf(stderr, "%u", i+1);
1557 i = j;
1558 } else
1559 i++;
1560 fprintf(stderr, "):");
1561 if (onebyte) {
1562 for (int i = 7; i < 19; i++) {
1563 int val = data[i];
1564 fprintf(stderr, " %d", val-64);
1565 }
1566 } else {
1567 for (int i = 7; i < 31; i++) {
1568 int val = data[i++] << 7;
1569 val |= data[i];
1570 fprintf(stderr, " %g", ((double)val-8192.0)/8192.0*100.0);
1571 }
1572 }
1573 fprintf(stderr, "\n");
1574 #endif
1575 }
1576 }
1577 }
1578
1579 // Change to a given preloaded tuning. The given tuning number may be in the
1580 // range 1..PFaustPlugin::n_tunings, zero denotes the default tuning (equal
1581 // temperament). This is only supported if FAUST_MTS is defined at compile
1582 // time.
1583
change_tuningLV2Plugin1584 void change_tuning(int num)
1585 {
1586 #if FAUST_MTS
1587 if (!mts || num == tuning_no) return;
1588 if (num < 0) num = 0;
1589 if (num > mts->tuning.size())
1590 num = mts->tuning.size();
1591 tuning_no = num;
1592 if (tuning_no > 0) {
1593 process_sysex(mts->tuning[tuning_no-1].data,
1594 mts->tuning[tuning_no-1].len);
1595 } else {
1596 memset(vd->tuning, 0, sizeof(vd->tuning));
1597 #if DEBUG_MTS
1598 fprintf(stderr,
1599 "octave-tuning-default (chan 1-16): equal temperament\n");
1600 #endif
1601 }
1602 #endif
1603 }
1604
1605 };
1606
1607 Meta *LV2Plugin::meta = 0;
1608 int LV2Plugin::n_tunings = 0;
1609 #if FAUST_MTS
1610 MTSTunings *LV2Plugin::mts = 0;
1611 #endif
1612
1613 /* LV2-specific part starts here. ********************************************/
1614
1615 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)1616 instantiate(const LV2_Descriptor* descriptor,
1617 double rate,
1618 const char* bundle_path,
1619 const LV2_Feature* const* features)
1620 {
1621 LV2Plugin* plugin =
1622 new LV2Plugin(LV2Plugin::numVoices(), (int)rate);
1623 // Scan host features for URID map.
1624 for (int i = 0; features[i]; i++) {
1625 if (!strcmp(features[i]->URI, LV2_URID_URI "#map")) {
1626 plugin->map = (LV2_URID_Map*)features[i]->data;
1627 plugin->midi_event =
1628 plugin->map->map(plugin->map->handle, MIDI_EVENT_URI);
1629 }
1630 }
1631 if (!plugin->map) {
1632 fprintf
1633 (stderr, "%s: host doesn't support urid:map, giving up\n",
1634 PLUGIN_URI);
1635 delete plugin;
1636 return 0;
1637 }
1638 return (LV2_Handle)plugin;
1639 }
1640
1641 static void
cleanup(LV2_Handle instance)1642 cleanup(LV2_Handle instance)
1643 {
1644 LV2Plugin* plugin = (LV2Plugin*)instance;
1645 delete plugin;
1646 }
1647
1648 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)1649 connect_port(LV2_Handle instance,
1650 uint32_t port,
1651 void* data)
1652 {
1653 LV2Plugin* plugin = (LV2Plugin*)instance;
1654 int i = port, k = plugin->ui[0]->nports;
1655 int n = plugin->dsp[0]->getNumInputs(), m = plugin->dsp[0]->getNumOutputs();
1656 if (i < k)
1657 plugin->ports[i] = (float*)data;
1658 else {
1659 i -= k;
1660 if (i < n)
1661 plugin->inputs[i] = (float*)data;
1662 else {
1663 i -= n;
1664 if (i < m)
1665 plugin->outputs[i] = (float*)data;
1666 else if (i == m)
1667 plugin->event_port = (LV2_Atom_Sequence*)data;
1668 else if (i == m+1)
1669 plugin->poly = (float*)data;
1670 else if (i == m+2)
1671 plugin->tuning = (float*)data;
1672 else
1673 fprintf(stderr, "%s: bad port number %u\n", PLUGIN_URI, port);
1674 }
1675 }
1676 }
1677
1678 static void
run(LV2_Handle instance,uint32_t n_samples)1679 run(LV2_Handle instance, uint32_t n_samples)
1680 {
1681 LV2Plugin* plugin = (LV2Plugin*)instance;
1682 // Process incoming MIDI events.
1683 if (plugin->event_port) {
1684 LV2_ATOM_SEQUENCE_FOREACH(plugin->event_port, ev) {
1685 if (ev->body.type == plugin->midi_event) {
1686 uint8_t *data = (uint8_t*)(ev+1);
1687 #if 0
1688 // FIXME: Consider doing sample-accurate note onsets here. LV2 keeps
1689 // track of the exact onset in the frames and subframes fields
1690 // (http://lv2plug.in/ns/doc/html/structLV2__Atom__Event.html), but we
1691 // can't use that information at present, since our gate parameter is
1692 // a control variable which can only change at block boundaries. In
1693 // the future, the gate could be implemented as an audio signal to get
1694 // sample-accurate note onsets.
1695 uint32_t frames = ev->body.frames;
1696 #endif
1697 if (data[0] == 0xf0)
1698 plugin->process_sysex(data, ev->body.size);
1699 else
1700 plugin->process_midi(data, ev->body.size);
1701 }
1702 }
1703 }
1704 // Process audio.
1705 plugin->process_audio(n_samples, plugin->inputs, plugin->outputs);
1706 }
1707
1708 static void
activate(LV2_Handle instance)1709 activate(LV2_Handle instance)
1710 {
1711 LV2Plugin* plugin = (LV2Plugin*)instance;
1712 plugin->resume();
1713 }
1714
1715 static void
deactivate(LV2_Handle instance)1716 deactivate(LV2_Handle instance)
1717 {
1718 LV2Plugin* plugin = (LV2Plugin*)instance;
1719 plugin->suspend();
1720 }
1721
1722 const void*
extension_data(const char * uri)1723 extension_data(const char* uri)
1724 {
1725 return NULL;
1726 }
1727
1728 static const LV2_Descriptor descriptor = {
1729 PLUGIN_URI,
1730 instantiate,
1731 connect_port,
1732 activate,
1733 run,
1734 deactivate,
1735 cleanup,
1736 extension_data
1737 };
1738
1739 extern "C"
1740 LV2_SYMBOL_EXPORT
1741 const LV2_Descriptor*
lv2_descriptor(uint32_t index)1742 lv2_descriptor(uint32_t index)
1743 {
1744 switch (index) {
1745 case 0:
1746 return &descriptor;
1747 default:
1748 return NULL;
1749 }
1750 }
1751
1752 //----------------------------------------------------------------------------
1753 // Dynamic manifest
1754 //----------------------------------------------------------------------------
1755
1756 // NOTE: If your LV2 host doesn't offer this extension then you'll have to
1757 // create a static ttl file with the descriptions of the ports. You can do
1758 // this by compiling this code to a standalone executable. Running the
1759 // executable then prints the manifest on stdout.
1760
1761 extern "C"
1762 LV2_SYMBOL_EXPORT
lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle * handle,const LV2_Feature * const * features)1763 int lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle *handle,
1764 const LV2_Feature *const *features)
1765 {
1766 LV2Plugin* plugin =
1767 new LV2Plugin(LV2Plugin::numVoices(), 48000);
1768 *handle = (LV2_Dyn_Manifest_Handle)plugin;
1769 return 0;
1770 }
1771
1772 extern "C"
1773 LV2_SYMBOL_EXPORT
lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle,FILE * fp)1774 int lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle,
1775 FILE *fp)
1776 {
1777 fprintf(fp, "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
1778 <%s> a lv2:Plugin .\n", PLUGIN_URI);
1779 return 0;
1780 }
1781
1782 #include <string>
1783 #include <ctype.h>
1784
mangle(const string & s)1785 static string mangle(const string &s)
1786 {
1787 string t = s;
1788 size_t n = s.size();
1789 for (size_t i = 0; i < n; i++)
1790 if ((i == 0 && !isalpha(t[i]) && t[i] != '_') ||
1791 (!isalnum(t[i]) && t[i] != '_'))
1792 t[i] = '_';
1793 return t;
1794 }
1795
steps(float min,float max,float step)1796 static unsigned steps(float min, float max, float step)
1797 {
1798 if (step == 0.0) return 1;
1799 int n = (max-min)/step;
1800 if (n < 0) n = -n;
1801 if (n == 0) n = 1;
1802 return n;
1803 }
1804
1805 #if FAUST_META
is_xmlstring(const char * s)1806 static bool is_xmlstring(const char *s)
1807 {
1808 // This is just a basic sanity check. The string must not contain any
1809 // (unescaped) newlines, carriage returns or double quotes.
1810 return !strchr(s, '\n') && !strchr(s, '\r') && !strchr(s, '"');
1811 }
1812 #endif
1813
1814 extern "C"
1815 LV2_SYMBOL_EXPORT
lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle,FILE * fp,const char * uri)1816 int lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle,
1817 FILE *fp,
1818 const char *uri)
1819 {
1820 LV2Plugin* plugin = (LV2Plugin*)handle;
1821 int k = plugin->ui[0]->nports;
1822 int n = plugin->dsp[0]->getNumInputs(), m = plugin->dsp[0]->getNumOutputs();
1823 bool is_instr = plugin->maxvoices > 0, have_midi = is_instr;
1824 // Scan the global metadata for plugin name, description, license etc.
1825 const char *plugin_name = NULL, *plugin_author = NULL, *plugin_descr = NULL,
1826 *plugin_version = NULL, *plugin_license = NULL;
1827 #if FAUST_META
1828 plugin_name = plugin->pluginName();
1829 plugin_descr = plugin->pluginDescription();
1830 plugin_author = plugin->pluginAuthor();
1831 plugin_version = plugin->pluginVersion();
1832 plugin_license = plugin->pluginLicense();
1833 #endif
1834 if (!plugin_name || !*plugin_name) plugin_name = "mydsp";
1835 fprintf(fp, "@prefix doap: <http://usefulinc.com/ns/doap#> .\n\
1836 @prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\
1837 @prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n\
1838 @prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n\
1839 @prefix epp: <http://lv2plug.in/ns/ext/port-props#> .\n\
1840 @prefix atom: <http://lv2plug.in/ns/ext/atom#> .\n\
1841 @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n\
1842 @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n\
1843 @prefix units: <http://lv2plug.in/ns/extensions/units#> .\n\
1844 @prefix urid: <http://lv2plug.in/ns/ext/urid#> .\n\
1845 <%s>\n\
1846 a lv2:Plugin%s ;\n\
1847 doap:name \"%s\" ;\n\
1848 lv2:binary <mydsp%s> ;\n\
1849 lv2:requiredFeature urid:map ;\n\
1850 lv2:optionalFeature epp:supportsStrictBounds ;\n\
1851 lv2:optionalFeature lv2:hardRTCapable ;\n", PLUGIN_URI,
1852 is_instr?", lv2:InstrumentPlugin":"",
1853 plugin_name, DLLEXT);
1854 if (plugin_author && *plugin_author)
1855 fprintf(fp, "\
1856 doap:maintainer [ foaf:name \"%s\" ] ;\n", plugin_author);
1857 // doap:description just seems to be ignored by all LV2 hosts anyway, so we
1858 // rather use rdfs:comment now which works with Ardour at least.
1859 if (plugin_descr && *plugin_descr)
1860 fprintf(fp, "\
1861 rdfs:comment \"%s\" ;\n", plugin_descr);
1862 if (plugin_version && *plugin_version)
1863 fprintf(fp, "\
1864 doap:revision \"%s\" ;\n", plugin_version);
1865 if (plugin_license && *plugin_license)
1866 fprintf(fp, "\
1867 doap:license \"%s\" ;\n", plugin_license);
1868 #if FAUST_UI
1869 fprintf(fp, "\
1870 ui:ui <%sui> ;\n", PLUGIN_URI);
1871 #endif
1872 int idx = 0;
1873 // control ports
1874 for (int i = 0; i < k; i++, idx++) {
1875 int j = plugin->ctrls[i];
1876 assert(idx == plugin->ui[0]->elems[j].port);
1877 fprintf(fp, "%s [\n", idx==0?" lv2:port":" ,");
1878 const char *label = plugin->ui[0]->elems[j].label;
1879 assert(label);
1880 string sym = mangle(plugin->ui[0]->elems[j].label);
1881 switch (plugin->ui[0]->elems[j].type) {
1882 // active controls (input ports)
1883 case UI_BUTTON: case UI_CHECK_BUTTON:
1884 fprintf(fp, "\
1885 a lv2:InputPort ;\n\
1886 a lv2:ControlPort ;\n\
1887 lv2:index %d ;\n\
1888 lv2:symbol \"%s_%d\" ;\n\
1889 lv2:name \"%s\" ;\n\
1890 lv2:portProperty epp:hasStrictBounds ;\n\
1891 lv2:portProperty lv2:toggled ;\n\
1892 lv2:default 0.00000 ;\n\
1893 lv2:minimum 0.00000 ;\n\
1894 lv2:maximum 1.00000 ;\n", idx, sym.c_str(), idx, label);
1895 break;
1896 case UI_NUM_ENTRY: case UI_H_SLIDER: case UI_V_SLIDER:
1897 fprintf(fp, "\
1898 a lv2:InputPort ;\n\
1899 a lv2:ControlPort ;\n\
1900 lv2:index %d ;\n\
1901 lv2:symbol \"%s_%d\" ;\n\
1902 lv2:name \"%s\" ;\n\
1903 lv2:portProperty epp:hasStrictBounds ;\n\
1904 epp:rangeSteps %u ;\n\
1905 lv2:default %g ;\n\
1906 lv2:minimum %g ;\n\
1907 lv2:maximum %g ;\n", idx, sym.c_str(), idx, label,
1908 steps(plugin->ui[0]->elems[j].min,
1909 plugin->ui[0]->elems[j].max,
1910 plugin->ui[0]->elems[j].step),
1911 plugin->ui[0]->elems[j].init,
1912 plugin->ui[0]->elems[j].min,
1913 plugin->ui[0]->elems[j].max);
1914 break;
1915 // passive controls (output ports)
1916 case UI_H_BARGRAPH: case UI_V_BARGRAPH:
1917 fprintf(fp, "\
1918 a lv2:OutputPort ;\n\
1919 a lv2:ControlPort ;\n\
1920 lv2:index %d ;\n\
1921 lv2:symbol \"%s_%d\" ;\n\
1922 lv2:name \"%s\" ;\n\
1923 lv2:default %g ;\n\
1924 lv2:minimum %g ;\n\
1925 lv2:maximum %g ;\n", idx, sym.c_str(), idx, label,
1926 plugin->ui[0]->elems[j].min,
1927 plugin->ui[0]->elems[j].min,
1928 plugin->ui[0]->elems[j].max);
1929 break;
1930 default:
1931 assert(0 && "this can't happen");
1932 break;
1933 }
1934 // Scan for Faust control metadata we understand and add corresponding
1935 // hints to the LV2 description of the port.
1936 std::map< int, list<strpair> >::iterator it =
1937 plugin->ui[0]->metadata.find(j);
1938 if (it != plugin->ui[0]->metadata.end()) {
1939 for (std::list<strpair>::iterator jt = it->second.begin();
1940 jt != it->second.end(); jt++) {
1941 const char *key = jt->first, *val = jt->second;
1942 #if FAUST_MIDICC
1943 unsigned num;
1944 if (!strcmp(key, "midi") && sscanf(val, "ctrl %u", &num) == 1)
1945 have_midi = true;
1946 #endif
1947 if (!strcmp(key, "unit"))
1948 fprintf(fp, "\
1949 units:unit [\n\
1950 a units:Unit ;\n\
1951 units:name \"%s\" ;\n\
1952 units:symbol \"%s\" ;\n\
1953 units:render \"%%f %s\"\n\
1954 ] ;\n", val, val, val);
1955 if (strcmp(key, "lv2")) continue;
1956 if (!strcmp(val, "integer"))
1957 fprintf(fp, "\
1958 lv2:portProperty lv2:integer ;\n");
1959 else if (!strcmp(val, "reportsLatency"))
1960 fprintf(fp, "\
1961 lv2:portProperty lv2:reportsLatency ;\n\
1962 lv2:designation lv2:latency ;\n");
1963 else if (!strcmp(val, "hidden") || !strcmp(val, "notOnGUI"))
1964 fprintf(fp, "\
1965 lv2:portProperty epp:notOnGUI ;\n");
1966 else if (!strncmp(val, "scalepoint", 10) ||
1967 !strncmp(val, "scalePoint", 10)) {
1968 val += 10;
1969 if (!isspace(*val)) continue;
1970 char *label = (char*)malloc(strlen(val)+1);
1971 float point;
1972 int pos;
1973 while (sscanf(val, "%s %g%n", label, &point, &pos) == 2) {
1974 fprintf(fp, "\
1975 lv2:scalePoint [ rdfs:label \"%s\"; rdf:value %g ] ;\n",
1976 label, point);
1977 val += pos;
1978 }
1979 free(label);
1980 } else
1981 fprintf(stderr, "%s: bad port property '%s:%s'\n", PLUGIN_URI,
1982 key, val);
1983 }
1984 }
1985 fprintf(fp, " ]");
1986 }
1987 // audio inputs
1988 for (int i = 0; i < n; i++, idx++)
1989 fprintf(fp, "%s [\n\
1990 a lv2:InputPort ;\n\
1991 a lv2:AudioPort ;\n\
1992 lv2:index %d ;\n\
1993 lv2:symbol \"in%d\" ;\n\
1994 lv2:name \"in%d\" ;\n\
1995 ]", idx==0?" lv2:port":" ,", idx, i, i);
1996 // audio outputs
1997 for (int i = 0; i < m; i++, idx++)
1998 fprintf(fp, "%s [\n\
1999 a lv2:OutputPort ;\n\
2000 a lv2:AudioPort ;\n\
2001 lv2:index %d ;\n\
2002 lv2:symbol \"out%d\" ;\n\
2003 lv2:name \"out%d\" ;\n\
2004 ]", idx==0?" lv2:port":" ,", idx, i, i);
2005 if (have_midi) {
2006 // midi input
2007 fprintf(fp, "%s [\n\
2008 a lv2:InputPort ;\n\
2009 a atom:AtomPort ;\n\
2010 atom:bufferType atom:Sequence ;\n\
2011 atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n\
2012 lv2:index %d ;\n\
2013 lv2:symbol \"midiin\" ;\n\
2014 lv2:name \"midiin\"\n\
2015 ]", idx==0?" lv2:port":" ,", idx);
2016 idx++;
2017 }
2018 if (is_instr) {
2019 // polyphony control
2020 fprintf(fp, "%s [\n\
2021 a lv2:InputPort ;\n\
2022 a lv2:ControlPort ;\n\
2023 lv2:index %d ;\n\
2024 lv2:symbol \"polyphony\" ;\n\
2025 lv2:name \"polyphony\" ;\n\
2026 lv2:portProperty epp:hasStrictBounds ;\n\
2027 # lv2:portProperty epp:expensive ;\n\
2028 lv2:portProperty lv2:integer ;\n\
2029 epp:rangeSteps %d ;\n\
2030 lv2:default %d ;\n\
2031 lv2:minimum 1 ;\n\
2032 lv2:maximum %d ;\n\
2033 ]", idx==0?" lv2:port":" ,", idx, plugin->maxvoices-1,
2034 plugin->maxvoices>1?plugin->maxvoices/2:1,
2035 plugin->maxvoices);
2036 idx++;
2037 #if FAUST_MTS
2038 if (plugin->n_tunings > 0) {
2039 // tuning control
2040 fprintf(fp, "%s [\n\
2041 a lv2:InputPort ;\n\
2042 a lv2:ControlPort ;\n\
2043 lv2:index %d ;\n\
2044 lv2:symbol \"tuning\" ;\n\
2045 lv2:name \"tuning\" ;\n\
2046 lv2:portProperty epp:hasStrictBounds ;\n\
2047 lv2:portProperty lv2:integer ;\n\
2048 epp:rangeSteps %d ;\n\
2049 lv2:default 0 ;\n\
2050 lv2:minimum 0 ;\n\
2051 lv2:maximum %d ;\n",
2052 idx==0?" lv2:port":" ,", idx, plugin->n_tunings, plugin->n_tunings);
2053 for (int i = 0; i <= plugin->n_tunings; i++)
2054 fprintf(fp, "\
2055 lv2:scalePoint [ rdfs:label \"%s\"; rdf:value %d ] ;\n",
2056 (i>0)?plugin->mts->tuning[i-1].name:"default", i);
2057 fprintf(fp, " ]");
2058 idx++;
2059 }
2060 #endif
2061 }
2062 fprintf(fp, "\n.\n");
2063 return 0;
2064 }
2065
2066 extern "C"
2067 LV2_SYMBOL_EXPORT
lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle)2068 void lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle)
2069 {
2070 LV2Plugin* plugin = (LV2Plugin*)handle;
2071 delete plugin;
2072 }
2073
main()2074 int main()
2075 {
2076 LV2_Dyn_Manifest_Handle handle;
2077 LV2_Feature **features = { NULL };
2078 int res = lv2_dyn_manifest_open(&handle, features);
2079 if (res) return res;
2080 res = lv2_dyn_manifest_get_data(handle, stdout, PLUGIN_URI);
2081 return res;
2082 }
2083