1 /************************************************************************
2  ************************************************************************
3     FAUST compiler
4     Copyright (C) 2003-2018 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.
10 
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.
15 
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  ************************************************************************/
21 
22 #include "compile_sched.hh"
23 #include "floats.hh"
24 #include "ppsig.hh"
25 
compileMultiSignal(Tree L)26 void SchedulerCompiler::compileMultiSignal(Tree L)
27 {
28     // contextor recursivness(0);
29     L = prepare(L);  // optimize, share and annotate expression
30 
31     for (int i = 0; i < fClass->inputs(); i++) {
32         fClass->addZone3(subst("$1* input$0 = &input[$0][fIndex];", T(i), xfloat()));
33     }
34     for (int i = 0; i < fClass->outputs(); i++) {
35         fClass->addZone3(subst("$1* output$0 = &output[$0][fIndex];", T(i), xfloat()));
36     }
37 
38     fClass->addSharedDecl("fullcount");
39     fClass->addSharedDecl("input");
40     fClass->addSharedDecl("output");
41 
42     for (int i = 0; isList(L); L = tl(L), i++) {
43         Tree sig = hd(L);
44         fClass->openLoop("count");
45         fClass->addExecCode(Statement("", subst("output$0[i] = $2$1;", T(i), CS(sig), xcast())));
46         fClass->closeLoop(sig);
47     }
48 
49     // Build tasks list
50     fClass->buildTasksList();
51 
52     generateUserInterfaceTree(prepareUserInterfaceTree(fUIRoot), true);
53     generateMacroInterfaceTree("", prepareUserInterfaceTree(fUIRoot));
54     if (fDescription) {
55         fDescription->ui(prepareUserInterfaceTree(fUIRoot));
56     }
57 }
58 
59 /**
60  * Generate the code for a (short) delay line
61  * @param k the c++ class where the delay line will be placed.
62  * @param l the loop where the code will be placed.
63  * @param tname the name of the C++ type (float or int)
64  * @param dlname the name of the delay line (vector) to be used.
65  * @param delay the maximum delay
66  * @param cexp the content of the signal as a C++ expression
67  */
vectorLoop(const string & tname,const string & vecname,const string & cexp,const string & ccs)68 void SchedulerCompiler::vectorLoop(const string& tname, const string& vecname, const string& cexp, const string& ccs)
69 {
70     // -- declare the vector
71     fClass->addSharedDecl(vecname);
72 
73     // -- variables moved as class fields...
74     fClass->addDeclCode(subst("$0 \t$1[$2];", tname, vecname, T(gGlobal->gVecSize)));
75 
76     // -- compute the new samples
77     fClass->addExecCode(Statement(ccs, subst("$0[i] = $1;", vecname, cexp)));
78 }
79 
80 /**
81  * Generate the code for a (short) delay line
82  * @param k the c++ class where the delay line will be placed.
83  * @param l the loop where the code will be placed.
84  * @param tname the name of the C++ type (float or int)
85  * @param dlname the name of the delay line (vector) to be used.
86  * @param delay the maximum delay
87  * @param cexp the content of the signal as a C++ expression
88  */
dlineLoop(const string & tname,const string & dlname,int delay,const string & cexp,const string & ccs)89 void SchedulerCompiler::dlineLoop(const string& tname, const string& dlname, int delay, const string& cexp,
90                                   const string& ccs)
91 {
92     if (delay < gGlobal->gMaxCopyDelay) {
93         // Implementation of a copy based delayline
94 
95         // create names for temporary and permanent storage
96         string buf  = subst("$0_tmp", dlname);
97         string pmem = subst("$0_perm", dlname);
98 
99         // constraints delay size to be multiple of 4
100         delay = (delay + 3) & -4;
101 
102         // allocate permanent storage for delayed samples
103         string dsize = T(delay);
104         fClass->addDeclCode(subst("$0 \t$1[$2];", tname, pmem, dsize));
105 
106         // init permanent memory
107         fClass->addClearCode(subst("for (int i=0; i<$1; i++) $0[i]=0;", pmem, dsize));
108 
109         // compute method
110 
111         // -- declare a buffer and a "shifted" vector
112         fClass->addSharedDecl(buf);
113 
114         // -- variables moved as class fields...
115         fClass->addDeclCode(subst("$0 \t$1[$2+$3];", tname, buf, T(gGlobal->gVecSize), dsize));
116 
117         fClass->addFirstPrivateDecl(dlname);
118         fClass->addZone2(subst("$0* \t$1 = &$2[$3];", tname, dlname, buf, dsize));
119 
120         // -- copy the stored samples to the delay line
121         fClass->addPreCode(Statement(ccs, subst("for (int i=0; i<$2; i++) $0[i]=$1[i];", buf, pmem, dsize)));
122 
123         // -- compute the new samples
124         fClass->addExecCode(Statement(ccs, subst("$0[i] = $1;", dlname, cexp)));
125 
126         // -- copy back to stored samples
127         fClass->addPostCode(Statement(ccs, subst("for (int i=0; i<$2; i++) $0[i]=$1[count+i];", pmem, buf, dsize)));
128 
129     } else {
130         // Implementation of a ring-buffer delayline
131 
132         // the size should be large enough and aligned on a power of two
133         delay        = pow2limit(delay + gGlobal->gVecSize);
134         string dsize = T(delay);
135         string mask  = T(delay - 1);
136 
137         // create names for temporary and permanent storage
138         string idx      = subst("$0_idx", dlname);
139         string idx_save = subst("$0_idx_save", dlname);
140 
141         // allocate permanent storage for delayed samples
142         fClass->addDeclCode(subst("$0 \t$1[$2];", tname, dlname, dsize));
143         fClass->addDeclCode(subst("int \t$0;", idx));
144         fClass->addDeclCode(subst("int \t$0;", idx_save));
145 
146         // init permanent memory
147         fClass->addClearCode(subst("for (int i=0; i<$1; i++) $0[i]=0;", dlname, dsize));
148         fClass->addClearCode(subst("$0 = 0;", idx));
149         fClass->addClearCode(subst("$0 = 0;", idx_save));
150 
151         // -- update index
152         fClass->addPreCode(Statement(ccs, subst("$0 = ($0+$1)&$2;", idx, idx_save, mask)));
153 
154         // -- compute the new samples
155         fClass->addExecCode(Statement(ccs, subst("$0[($2+i)&$3] = $1;", dlname, cexp, idx, mask)));
156 
157         // -- save index
158         fClass->addPostCode(Statement(ccs, subst("$0 = count;", idx_save)));
159     }
160 }
161