1 /************************************************************************
2 IMPORTANT NOTE : this file contains two clearly delimited
3 sections : the ARCHITECTURE section (in two parts) and the
4 USER section. Each section is governed by its own copyright
5 and license. Please check individually each section for
6 license and copyright information.
7 *************************************************************************/
9 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
11 /************************************************************************
12 FAUST Architecture File
13 Copyright (C) 2011 Michael J. Wilson
15 ---------------------------------------------------------------------
16 This Architecture section is free software; you can redistribute
17 it and/or modify it under the terms of the GNU General Public
18 License as published by the Free Software Foundation; either
19 version 3 of the License, or (at your option) any later version.
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program; If not, see <http://www.gnu.org/licenses/>.
29 EXCEPTION : As a special exception, you may create a larger work
30 that contains this FAUST architecture section and distribute that
31 work under terms of your choice, so long as this FAUST
32 architecture section is not modified.
33 ---------------------------------------------------------------------
35 ************************************************************************/
37 /********************************************************************
38 * dssi.cpp - Polyphonic dssi wrapper for the FAUST language.
40 * Usage: faust -a dssi.cpp myfaustprog.dsp
42 * By Michael J. Wilson (mwilson@alumni.caltech.edu)
44 * Made with reference to:
45 * - vsti-mono.cpp by Julius Smith (http://ccrma.stanford.edu/~jos/)
46 * - ladspa.cpp by GRAME, Centre National de Creation Musicale
47 * - karplong.cpp by Chris Cannam, Steve Harris, Sean Bolton
49 * Because of the inclusion of code from ladspa.cpp, this architecture
50 * file is also released under the GNU General Public Licenses version
51 * 3. Sections which were taken from ladspa.cpp are clearly marked
52 * below, in order to trace the GPL dependency.
53 * As with faust2pd and vsti-mono.cpp, to obtain MIDI control via
54 * NoteOn/Off, Velocity, and KeyNumber, there must be a button named
55 * "gate" and sliders (or numeric entries) named "gain" and "freq" in
56 * the Faust patch specified in myfaustprog.dsp.
59 * Copyright (C) 2003-2007 GRAME, Centre National de Creation Musicale
60 * http://www.grame.fr/
62 ********************************************************************/
77 // On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
78 // flags to avoid costly denormals
80 #include <xmmintrin.h>
82 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
84 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
87 #warning *** dssi.cpp: NO SSE FLAG (denormals may slow things down) ***
88 #define AVOIDDENORMALS
91 struct Meta
: std::map
<const char*, const char*>
93 void declare (const char* key
, const char* value
) { (*this)[key
]=value
; }
96 #define max(x,y) (((x)>(y)) ? (x) : (y))
97 #define min(x,y) (((x)<(y)) ? (x) : (y))
99 #define sym(name) xsym(name)
100 #define xsym(name) #name
102 inline int lsr (int x
, int n
) { return int(((unsigned int)x
) >> n
); }
103 inline int int2pow2 (int x
) { int r
=0; while ((1<<r
)<x
) r
++; return r
; }
105 /******************************************************************************
106 *******************************************************************************
110 *******************************************************************************
111 *******************************************************************************/
115 //---------------------Abstract User Interface--------------------
117 // Abstract definition of a User Interface to be passed to the
118 // buildUserInterface method of a Faust Signal Processor
120 //----------------------------------------------------------------
126 UI() : fStopped(false) {}
129 virtual void addButton(const char* label
, float* zone
) = 0;
130 virtual void addToggleButton(const char* label
, float* zone
) = 0;
131 virtual void addCheckButton(const char* label
, float* zone
) = 0;
132 virtual void addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
133 virtual void addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
134 virtual void addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
136 // -- passive widgets
137 virtual void addNumDisplay(const char* label
, float* zone
, int precision
) = 0;
138 virtual void addTextDisplay(const char* label
, float* zone
, char* names
[], float min
, float max
) = 0;
139 virtual void addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
) = 0;
140 virtual void addVerticalBargraph(const char* label
, float* zone
, float min
, float max
) = 0;
142 // -- frames and labels
143 virtual void openFrameBox(const char* label
) = 0;
144 virtual void openTabBox(const char* label
) = 0;
145 virtual void openHorizontalBox(const char* label
) = 0;
146 virtual void openVerticalBox(const char* label
) = 0;
147 virtual void closeBox() = 0;
149 virtual void show() = 0;
150 virtual void run() = 0;
152 void stop() { fStopped
= true; }
153 bool stopped() { return fStopped
; }
155 virtual void declare(float* zone
, const char* key
, const char* value
) {}
158 //------------------Abstract Signal Processor---------------------
160 // Abstract definition of a Faust Signal Processor
162 //----------------------------------------------------------------
170 virtual int getNumInputs() = 0;
171 virtual int getNumOutputs() = 0;
172 virtual void buildUserInterface(UI
* interface
) = 0;
173 virtual void init(int samplingRate
) = 0;
174 virtual void compute(int len
, float** inputs
, float** outputs
)= 0;
177 /********************END ARCHITECTURE SECTION (part 1/2)****************/
179 /**************************BEGIN USER SECTION **************************/
183 /***************************END USER SECTION ***************************/
185 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
187 ////////////////////////////////////////////////////////////////////////////////
188 // Forward declarations
189 ////////////////////////////////////////////////////////////////////////////////
194 ////////////////////////////////////////////////////////////////////////////////
196 ////////////////////////////////////////////////////////////////////////////////
197 // Maximum polyphony, must be at least 1 (TODO make this configurable at compile / runtime?)
198 const int MAX_POLYPHONY
= 64;
200 DSSI_Descriptor
* g_dssi_descriptor
;
201 // Additional data for descriptor:
202 LADSPA_Descriptor
* g_ladspa_descriptor
;
203 // Program descriptor:
204 DSSI_Program_Descriptor g_program_descriptor
;
206 // Global data for the descriptor:
207 std::vector
<LADSPA_PortDescriptor
> g_port_descriptors
;
208 std::vector
<LADSPA_PortRangeHint
> g_port_range_hints
;
209 std::vector
<const char*> g_port_names
;
212 ////////////////////////////////////////////////////////////////////////////////
213 // The enclosed code is from ladspa.cpp
214 // TODO groups of port names
215 static const char* inames
[] =
217 "input00", "input01", "input02", "input03", "input04",
218 "input05", "input06", "input07", "input08", "input09",
219 "input10", "input11", "input12", "input13", "input14",
220 "input15", "input16", "input17", "input18", "input19",
221 "input20", "input21", "input22", "input23", "input24",
222 "input25", "input26", "input27", "input28", "input29",
223 "input30", "input31", "input32", "input33", "input34",
224 "input35", "input36", "input37", "input38", "input39"
226 static const char* onames
[] =
228 "output00", "output01", "output02", "output03", "output04",
229 "output05", "output06", "output07", "output08", "output09",
230 "output10", "output11", "output12", "output13", "output14",
231 "output15", "output16", "output17", "output18", "output19",
232 "output20", "output21", "output22", "output23", "output24",
233 "output25", "output26", "output27", "output28", "output29",
234 "output30", "output31", "output32", "output33", "output34",
235 "output35", "output36", "output37", "output38", "output39"
237 // END code from ladspa.cpp
238 ////////////////////////////////////////////////////////////////////////////////
240 ////////////////////////////////////////////////////////////////////////////////
241 // Global helper functions
242 ////////////////////////////////////////////////////////////////////////////////
243 char* get_metadata_if_exists(const char* key
, const char* default_string
)
245 // TODO probably want to free these somehow. Currently only used for ladspa descriptor
247 mydsp::metadata(&meta
);
248 if(meta
.find(key
) != meta
.end())
250 return strdup(meta
[key
]);
254 return strdup(default_string
);
258 ////////////////////////////////////////////////////////////////////////////////
259 // The enclosed code is from ladspa.cpp
260 std::string
simplify(const std::string
& src
)
273 // Skip the begin of the label "--foo-"
274 // until 3 '-' have been read
275 if (src
[i
]=='-') { level
++; }
279 // copy the content, but skip non alphnum
280 // and content in parenthesis
292 if (isalnum(src
[i
])) {
293 dst
+= tolower(src
[i
]);
300 // here we are inside parenthesis and
301 // we skip the content until we are back to
321 return (dst
.size() > 0) ? dst
:src
;
323 // END code from ladspa.cpp
324 ////////////////////////////////////////////////////////////////////////////////
326 ////////////////////////////////////////////////////////////////////////////////
327 // Single voice; use multiple for polyphony
328 ////////////////////////////////////////////////////////////////////////////////
329 class Voice
: public UI
332 Voice(int sampleRate
);
336 // TODO don't hardcode these so hard maybe
337 void setFreq(float val
);
338 void setGate(float val
);
339 void setGain(float val
);
341 virtual void addButton(const char* label
, float* zone
);
342 virtual void addToggleButton(const char* label
, float* zone
);
343 virtual void addCheckButton(const char* label
, float* zone
);
344 virtual void addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
345 virtual void addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
346 virtual void addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
348 virtual void addNumDisplay(const char* label
, float* zone
, int precision
);
349 virtual void addTextDisplay(const char* label
, float* zone
, char* names
[], float min
, float max
);
350 virtual void addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
);
351 virtual void addVerticalBargraph(const char* label
, float* zone
, float min
, float max
);
353 virtual void openFrameBox(const char* label
);
354 virtual void openTabBox(const char* label
);
355 virtual void openHorizontalBox(const char* label
);
356 virtual void openVerticalBox(const char* label
);
357 virtual void closeBox();
362 // Internal control (to Faust DSP)
363 std::vector
<float*> m_controls
;
365 // TODO maybe don't make this public eventually
369 // Helpers for UI building:
370 // TODO organize this a bit better later...
371 bool ckAnyMatch(const char* label
, const char* indexName
, float **zone
, float* newZone
);
372 bool ckAllMatches(const char* label
, float* zone
);
373 void addZone(float* zone
);
382 ////////////////////////////////////////////////////////////////////////////////
383 // Plugin class to handle DSSI methods:
384 ////////////////////////////////////////////////////////////////////////////////
385 class Plugin
: public UI
389 static LADSPA_Handle
instantiate(const LADSPA_Descriptor
*, unsigned long);
390 static void connectPort(LADSPA_Handle
, unsigned long, LADSPA_Data
*);
391 static void activate(LADSPA_Handle
);
392 static void run(LADSPA_Handle
, unsigned long);
393 static void cleanup(LADSPA_Handle
);
396 static const DSSI_Program_Descriptor
* getProgram(LADSPA_Handle
, unsigned long);
397 static void selectProgram(LADSPA_Handle
, unsigned long, unsigned long);
398 static int getMidiController(LADSPA_Handle
, unsigned long);
399 static void runSynth(LADSPA_Handle
, unsigned long, snd_seq_event_t
*, unsigned long);
402 // TODO don't hardcode these so hard maybe
403 void setFreq(float val
, int voice
= 0);
404 void setGate(float val
, int voice
= 0);
405 void setGain(float val
, int voice
= 0);
407 virtual void addButton(const char* label
, float* zone
);
408 virtual void addToggleButton(const char* label
, float* zone
);
409 virtual void addCheckButton(const char* label
, float* zone
);
410 virtual void addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
411 virtual void addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
412 virtual void addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
);
414 virtual void addNumDisplay(const char* label
, float* zone
, int precision
);
415 virtual void addTextDisplay(const char* label
, float* zone
, char* names
[], float min
, float max
);
416 virtual void addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
);
417 virtual void addVerticalBargraph(const char* label
, float* zone
, float min
, float max
);
419 virtual void openFrameBox(const char* label
);
420 virtual void openTabBox(const char* label
);
421 virtual void openHorizontalBox(const char* label
);
422 virtual void openVerticalBox(const char* label
);
423 virtual void closeBox();
429 Plugin(int sampleRate
);
433 void updateControlZones();
434 void runImpl(unsigned long, snd_seq_event_t
*, unsigned long);
435 void addSamples(int);
437 // Helpers for UI building:
438 // TODO organize this a bit better later...
439 bool ckAnyMatch(const char* label
, const char* indexName
);
440 bool ckAllMatches(const char* label
);
441 void add_control_with_default(float default_value
);
445 // Voice allocation memebers (TODO maybe break voice allocator into separate class later)
446 // Note each voice is playing
447 std::vector
<int> voice_notes
;
448 // Queue of free voices
449 std::list
<size_t> voice_free
;
451 // Voices for polyphony
452 std::vector
<Voice
*> m_voices
;
454 // Top-level inputs (from DSSI host)
455 std::vector
<float*> m_inputs
;
456 // Top-level outputs (to DSSI host)
457 std::vector
<float*> m_outputs
;
458 // Temp vector for collecting outputs TODO this is an ugly way to do it...
459 std::vector
<std::vector
<float> > m_temp_outputs
;
460 // External control (from DSSI host)
461 std::vector
<float*> m_controls
;
463 // Control default values
464 std::vector
<float> m_control_defaults
;
467 ////////////////////////////////////////////////////////////////////////////////
468 // UI class to build descriptor, analogous to ladspa.cpp's portCollector
469 ////////////////////////////////////////////////////////////////////////////////
470 const int ICONTROL
= LADSPA_PORT_INPUT
|LADSPA_PORT_CONTROL
;
471 const int OCONTROL
= LADSPA_PORT_OUTPUT
|LADSPA_PORT_CONTROL
;
473 class DescriptorUI
: public UI
476 DescriptorUI(int ins
, int outs
);
478 virtual void addButton(const char* label
, float* zone
) {
479 if (!ckAnyMatch(label
, "gate"))
481 addPortDescr(ICONTROL
, label
, LADSPA_HINT_TOGGLED
);
484 virtual void addToggleButton(const char* label
, float* zone
) {
485 addPortDescr(ICONTROL
, label
, LADSPA_HINT_TOGGLED
);
487 virtual void addCheckButton(const char* label
, float* zone
) {
488 addPortDescr(ICONTROL
, label
, LADSPA_HINT_TOGGLED
);
490 virtual void addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
) {
491 if (!ckAllMatches(label
))
493 addPortDescr(ICONTROL
, label
, LADSPA_HINT_BOUNDED_BELOW
| LADSPA_HINT_BOUNDED_ABOVE
, min
, max
);
496 virtual void addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
) {
497 if (!ckAllMatches(label
))
499 addPortDescr(ICONTROL
, label
, LADSPA_HINT_BOUNDED_BELOW
| LADSPA_HINT_BOUNDED_ABOVE
, min
, max
);
502 virtual void addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
) {
503 if (!ckAllMatches(label
))
505 addPortDescr(ICONTROL
, label
, LADSPA_HINT_BOUNDED_BELOW
| LADSPA_HINT_BOUNDED_ABOVE
, min
, max
);
508 virtual void addNumDisplay(const char* label
, float* zone
, int precision
) {
509 addPortDescr(OCONTROL
, label
, 0, -10000, +10000);
511 virtual void addTextDisplay(const char* label
, float* zone
, char* names
[], float min
, float max
) {
512 addPortDescr(OCONTROL
, label
, LADSPA_HINT_BOUNDED_BELOW
| LADSPA_HINT_BOUNDED_ABOVE
, min
, max
);
514 virtual void addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
) {
515 addPortDescr(OCONTROL
, label
, LADSPA_HINT_BOUNDED_BELOW
| LADSPA_HINT_BOUNDED_ABOVE
, min
, max
);
517 virtual void addVerticalBargraph(const char* label
, float* zone
, float min
, float max
){
518 addPortDescr(OCONTROL
, label
, LADSPA_HINT_BOUNDED_BELOW
| LADSPA_HINT_BOUNDED_ABOVE
, min
, max
);
521 virtual void openFrameBox(const char* label
) { openAnyBox(label
); }
522 virtual void openTabBox(const char* label
) { openAnyBox(label
); }
523 virtual void openHorizontalBox(const char* label
) { openAnyBox(label
); }
524 virtual void openVerticalBox(const char* label
) { openAnyBox(label
); }
526 virtual void closeBox() { fPrefix
.pop(); }
528 virtual void show() {}
529 virtual void run() {}
532 std::stack
<std::string
> fPrefix
;
534 void addPortDescr(int type
, const char* label
, int hint
, float min
=0.0, float max
=0.0);
536 void openAnyBox(const char* label
);
538 bool ckAnyMatch(const char* label
, const char* indexName
)
540 // TODO do case-insensitive here...
541 if (strcmp(label
,indexName
)==0)
543 // Don't set values in the DescriptorUI
544 // TODO consolidate this later
549 bool ckAllMatches(const char* label
)
552 result
= result
|| ckAnyMatch(label
,"gain");
553 result
= result
|| ckAnyMatch(label
,"gate");
554 result
= result
|| ckAnyMatch(label
,"freq");
559 ////////////////////////////////////////////////////////////////////////////////
560 // DescriptorUI methods
561 ////////////////////////////////////////////////////////////////////////////////
562 DescriptorUI::DescriptorUI(int ins
, int outs
)
564 // Note inputs and outputs
565 for (int i
= 0; i
< ins
; i
++)
567 g_port_descriptors
.push_back(LADSPA_PORT_INPUT
| LADSPA_PORT_AUDIO
);
568 LADSPA_PortRangeHint temp
;
569 temp
.HintDescriptor
= 0;
572 g_port_range_hints
.push_back(temp
);
573 g_port_names
.push_back(inames
[i
]);
575 for (int j
= 0; j
< outs
; j
++)
577 g_port_descriptors
.push_back(LADSPA_PORT_OUTPUT
| LADSPA_PORT_AUDIO
);
578 LADSPA_PortRangeHint temp
;
579 temp
.HintDescriptor
= 0;
582 g_port_range_hints
.push_back(temp
);
583 g_port_names
.push_back(onames
[j
]);
587 void DescriptorUI::addPortDescr(int type
, const char* label
, int hint
, float min
, float max
)
589 ////////////////////////////////////////////////////////////////////////////////
590 // The enclosed code is derived from ladspa.cpp
591 std::string fullname
= simplify(fPrefix
.top() + "-" + label
);
592 // TODO for debugging, I'm just using the label for now instead of the full name (since fullname can get long)
593 // char * str = strdup(fullname.c_str());
594 char * str
= strdup(label
);
595 // END code from ladspa.cpp
596 ////////////////////////////////////////////////////////////////////////////////
598 g_port_descriptors
.push_back(type
);
599 LADSPA_PortRangeHint temp
;
600 temp
.HintDescriptor
= hint
;
601 temp
.LowerBound
= min
;
602 temp
.UpperBound
= max
;
603 g_port_range_hints
.push_back(temp
);
604 g_port_names
.push_back(str
); // TODO memory leak; need to free
607 void DescriptorUI::openAnyBox(const char* label
)
609 ////////////////////////////////////////////////////////////////////////////////
610 // The enclosed code is from ladspa.cpp
611 if (fPrefix
.size() == 0)
613 // top level label is used as plugin name
620 if (label
&& label
[0])
622 s
= fPrefix
.top() + "-" + label
;
630 // END code from ladspa.cpp
631 ////////////////////////////////////////////////////////////////////////////////
634 ////////////////////////////////////////////////////////////////////////////////
636 ////////////////////////////////////////////////////////////////////////////////
637 Plugin::Plugin(int sampleRate
) :
638 m_samplerate(sampleRate
)
644 for (i
= 0; i
< MAX_POLYPHONY
; i
++)
646 m_voices
.push_back(new Voice(m_samplerate
));
649 voice_free
.push_back(i
);
650 // TODO using -1 to represent nothing; think of a more clear way to do this
651 voice_notes
.push_back(-1);
653 for (i
= 0; i
< temp_mydsp
.getNumInputs(); i
++)
655 m_inputs
.push_back(0);
657 for (i
= 0; i
< temp_mydsp
.getNumOutputs(); i
++)
659 m_outputs
.push_back(0);
660 std::vector
<float> temp
;
662 m_temp_outputs
.push_back(temp
);
669 for (i
= 0; i
< m_voices
.size(); i
++)
675 LADSPA_Handle
Plugin::instantiate(const LADSPA_Descriptor
*, unsigned long rate
)
677 Plugin
*plugin
= new Plugin(rate
);
680 mydsp
* temp_mydsp
= new mydsp();
681 temp_mydsp
->buildUserInterface(plugin
);
684 for (i
= 0; i
< plugin
->m_voices
.size(); i
++)
686 plugin
->m_voices
[i
]->m_mydsp
->buildUserInterface(plugin
->m_voices
[i
]);
691 void Plugin::connectPort(LADSPA_Handle handle
, unsigned long port
, LADSPA_Data
*location
)
693 Plugin
*plugin
= (Plugin
*)handle
;
695 // Map inputs, then outputs, then controls:
696 if (port
< plugin
->m_inputs
.size())
698 *(&plugin
->m_inputs
[port
]) = (float *)location
;
700 else if (port
< plugin
->m_inputs
.size() + plugin
->m_outputs
.size())
702 *(&plugin
->m_outputs
[port
- plugin
->m_inputs
.size()]) = (float *)location
;
706 plugin
->m_controls
[port
- plugin
->m_inputs
.size() - plugin
->m_outputs
.size()] = (float *)location
;
710 void Plugin::activate(LADSPA_Handle handle
)
712 Plugin
*plugin
= (Plugin
*)handle
;
713 for (size_t i
= 0; i
< plugin
->m_voices
.size(); i
++)
715 plugin
->m_voices
[i
]->m_mydsp
->init(plugin
->m_samplerate
);
719 void Plugin::run(LADSPA_Handle handle
, unsigned long samples
)
721 runSynth(handle
, samples
, 0, 0);
724 void Plugin::cleanup(LADSPA_Handle handle
)
726 delete (Plugin
*)handle
;
729 const DSSI_Program_Descriptor
* Plugin::getProgram(LADSPA_Handle handle
, unsigned long index
)
733 return &g_program_descriptor
;
741 void Plugin::selectProgram(LADSPA_Handle handle
, unsigned long bank
, unsigned long program
)
743 Plugin
*plugin
= (Plugin
*)handle
;
744 for (size_t i
= 0; i
< plugin
->m_controls
.size(); i
++)
746 *(plugin
->m_controls
[i
]) = plugin
->m_control_defaults
[i
];
750 int Plugin::getMidiController(LADSPA_Handle
, unsigned long port
)
752 // TODO this is where we need to map MIDI controllers to ports
756 void Plugin::updateControlZones()
758 for (size_t i
= 0; i
< m_controls
.size(); i
++)
760 for (size_t j
= 0; j
< m_voices
.size(); j
++)
762 *(m_voices
[j
]->m_controls
[i
]) = *(m_controls
[i
]);
767 void Plugin::runSynth(LADSPA_Handle handle
, unsigned long samples
, snd_seq_event_t
*events
, unsigned long eventCount
)
769 Plugin
*plugin
= (Plugin
*)handle
;
770 plugin
->updateControlZones();
771 plugin
->runImpl(samples
, events
, eventCount
);
774 void Plugin::runImpl(unsigned long sampleCount
, snd_seq_event_t
*events
, unsigned long eventCount
)
778 unsigned long eventPos
;
785 while (pos
< sampleCount
)
787 while ((eventPos
< eventCount
) &&
788 (pos
>= events
[eventPos
].time
.tick
))
790 switch (events
[eventPos
].type
)
792 case SND_SEQ_EVENT_NOTEON
:
793 n
= events
[eventPos
].data
.note
;
796 // Look for the next free voice:
797 if (!voice_free
.empty())
799 // Get the index of the first free string and remove it from the list
800 voice_index
= voice_free
.front();
801 voice_free
.pop_front();
803 // Play the note on that voice
804 voice_notes
[voice_index
] = n
.note
;
805 float freq
= 440.0f
* powf(2.0f
,(((float)n
.note
)-69.0f
)/12.0f
);
806 float gain
= n
.velocity
/127.0f
;
807 setFreq(freq
, voice_index
); // Hz - requires Faust control-signal "freq"
808 setGain(gain
, voice_index
); // 0-1 - requires Faust control-signal "gain"
809 setGate(1.0f
, voice_index
); // 0 or 1 - requires Faust button-signal "gate"
813 case SND_SEQ_EVENT_NOTEOFF
:
814 for (voice_index
= 0; voice_index
< voice_notes
.size(); voice_index
++)
816 if (voice_notes
[voice_index
] == events
[eventPos
].data
.note
.note
)
818 setGate(0, voice_index
);
819 // TODO using -1 to represent nothing; think of a more clear way to do this
820 voice_notes
[voice_index
] = -1;
821 voice_free
.push_back(voice_index
);
831 if ((eventPos
< eventCount
) && (events
[eventPos
].time
.tick
< sampleCount
))
833 count
= events
[eventPos
].time
.tick
- pos
;
837 count
= sampleCount
- pos
;
845 void Plugin::addSamples(int samples
)
851 // TODO this isn't very efficient right now...
853 // Grow temp buffers to appropriate size / zero them:
854 for (i
= 0; i
< m_temp_outputs
.size(); i
++)
856 for (j
= 0; j
< samples
; j
++)
858 if (m_temp_outputs
[i
].size() < (j
+1))
860 m_temp_outputs
[i
].push_back(0.0);
864 m_temp_outputs
[i
][j
] = 0.0;
871 // Add all voices together
872 for (v
= 0; v
< m_voices
.size(); v
++)
874 m_voices
[v
]->m_mydsp
->compute(samples
, &m_inputs
[0], &m_outputs
[0]);
876 // Accumulate in temp buffer
877 for (i
= 0; i
< m_outputs
.size(); i
++)
879 for (j
= 0; j
< samples
; j
++)
881 m_temp_outputs
[i
][j
] += m_outputs
[i
][j
];
886 // Transfer accumulator to actual outputs
887 for (i
= 0; i
< m_outputs
.size(); i
++)
889 for (j
= 0; j
< samples
; j
++)
891 // TODO find a better way to protect against clipping.
892 m_outputs
[i
][j
] = m_temp_outputs
[i
][j
] / (float)MAX_POLYPHONY
;
897 void Plugin::setFreq(float val
, int voice
)
899 m_voices
[voice
]->setFreq(val
);
902 void Plugin::setGate(float val
, int voice
)
904 m_voices
[voice
]->setGate(val
);
907 void Plugin::setGain(float val
, int voice
)
909 m_voices
[voice
]->setGain(val
);
912 void Plugin::addButton(const char* label
, float* zone
)
914 if (!ckAnyMatch(label
, "gate"))
916 add_control_with_default(0);
920 void Plugin::addToggleButton(const char* label
, float* zone
)
922 add_control_with_default(0);
925 void Plugin::addCheckButton(const char* label
, float* zone
)
927 add_control_with_default(0);
930 void Plugin::addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
932 if (!ckAllMatches(label
))
934 add_control_with_default(init
);
937 void Plugin::addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
939 if (!ckAllMatches(label
))
941 add_control_with_default(init
);
944 void Plugin::addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
946 if (!ckAllMatches(label
))
948 add_control_with_default(init
);
952 void Plugin::addNumDisplay(const char* label
, float* zone
, int precision
)
954 add_control_with_default(0);
956 void Plugin::addTextDisplay(const char* label
, float* zone
, char* names
[], float min
, float max
)
958 add_control_with_default(0);
960 void Plugin::addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
)
962 add_control_with_default(min
);
964 void Plugin::addVerticalBargraph(const char* label
, float* zone
, float min
, float max
)
966 add_control_with_default(min
);
969 void Plugin::openFrameBox(const char* label
)
972 void Plugin::openTabBox(const char* label
)
975 void Plugin::openHorizontalBox(const char* label
)
978 void Plugin::openVerticalBox(const char* label
)
981 void Plugin::closeBox()
992 bool Plugin::ckAnyMatch(const char* label
, const char* indexName
)
994 // TODO do case-insensitive here...
995 if (strcmp(label
,indexName
)==0)
1001 bool Plugin::ckAllMatches(const char* label
)
1003 bool result
= false;
1004 result
= result
|| ckAnyMatch(label
,"gain");
1005 result
= result
|| ckAnyMatch(label
,"gate");
1006 result
= result
|| ckAnyMatch(label
,"freq");
1009 void Plugin::add_control_with_default(float default_value
)
1011 // TODO may need to consider different things for input and output controls...
1012 m_controls
.push_back(0);
1013 m_control_defaults
.push_back(default_value
);
1017 ////////////////////////////////////////////////////////////////////////////////
1019 ////////////////////////////////////////////////////////////////////////////////
1020 Voice::Voice(int sampleRate
) :
1021 m_samplerate(sampleRate
),
1026 m_mydsp
= new mydsp();
1034 void Voice::setFreq(float val
)
1042 void Voice::setGate(float val
)
1050 void Voice::setGain(float val
)
1058 void Voice::addButton(const char* label
, float* zone
)
1060 if (!ckAnyMatch(label
, "gate", &m_gate_zone
, zone
))
1066 void Voice::addToggleButton(const char* label
, float* zone
)
1071 void Voice::addCheckButton(const char* label
, float* zone
)
1076 void Voice::addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1078 if (!ckAllMatches(label
, zone
))
1083 void Voice::addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1085 if (!ckAllMatches(label
, zone
))
1090 void Voice::addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1092 if (!ckAllMatches(label
, zone
))
1098 void Voice::addNumDisplay(const char* label
, float* zone
, int precision
)
1102 void Voice::addTextDisplay(const char* label
, float* zone
, char* names
[], float min
, float max
)
1106 void Voice::addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
)
1110 void Voice::addVerticalBargraph(const char* label
, float* zone
, float min
, float max
)
1115 void Voice::openFrameBox(const char* label
)
1118 void Voice::openTabBox(const char* label
)
1121 void Voice::openHorizontalBox(const char* label
)
1124 void Voice::openVerticalBox(const char* label
)
1127 void Voice::closeBox()
1138 bool Voice::ckAnyMatch(const char* label
, const char* indexName
, float **zone
, float* newZone
)
1140 // TODO do case-insensitive here...
1141 if (strcmp(label
,indexName
)==0)
1148 bool Voice::ckAllMatches(const char* label
, float* zone
)
1150 bool result
= false;
1151 result
= result
|| ckAnyMatch(label
,"gain", &m_gain_zone
, zone
);
1152 result
= result
|| ckAnyMatch(label
,"gate", &m_gate_zone
, zone
);
1153 result
= result
|| ckAnyMatch(label
,"freq", &m_freq_zone
, zone
);
1156 void Voice::addZone(float* zone
)
1158 m_controls
.push_back(zone
);
1162 ////////////////////////////////////////////////////////////////////////////////
1163 // Shared object hooks
1164 ////////////////////////////////////////////////////////////////////////////////
1169 __attribute__((constructor
)) void init(void)
1176 if (g_dssi_descriptor
== 0)
1178 g_ladspa_descriptor
= new LADSPA_Descriptor();
1179 g_dssi_descriptor
= new DSSI_Descriptor();
1181 mydsp
* temp_mydsp
= new mydsp();
1182 DescriptorUI
* temp_descriptor_ui
= new DescriptorUI(temp_mydsp
->getNumInputs(), temp_mydsp
->getNumOutputs());
1183 temp_mydsp
->buildUserInterface(temp_descriptor_ui
);
1185 // Fill the descriptors:
1186 // TODO figure out strdup with const strings
1187 g_ladspa_descriptor
->UniqueID
= 0;
1188 g_ladspa_descriptor
->Label
= get_metadata_if_exists("name", g_name
.c_str());
1189 g_ladspa_descriptor
->Properties
= LADSPA_PROPERTY_HARD_RT_CAPABLE
;
1190 g_ladspa_descriptor
->Name
= get_metadata_if_exists("name", g_name
.c_str());
1191 g_ladspa_descriptor
->Maker
= get_metadata_if_exists("author", "Maker");
1192 g_ladspa_descriptor
->Copyright
= get_metadata_if_exists("copyright", "Copyright");
1193 g_ladspa_descriptor
->PortCount
= g_port_descriptors
.size();
1194 g_ladspa_descriptor
->PortDescriptors
= &g_port_descriptors
[0];
1195 g_ladspa_descriptor
->PortNames
= &g_port_names
[0];
1196 g_ladspa_descriptor
->PortRangeHints
= &g_port_range_hints
[0];
1197 g_ladspa_descriptor
->ImplementationData
= 0;
1198 g_ladspa_descriptor
->instantiate
= Plugin::instantiate
;
1199 g_ladspa_descriptor
->connect_port
= Plugin::connectPort
;
1200 g_ladspa_descriptor
->activate
= Plugin::activate
;
1201 g_ladspa_descriptor
->run
= Plugin::run
;
1202 g_ladspa_descriptor
->run_adding
= 0;
1203 g_ladspa_descriptor
->set_run_adding_gain
= 0;
1204 g_ladspa_descriptor
->deactivate
= 0;
1205 g_ladspa_descriptor
->cleanup
= Plugin::cleanup
;
1207 g_dssi_descriptor
->DSSI_API_Version
= 1;
1208 g_dssi_descriptor
->LADSPA_Plugin
= g_ladspa_descriptor
;
1209 g_dssi_descriptor
->configure
= 0;
1210 g_dssi_descriptor
->get_program
= Plugin::getProgram
;
1211 g_dssi_descriptor
->select_program
= Plugin::selectProgram
;
1212 g_dssi_descriptor
->get_midi_controller_for_port
= Plugin::getMidiController
;
1213 g_dssi_descriptor
->run_synth
= Plugin::runSynth
;
1214 g_dssi_descriptor
->run_synth_adding
= 0;
1215 g_dssi_descriptor
->run_multiple_synths
= 0;
1216 g_dssi_descriptor
->run_multiple_synths_adding
= 0;
1218 // Program description (TODO if we eventually support multiple programs we will need to handle this differently)
1219 g_program_descriptor
.Bank
= 0;
1220 g_program_descriptor
.Program
= 0;
1221 g_program_descriptor
.Name
= get_metadata_if_exists("name", g_name
.c_str());
1224 delete temp_descriptor_ui
;
1229 __attribute__((destructor
)) void fini(void)
1234 if (g_ladspa_descriptor
)
1236 delete g_ladspa_descriptor
;
1238 if (g_dssi_descriptor
)
1240 delete g_dssi_descriptor
;
1244 const LADSPA_Descriptor
*ladspa_descriptor(unsigned long index
)
1249 const DSSI_Descriptor
*dssi_descriptor(unsigned long index
)
1253 return g_dssi_descriptor
;
1262 /********************END ARCHITECTURE SECTION (part 2/2)****************/