1 /************************************************************************
3 IMPORTANT NOTE : this file contains two clearly delimited sections :
4 the ARCHITECTURE section (in two parts) and the USER section. Each section
5 is governed by its own copyright and license. Please check individually
6 each section for license and copyright information.
7 *************************************************************************/
9 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
11 /************************************************************************
12 ************************************************************************
13 FAUST Architecture File
14 Copyright (C) 2007-2011 Julius Smith
16 ----------------------------BSD License------------------------------
17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions
21 * Redistributions of source code must retain the above copyright
22 notice, this list of conditions and the following disclaimer.
23 * Redistributions in binary form must reproduce the above
24 copyright notice, this list of conditions and the following
25 disclaimer in the documentation and/or other materials provided
26 with the distribution.
27 * Neither the name of Julius Smith nor the names of its
28 contributors may be used to endorse or promote products derived
29 from this software without specific prior written permission.
31 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
34 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
35 COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
36 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
37 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
42 OF THE POSSIBILITY OF SUCH DAMAGE.
44 ----------------------------VST SDK----------------------------------
45 In order to compile a VST (TM) plugin with this architecture file
46 you will need the proprietary VST SDK from Steinberg. Please check
47 the corresponding license.
49 ************************************************************************
50 ************************************************************************/
52 /********************************************************************
53 * vsti-mono.cpp - Monaural VSTi-2.4 wrapper for the FAUST language.
55 * Usage: faust -a vsti-mono.cpp myfaustprog.dsp
57 * By Julius Smith (http://ccrma.stanford.edu/~jos/), based on vst.cpp
58 * by remy muller <remy.muller at ircam.fr>
59 * (http://www.smartelectronix.com/~mdsp/). Essentially, vst.cpp was
60 * first edited to look more like the "again" programming sample that
61 * comes with the VST-2.4 SDK from Steinberg. Next, features from the
62 * "vstxsynth" program sample were added to give simple MIDI synth
63 * support analogous to that of faust2pd, except that only one voice
64 * is supported. (If the Faust patch has any input signals, this
65 * architecture file should reduce to vst2p4.cpp --- i.e., basic VST
66 * plugin support.) As with faust2pd, to obtain MIDI control via
67 * NoteOn/Off, Velocity, and KeyNumber, there must be a button named
68 * "gate" and sliders (or numeric entries) named "gain" and "freq" in
69 * the Faust patch specified in myfaustprog.dsp.
72 * Relies on automatically generated slider GUI for VST plugins.
73 * - Horizontal and vertical sliders mapped to "vstSlider"
74 * - Numeric Entries similarly converted to "vstSlider"
75 * - No support for bar graphs or additional numeric and text displays
76 * - Tested on the Muse Receptor Pro 1.0, System Version 1.6.20070717,
77 * using Visual C++ 2008 Express Edition
78 * (part of the Microsoft Visual Studio 2008, Beta 2)
80 * http://ccrma.stanford.edu/realsimple/faust/Generating_VST_Plugin_Faust.html
83 * Copyright (C) 2003-2007 GRAME, Centre National de Creation Musicale
84 * http://www.grame.fr/
86 ********************************************************************/
88 // Suggestion: Faust could replace all leading comments in this file
89 // by the following shorter comment:
91 /********************************************************************
92 * C++ source generated by the following command line:
94 * faust -a vsti.cpp name.dsp -o name-vsti.cpp
96 ********************************************************************/
98 // (where the filenames could be really right, and the path to vsti.cpp
99 // could be included as well.)
109 //#include <unistd.h>
116 using namespace std
;
118 // There is a bug with powf() when cross compiling with mingw
119 // the following macro avoid the problem
121 #define powf(x,y) pow(x,y)
122 #define expf(x) exp(x)
125 // On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
126 // flags to avoid costly denormals
128 #include <xmmintrin.h>
130 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
132 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
135 #define AVOIDDENORMALS
140 void declare (const char* key
, const char* value
) { }
146 //-------------------------------------------------------------------
147 // Generic min and max using gcc extensions
148 //-------------------------------------------------------------------
150 #define max(x,y) ((x)>?(y))
151 #define min(x,y) ((x)<?(y))
153 //abs(x) should be already predefined
157 //-------------------------------------------------------------------
158 // Generic min and max using c++ inline
159 //-------------------------------------------------------------------
161 inline int max (unsigned int a
, unsigned int b
) { return (a
>b
) ? a
: b
; }
162 inline int max (int a
, int b
) { return (a
>b
) ? a
: b
; }
164 inline long max (long a
, long b
) { return (a
>b
) ? a
: b
; }
165 inline long max (int a
, long b
) { return (a
>b
) ? a
: b
; }
166 inline long max (long a
, int b
) { return (a
>b
) ? a
: b
; }
168 inline float max (float a
, float b
) { return (a
>b
) ? a
: b
; }
169 inline float max (int a
, float b
) { return (a
>b
) ? a
: b
; }
170 inline float max (float a
, int b
) { return (a
>b
) ? a
: b
; }
171 inline float max (long a
, float b
) { return (a
>b
) ? a
: b
; }
172 inline float max (float a
, long b
) { return (a
>b
) ? a
: b
; }
174 inline double max (double a
, double b
) { return (a
>b
) ? a
: b
; }
175 inline double max (int a
, double b
) { return (a
>b
) ? a
: b
; }
176 inline double max (double a
, int b
) { return (a
>b
) ? a
: b
; }
177 inline double max (long a
, double b
) { return (a
>b
) ? a
: b
; }
178 inline double max (double a
, long b
) { return (a
>b
) ? a
: b
; }
179 inline double max (float a
, double b
) { return (a
>b
) ? a
: b
; }
180 inline double max (double a
, float b
) { return (a
>b
) ? a
: b
; }
182 inline int min (int a
, int b
) { return (a
<b
) ? a
: b
; }
184 inline long min (long a
, long b
) { return (a
<b
) ? a
: b
; }
185 inline long min (int a
, long b
) { return (a
<b
) ? a
: b
; }
186 inline long min (long a
, int b
) { return (a
<b
) ? a
: b
; }
188 inline float min (float a
, float b
) { return (a
<b
) ? a
: b
; }
189 inline float min (int a
, float b
) { return (a
<b
) ? a
: b
; }
190 inline float min (float a
, int b
) { return (a
<b
) ? a
: b
; }
191 inline float min (long a
, float b
) { return (a
<b
) ? a
: b
; }
192 inline float min (float a
, long b
) { return (a
<b
) ? a
: b
; }
194 inline double min (double a
, double b
) { return (a
<b
) ? a
: b
; }
195 inline double min (int a
, double b
) { return (a
<b
) ? a
: b
; }
196 inline double min (double a
, int b
) { return (a
<b
) ? a
: b
; }
197 inline double min (long a
, double b
) { return (a
<b
) ? a
: b
; }
198 inline double min (double a
, long b
) { return (a
<b
) ? a
: b
; }
199 inline double min (float a
, double b
) { return (a
<b
) ? a
: b
; }
200 inline double min (double a
, float b
) { return (a
<b
) ? a
: b
; }
204 // abs is now predefined
205 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
207 inline int lsr (int x
, int n
) { return int(((unsigned int)x
) >> n
); }
209 inline int int2pow2 (int x
) { int r
=0; while ((1<<r
)<x
) r
++; return r
; }
211 /******************************************************************************
212 *******************************************************************************
216 *******************************************************************************
217 *******************************************************************************/
219 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
220 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
224 /******************************************************************************
225 *******************************************************************************
229 *******************************************************************************
230 *******************************************************************************/
238 UI() : fStopped(false) {}
241 virtual void addButton(char* label
, float* zone
) = 0;
242 virtual void addToggleButton(char* label
, float* zone
) = 0;
243 virtual void addCheckButton(char* label
, float* zone
) = 0;
244 virtual void addVerticalSlider(char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
245 virtual void addHorizontalSlider(char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
246 virtual void addNumEntry(char* label
, float* zone
, float init
, float min
, float max
, float step
) = 0;
248 virtual void addNumDisplay(char* label
, float* zone
, int precision
) = 0;
249 virtual void addTextDisplay(char* label
, float* zone
, char* names
[], float min
, float max
) = 0;
250 virtual void addHorizontalBargraph(char* label
, float* zone
, float min
, float max
) = 0;
251 virtual void addVerticalBargraph(char* label
, float* zone
, float min
, float max
) = 0;
253 virtual void openFrameBox(char* label
) = 0;
254 virtual void openTabBox(char* label
) = 0;
255 virtual void openHorizontalBox(char* label
) = 0;
256 virtual void openVerticalBox(char* label
) = 0;
257 virtual void closeBox() = 0;
259 virtual void run() {};
261 void stop() { fStopped
= true; }
262 bool stopped() { return fStopped
; }
264 virtual void declare(float* zone
, const char* key
, const char* value
) {}
268 /******************************************************************************
269 *******************************************************************************
273 *******************************************************************************
274 *******************************************************************************/
278 //----------------------------------------------------------------
279 // Base dsp class for this architecture
280 //----------------------------------------------------------------
292 virtual int getNumInputs() = 0;
293 virtual int getNumOutputs() = 0;
294 virtual void buildUserInterface(UI
* interface
) = 0;
295 virtual void init(int samplingRate
) = 0;
296 virtual void compute(int len
, float** inputs
, float** outputs
) = 0;
299 /********************END ARCHITECTURE SECTION (part 1/2)****************/
301 /**************************BEGIN USER SECTION **************************/
305 /***************************END USER SECTION ***************************/
307 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
309 /******************************************************************************
313 ******************************************************************************/
315 #include "audioeffectx.h"
319 //------------------------------------------------------------------------------
320 // Faust class prototype
321 //------------------------------------------------------------------------------
322 class Faust
: public AudioEffectX
325 Faust(audioMasterCallback audioMaster
, mydsp
* dspi
, vstUI
* dspUIi
);
328 virtual void processReplacing (float **inputs
, float **outputs
, VstInt32 sampleFrames
);
329 virtual VstInt32
processEvents (VstEvents
* events
);
331 virtual void setProgram (VstInt32 program
);
332 virtual void setProgramName (char *name
);
333 virtual void getProgramName (char *name
);
334 virtual bool getProgramNameIndexed (VstInt32 category
, VstInt32 index
, char *text
);
336 virtual void setParameter (VstInt32 index
, float value
);
337 virtual float getParameter (VstInt32 index
);
338 virtual void getParameterLabel (VstInt32 index
, char *label
);
339 virtual void getParameterDisplay (VstInt32 index
, char *text
);
340 virtual void getParameterName (VstInt32 index
, char *text
);
342 virtual void setSampleRate (float sampleRate
);
344 virtual bool getInputProperties (VstInt32 index
, VstPinProperties
*properties
);
345 virtual bool getOutputProperties (VstInt32 index
, VstPinProperties
*properties
);
347 virtual bool getEffectName (char *name
);
348 virtual bool getVendorString (char *text
);
349 virtual bool getProductString (char *text
);
350 virtual VstInt32
getVendorVersion ();
351 virtual VstInt32
canDo (char *text
);
353 virtual VstInt32
getNumMidiInputChannels ();
354 virtual VstInt32
getNumMidiOutputChannels ();
356 virtual VstInt32
getMidiProgramName (VstInt32 channel
, MidiProgramName
*midiProgramName
);
357 virtual VstInt32
getCurrentMidiProgram (VstInt32 channel
, MidiProgramName
*currentProgram
);
358 virtual VstInt32
getMidiProgramCategory (VstInt32 channel
, MidiProgramCategory
*category
);
366 VstInt32 currentNote
;
367 VstInt32 currentVelocity
;
368 VstInt32 currentDelta
;
371 void noteOn (VstInt32 note
, VstInt32 velocity
, VstInt32 delta
);
373 void fillProgram (VstInt32 channel
, VstInt32 prg
, MidiProgramName
* mpn
);
375 char programName
[kVstMaxProgNameLen
+ 1];
378 /*--------------------------------------------------------------------------*/
379 class vstUIObject
{ /* superclass of all VST UI widgets */
384 inline float clip(float min
, float max
, float val
)
386 return (val
< min
) ? min
: (val
> max
) ? max
: val
;
389 inline float normalize(float min
, float max
, float val
)
390 { // VST parameters are normalized to the range [0;1] on the host
391 val
= min
+ val
* (max
- min
);
392 return (val
< min
) ? min
: (val
> max
) ? max
: val
;
396 vstUIObject(char* label
, float* zone
):fLabel(label
),fZone(zone
) {}
397 virtual ~vstUIObject() {}
399 virtual void GetName(char *text
){std::strcpy(text
,fLabel
.c_str());}
400 virtual void SetValue(double f
) {*fZone
= normalize(0.0f
,1.0f
,(float)f
);}
401 virtual void SetValueNoNormalization(double f
) {*fZone
= clip(0.0f
,1.0f
,(float)f
);}
402 virtual float GetValue() {return *fZone
;}
403 virtual void GetDisplay(char *text
){std::sprintf(text
,"%f",*fZone
);}
405 { /* returns the sum of all the ASCII characters contained in the parameter's label */
408 for(i
=0,acc
= 0;i
<fLabel
.length();i
++) acc
+= (fLabel
.c_str())[i
];
413 /*--------------------------------------------------------------------------*/
414 class vstToggleButton
: public vstUIObject
{
418 vstToggleButton(char* label
, float* zone
):vstUIObject(label
,zone
) {}
419 virtual ~vstToggleButton() {}
420 virtual float GetValue() {return *fZone
;}
421 virtual void SetValue(double f
) {*fZone
= (f
>0.5f
)?1.0f
:0.0f
;}
422 virtual void GetDisplay(char *text
){(*fZone
>0.5f
)? std::strcpy(text
,"ON"): std::strcpy(text
,"OFF");}
425 /*--------------------------------------------------------------------------*/
426 class vstCheckButton
: public vstUIObject
{
430 vstCheckButton(char* label
, float* zone
):vstUIObject(label
,zone
) {}
431 virtual ~vstCheckButton() {}
432 virtual float GetValue() {return *fZone
;}
433 virtual void SetValue(double f
) {*fZone
= (f
>0.5f
)?1.0f
:0.0f
;}
434 virtual void GetDisplay(char *text
){(*fZone
>0.5f
)? std::strcpy(text
,"ON"): std::strcpy(text
,"OFF");}
437 /*--------------------------------------------------------------------------*/
438 class vstButton
: public vstUIObject
{
442 vstButton(char* label
, float* zone
):vstUIObject(label
,zone
) {}
443 virtual ~vstButton() {}
444 virtual float GetValue() {return *fZone
;}
445 virtual void SetValue(double f
) {*fZone
= (f
>0.5f
)?1.0f
:0.0f
;}
446 virtual void GetDisplay(char *text
){(*fZone
>0.5f
)? std::strcpy(text
,"ON"): std::strcpy(text
,"OFF");}
449 /*--------------------------------------------------------------------------*/
450 class vstSlider
: public vstUIObject
{
461 vstSlider(char* label
, float* zone
, float init
, float min
, float max
, float step
)
462 :vstUIObject(label
,zone
), fInit(init
), fMin(min
), fMax(max
),fStep(step
) {}
463 virtual ~vstSlider() {}
465 // The VST host calls GetValue() and expects a result in [0,1].
466 // The VST host calls SetValue(f) with f in [0,1]. We convert to real units.
467 // When we process MIDI controls, we call SetValueNoNormalization(f) with f in real units.
468 virtual float GetValue() {return (*fZone
-fMin
)/(fMax
-fMin
);} // normalize
469 virtual void SetValue(double f
) {*fZone
= normalize(fMin
,fMax
,(float)f
);} // denormalize
470 virtual void SetValueNoNormalization(double f
) {*fZone
= clip(fMin
,fMax
,(float)f
);} // raw
473 /*--------------------------------------------------------------------------*/
474 class vstUI
: public UI
478 vector
<vstUIObject
*> fUITable
;
487 freqIndex
= gainIndex
= gateIndex
= -1;
491 for (vector
<vstUIObject
*>::iterator iter
= fUITable
.begin(); iter
!= fUITable
.end(); iter
++) delete *iter
;
494 void setAny(int anyIndex
, float val
, char *str
) {
497 // On the Receptor, and perhaps other hosts, output to stderr is logged in a file.
498 fprintf(stderr
,"*** Faust vsti: %sIndex = %d never set!\n",str
,anyIndex
);
502 if (anyIndex
>= fUITable
.size()) {
504 fprintf(stderr
,"*** Faust vsti: %sIndex = %d too large!\n",str
,anyIndex
);
509 fprintf(stderr
,"*** Faust vsti: Setting %sIndex = %d to %f\n",str
,anyIndex
,val
);
511 fUITable
[anyIndex
]->SetValueNoNormalization(val
);
514 void setFreq(float val
) {
515 setAny(freqIndex
, val
, "freq");
518 void setGate(float val
) {
519 setAny(gateIndex
, val
, "gate");
522 void setGain(float val
) {
523 setAny(gainIndex
, val
, "gain");
526 bool ckAnyMatch(char* label
, char* indexName
, int *index
) {
527 if (_stricmp(label
,indexName
)==0) {
529 fprintf(stderr
,"=== Faust vsti: label '%s' matches '%s'\n",label
,indexName
);
531 *index
= fUITable
.size() - 1;
537 void ckAllMatches(char* label
) {
538 ckAnyMatch(label
,"gain",&gainIndex
);
539 ckAnyMatch(label
,"gate",&gateIndex
);
540 ckAnyMatch(label
,"freq",&freqIndex
);
543 void addButton(char* label
, float* zone
) {
544 vstButton
* theButton
= new vstButton(label
, zone
);
545 fUITable
.push_back(theButton
);
547 fprintf(stderr
,"=== Faust vsti: Adding Button with label '%s'\n",label
);
549 ckAnyMatch(label
,"gate",&gateIndex
);
552 void addToggleButton(char* label
, float* zone
) {fUITable
.push_back(new vstToggleButton(label
, zone
));}
554 void addCheckButton(char* label
, float* zone
) {fUITable
.push_back(new vstCheckButton(label
, zone
));}
556 void addVerticalSlider(char* label
, float* zone
, float init
, float min
, float max
, float step
)
558 vstSlider
* theSlider
= new vstSlider(label
, zone
, init
, min
, max
, step
);
559 fUITable
.push_back(theSlider
);
561 fprintf(stderr
,"=== Faust vsti: Adding VSlider (HSlider) with label '%s'\n",label
);
566 void addHorizontalSlider(char* label
, float* zone
, float init
, float min
, float max
, float step
)
568 vstSlider
* theSlider
= new vstSlider(label
, zone
, init
, min
, max
, step
);
569 fUITable
.push_back(theSlider
);
571 fprintf(stderr
,"=== Faust vsti: Adding HSlider with label '%s'\n",label
);
576 void addNumEntry(char* label
, float* zone
, float init
, float min
, float max
, float step
)
577 { /* Number entries converted to horizontal sliders */
578 vstSlider
* theSlider
= new vstSlider(label
, zone
, init
, min
, max
, step
);
579 fUITable
.push_back(theSlider
);
581 fprintf(stderr
,"=== Faust vsti: Adding NumEntry (HSlider) with label '%s'\n",label
);
586 void openFrameBox(char* label
) {}
587 void openTabBox(char* label
) {}
588 void openHorizontalBox(char* label
) {}
589 void openVerticalBox(char* label
) {}
592 void SetValue(VstInt32 index
, double f
) {assert(index
<fUITable
.size()); fUITable
[index
]->SetValue(f
);}
593 float GetValue(VstInt32 index
) {assert(index
<fUITable
.size()); return fUITable
[index
]->GetValue();}
594 void GetDisplay(VstInt32 index
, char *text
) {assert(index
<fUITable
.size()); fUITable
[index
]->GetDisplay(text
);}
595 void GetName(VstInt32 index
, char *text
) {assert(index
<fUITable
.size()); fUITable
[index
]->GetName(text
);}
596 long GetNumParams() {return fUITable
.size();}
599 /* Creates a (unique?)id by summing all the parameter's labels,
600 * then wrapping it in the range [0;maxNumberOfId] and adding
601 * this number to the offset made by the Four Character ID: 'FAUS'
604 const long maxNumberOfId
= 128;
605 long baseid
= 'FAUS';
607 for(int i
=0;i
<fUITable
.size();i
++) id
+= fUITable
[i
]->GetID();
608 return baseid
+ id
% maxNumberOfId
;
612 void addNumDisplay(char* label
, float* zone
, int precision
){}
613 void addTextDisplay(char* label
, float* zone
, char* names
[], float min
, float max
){}
614 void addHorizontalBargraph(char* label
, float* zone
, float min
, float max
){}
615 void addVerticalBargraph(char* label
, float* zone
, float min
, float max
){}
618 //-----------------------------------------------------------------------------
619 // Class Implementations
620 //-----------------------------------------------------------------------------
622 #define kNumPrograms 1
624 AudioEffect
* createEffectInstance (audioMasterCallback audioMaster
)
626 // The dsp and its UI need to be allocated now because
627 // AudioEffectX wants the no. parameters available as an instance argument:
628 mydsp
* dspi
= new mydsp();
629 vstUI
* dspUIi
= new vstUI();
630 dspi
->buildUserInterface(dspUIi
);
632 fprintf(stderr
,"=== Faust vsti: created\n"); // look for this in the system log
634 return new Faust(audioMaster
,dspi
,dspUIi
);
637 //-----------------------------------------------------------------------------
639 //-----------------------------------------------------------------------------
640 Faust::Faust(audioMasterCallback audioMaster
, mydsp
* dspi
, vstUI
* dspUIi
)
641 :AudioEffectX(audioMaster
, kNumPrograms
,dspUIi
->GetNumParams())
643 // Copy the pointers to dsp and dspUI instances and take them over
644 // (we'll also deallocate):
649 fprintf(stderr
,"=== Faust vsti: classInit:\n");
652 dsp
->classInit((int)getSampleRate()); // Ask AudioEffect for sample-rate
655 setProgramName("Default");
658 setNumInputs(dsp
->getNumInputs());
659 setNumOutputs(dsp
->getNumOutputs());
660 canProcessReplacing();
661 if (dsp
->getNumInputs() == 0) {
662 isSynth(); // at least let's hope so!
663 if (dsp
->getNumOutputs() < 1) {
664 fprintf(stderr
,"*** faust: vsti: No signal inputs or outputs, and Faust has no MIDI outputs!\n");
667 setUniqueID(dspUI
->makeID());
670 if (dsp
->getNumInputs() == 0) {
671 suspend(); // Synths start out quiet
675 //----------------------------------------------------------------------------
679 if (dspUI
) delete dspUI
;
682 //-----------------------------------------------------------------------------
683 void Faust::setProgram (VstInt32 program
)
684 // Override this method of AudioEffect in order to set
685 // local instance variables corresponding to the current MIDI program.
686 // Here there is only one program.
688 if (program
< 0 || program
>= kNumPrograms
) {
689 fprintf(stderr
,"*** Faust vsti: setting program to %d is OUT OF RANGE\n",program
);
693 fprintf(stderr
,"=== Faust vsti: setting program to %d\n",program
);
695 curProgram
= program
; // curProgram defined in audioeffect.h
698 //------------------------------------------------------------------------------
699 void Faust::setProgramName (char* name
)
701 vst_strncpy (programName
, name
, kVstMaxProgNameLen
);
704 //-----------------------------------------------------------------------------
705 void Faust::getProgramName(char *name
)
707 vst_strncpy (name
, programName
, kVstMaxProgNameLen
);
710 //-----------------------------------------------------------------------------
711 void Faust::getParameterLabel(VstInt32 index
, char *label
)
713 // We are not using parameter "units" display:
714 vst_strncpy (label
, "", kVstMaxParamStrLen
); // parameter units in Name
717 //-----------------------------------------------------------------------------
718 void Faust::getParameterDisplay(VstInt32 index
, char *text
)
721 dspUI
->GetDisplay(index
,text
); // get displayed float value as text
723 vst_strncpy (text
, "IndexOutOfRange", kVstMaxParamStrLen
);
726 //-----------------------------------------------------------------------------
727 void Faust::getParameterName(VstInt32 index
, char *label
)
730 dspUI
->GetName(index
,label
); // parameter name, including units
732 vst_strncpy (label
, "IndexOutOfRange", kVstMaxParamStrLen
);
735 //-----------------------------------------------------------------------------
736 void Faust::setParameter(VstInt32 index
, float value
)
739 dspUI
->SetValue(index
,value
);
742 //-----------------------------------------------------------------------------
743 float Faust::getParameter(VstInt32 index
)
746 return dspUI
->GetValue(index
);
751 //-----------------------------------------------------------------------------
752 bool Faust::getInputProperties (VstInt32 index
, VstPinProperties
* properties
)
754 if(index
>=0 && index
<dsp
->getNumInputs())
756 sprintf (properties
->label
, "Grame Faust DSP input: %d",index
);
757 sprintf (properties
->shortLabel
, "In %d",index
);
758 properties
->flags
= kVstPinIsActive
;
759 if (dsp
->getNumInputs() == 2) {
760 properties
->flags
|= kVstPinIsStereo
;
768 //-----------------------------------------------------------------------------
769 bool Faust::getOutputProperties (VstInt32 index
, VstPinProperties
* properties
)
771 if(index
>=0 && index
<dsp
->getNumOutputs())
773 sprintf (properties
->label
, "Grame Faust DSP output: %d",index
);
774 sprintf (properties
->shortLabel
, "Out %d",index
);
775 properties
->flags
= kVstPinIsActive
;
776 if (dsp
->getNumOutputs() == 2) {
777 properties
->flags
|= kVstPinIsStereo
;
785 //-----------------------------------------------------------------------------
786 bool Faust::getProgramNameIndexed (VstInt32 category
, VstInt32 index
, char* text
)
788 if (index
< kNumPrograms
) {
789 vst_strncpy (text
, programName
, kVstMaxProgNameLen
);
795 //-----------------------------------------------------------------------------
796 bool Faust::getEffectName (char* name
)
798 // Get from Faust-supplied metadata?
799 vst_strncpy (name
, "Effect Name goes here", kVstMaxEffectNameLen
);
803 //-----------------------------------------------------------------------------
804 bool Faust::getVendorString (char* text
)
806 vst_strncpy (text
, "Vendor String goes here", kVstMaxVendorStrLen
);
810 //-----------------------------------------------------------------------------
811 bool Faust::getProductString (char* text
)
813 vst_strncpy (text
, "Product String goes here", kVstMaxProductStrLen
);
817 //-----------------------------------------------------------------------------
818 VstInt32
Faust::getVendorVersion ()
823 //-----------------------------------------------------------------------------
824 VstInt32
Faust::canDo (char* text
)
826 if (!strcmp (text
, "receiveVstEvents"))
828 if (!strcmp (text
, "receiveVstMidiEvent"))
830 if (!strcmp (text
, "midiProgramNames"))
832 return -1; // explicitly can't do; 0 => don't know
835 //-----------------------------------------------------------------------------
836 VstInt32
Faust::getNumMidiInputChannels ()
838 return 1; // one MIDI-in channel
841 //-----------------------------------------------------------------------------
842 VstInt32
Faust::getNumMidiOutputChannels ()
844 return 0; // no MIDI-outs
847 //-----------------------------------------------------------------------------
848 VstInt32
Faust::getMidiProgramName (VstInt32 channel
, MidiProgramName
* mpn
)
850 VstInt32 prg
= mpn
->thisProgramIndex
;
851 if (prg
< 0 || prg
> 0) return 0;
852 fillProgram (channel
, prg
, mpn
);
853 return 1; // we have only 1 "MIDI program"
856 //------------------------------------------------------------------------
857 VstInt32
Faust::getCurrentMidiProgram (VstInt32 channel
, MidiProgramName
* mpn
)
859 // There is only one MIDI program here, so return it regardless of MIDI channel:
860 if (channel
< 0 || channel
>= 16 || !mpn
) return -1;
862 mpn
->thisProgramIndex
= prg
;
863 fillProgram (channel
, prg
, mpn
);
867 //------------------------------------------------------------------------
868 void Faust::fillProgram (VstInt32 channel
, VstInt32 prg
, MidiProgramName
* mpn
)
869 // Fill mpn struct for given channel. Here there should be only one.
871 mpn
->midiBankMsb
= mpn
->midiBankLsb
= -1;
874 vst_strncpy (mpn
->name
, programName
, kVstMaxProgNameLen
);
875 mpn
->midiProgram
= (char)prg
; // prg should only be 0
876 mpn
->parentCategoryIndex
= -1;
879 //------------------------------------------------------------------------
880 VstInt32
Faust::getMidiProgramCategory (VstInt32 channel
, MidiProgramCategory
* cat
)
881 // VST host wants to fill cat struct for given channel. We have only one category.
883 cat
->parentCategoryIndex
= -1; // -1:no parent category
884 cat
->flags
= 0; // reserved, none defined yet, zero.
885 VstInt32 category
= cat
->thisCategoryIndex
;
886 vst_strncpy (cat
->name
, "Faust Patch", kVstMaxProgNameLen
);
887 return 1; // one category
890 //***********************************************************************
892 //-----------------------------------------------------------------------------
893 void Faust::setSampleRate(float sampleRate
)
895 AudioEffect::setSampleRate(sampleRate
);
896 dsp
->instanceInit((int)getSampleRate()); // in case AudioEffect altered it
899 //-----------------------------------------------------------------------------
900 void Faust::initProcess ()
903 currentDelta
= currentNote
= currentDelta
= 0;
904 dsp
->instanceInit((int)getSampleRate());
907 //-----------------------------------------------------------------------------
908 void Faust::processReplacing(float **inputs
, float **outputs
, VstInt32 sampleFrames
)
912 fprintf(stderr
,"=== Faust vsti: processReplacing . . .\n");
915 if (dsp
->getNumInputs() > 0) { // We're an effect . . . keep going:
917 dsp
->compute(sampleFrames
, inputs
, outputs
);
919 } else { // We're a synth . . .
920 int i
, nouts
= dsp
->getNumOutputs();
922 if (noteIsOn
) { // we're synthesizing . . .
924 if (currentDelta
> 0) { // but waiting out a timestamp delay . . .
925 if (currentDelta
>= sampleFrames
) { // start time is after this chunk
926 currentDelta
-= sampleFrames
;
927 // According to the VST programming sample, we DON'T clear the output buffers yet.
928 // Could this be a bug in the sample program? I would like to add the following:
929 // for (i=0; i<nouts; i++) { memset (outptr[i], 0, sampleFrames * sizeof (float)); }
932 // float* outptr[nouts];
933 float** outptr
= (float **)malloc(nouts
* sizeof(float*));
936 fprintf(stderr
,"*** Faust vsti: currentDelta = %d\n",currentDelta
);
939 for (i
=0; i
<nouts
; i
++) {
940 outptr
[i
] = outputs
[i
]; // leaving caller's pointers alone
941 // According to the VST programming sample, we DO clear the output buffers now
942 // (since the start-time for the note is somewhere within the current chunk buf).
943 memset (outptr
[i
], 0, currentDelta
* sizeof (float));
944 outptr
[i
] += currentDelta
;
946 sampleFrames
-= currentDelta
;
948 dsp
->compute(sampleFrames
, inputs
, outptr
);
952 dsp
->compute(sampleFrames
, inputs
, outputs
);
955 } else { // silence until NoteOn . . .
956 for (i
=0; i
<nouts
; i
++) { memset (outputs
[i
], 0, sampleFrames
* sizeof (float)); }
961 //-----------------------------------------------------------------------------
962 VstInt32
Faust::processEvents (VstEvents
* ev
)
964 if (ev
->numEvents
> 0) {
966 fprintf(stderr
,"=== Faust vsti: processEvents processing %d events\n",
971 for (VstInt32 i
= 0; i
< ev
->numEvents
; i
++)
974 fprintf(stderr
,"=== Faust vsti: event type = %d\n",
975 (ev
->events
[i
])->type
);
977 if ((ev
->events
[i
])->type
!= kVstMidiType
) {
979 fprintf(stderr
,"=== Faust vsti: EVENT IGNORED!\n");
983 VstMidiEvent
* event
= (VstMidiEvent
*)ev
->events
[i
];
984 char* midiData
= event
->midiData
;
985 VstInt32 chan
= midiData
[0] & 0xf;
986 VstInt32 status
= midiData
[0] & 0xf0;
988 fprintf(stderr
,"\n=== Faust vsti: event->midiData[0] = 0x%x\n",
990 fprintf(stderr
,"=== Faust vsti: midi channel = 0x%x\n", chan
);
991 fprintf(stderr
,"=== Faust vsti: midi status = 0x%x\n", status
);
992 fprintf(stderr
,"=== Faust vsti: event->midiData[1] = 0x%x\n",
994 fprintf(stderr
,"=== Faust vsti: event->midiData[2] = 0x%x\n",
998 if (status
== 0x90) { // note on
999 VstInt32 note
= midiData
[1] & 0x7f;
1000 VstInt32 velocity
= midiData
[2] & 0x7f;
1003 "=== Faust vsti: note = %d, velocity = %d, delay = %d\n",
1004 note
,velocity
,event
->deltaFrames
);
1007 noteOn(note
, velocity
, event
->deltaFrames
);
1011 } else if (status
== 0x80) { // note off
1013 // } else if (status == 0xA0) { // poly aftertouch
1014 } else if (status
== 0xB0) { // control change
1015 /* DO SOMETHING WITH THE CONTROLLER DATA */
1016 fprintf(stderr
,"=== Faust vsti: CONTROL CHANGE (status 0xB0)!\n");
1017 if (midiData
[1] == 0x7e || midiData
[1] == 0x7b) { // all notes off
1018 fprintf(stderr
,"=== Faust vsti: ALL NOTES OFF!\n");
1019 noteOff (); // why is all-notes-off inside a "control change" event?
1021 // } else if (status == 0xC0) { // program change
1022 // } else if (status == 0xD0) { // mono aftertouch
1023 // } else if (status == 0xE0) { // pitch change
1024 // } else if (status == 0xF0) { // SYSX ...
1027 // http://www.alfred-j-faust.de/rft/midi%20status%20types.html
1030 fprintf(stderr
,"=== Faust vsti: Going to next event\n", event
->midiData
[2]);
1038 //-----------------------------------------------------------------------------
1039 void Faust::noteOn (VstInt32 note
, VstInt32 velocity
, VstInt32 delta
)
1042 fprintf(stderr
,"=== Faust vsti: noteOn: note = %d, vel = %d, del = %d\n",note
,velocity
,delta
);
1045 currentVelocity
= velocity
;
1046 currentDelta
= delta
;
1048 float freq
= 440.0f
* powf(2.0f
,(((float)note
)-69.0f
)/12.0f
);
1049 float gain
= velocity
/127.0f
;
1050 dspUI
->setFreq(freq
); // Hz - requires Faust control-signal "freq"
1051 dspUI
->setGain(gain
); // 0-1 - requires Faust control-signal "gain"
1052 dspUI
->setGate(1.0f
); // 0 or 1 - requires Faust button-signal "gate"
1055 //-----------------------------------------------------------------------------
1056 void Faust::noteOff ()
1060 fprintf(stderr
,"=== Faust vsti: noteOff\n");
1065 fprintf(stderr
,"=== Faust vsti: noteOff IGNORED (note was not on)\n");
1071 /********************END ARCHITECTURE SECTION (part 2/2)****************/