Stdin, stdout and stderr updated, tested.
[Faustine.git] / interpreter / preprocessor / faust-0.9.47mr3 / architecture / vst2p4.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 Remy Muller & 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 Remy Muller or Julius Smith or 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
54 /********************************************************************
55 * VST-2.4 wrapper for the FAUST language.
56 *
57 * Usage: faust -a vst2p4.cpp myfaustprog.dsp
58 *
59 * By Julius Smith (http://ccrma.stanford.edu/~jos/), based on
60 * vst.cpp by remy muller remy.muller@ircam.fr
61 * http://www.smartelectronix.com/~mdsp/.
62 * Essentially, vst.cpp was edited to look more like the "again"
63 * programming sample that comes with the VST-2.4 SDK from Steinberg.
64 *
65 * NOTES:
66 * Relies on automatically generated slider GUI for VST plugins.
67 * - Horizontal and vertical sliders mapped to "vstSlider"
68 * - Numeric Entries similarly converted to "vstSlider"
69 * - No support for bar graphs or additional numeric and text displays
70 * - Tested on the Muse Receptor Pro 1.0, System Version 1.6.20070717,
71 * using Visual C++ 2008 Express Edition
72 * (part of the Microsoft Visual Studio 2008, Beta 2)
73 * - Reference:
74 * http://ccrma.stanford.edu/realsimple/faust/Generating_VST_Plugin_Faust.html
75 *
76 * FAUST
77 * Copyright (C) 2003-2007 GRAME, Centre National de Creation Musicale
78 * http://www.grame.fr/
79 *
80 ********************************************************************/
81
82 #include <stdlib.h>
83 #include <stdio.h>
84 #include <string.h>
85 #include <limits.h>
86 #include <math.h>
87 #include <errno.h>
88 #include <time.h>
89 //#include <unistd.h>
90 #include <fcntl.h>
91 #include <assert.h>
92 #include <string>
93 #include <vector>
94 #include <map>
95 #include <cstring>
96 #include <cmath>
97
98 using namespace std ;
99
100 // There is a bug with powf() when cross compiling with mingw
101 // the following macro avoid the problem
102 #ifdef WIN32
103 #define powf(x,y) pow(x,y)
104 #define expf(x) exp(x)
105 #endif
106
107 // On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
108 // flags to avoid costly denormals
109 #ifdef __SSE__
110 #include <xmmintrin.h>
111 #ifdef __SSE2__
112 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
113 #else
114 #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
115 #endif
116 #else
117 #define AVOIDDENORMALS
118 #endif
119
120 struct Meta : std::map<std::string, std::string>
121 {
122 void declare(const char* key, const char* value)
123 {
124 (*this)[key] = value;
125 }
126 };
127
128
129 //-------------------------------------------------------------------
130 // Generic min and max using c++ inline
131 //-------------------------------------------------------------------
132
133 inline int max (unsigned int a, unsigned int b) { return (a>b) ? a : b; }
134 inline int max (int a, int b) { return (a>b) ? a : b; }
135
136 inline long max (long a, long b) { return (a>b) ? a : b; }
137 inline long max (int a, long b) { return (a>b) ? a : b; }
138 inline long max (long a, int b) { return (a>b) ? a : b; }
139
140 inline float max (float a, float b) { return (a>b) ? a : b; }
141 inline float max (int a, float b) { return (a>b) ? a : b; }
142 inline float max (float a, int b) { return (a>b) ? a : b; }
143 inline float max (long a, float b) { return (a>b) ? a : b; }
144 inline float max (float a, long b) { return (a>b) ? a : b; }
145
146 inline double max (double a, double b) { return (a>b) ? a : b; }
147 inline double max (int a, double b) { return (a>b) ? a : b; }
148 inline double max (double a, int b) { return (a>b) ? a : b; }
149 inline double max (long a, double b) { return (a>b) ? a : b; }
150 inline double max (double a, long b) { return (a>b) ? a : b; }
151 inline double max (float a, double b) { return (a>b) ? a : b; }
152 inline double max (double a, float b) { return (a>b) ? a : b; }
153
154 inline int min (int a, int b) { return (a<b) ? a : b; }
155
156 inline long min (long a, long b) { return (a<b) ? a : b; }
157 inline long min (int a, long b) { return (a<b) ? a : b; }
158 inline long min (long a, int b) { return (a<b) ? a : b; }
159
160 inline float min (float a, float b) { return (a<b) ? a : b; }
161 inline float min (int a, float b) { return (a<b) ? a : b; }
162 inline float min (float a, int b) { return (a<b) ? a : b; }
163 inline float min (long a, float b) { return (a<b) ? a : b; }
164 inline float min (float a, long b) { return (a<b) ? a : b; }
165
166 inline double min (double a, double b) { return (a<b) ? a : b; }
167 inline double min (int a, double b) { return (a<b) ? a : b; }
168 inline double min (double a, int b) { return (a<b) ? a : b; }
169 inline double min (long a, double b) { return (a<b) ? a : b; }
170 inline double min (double a, long b) { return (a<b) ? a : b; }
171 inline double min (float a, double b) { return (a<b) ? a : b; }
172 inline double min (double a, float b) { return (a<b) ? a : b; }
173
174 // abs is now predefined
175 //template<typename T> T abs (T a) { return (a<T(0)) ? -a : a; }
176
177 inline int lsr (int x, int n) { return int(((unsigned int)x) >> n); }
178
179 inline int int2pow2 (int x) { int r=0; while ((1<<r)<x) r++; return r; }
180
181 /******************************************************************************
182 *******************************************************************************
183 *
184 * VECTOR INTRINSICS
185 *
186 *******************************************************************************
187 *******************************************************************************/
188
189 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((unsigned)(calloc((nmemb*size)+15,sizeof(char)))+15 & 0xfffffff0); }
190 //inline void *aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size)+15,sizeof(char)))+15 & ~15); }
191
192 <<includeIntrinsic>>
193
194 /******************************************************************************
195 *******************************************************************************
196 *
197 * USER INTERFACE
198 *
199 *******************************************************************************
200 *******************************************************************************/
201
202 class UI
203 {
204 bool fStopped;
205
206 public:
207
208 UI() : fStopped(false) {}
209 virtual ~UI() {}
210
211 virtual void addButton(const char* label, float* zone) = 0;
212 virtual void addToggleButton(const char* label, float* zone) = 0;
213 virtual void addCheckButton(const char* label, float* zone) = 0;
214 virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
215 virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0;
216 virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0;
217
218 virtual void addNumDisplay(const char* label, float* zone, int precision) = 0;
219 virtual void addTextDisplay(const char* label, float* zone, char* names[], float min, float max) = 0;
220 virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0;
221 virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0;
222
223 virtual void openFrameBox(const char* label) = 0;
224 virtual void openTabBox(const char* label) = 0;
225 virtual void openHorizontalBox(const char* label) = 0;
226 virtual void openVerticalBox(const char* label) = 0;
227 virtual void closeBox() = 0;
228
229 virtual void run() {};
230
231 void stop() { fStopped = true; }
232 bool stopped() { return fStopped; }
233
234 virtual void declare(float* zone, const char* key, const char* value) {}
235 };
236
237
238 /******************************************************************************
239 *******************************************************************************
240 *
241 * FAUST DSP
242 *
243 *******************************************************************************
244 *******************************************************************************/
245
246
247
248 //----------------------------------------------------------------
249 // Base dsp class for this architecture
250 //----------------------------------------------------------------
251
252 class dsp {
253
254 protected:
255
256 int fSamplingFreq;
257
258 public:
259
260 dsp() {}
261 virtual ~dsp() {}
262 virtual int getNumInputs() = 0;
263 virtual int getNumOutputs() = 0;
264 virtual void buildUserInterface(UI* interface) = 0;
265 virtual void init(int samplingRate) = 0;
266 virtual void compute(int len, float** inputs, float** outputs) = 0;
267 };
268
269 /********************END ARCHITECTURE SECTION (part 1/2)****************/
270
271 /**************************BEGIN USER SECTION **************************/
272
273 <<includeclass>>
274
275 /***************************END USER SECTION ***************************/
276
277 /*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
278
279
280 /******************************************************************************
281 *
282 * VST wrapper
283 *
284 ******************************************************************************/
285
286 #include "audioeffectx.h"
287
288 class vstUI;
289
290 class Faust : public AudioEffectX
291 {
292
293 private:
294 mydsp* dsp;
295 vstUI* dspUI;
296 char programName[kVstMaxProgNameLen + 1];
297 Meta meta;
298
299 public:
300 Faust(audioMasterCallback audioMaster, mydsp* dspi, vstUI* dspUIi);
301 virtual ~Faust();
302
303 virtual void processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames);
304
305 virtual void setProgramName(char *name);
306 virtual void getProgramName(char *name);
307
308 virtual void setParameter(VstInt32 index, float value);
309 virtual float getParameter(VstInt32 index);
310 virtual void getParameterLabel(VstInt32 index, char *label);
311 virtual void getParameterDisplay(VstInt32 index, char *text);
312 virtual void getParameterName(VstInt32 index, char *text);
313
314 virtual void setSampleRate(float sampleRate);
315
316 virtual bool getEffectName (char* name);
317 virtual bool getVendorString (char* text);
318 virtual bool getProductString (char* text);
319 virtual VstInt32 getVendorVersion ();
320
321 virtual bool getInputProperties (VstInt32 index, VstPinProperties* properties);
322 virtual bool getOutputProperties (VstInt32 index, VstPinProperties* properties);
323 };
324
325 /*--------------------------------------------------------------------------*/
326 class vstUIObject {
327 protected:
328 string fLabel;
329 float* fZone;
330
331 float range(float min, float max, float val)
332 { // VST parameters are normalized in the range [0;1]
333 val = min + val * (max - min);
334 return (val < min) ? min : (val > max) ? max : val;
335 }
336
337 public:
338 vstUIObject(const char* label, float* zone):fLabel(label),fZone(zone) {}
339 virtual ~vstUIObject() {}
340
341 virtual void GetName(char *text){std::strcpy(text,fLabel.c_str());}
342 virtual void SetValue(double f) {*fZone = range(0.0f,1.0f,(float)f);}
343 virtual float GetValue() {return *fZone;}
344 virtual void GetDisplay(char *text){std::sprintf(text,"%f",*fZone);}
345 virtual long GetID()
346 { /* returns the sum of all the ASCII characters contained in the parameter's label */
347 unsigned int i;
348 long acc;
349 for(i=0,acc = 0;i<fLabel.length();i++) acc += (fLabel.c_str())[i];
350 return acc;
351 }
352 };
353
354 /*--------------------------------------------------------------------------*/
355 class vstToggleButton : public vstUIObject {
356
357 public:
358
359 vstToggleButton(const char* label, float* zone):vstUIObject(label,zone) {}
360 virtual ~vstToggleButton() {}
361 virtual float GetValue() {return *fZone;}
362 virtual void SetValue(double f) {*fZone = (f>0.5f)?1.0f:0.0f;}
363 virtual void GetDisplay(char *text){(*fZone>0.5f)? std::strcpy(text,"ON"): std::strcpy(text,"OFF");}
364 };
365
366 /*--------------------------------------------------------------------------*/
367 class vstCheckButton : public vstUIObject {
368
369 public:
370
371 vstCheckButton(const char* label, float* zone):vstUIObject(label,zone) {}
372 virtual ~vstCheckButton() {}
373 virtual float GetValue() {return *fZone;}
374 virtual void SetValue(double f) {*fZone = (f>0.5f)?1.0f:0.0f;}
375 virtual void GetDisplay(char *text){(*fZone>0.5f)? std::strcpy(text,"ON"): std::strcpy(text,"OFF");}
376 };
377
378 /*--------------------------------------------------------------------------*/
379 class vstButton : public vstUIObject {
380
381 public:
382
383 vstButton(const char* label, float* zone):vstUIObject(label,zone) {}
384 virtual ~vstButton() {}
385 virtual float GetValue() {return *fZone;}
386 virtual void SetValue(double f) {*fZone = (f>0.5f)?1.0f:0.0f;}
387 virtual void GetDisplay(char *text){(*fZone>0.5f)? std::strcpy(text,"ON"): std::strcpy(text,"OFF");}
388 };
389
390 /*--------------------------------------------------------------------------*/
391 class vstSlider : public vstUIObject{
392
393 private:
394
395 float fInit;
396 float fMin;
397 float fMax;
398 float fStep;
399
400 public:
401
402 vstSlider(const char* label, float* zone, float init, float min, float max, float step)
403 :vstUIObject(label,zone), fInit(init), fMin(min), fMax(max),fStep(step) {}
404 virtual ~vstSlider() {}
405
406 virtual float GetValue() {return (*fZone-fMin)/(fMax-fMin);} // normalize
407 virtual void SetValue(double f) {*fZone = range(fMin,fMax,(float)f);} // expand
408 };
409
410 /*--------------------------------------------------------------------------*/
411 class vstUI : public UI
412 {
413 private:
414
415 vector<vstUIObject*> fUITable;
416
417 public:
418
419 vstUI(){}
420 virtual ~vstUI()
421 {
422 for (vector<vstUIObject*>::iterator iter = fUITable.begin(); iter != fUITable.end(); iter++) delete *iter;
423 }
424
425 void addButton(const char* label, float* zone) {fUITable.push_back(new vstButton(label, zone));}
426
427 void addToggleButton(const char* label, float* zone) {fUITable.push_back(new vstToggleButton(label, zone));}
428
429 void addCheckButton(const char* label, float* zone) {fUITable.push_back(new vstCheckButton(label, zone));}
430
431 void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step)
432 {
433 fUITable.push_back(new vstSlider(label, zone, init, min, max, step));
434 }
435
436 void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step)
437 {
438 fUITable.push_back(new vstSlider(label, zone, init, min, max, step));
439 }
440
441 void addNumEntry(const char* label, float* zone, float init, float min, float max, float step)
442 { /* Number entries converted to horizontal sliders */
443 fUITable.push_back(new vstSlider(label, zone, init, min, max, step));
444 }
445
446 void openFrameBox(const char* label) {}
447 void openTabBox(const char* label) {}
448 void openHorizontalBox(const char* label) {}
449 void openVerticalBox(const char* label) {}
450 void closeBox() {}
451
452 void SetValue(VstInt32 index, double f) {assert(index<fUITable.size()); fUITable[index]->SetValue(f);}
453 float GetValue(VstInt32 index) {assert(index<fUITable.size()); return fUITable[index]->GetValue();}
454 void GetDisplay(VstInt32 index, char *text) {assert(index<fUITable.size()); fUITable[index]->GetDisplay(text);}
455 void GetName(VstInt32 index, char *text) {assert(index<fUITable.size()); fUITable[index]->GetName(text);}
456 long GetNumParams() {return fUITable.size();}
457
458 long makeID()
459 /* Creates a (unique?)id by summing all the parameter's labels,
460 * then wrapping it in the range [0;maxNumberOfId] and adding
461 * this number to the offset made by the Four Character ID: 'FAUS'
462 */
463 {
464 const long maxNumberOfId = 128;
465 long baseid = 'FAUS';
466 long id=0;
467 for(int i=0;i<fUITable.size();i++) id += fUITable[i]->GetID();
468 return baseid + id % maxNumberOfId;
469 }
470
471 // To be implemented
472 void addNumDisplay(const char* label, float* zone, int precision){}
473 void addTextDisplay(const char* label, float* zone, char* names[], float min, float max){}
474 void addHorizontalBargraph(const char* label, float* zone, float min, float max){}
475 void addVerticalBargraph(const char* label, float* zone, float min, float max){}
476 };
477
478 //-----------------------------------------------------------------------------
479 #define NUM_PROGRAMS 0
480
481 AudioEffect* createEffectInstance (audioMasterCallback audioMaster)
482 {
483 // The dsp and its UI need to be allocated now because
484 // AudioEffectX wants the no. parameters available as an instance argument:
485 mydsp* dspi = new mydsp();
486 vstUI* dspUIi = new vstUI();
487 dspi->buildUserInterface(dspUIi);
488 return new Faust(audioMaster,dspi,dspUIi);
489 }
490
491 Faust::Faust(audioMasterCallback audioMaster, mydsp* dspi, vstUI* dspUIi)
492 : AudioEffectX(audioMaster, NUM_PROGRAMS, dspUIi->GetNumParams())
493 {
494 // Copy the pointers to dsp and dspUI instances and take them over
495 // (we'll also deallocate):
496 dsp = dspi;
497 dspUI = dspUIi;
498 dsp->init(long(getSampleRate()));
499 meta["name"] = "FaustFx";
500 mydsp::metadata(&meta);
501 setNumInputs(dsp->getNumInputs());
502 setNumOutputs(dsp->getNumOutputs());
503 setUniqueID(dspUI->makeID());
504 canProcessReplacing();
505
506 vst_strncpy(programName, "Default", kVstMaxProgNameLen); // default program name
507 }
508
509 //----------------------------------------------------------------------------
510 Faust::~Faust()
511 {
512 if (dsp) delete dsp;
513 if (dspUI) delete dspUI;
514 }
515
516 //-------------------------------------------------------------------------------------------------------
517 void Faust::setProgramName (char* name)
518 {
519 // this template does not use programs yet - just say "Default":
520 vst_strncpy (programName, name, kVstMaxProgNameLen);
521 }
522
523 //-----------------------------------------------------------------------------
524 void Faust::getProgramName(char *name)
525 {
526 vst_strncpy (name, programName, kVstMaxProgNameLen);
527 }
528
529 //-----------------------------------------------------------------------------
530 void Faust::setParameter(VstInt32 index, float value)
531 {
532 if(index<numParams)
533 dspUI->SetValue(index,value);
534 }
535
536 //-----------------------------------------------------------------------------
537 float Faust::getParameter(VstInt32 index)
538 {
539 if(index<numParams)
540 return dspUI->GetValue(index);
541 else
542 return 0.0f;
543 }
544 //-----------------------------------------------------------------------------
545 void Faust::getParameterName(VstInt32 index, char *label)
546 {
547 if(index<numParams)
548 dspUI->GetName(index,label); // parameter name, including units
549 else
550 vst_strncpy (label, "IndexOutOfRange", kVstMaxParamStrLen);
551 }
552 //-----------------------------------------------------------------------------
553 void Faust::getParameterDisplay(VstInt32 index, char *text)
554 {
555 if(index<numParams)
556 dspUI->GetDisplay(index,text); // displayed float value as text
557 else
558 vst_strncpy (text, "IndexOutOfRange", kVstMaxParamStrLen);
559 }
560 //-----------------------------------------------------------------------------
561 void Faust::getParameterLabel(VstInt32 index, char *label)
562 {
563 vst_strncpy (label, "", kVstMaxParamStrLen); // parameter units in Name
564 }
565
566 //-----------------------------------------------------------------------------
567 void Faust::setSampleRate(float sampleRate)
568 {
569 // allways call this
570 AudioEffect::setSampleRate(sampleRate);
571 dsp->init(long(getSampleRate()));
572 }
573
574 //-----------------------------------------------------------------------------------------
575 bool Faust::getEffectName (char* text)
576 {
577 vst_strncpy (text, meta["name"].c_str(), kVstMaxProductStrLen);
578 return true;
579 }
580
581 //-----------------------------------------------------------------------------------------
582 bool Faust::getVendorString (char* text)
583 {
584 if (meta.count("author") > 0) {
585 vst_strncpy (text, meta["author"].c_str(), kVstMaxVendorStrLen);
586 return true;
587 } else {
588 return false;
589 }
590 }
591
592 //-----------------------------------------------------------------------------------------
593 bool Faust::getProductString (char* text)
594 {
595 vst_strncpy (text, meta["name"].c_str(), kVstMaxProductStrLen);
596 return true;
597 }
598
599 //-----------------------------------------------------------------------------------------
600 VstInt32 Faust::getVendorVersion ()
601 {
602 return 1000;
603 }
604
605 //-----------------------------------------------------------------------------
606 void Faust::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames)
607 {
608 AVOIDDENORMALS;
609 dsp->compute(sampleFrames, inputs, outputs);
610 }
611
612 //-----------------------------------------------------------------------------------------
613 bool Faust::getInputProperties (VstInt32 index, VstPinProperties* properties)
614 {
615 if(index>=0 && index<dsp->getNumInputs())
616 {
617 sprintf (properties->label, "Grame Faust DSP input: %d",index);
618 sprintf (properties->shortLabel, "In %d",index);
619 properties->flags = kVstPinIsActive;
620 if (dsp->getNumInputs() == 2) {
621 properties->flags |= kVstPinIsStereo;
622 }
623 return true;
624 }
625 else
626 return false;
627 }
628
629 //-----------------------------------------------------------------------------------------
630 bool Faust::getOutputProperties (VstInt32 index, VstPinProperties* properties)
631 {
632 if(index>=0 && index<dsp->getNumOutputs())
633 {
634 sprintf (properties->label, "Grame Faust DSP output: %d",index);
635 sprintf (properties->shortLabel, "Out %d",index);
636 properties->flags = kVstPinIsActive;
637 if (dsp->getNumOutputs() == 2) {
638 properties->flags |= kVstPinIsStereo;
639 }
640 return true;
641 }
642 else
643 return false;
644 }
645
646 /********************END ARCHITECTURE SECTION (part 2/2)****************/
647
648