1 /************************************************************************
2  FAUST Architecture File
3  Copyright (C) 2021 GRAME, Centre National de Creation Musicale
4  ---------------------------------------------------------------------
5  This Architecture section is free software; you can redistribute it
6  and/or modify it under the terms of the GNU General Public License
7  as published by the Free Software Foundation; either version 3 of
8  the License, or (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; If not, see <http://www.gnu.org/licenses/>.
17 
18  EXCEPTION : As a special exception, you may create a larger work
19  that contains this FAUST architecture section and distribute
20  that work under terms of your choice, so long as this FAUST
21  architecture section is not modified.
22 
23  ************************************************************************/
24 
25 #include <iostream>
26 #include <ostream>
27 #include <sstream>
28 #include <vector>
29 
30 #include "faust/dsp/dsp.h"
31 #include "faust/gui/DecoratorUI.h"
32 #include "faust/misc.h"
33 
34 using namespace std;
35 
36 <<includeIntrinsic>>
37 <<includeclass>>
38 
39 struct SwiftFilePrinter : public GenericUI
40 {
41     ofstream& fOutFile;
42     string fKlassName;
43     string fDSPName;
44     string fUniqueCode;
45     string fUnit;
46     stringstream fInit1;
47     stringstream fInit2;
48     vector<string> fInit3;
49 
SwiftFilePrinterSwiftFilePrinter50     SwiftFilePrinter(const string& class_name, ofstream& out_file):fKlassName("Faust" + class_name), fDSPName(class_name), fOutFile(out_file)
51     {
52         fInit1 << "public init(_ input: Node? = nil";
53         // this may need to be unique per node
54         fUniqueCode = "Fdsp";
55     }
56 
printHeaderSwiftFilePrinter57     void printHeader()
58     {
59         fOutFile << "// Copyright AudioKit. All Rights Reserved. Revision History at http://github.com/AudioKit/AudioKit/" << endl;
60         fOutFile << "import AVFoundation" << endl;
61         fOutFile << "import CAudioKit" << endl;
62         fOutFile << "import AudioKit" << endl;
63         fOutFile << endl;
64         fOutFile << "/// Faust node" << endl;
65         fOutFile << "public class " << fKlassName << ": Node, AudioUnitContainer, Toggleable {" << endl;
66         fOutFile << endl;
67         fOutFile << "\t" << "/// Unique four-letter identifier. If using multiple Faust generated nodes, make this unique for each" << endl;
68         fOutFile << "\t" << "public static let ComponentDescription = AudioComponentDescription(instrument: \"" << fUniqueCode << "\")" << endl;
69         fOutFile << endl;
70         fOutFile << "\t" << "/// Internal type of audio unit for this node" << endl;
71         fOutFile << "\t" << "public typealias AudioUnitType = InternalAU" << endl;
72         fOutFile << endl;
73         fOutFile << "\t" << "public private(set) var internalAU: AudioUnitType?" << endl;
74         fOutFile << endl;
75         fOutFile << "\t" << "// MARK: - Parameters" << endl;
76         fOutFile << endl;
77     }
78 
printFooterSwiftFilePrinter79     void printFooter()
80     {
81 
82         fOutFile << "\t" << "// MARK: - Audio Unit" << endl;
83         fOutFile << "\tpublic class InternalAU: AudioUnitBase {" << endl;
84         fOutFile << "\t\t" << "/// Get an array of the parameter definitions" << endl;
85         fOutFile << "\t\t" << "/// - Returns: Array of parameter definitions" << endl;
86         fOutFile << "\t\t" << "public override func getParameterDefs() -> [NodeParameterDef] {" << endl;
87         fOutFile << "\t\t\t" << "[";
88         for (int i = 0; i < fInit3.size(); i++) {
89             fOutFile << fInit3[i];
90             if (i < fInit3.size() - 1) fOutFile << ",\n\t\t\t";
91         }
92         fOutFile << "]" << endl;
93         fOutFile << "\t\t}" << endl;
94 
95         fOutFile << "\t\t/// Create the DSP Refence for this node" << endl;
96         fOutFile << "\t\t/// - Returns: DSP Reference" << endl;
97         fOutFile << "\t\tpublic override func createDSP() -> DSPRef { akCreateDSP(\"" << fKlassName << "\") }" << endl;
98         fOutFile << "\t}" << endl << endl;
99 
100         fOutFile << "\t" << "// MARK: - Initialization" << endl;
101         fOutFile << "\t" << fInit1.str() << ") {" << endl;
102         fOutFile << "\t\t" << "super.init(avAudioNode: input?.avAudioUnitOrNode ?? AVAudioNode())" << endl;
103         fOutFile << "\t\t" << "instantiateAudioUnit { avAudioUnit in" << endl;
104         fOutFile << "\t\t\t" << "self.avAudioUnit = avAudioUnit" << endl;
105         fOutFile << "\t\t\t" << "self.avAudioNode = avAudioUnit" << endl;
106         fOutFile << "\t\t\t" << "guard let audioUnit = avAudioUnit.auAudioUnit as? AudioUnitType else { fatalError(\"Couldn't create audio unit\") }" << endl;
107         fOutFile << "\t\t\t" << "self.internalAU = audioUnit" << endl;
108         fOutFile << "\t\t\t" << "self.stop()" << endl;
109         fOutFile << fInit2.str();
110         fOutFile << "\t\t}" << endl;
111         fOutFile << "\t}" << endl;
112 
113         fOutFile << "}" << endl << endl;
114     }
115 
printUnitSwiftFilePrinter116     string printUnit()
117     {
118         if (fUnit == "Hz") {
119             return ".hertz";
120         } else if (fUnit == "dB") {
121             return ".decibels";
122         } else {
123             return ".customUnit";
124         }
125     }
126 
printButtonSwiftFilePrinter127     void printButton(const char* label_aux)
128     {
129         string label = label_aux;
130         std::replace(label.begin(), label.end(), ' ', '_');
131     }
132 
printParamSwiftFilePrinter133     void printParam(const char* label_aux, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT init)
134     {
135         string label = label_aux;
136         std::replace(label.begin(), label.end(), ' ', '_');
137 
138         fOutFile << "\t" << "// " << label << endl;
139         fOutFile << "\t" << "public static var let" << label << "Def = NodeParameterDef(identifier: \"" << label << "\", ";
140         fInit3.push_back(fKlassName + ".let" + string(label) + "Def");
141         fOutFile << "name: \"" << label << "\", ";
142         fOutFile << "address: akGetParameterAddress(\"" << fDSPName << "_" << label << "\"), ";
143         fOutFile << "range: " << min << " ... " << max << ", ";
144         fOutFile << "unit: " << printUnit() << ", ";
145         fOutFile << "flags: .default)";
146         fOutFile << endl << endl;
147         fOutFile << "\t" << "@Parameter public var " << label << ": AUValue" << endl << endl;
148 
149         // Complete fInit1
150         fInit1 << ", " << label << ": AUValue = " << init;
151 
152         // Complete fInit2
153         fInit2 << "\t\t\t" << "self." << label << " = " << label << endl;
154 
155         // Reset unit metadata
156         fUnit = "";
157     }
158 
159     // -- active widgets
addButtonSwiftFilePrinter160     virtual void addButton(const char* label, FAUSTFLOAT* zone)
161     {
162         printButton(label);
163     }
addCheckButtonSwiftFilePrinter164     virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
165     {
166         printButton(label);
167     }
addVerticalSliderSwiftFilePrinter168     virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
169     {
170         printParam(label, min, max, init);
171     }
addHorizontalSliderSwiftFilePrinter172     virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
173     {
174         printParam(label, min, max, init);
175     }
addNumEntrySwiftFilePrinter176     virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
177     {
178         printParam(label, min, max, init);
179     }
180 
181     // -- passive widgets
addHorizontalBargraphSwiftFilePrinter182     virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) {}
addVerticalBargraphSwiftFilePrinter183     virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) {}
184 
declareSwiftFilePrinter185     virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
186     {
187         if (strcmp(key, "unit") == 0) {
188             fUnit = val;
189         }
190     }
191 
192 };
193 
194 struct Meta1 : Meta
195 {
196     string fFileName;
declareMeta1197     void declare(const char* key, const char* value)
198     {
199         if (strcmp("filename", key) == 0) {
200             fFileName = value;
201         }
202     }
203 };
204 
main(int argc,char * argv[])205 int main(int argc, char* argv[])
206 {
207     mydsp dsp;
208 
209     Meta1 meta1;
210     dsp.metadata(&meta1);
211 
212     // Generate the swift output file
213     string file_name = meta1.fFileName;
214     file_name.erase(file_name.end() - 4, file_name.end());
215 
216     ofstream out_file("Faust" + file_name + ".swift");
217     SwiftFilePrinter printer(file_name, out_file);
218     printer.printHeader();
219     dsp.buildUserInterface(&printer);
220     printer.printFooter();
221 
222     return 0;
223 }
224