1 /************************************************************************
2 ************************************************************************
4 Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 ************************************************************************
20 ************************************************************************/
24 /*****************************************************************************
25 ******************************************************************************
27 Y. Orlarey, (c) Grame 2002
28 ------------------------------------------------------------------------------
29 Compile a list of FAUST signals into a C++ class .
33 2002-02-08 : First version
35 ******************************************************************************
36 *****************************************************************************/
48 #include "sigprint.hh"
51 #include "sigtyperules.hh"
52 #include "simplify.hh"
53 #include "privatise.hh"
54 //#include "factorize.hh"
56 //#include "grouper.hh"
57 //#include "sigvisitor.hh"
62 /*****************************************************************************
63 ******************************************************************************
67 ******************************************************************************
68 *****************************************************************************/
70 extern int gDetailsSwitch
;
71 extern string gMasterName
;
76 /*****************************************************************************
77 ******************************************************************************
79 GENERAL COMPILER METHODS
81 ******************************************************************************
82 *****************************************************************************/
90 /*****************************************************************************
92 *****************************************************************************/
94 Compiler::Compiler(const string
& name
, const string
& super
, int numInputs
, int numOutputs
, bool vec
)
95 : fClass(new Klass(name
, super
, numInputs
, numOutputs
, vec
)),
96 fNeedToDeleteClass(true),
97 fUIRoot(uiFolder(cons(tree(0), tree(subst("$0", gMasterName
))))),
101 Compiler::Compiler(Klass
* k
)
103 fNeedToDeleteClass(false),
104 fUIRoot(uiFolder(cons(tree(0), tree(subst("$0", gMasterName
))))),
109 Compiler::~Compiler()
111 if (fNeedToDeleteClass
) delete fClass
;
116 /*****************************************************************************
117 user interface elements
118 *****************************************************************************/
121 * Add a widget with a certain path to the user interface tree
123 void Compiler::addUIWidget(Tree path
, Tree widget
)
125 fUIRoot
= putSubFolder(fUIRoot
, path
, widget
);
130 * Remove fake root folder if not needed (that is if the UI
131 * is completely enclosed in one folder
133 Tree
Compiler::prepareUserInterfaceTree(Tree t
)
136 if (isUiFolder(t
, root
, elems
) && isList(elems
) && isNil(tl(elems
)) ) {
137 Tree folder
= right(hd(elems
));
138 return (isUiFolder(folder
)) ? folder
: t
;
143 //================================= some string processing utilities =================================
146 * Removes enclosing whitespaces : ' toto ' -> 'toto'
148 static string
wdel(const string
& s
)
152 while (i
<j
&& s
[i
]==' ') i
++;
153 while (j
>i
&& s
[j
-1] == ' ') j
--;
154 return s
.substr(i
,j
-i
);
158 //================================= BUILD USER INTERFACE METHOD =================================
161 * Generate buildUserInterface C++ lines of code corresponding
162 * to user interface element t
164 void Compiler::generateUserInterfaceTree(Tree t
)
166 Tree label
, elements
, varname
, sig
;
168 if (isUiFolder(t
, label
, elements
)) {
169 const int orient
= tree2int(left(label
));
170 const char * str
= tree2str(right(label
));
173 // extract metadata from group label str resulting in a simplifiedLabel
174 // and metadata declarations for fictive zone at address 0
175 string simplifiedLabel
;
176 map
<string
, set
<string
> > metadata
;
177 extractMetadata(str
, simplifiedLabel
, metadata
);
179 // add metadata if any
180 for (map
<string
, set
<string
> >::iterator i
= metadata
.begin(); i
!= metadata
.end(); i
++) {
181 const string
& key
= i
->first
;
182 const set
<string
>& values
= i
->second
;
183 for (set
<string
>::const_iterator j
= values
.begin(); j
!= values
.end(); j
++) {
184 fClass
->addUICode(subst("interface->declare($0, \"$1\", \"$2\");", "0", wdel(key
) ,wdel(*j
)));
191 case 0 : model
= "interface->openVerticalBox(\"$0\");"; break;
192 case 1 : model
= "interface->openHorizontalBox(\"$0\");"; break;
193 case 2 : model
= "interface->openTabBox(\"$0\");"; break;
195 fprintf(stderr
, "error in user interface generation 1\n");
198 fClass
->addUICode(subst(model
, simplifiedLabel
));
199 generateUserInterfaceElements(elements
);
200 fClass
->addUICode("interface->closeBox();");
202 } else if (isUiWidget(t
, label
, varname
, sig
)) {
204 generateWidgetCode(label
, varname
, sig
);
208 fprintf(stderr
, "error in user interface generation 2\n");
215 * Iterate generateUserInterfaceTree on a list of user interface elements
217 void Compiler::generateUserInterfaceElements(Tree elements
)
219 while (!isNil(elements
)) {
220 generateUserInterfaceTree(right(hd(elements
)));
221 elements
= tl(elements
);
226 * Generate buildUserInterface C++ lines of code corresponding
227 * to user interface widget t
229 void Compiler::generateWidgetCode(Tree fulllabel
, Tree varname
, Tree sig
)
231 Tree path
, c
, x
, y
, z
;
233 map
<string
, set
<string
> > metadata
;
235 extractMetadata(tree2str(fulllabel
), label
, metadata
);
237 // add metadata if any
238 for (map
<string
, set
<string
> >::iterator i
= metadata
.begin(); i
!= metadata
.end(); i
++) {
239 const string
& key
= i
->first
;
240 const set
<string
>& values
= i
->second
;
241 for (set
<string
>::const_iterator j
= values
.begin(); j
!= values
.end(); j
++) {
242 fClass
->addUICode(subst("interface->declare(&$0, \"$1\", \"$2\");", tree2str(varname
), wdel(key
) ,wdel(*j
)));
246 if ( isSigButton(sig
, path
) ) {
247 fClass
->incUIActiveCount();
248 fClass
->addUICode(subst("interface->addButton(\"$0\", &$1);", label
, tree2str(varname
)));
250 } else if ( isSigCheckbox(sig
, path
) ) {
251 fClass
->incUIActiveCount();
252 fClass
->addUICode(subst("interface->addCheckButton(\"$0\", &$1);", label
, tree2str(varname
)));
254 } else if ( isSigVSlider(sig
, path
,c
,x
,y
,z
) ) {
255 fClass
->incUIActiveCount();
256 fClass
->addUICode(subst("interface->addVerticalSlider(\"$0\", &$1, $2, $3, $4, $5);",
264 } else if ( isSigHSlider(sig
, path
,c
,x
,y
,z
) ) {
265 fClass
->incUIActiveCount();
266 fClass
->addUICode(subst("interface->addHorizontalSlider(\"$0\", &$1, $2, $3, $4, $5);",
274 } else if ( isSigNumEntry(sig
, path
,c
,x
,y
,z
) ) {
275 fClass
->incUIActiveCount();
276 fClass
->addUICode(subst("interface->addNumEntry(\"$0\", &$1, $2, $3, $4, $5);",
284 } else if ( isSigVBargraph(sig
, path
,x
,y
,z
) ) {
285 fClass
->incUIPassiveCount();
286 fClass
->addUICode(subst("interface->addVerticalBargraph(\"$0\", &$1, $2, $3);",
292 } else if ( isSigHBargraph(sig
, path
,x
,y
,z
) ) {
293 fClass
->incUIPassiveCount();
294 fClass
->addUICode(subst("interface->addHorizontalBargraph(\"$0\", &$1, $2, $3);",
301 fprintf(stderr
, "Error in generating widget code\n");
306 //==================================== USER INTERFACE MACROS ==================================
309 * Generate user interface macros corresponding
310 * to user interface element t
312 void Compiler::generateMacroInterfaceTree(const string
& pathname
, Tree t
)
314 Tree label
, elements
, varname
, sig
;
316 if (isUiFolder(t
, label
, elements
)) {
317 string pathname2
= pathname
;
318 //string str = unquote(tree2str(right(label)));
319 string str
= tree2str(right(label
));
320 if (str
.length()>0) pathname2
+= str
+ "/";
321 generateMacroInterfaceElements(pathname2
, elements
);
323 } else if (isUiWidget(t
, label
, varname
, sig
)) {
325 generateWidgetMacro(pathname
, label
, varname
, sig
);
329 fprintf(stderr
, "error in user interface macro generation 2\n");
337 * Iterate generateMacroInterfaceTree on a list of user interface elements
339 void Compiler::generateMacroInterfaceElements(const string
& pathname
, Tree elements
)
341 while (!isNil(elements
)) {
342 generateMacroInterfaceTree(pathname
, right(hd(elements
)));
343 elements
= tl(elements
);
349 * Generate user interface macros corresponding
350 * to a user interface widget
352 void Compiler::generateWidgetMacro(const string
& pathname
, Tree fulllabel
, Tree varname
, Tree sig
)
354 Tree path
, c
, x
, y
, z
;
356 map
<string
, set
<string
> > metadata
;
358 extractMetadata(tree2str(fulllabel
), label
, metadata
);
360 //string pathlabel = pathname+unquote(label);
361 string pathlabel
= pathname
+label
;
364 if ( isSigButton(sig
, path
) ) {
365 fClass
->addUIMacro(subst("FAUST_ADDBUTTON(\"$0\", $1);", pathlabel
, tree2str(varname
)));
367 } else if ( isSigCheckbox(sig
, path
) ) {
368 fClass
->addUIMacro(subst("FAUST_ADDCHECKBOX(\"$0\", $1);", pathlabel
, tree2str(varname
)));
370 } else if ( isSigVSlider(sig
, path
,c
,x
,y
,z
) ) {
371 fClass
->addUIMacro(subst("FAUST_ADDVERTICALSLIDER(\"$0\", $1, $2, $3, $4, $5);",
379 } else if ( isSigHSlider(sig
, path
,c
,x
,y
,z
) ) {
380 fClass
->addUIMacro(subst("FAUST_ADDHORIZONTALSLIDER(\"$0\", $1, $2, $3, $4, $5);",
388 } else if ( isSigNumEntry(sig
, path
,c
,x
,y
,z
) ) {
389 fClass
->addUIMacro(subst("FAUST_ADDNUMENTRY(\"$0\", $1, $2, $3, $4, $5);",
397 } else if ( isSigVBargraph(sig
, path
,x
,y
,z
) ) {
398 fClass
->addUIMacro(subst("FAUST_ADDVERTICALBARGRAPH(\"$0\", $1, $2, $3);",
404 } else if ( isSigHBargraph(sig
, path
,x
,y
,z
) ) {
405 fClass
->addUIMacro(subst("FAUST_ADDHORIZONTALBARGRAPH(\"$0\", $1, $2, $3);",
412 fprintf(stderr
, "Error in generating widget code\n");