Add sinwave, fft and fft2d examples.
[Faustine.git] / interpretor / preprocessor / faust-0.9.47mr3 / architecture / vsti-mono.cpp
1 /************************************************************************
2
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 *************************************************************************/
8
9 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
10
11 /************************************************************************
12 ************************************************************************
13 FAUST Architecture File
14 Copyright (C) 2007-2011 Julius Smith
15 All rights reserved.
16 ----------------------------BSD License------------------------------
17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions
19 are met:
20
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.
30
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.
43
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.
48
49 ************************************************************************
50 ************************************************************************/
51
52 /********************************************************************
53 * vsti-mono.cpp - Monaural VSTi-2.4 wrapper for the FAUST language.
54 *
55 * Usage: faust -a vsti-mono.cpp myfaustprog.dsp
56 *
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.
70 *
71 * NOTES:
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)
79 * - Reference:
80 * http://ccrma.stanford.edu/realsimple/faust/Generating_VST_Plugin_Faust.html
81 *
82 * FAUST
83 * Copyright (C) 2003-2007 GRAME, Centre National de Creation Musicale
84 * http://www.grame.fr/
85 *
86 ********************************************************************/
87
88 // Suggestion: Faust could replace all leading comments in this file
89 // by the following shorter comment:
90
91 /********************************************************************
92 * C++ source generated by the following command line:
93 *
94 * faust -a vsti.cpp name.dsp -o name-vsti.cpp
95 *
96 ********************************************************************/
97
98 // (where the filenames could be really right, and the path to vsti.cpp
99 // could be included as well.)
100
101 #include <stdlib.h>
102 #include <stdlib.h>
103 #include <stdio.h>
104 #include <string.h>
105 #include <limits.h>
106 #include <math.h>
107 #include <errno.h>
108 #include <time.h>
109 //#include <unistd.h>
110 #include <fcntl.h>
111 #include <assert.h>
112 #include <string>
113 #include <vector>
114 #include <math.h>
115
116 using namespace std ;
117
118 // There is a bug with powf() when cross compiling with mingw
119 // the following macro avoid the problem
120 #ifdef WIN32
121 #define powf(x,y) pow(x,y)
122 #define expf(x) exp(x)
123 #endif
124
125 // On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
126 // flags to avoid costly denormals
127 #ifdef __SSE__
128 #include <xmmintrin.h>
129 #ifdef __SSE2__
130 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
131 #else
132 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
133 #endif
134 #else
135 #define AVOIDDENORMALS
136 #endif
137
138 struct Meta
139 {
140 void declare (const char* key, const char* value) { }
141 };
142
143
144 #ifdef __GNUC__
145
146 //-------------------------------------------------------------------
147 // Generic min and max using gcc extensions
148 //-------------------------------------------------------------------
149
150 #define max(x,y) ((x)>?(y))
151 #define min(x,y) ((x)<?(y))
152
153 //abs(x) should be already predefined
154
155 #else
156
157 //-------------------------------------------------------------------
158 // Generic min and max using c++ inline
159 //-------------------------------------------------------------------
160
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; }
163
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; }
167
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; }
173
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; }
181
182 inline int min (int a, int b) { return (a<b) ? a : b; }
183
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; }
187
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; }
193
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; }
201
202 #endif
203
204 // abs is now predefined
205 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
206
207 inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
208
209 inline int int2pow2 (int x) { int r=0; while ((1<<r)<x) r++; return r; }
210
211 /******************************************************************************
212 *******************************************************************************
213 *
214 * VECTOR INTRINSICS
215 *
216 *******************************************************************************
217 *******************************************************************************/
218
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); }
221
222 <<includeIntrinsic>>
223
224 /******************************************************************************
225 *******************************************************************************
226 *
227 * USER INTERFACE
228 *
229 *******************************************************************************
230 *******************************************************************************/
231
232 class UI
233 {
234 bool fStopped;
235
236 public:
237
238 UI() : fStopped(false) {}
239 virtual ~UI() {}
240
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;
247
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;
252
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;
258
259 virtual void run() {};
260
261 void stop() { fStopped = true; }
262 bool stopped() { return fStopped; }
263
264 virtual void declare(float* zone, const char* key, const char* value) {}
265 };
266
267
268 /******************************************************************************
269 *******************************************************************************
270 *
271 * FAUST DSP
272 *
273 *******************************************************************************
274 *******************************************************************************/
275
276
277
278 //----------------------------------------------------------------
279 // Base dsp class for this architecture
280 //----------------------------------------------------------------
281
282 class dsp {
283
284 protected:
285
286 int fSamplingFreq;
287
288 public:
289
290 dsp() {}
291 virtual ~dsp() {}
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;
297 };
298
299 /********************END ARCHITECTURE SECTION (part 1/2)****************/
300
301 /**************************BEGIN USER SECTION **************************/
302
303 <<includeclass>>
304
305 /***************************END USER SECTION ***************************/
306
307 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
308
309 /******************************************************************************
310 *
311 * VST wrapper
312 *
313 ******************************************************************************/
314
315 #include "audioeffectx.h"
316
317 class vstUI;
318
319 //------------------------------------------------------------------------------
320 // Faust class prototype
321 //------------------------------------------------------------------------------
322 class Faust : public AudioEffectX
323 {
324 public:
325 Faust(audioMasterCallback audioMaster, mydsp* dspi, vstUI* dspUIi);
326 virtual ~Faust();
327
328 virtual void processReplacing (float **inputs, float **outputs, VstInt32 sampleFrames);
329 virtual VstInt32 processEvents (VstEvents* events);
330
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);
335
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);
341
342 virtual void setSampleRate (float sampleRate);
343
344 virtual bool getInputProperties (VstInt32 index, VstPinProperties *properties);
345 virtual bool getOutputProperties (VstInt32 index, VstPinProperties *properties);
346
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);
352
353 virtual VstInt32 getNumMidiInputChannels ();
354 virtual VstInt32 getNumMidiOutputChannels ();
355
356 virtual VstInt32 getMidiProgramName (VstInt32 channel, MidiProgramName *midiProgramName);
357 virtual VstInt32 getCurrentMidiProgram (VstInt32 channel, MidiProgramName *currentProgram);
358 virtual VstInt32 getMidiProgramCategory (VstInt32 channel, MidiProgramCategory *category);
359
360 private:
361 mydsp* dsp;
362 vstUI* dspUI;
363
364 // For synths:
365 bool noteIsOn;
366 VstInt32 currentNote;
367 VstInt32 currentVelocity;
368 VstInt32 currentDelta;
369
370 void initProcess ();
371 void noteOn (VstInt32 note, VstInt32 velocity, VstInt32 delta);
372 void noteOff ();
373 void fillProgram (VstInt32 channel, VstInt32 prg, MidiProgramName* mpn);
374
375 char programName[kVstMaxProgNameLen + 1];
376 };
377
378 /*--------------------------------------------------------------------------*/
379 class vstUIObject { /* superclass of all VST UI widgets */
380 protected:
381 string fLabel;
382 float* fZone;
383
384 inline float clip(float min, float max, float val)
385 {
386 return (val < min) ? min : (val > max) ? max : val;
387 }
388
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;
393 }
394
395 public:
396 vstUIObject(char* label, float* zone):fLabel(label),fZone(zone) {}
397 virtual ~vstUIObject() {}
398
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);}
404 virtual long GetID()
405 { /* returns the sum of all the ASCII characters contained in the parameter's label */
406 unsigned int i;
407 long acc;
408 for(i=0,acc = 0;i<fLabel.length();i++) acc += (fLabel.c_str())[i];
409 return acc;
410 }
411 };
412
413 /*--------------------------------------------------------------------------*/
414 class vstToggleButton : public vstUIObject {
415
416 public:
417
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");}
423 };
424
425 /*--------------------------------------------------------------------------*/
426 class vstCheckButton : public vstUIObject {
427
428 public:
429
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");}
435 };
436
437 /*--------------------------------------------------------------------------*/
438 class vstButton : public vstUIObject {
439
440 public:
441
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");}
447 };
448
449 /*--------------------------------------------------------------------------*/
450 class vstSlider : public vstUIObject{
451
452 private:
453
454 float fInit;
455 float fMin;
456 float fMax;
457 float fStep;
458
459 public:
460
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() {}
464
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
471 };
472
473 /*--------------------------------------------------------------------------*/
474 class vstUI : public UI
475 {
476 private:
477
478 vector<vstUIObject*> fUITable;
479
480 public:
481
482 int freqIndex;
483 int gainIndex;
484 int gateIndex;
485
486 vstUI(){
487 freqIndex = gainIndex = gateIndex = -1;
488 }
489 virtual ~vstUI()
490 {
491 for (vector<vstUIObject*>::iterator iter = fUITable.begin(); iter != fUITable.end(); iter++) delete *iter;
492 }
493
494 void setAny(int anyIndex, float val, char *str) {
495 if (anyIndex<0) {
496 #ifdef DEBUG
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);
499 #endif
500 return;
501 }
502 if (anyIndex >= fUITable.size()) {
503 #ifdef DEBUG
504 fprintf(stderr,"*** Faust vsti: %sIndex = %d too large!\n",str,anyIndex);
505 #endif
506 return;
507 }
508 #ifdef DEBUG
509 fprintf(stderr,"*** Faust vsti: Setting %sIndex = %d to %f\n",str,anyIndex,val);
510 #endif
511 fUITable[anyIndex]->SetValueNoNormalization(val);
512 }
513
514 void setFreq(float val) {
515 setAny(freqIndex, val, "freq");
516 }
517
518 void setGate(float val) {
519 setAny(gateIndex, val, "gate");
520 }
521
522 void setGain(float val) {
523 setAny(gainIndex, val, "gain");
524 }
525
526 bool ckAnyMatch(char* label, char* indexName, int *index) {
527 if (_stricmp(label,indexName)==0) {
528 #ifdef DEBUG
529 fprintf(stderr,"=== Faust vsti: label '%s' matches '%s'\n",label,indexName);
530 #endif
531 *index = fUITable.size() - 1;
532 return true;
533 }
534 return false;
535 }
536
537 void ckAllMatches(char* label) {
538 ckAnyMatch(label,"gain",&gainIndex);
539 ckAnyMatch(label,"gate",&gateIndex);
540 ckAnyMatch(label,"freq",&freqIndex);
541 }
542
543 void addButton(char* label, float* zone) {
544 vstButton* theButton = new vstButton(label, zone);
545 fUITable.push_back(theButton);
546 #ifdef DEBUG
547 fprintf(stderr,"=== Faust vsti: Adding Button with label '%s'\n",label);
548 #endif
549 ckAnyMatch(label,"gate",&gateIndex);
550 }
551
552 void addToggleButton(char* label, float* zone) {fUITable.push_back(new vstToggleButton(label, zone));}
553
554 void addCheckButton(char* label, float* zone) {fUITable.push_back(new vstCheckButton(label, zone));}
555
556 void addVerticalSlider(char* label, float* zone, float init, float min, float max, float step)
557 {
558 vstSlider* theSlider = new vstSlider(label, zone, init, min, max, step);
559 fUITable.push_back(theSlider);
560 #ifdef DEBUG
561 fprintf(stderr,"=== Faust vsti: Adding VSlider (HSlider) with label '%s'\n",label);
562 #endif
563 ckAllMatches(label);
564 }
565
566 void addHorizontalSlider(char* label, float* zone, float init, float min, float max, float step)
567 {
568 vstSlider* theSlider = new vstSlider(label, zone, init, min, max, step);
569 fUITable.push_back(theSlider);
570 #ifdef DEBUG
571 fprintf(stderr,"=== Faust vsti: Adding HSlider with label '%s'\n",label);
572 #endif
573 ckAllMatches(label);
574 }
575
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);
580 #ifdef DEBUG
581 fprintf(stderr,"=== Faust vsti: Adding NumEntry (HSlider) with label '%s'\n",label);
582 #endif
583 ckAllMatches(label);
584 }
585
586 void openFrameBox(char* label) {}
587 void openTabBox(char* label) {}
588 void openHorizontalBox(char* label) {}
589 void openVerticalBox(char* label) {}
590 void closeBox() {}
591
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();}
597
598 long makeID()
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'
602 */
603 {
604 const long maxNumberOfId = 128;
605 long baseid = 'FAUS';
606 long id=0;
607 for(int i=0;i<fUITable.size();i++) id += fUITable[i]->GetID();
608 return baseid + id % maxNumberOfId;
609 }
610
611 // To be implemented
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){}
616 };
617
618 //-----------------------------------------------------------------------------
619 // Class Implementations
620 //-----------------------------------------------------------------------------
621
622 #define kNumPrograms 1
623
624 AudioEffect* createEffectInstance (audioMasterCallback audioMaster)
625 {
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);
631 #ifdef DEBUG
632 fprintf(stderr,"=== Faust vsti: created\n"); // look for this in the system log
633 #endif
634 return new Faust(audioMaster,dspi,dspUIi);
635 }
636
637 //-----------------------------------------------------------------------------
638 // Faust
639 //-----------------------------------------------------------------------------
640 Faust::Faust(audioMasterCallback audioMaster, mydsp* dspi, vstUI* dspUIi)
641 :AudioEffectX(audioMaster, kNumPrograms,dspUIi->GetNumParams())
642 {
643 // Copy the pointers to dsp and dspUI instances and take them over
644 // (we'll also deallocate):
645 dsp = dspi;
646 dspUI = dspUIi;
647
648 #ifdef DEBUG
649 fprintf(stderr,"=== Faust vsti: classInit:\n");
650 #endif
651
652 dsp->classInit((int)getSampleRate()); // Ask AudioEffect for sample-rate
653
654 setProgram(0);
655 setProgramName("Default");
656
657 if (audioMaster) {
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");
665 }
666 }
667 setUniqueID(dspUI->makeID());
668 }
669 initProcess();
670 if (dsp->getNumInputs() == 0) {
671 suspend(); // Synths start out quiet
672 }
673 }
674
675 //----------------------------------------------------------------------------
676 Faust::~Faust()
677 {
678 if (dsp) delete dsp;
679 if (dspUI) delete dspUI;
680 }
681
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.
687 {
688 if (program < 0 || program >= kNumPrograms) {
689 fprintf(stderr,"*** Faust vsti: setting program to %d is OUT OF RANGE\n",program);
690 return;
691 }
692 #ifdef DEBUG
693 fprintf(stderr,"=== Faust vsti: setting program to %d\n",program);
694 #endif
695 curProgram = program; // curProgram defined in audioeffect.h
696 }
697
698 //------------------------------------------------------------------------------
699 void Faust::setProgramName (char* name)
700 {
701 vst_strncpy (programName, name, kVstMaxProgNameLen);
702 }
703
704 //-----------------------------------------------------------------------------
705 void Faust::getProgramName(char *name)
706 {
707 vst_strncpy (name, programName, kVstMaxProgNameLen);
708 }
709
710 //-----------------------------------------------------------------------------
711 void Faust::getParameterLabel(VstInt32 index, char *label)
712 {
713 // We are not using parameter "units" display:
714 vst_strncpy (label, "", kVstMaxParamStrLen); // parameter units in Name
715 }
716
717 //-----------------------------------------------------------------------------
718 void Faust::getParameterDisplay(VstInt32 index, char *text)
719 {
720 if(index<numParams)
721 dspUI->GetDisplay(index,text); // get displayed float value as text
722 else
723 vst_strncpy (text, "IndexOutOfRange", kVstMaxParamStrLen);
724 }
725
726 //-----------------------------------------------------------------------------
727 void Faust::getParameterName(VstInt32 index, char *label)
728 {
729 if(index<numParams)
730 dspUI->GetName(index,label); // parameter name, including units
731 else
732 vst_strncpy (label, "IndexOutOfRange", kVstMaxParamStrLen);
733 }
734
735 //-----------------------------------------------------------------------------
736 void Faust::setParameter(VstInt32 index, float value)
737 {
738 if(index<numParams)
739 dspUI->SetValue(index,value);
740 }
741
742 //-----------------------------------------------------------------------------
743 float Faust::getParameter(VstInt32 index)
744 {
745 if(index<numParams)
746 return dspUI->GetValue(index);
747 else
748 return 0.0f;
749 }
750
751 //-----------------------------------------------------------------------------
752 bool Faust::getInputProperties (VstInt32 index, VstPinProperties* properties)
753 {
754 if(index>=0 && index<dsp->getNumInputs())
755 {
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;
761 }
762 return true;
763 }
764 else
765 return false;
766 }
767
768 //-----------------------------------------------------------------------------
769 bool Faust::getOutputProperties (VstInt32 index, VstPinProperties* properties)
770 {
771 if(index>=0 && index<dsp->getNumOutputs())
772 {
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;
778 }
779 return true;
780 }
781 else
782 return false;
783 }
784
785 //-----------------------------------------------------------------------------
786 bool Faust::getProgramNameIndexed (VstInt32 category, VstInt32 index, char* text)
787 {
788 if (index < kNumPrograms) {
789 vst_strncpy (text, programName, kVstMaxProgNameLen);
790 return true;
791 }
792 return false;
793 }
794
795 //-----------------------------------------------------------------------------
796 bool Faust::getEffectName (char* name)
797 {
798 // Get from Faust-supplied metadata?
799 vst_strncpy (name, "Effect Name goes here", kVstMaxEffectNameLen);
800 return true;
801 }
802
803 //-----------------------------------------------------------------------------
804 bool Faust::getVendorString (char* text)
805 {
806 vst_strncpy (text, "Vendor String goes here", kVstMaxVendorStrLen);
807 return true;
808 }
809
810 //-----------------------------------------------------------------------------
811 bool Faust::getProductString (char* text)
812 {
813 vst_strncpy (text, "Product String goes here", kVstMaxProductStrLen);
814 return true;
815 }
816
817 //-----------------------------------------------------------------------------
818 VstInt32 Faust::getVendorVersion ()
819 {
820 return 1000;
821 }
822
823 //-----------------------------------------------------------------------------
824 VstInt32 Faust::canDo (char* text)
825 {
826 if (!strcmp (text, "receiveVstEvents"))
827 return 1;
828 if (!strcmp (text, "receiveVstMidiEvent"))
829 return 1;
830 if (!strcmp (text, "midiProgramNames"))
831 return 1;
832 return -1; // explicitly can't do; 0 => don't know
833 }
834
835 //-----------------------------------------------------------------------------
836 VstInt32 Faust::getNumMidiInputChannels ()
837 {
838 return 1; // one MIDI-in channel
839 }
840
841 //-----------------------------------------------------------------------------
842 VstInt32 Faust::getNumMidiOutputChannels ()
843 {
844 return 0; // no MIDI-outs
845 }
846
847 //-----------------------------------------------------------------------------
848 VstInt32 Faust::getMidiProgramName (VstInt32 channel, MidiProgramName* mpn)
849 {
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"
854 }
855
856 //------------------------------------------------------------------------
857 VstInt32 Faust::getCurrentMidiProgram (VstInt32 channel, MidiProgramName* mpn)
858 {
859 // There is only one MIDI program here, so return it regardless of MIDI channel:
860 if (channel < 0 || channel >= 16 || !mpn) return -1;
861 VstInt32 prg = 0;
862 mpn->thisProgramIndex = prg;
863 fillProgram (channel, prg, mpn);
864 return prg;
865 }
866
867 //------------------------------------------------------------------------
868 void Faust::fillProgram (VstInt32 channel, VstInt32 prg, MidiProgramName* mpn)
869 // Fill mpn struct for given channel. Here there should be only one.
870 {
871 mpn->midiBankMsb = mpn->midiBankLsb = -1;
872 mpn->reserved = 0;
873 mpn->flags = 0;
874 vst_strncpy (mpn->name, programName, kVstMaxProgNameLen);
875 mpn->midiProgram = (char)prg; // prg should only be 0
876 mpn->parentCategoryIndex = -1;
877 }
878
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.
882 {
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
888 }
889
890 //***********************************************************************
891
892 //-----------------------------------------------------------------------------
893 void Faust::setSampleRate(float sampleRate)
894 {
895 AudioEffect::setSampleRate(sampleRate);
896 dsp->instanceInit((int)getSampleRate()); // in case AudioEffect altered it
897 }
898
899 //-----------------------------------------------------------------------------
900 void Faust::initProcess ()
901 {
902 noteIsOn = false;
903 currentDelta = currentNote = currentDelta = 0;
904 dsp->instanceInit((int)getSampleRate());
905 }
906
907 //-----------------------------------------------------------------------------
908 void Faust::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames)
909 {
910 AVOIDDENORMALS;
911 #ifdef DEBUG
912 fprintf(stderr,"=== Faust vsti: processReplacing . . .\n");
913 #endif
914
915 if (dsp->getNumInputs() > 0) { // We're an effect . . . keep going:
916
917 dsp->compute(sampleFrames, inputs, outputs);
918
919 } else { // We're a synth . . .
920 int i, nouts = dsp->getNumOutputs();
921
922 if (noteIsOn) { // we're synthesizing . . .
923
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)); }
930 return;
931 } else {
932 // float* outptr[nouts];
933 float** outptr = (float **)malloc(nouts * sizeof(float*));
934
935 #ifdef DEBUG
936 fprintf(stderr,"*** Faust vsti: currentDelta = %d\n",currentDelta);
937 #endif
938
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;
945 }
946 sampleFrames -= currentDelta;
947 currentDelta = 0;
948 dsp->compute(sampleFrames, inputs, outptr);
949 free(outptr);
950 }
951 } else {
952 dsp->compute(sampleFrames, inputs, outputs);
953 }
954
955 } else { // silence until NoteOn . . .
956 for (i=0; i<nouts; i++) { memset (outputs[i], 0, sampleFrames * sizeof (float)); }
957 }
958 }
959 }
960
961 //-----------------------------------------------------------------------------
962 VstInt32 Faust::processEvents (VstEvents* ev)
963 {
964 if (ev->numEvents > 0) {
965 #ifdef DEBUG
966 fprintf(stderr,"=== Faust vsti: processEvents processing %d events\n",
967 ev->numEvents);
968 #endif
969 }
970
971 for (VstInt32 i = 0; i < ev->numEvents; i++)
972 {
973 #ifdef DEBUG
974 fprintf(stderr,"=== Faust vsti: event type = %d\n",
975 (ev->events[i])->type);
976 #endif
977 if ((ev->events[i])->type != kVstMidiType) {
978 #ifdef DEBUG
979 fprintf(stderr,"=== Faust vsti: EVENT IGNORED!\n");
980 #endif
981 continue;
982 }
983 VstMidiEvent* event = (VstMidiEvent*)ev->events[i];
984 char* midiData = event->midiData;
985 VstInt32 chan = midiData[0] & 0xf;
986 VstInt32 status = midiData[0] & 0xf0;
987 #ifdef DEBUG
988 fprintf(stderr,"\n=== Faust vsti: event->midiData[0] = 0x%x\n",
989 event->midiData[0]);
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",
993 event->midiData[1]);
994 fprintf(stderr,"=== Faust vsti: event->midiData[2] = 0x%x\n",
995 event->midiData[2]);
996 #endif
997
998 if (status == 0x90) { // note on
999 VstInt32 note = midiData[1] & 0x7f;
1000 VstInt32 velocity = midiData[2] & 0x7f;
1001 #ifdef DEBUG
1002 fprintf(stderr,
1003 "=== Faust vsti: note = %d, velocity = %d, delay = %d\n",
1004 note,velocity,event->deltaFrames);
1005 #endif
1006 if (velocity>0) {
1007 noteOn(note, velocity, event->deltaFrames);
1008 } else {
1009 noteOff();
1010 }
1011 } else if (status == 0x80) { // note off
1012 noteOff();
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?
1020 }
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 ...
1025 }
1026 // For a list, see
1027 // http://www.alfred-j-faust.de/rft/midi%20status%20types.html
1028
1029 #ifdef DEBUG
1030 fprintf(stderr,"=== Faust vsti: Going to next event\n", event->midiData[2]);
1031 #endif
1032
1033 event++;
1034 }
1035 return 1;
1036 }
1037
1038 //-----------------------------------------------------------------------------
1039 void Faust::noteOn (VstInt32 note, VstInt32 velocity, VstInt32 delta)
1040 {
1041 #ifdef DEBUG
1042 fprintf(stderr,"=== Faust vsti: noteOn: note = %d, vel = %d, del = %d\n",note,velocity,delta);
1043 #endif
1044 currentNote = note;
1045 currentVelocity = velocity;
1046 currentDelta = delta;
1047 noteIsOn = true;
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"
1053 }
1054
1055 //-----------------------------------------------------------------------------
1056 void Faust::noteOff ()
1057 {
1058 if (noteIsOn) {
1059 #ifdef DEBUG
1060 fprintf(stderr,"=== Faust vsti: noteOff\n");
1061 #endif
1062 dspUI->setGate(0);
1063 } else {
1064 #ifdef DEBUG
1065 fprintf(stderr,"=== Faust vsti: noteOff IGNORED (note was not on)\n");
1066 #endif
1067 }
1068 }
1069
1070
1071 /********************END ARCHITECTURE SECTION (part 2/2)****************/
1072