1 /************************************************************************
2     IMPORTANT NOTE : this file contains two clearly delimited sections :
3     the ARCHITECTURE section (in two parts) and the USER section. Each section
4     is governed by its own copyright and license. Please check individually
5     each section for license and copyright information.
6 *************************************************************************/
7 
8 /*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/
9 
10 /************************************************************************
11     FAUST Architecture File
12     Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
13     ---------------------------------------------------------------------
14     This Architecture section is free software; you can redistribute it
15     and/or modify it under the terms of the GNU General Public License
16     as published by the Free Software Foundation; either version 3 of
17     the License, or (at your option) any later version.
18 
19     This program is distributed in the hope that it will be useful,
20     but WITHOUT ANY WARRANTY; without even the implied warranty of
21     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22     GNU General Public License for more details.
23 
24     You should have received a copy of the GNU General Public License
25     along with this program; If not, see <http://www.gnu.org/licenses/>.
26 
27     EXCEPTION : As a special exception, you may create a larger work
28     that contains this FAUST architecture section and distribute
29     that work under terms of your choice, so long as this FAUST
30     architecture section is not modified.
31 
32  ************************************************************************
33  ************************************************************************/
34 
35 #ifndef __proxy_dsp__
36 #define __proxy_dsp__
37 
38 #include <vector>
39 #include <map>
40 
41 #include "faust/dsp/dsp.h"
42 #include "faust/gui/SimpleParser.h"
43 #include "faust/gui/JSONUI.h"
44 
45 #ifdef _WIN32
46 #include <windows.h>
47 #define snprintf _snprintf
48 #endif
49 
50 inline FAUSTFLOAT STR2REAL(const std::string& s) { return (strtod(s.c_str(), NULL)); }
51 
52 //-------------------------------------------------------------------
53 //  Decode a dsp JSON description and implement 'buildUserInterface'
54 //-------------------------------------------------------------------
55 
56 struct JSONUIDecoder {
57 
58     std::string fName;
59 
60     std::map<std::string, std::string> fMetadatas;
61     std::vector<itemInfo*> fUiItems;
62 
63     FAUSTFLOAT* fInControl;
64     FAUSTFLOAT* fOutControl;
65 
66     std::string fJSON;
67 
68     int fNumInputs, fNumOutputs;
69     int fInputItems, fOutputItems;
70 
71     JSONUIDecoder(const std::string& json)
72     {
73         fJSON = json;
74         const char* p = fJSON.c_str();
75         parseJson(p, fMetadatas, fUiItems);
76 
77         // fMetadatas will contain the "meta" section as well as <name : val>, <inputs : val>, <ouputs : val> pairs
78         if (fMetadatas.find("name") != fMetadatas.end()) {
79             fName = fMetadatas["name"];
80             fMetadatas.erase("name");
81         } else {
82             fName = "";
83         }
84 
85         if (fMetadatas.find("inputs") != fMetadatas.end()) {
86             fNumInputs = atoi(fMetadatas["inputs"].c_str());
87             fMetadatas.erase("inputs");
88         } else {
89             fNumInputs = -1;
90         }
91 
92         if (fMetadatas.find("outputs") != fMetadatas.end()) {
93             fNumOutputs = atoi(fMetadatas["outputs"].c_str());
94             fMetadatas.erase("outputs");
95         } else {
96             fNumOutputs = -1;
97         }
98 
99         vector<itemInfo*>::iterator it;
100         fInputItems = 0;
101         fOutputItems = 0;
102 
103         for (it = fUiItems.begin(); it != fUiItems.end(); it++) {
104             string type = (*it)->type;
105             if (type == "vslider" || type == "hslider" || type == "nentry" || type == "button") {
106                 fInputItems++;
107             } else if (type == "hbargraph" || type == "vbargraph") {
108                 fOutputItems++;
109             }
110         }
111 
112         fInControl = new FAUSTFLOAT[fInputItems];
113         fOutControl = new FAUSTFLOAT[fOutputItems];
114     }
115 
116     virtual ~JSONUIDecoder()
117     {
118         vector<itemInfo*>::iterator it;
119         for (it = fUiItems.begin(); it != fUiItems.end(); it++) {
120             delete(*it);
121         }
122         delete [] fInControl;
123         delete [] fOutControl;
124     }
125 
126     void metadata(Meta* m)
127     {
128         std::map<std::string, std::string>::iterator it;
129         for (it = fMetadatas.begin(); it != fMetadatas.end(); it++) {
130             m->declare((*it).first.c_str(), (*it).second.c_str());
131         }
132     }
133 
134     void buildUserInterface(UI* ui)
135     {
136         // To be sure the floats are correctly encoded
137         char* tmp_local = setlocale(LC_ALL, NULL);
138         setlocale(LC_ALL, "C");
139 
140         int counterIn = 0;
141         int counterOut = 0;
142         vector<itemInfo*>::iterator it;
143 
144         for (it = fUiItems.begin(); it != fUiItems.end(); it++) {
145 
146             bool isInItem = false;
147             bool isOutItem = false;
148             string type = (*it)->type;
149 
150             FAUSTFLOAT init = STR2REAL((*it)->init);
151             FAUSTFLOAT min = STR2REAL((*it)->min);
152             FAUSTFLOAT max = STR2REAL((*it)->max);
153             FAUSTFLOAT step = STR2REAL((*it)->step);
154 
155             if (type == "vslider" || type == "hslider" || type == "nentry" || type == "button") {
156                 isInItem = true;
157             } else if (type == "hbargraph" || type == "vbargraph") {
158                 isOutItem = true;
159             }
160 
161             // Meta data declaration for input items
162             if ((*it)->type.find("group") == string::npos && (*it)->type.find("bargraph") == string::npos && (*it)->type != "close") {
163                 fInControl[counterIn] = init;
164                 for (int i = 0; i < (*it)->meta.size(); i++) {
165                     ui->declare(&fInControl[counterIn], (*it)->meta[i].first.c_str(), (*it)->meta[i].second.c_str());
166                 }
167             }
168             // Meta data declaration for output items
169             else if ((*it)->type.find("bargraph") != string::npos) {
170                 fOutControl[counterOut] = init;
171                 for (int i = 0; i < (*it)->meta.size(); i++) {
172                     ui->declare(&fOutControl[counterOut], (*it)->meta[i].first.c_str(), (*it)->meta[i].second.c_str());
173                 }
174             }
175             // Meta data declaration for group opening or closing
176             else {
177                 for (int i = 0; i < (*it)->meta.size(); i++) {
178                     ui->declare(0, (*it)->meta[i].first.c_str(), (*it)->meta[i].second.c_str());
179                 }
180             }
181 
182             if (type == "hgroup") {
183                 ui->openHorizontalBox((*it)->label.c_str());
184             } else if (type == "vgroup") {
185                 ui->openVerticalBox((*it)->label.c_str());
186             } else if (type == "tgroup") {
187                 ui->openTabBox((*it)->label.c_str());
188             } else if (type == "vslider") {
189                 ui->addVerticalSlider((*it)->label.c_str(), &fInControl[counterIn], init, min, max, step);
190             } else if (type == "hslider") {
191                 ui->addHorizontalSlider((*it)->label.c_str(), &fInControl[counterIn], init, min, max, step);
192             } else if (type == "checkbox") {
193                 ui->addCheckButton((*it)->label.c_str(), &fInControl[counterIn]);
194             } else if (type == "hbargraph") {
195                 ui->addHorizontalBargraph((*it)->label.c_str(), &fOutControl[counterOut], min, max);
196             } else if (type == "vbargraph") {
197                 ui->addVerticalBargraph((*it)->label.c_str(), &fOutControl[counterOut], min, max);
198             } else if (type == "nentry") {
199                 ui->addNumEntry((*it)->label.c_str(), &fInControl[counterIn], init, min, max, step);
200             } else if (type == "button") {
201                 ui->addButton((*it)->label.c_str(), &fInControl[counterIn]);
202             } else if (type == "close") {
203                 ui->closeBox();
204             }
205 
206             if (isInItem) {
207                 counterIn++;
208             }
209 
210             if (isOutItem) {
211                 counterOut++;
212             }
213         }
214 
215         setlocale(LC_ALL, tmp_local);
216     }
217 
218 };
219 
220 //----------------------------------------------------------------
221 //  Proxy dsp definition created from the DSP JSON description
222 //  This class allows a 'proxy' dsp to control a real dsp
223 //  possibly running somewhere else.
224 //----------------------------------------------------------------
225 
226 class proxy_dsp : public dsp {
227 
228     private:
229 
230         int fSamplingFreq;
231         JSONUIDecoder* fDecoder;
232 
233     public:
234 
235         proxy_dsp(const string& json)
236         {
237             fDecoder = new JSONUIDecoder(json);
238             fSamplingFreq = -1;
239         }
240 
241         proxy_dsp(dsp* dsp)
242         {
243             JSONUI builder(dsp->getNumInputs(), dsp->getNumOutputs());
244             dsp->metadata(&builder);
245             dsp->buildUserInterface(&builder);
246             fSamplingFreq = dsp->getSampleRate();
247             fDecoder = new JSONUIDecoder(builder.JSON());
248         }
249 
250         virtual ~proxy_dsp()
251         {
252             delete fDecoder;
253         }
254 
255         virtual int getNumInputs() 	{ return fDecoder->fNumInputs; }
256         virtual int getNumOutputs() { return fDecoder->fNumOutputs; }
257 
258         virtual void buildUserInterface(UI* ui) { fDecoder->buildUserInterface(ui); }
259 
260         // To possibly implement in a concrete proxy dsp
261         virtual void init(int samplingRate) { fSamplingFreq = samplingRate; }
262         virtual void instanceInit(int samplingRate) {}
263         virtual void instanceConstants(int samplingRate) {}
264         virtual void instanceResetUserInterface() {}
265         virtual void instanceClear() {}
266 
267         virtual int getSampleRate() { return fSamplingFreq; }
268 
269         virtual proxy_dsp* clone() { return new proxy_dsp(fDecoder->fJSON); }
270         virtual void metadata(Meta* m) { fDecoder->metadata(m); }
271 
272         virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {}
273         virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {}
274 
275 };
276 
277 #endif
278