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 "interpreter_dsp.hh"
23 #include "compatibility.hh"
24 #include "libfaust.h"
25 #include "lock_api.hh"
26 
27 using namespace std;
28 
29 #ifdef MACHINE
30 #include "sha_key.hh"
faustassertaux(bool cond,const string & file,int line)31 void faustassertaux(bool cond, const string& file, int line)
32 {
33     if (!cond) {
34         stringstream str;
35         str << "ASSERT : please report this message, the stack trace, and the failing DSP file to Faust developers (";
36         str << "file: " << file.substr(file.find_last_of('/') + 1) << ", line: " << line << ", ";
37         str << "version: " << FAUSTVERSION;
38         str << ")\n";
39         stacktrace(str, 20);
40         throw faustexception(str.str());
41     }
42 }
43 #endif
44 
45 dsp_factory_table<SDsp_factory> gInterpreterFactoryTable;
46 
47 // External API
48 
getInterpreterDSPFactoryFromSHAKey(const string & sha_key)49 EXPORT interpreter_dsp_factory* getInterpreterDSPFactoryFromSHAKey(const string& sha_key)
50 {
51     LOCK_API
52     return static_cast<interpreter_dsp_factory*>(gInterpreterFactoryTable.getDSPFactoryFromSHAKey(sha_key));
53 }
54 
deleteInterpreterDSPFactory(interpreter_dsp_factory * factory)55 EXPORT bool deleteInterpreterDSPFactory(interpreter_dsp_factory* factory)
56 {
57     LOCK_API
58     return (factory) ? gInterpreterFactoryTable.deleteDSPFactory(factory) : false;
59  }
60 
getInterpreterDSPFactoryLibraryList(interpreter_dsp_factory * factory)61 EXPORT vector<string> getInterpreterDSPFactoryLibraryList(interpreter_dsp_factory* factory)
62 {
63     // TODO
64     LOCK_API
65     vector<string> res;
66     return res;
67 }
68 
getAllInterpreterDSPFactories()69 EXPORT vector<string> getAllInterpreterDSPFactories()
70 {
71     LOCK_API
72     return gInterpreterFactoryTable.getAllDSPFactories();
73 }
74 
deleteAllInterpreterDSPFactories()75 EXPORT void deleteAllInterpreterDSPFactories()
76 {
77     LOCK_API
78     gInterpreterFactoryTable.deleteAllDSPFactories();
79 }
80 
~interpreter_dsp()81 EXPORT interpreter_dsp::~interpreter_dsp()
82 {
83     LOCK_API
84     gInterpreterFactoryTable.removeDSP(fFactory, this);
85 
86     if (fFactory->getMemoryManager()) {
87         fDSP->~interpreter_dsp_base();
88         fFactory->getMemoryManager()->destroy(fDSP);
89     } else {
90         delete fDSP;
91     }
92 }
93 
createDSPInstance()94 EXPORT interpreter_dsp* interpreter_dsp_factory::createDSPInstance()
95 {
96     LOCK_API
97     dsp* dsp = fFactory->createDSPInstance(this);
98     gInterpreterFactoryTable.addDSP(this, dsp);
99     return static_cast<interpreter_dsp*>(dsp);
100 }
101 
102 // Use the memory manager if needed
operator delete(void * ptr)103 EXPORT void interpreter_dsp::operator delete(void* ptr)
104 {
105     if (ptr) {
106         dsp_memory_manager* manager = static_cast<interpreter_dsp*>(ptr)->fFactory->getMemoryManager();
107         if (manager) {
108             manager->destroy(ptr);
109         } else {
110             ::operator delete(ptr);
111         }
112     }
113 }
114 
115 // Read/write
116 
read_real_type(istream * in)117 static string read_real_type(istream* in)
118 {
119     string type_line;
120     getline(*in, type_line);
121 
122     stringstream type_reader(type_line);
123     string       dummy, type;
124     type_reader >> dummy;  // Read "interpreter_dsp_factory" token
125     checkToken(dummy, "interpreter_dsp_factory");
126     type_reader >> type;
127 
128     return type;
129 }
130 
readInterpreterDSPFactoryFromBitcodeAux(const string & bitcode,string & error_msg)131 static interpreter_dsp_factory* readInterpreterDSPFactoryFromBitcodeAux(const string& bitcode, string& error_msg)
132 {
133     try {
134         dsp_factory_table<SDsp_factory>::factory_iterator it;
135 
136         string sha_key = generateSHA1(bitcode);
137 
138         if (gInterpreterFactoryTable.getFactory(sha_key, it)) {
139             SDsp_factory sfactory = (*it).first;
140             sfactory->addReference();
141             return sfactory;
142         } else {
143             interpreter_dsp_factory* factory = nullptr;
144             stringstream             reader(bitcode);
145             string                   type = read_real_type(&reader);
146 
147             if (type == "float") {
148                 factory = new interpreter_dsp_factory(interpreter_dsp_factory_aux<float, 0>::read(&reader));
149             } else if (type == "double") {
150                 factory = new interpreter_dsp_factory(interpreter_dsp_factory_aux<double, 0>::read(&reader));
151             } else {
152                 throw faustexception("ERROR : unrecognized file format\n");
153             }
154 
155             gInterpreterFactoryTable.setFactory(factory);
156             factory->setSHAKey(sha_key);
157             factory->setDSPCode(bitcode);
158             return factory;
159         }
160     } catch (faustexception& e) {
161         error_msg = e.Message();
162         return nullptr;
163     }
164 }
165 
readInterpreterDSPFactoryFromBitcode(const string & bitcode,string & error_msg)166 EXPORT interpreter_dsp_factory* readInterpreterDSPFactoryFromBitcode(const string& bitcode, string& error_msg)
167 {
168     LOCK_API
169     return readInterpreterDSPFactoryFromBitcodeAux(bitcode, error_msg);
170 }
171 
writeInterpreterDSPFactoryToBitcode(interpreter_dsp_factory * factory)172 EXPORT string writeInterpreterDSPFactoryToBitcode(interpreter_dsp_factory* factory)
173 {
174     LOCK_API
175     stringstream writer;
176     factory->write(&writer, true);
177     return writer.str();
178 }
179 
readInterpreterDSPFactoryFromBitcodeFile(const string & bitcode_path,string & error_msg)180 EXPORT interpreter_dsp_factory* readInterpreterDSPFactoryFromBitcodeFile(const string& bitcode_path, string& error_msg)
181 {
182     LOCK_API
183     string base = basename((char*)bitcode_path.c_str());
184     size_t pos  = bitcode_path.find(".fbc");
185 
186     if (pos != string::npos) {
187         ifstream reader(bitcode_path.c_str());
188         if (reader.is_open()) {
189             string bitcode(istreambuf_iterator<char>(reader), {});
190             return readInterpreterDSPFactoryFromBitcodeAux(bitcode, error_msg);
191         } else {
192             error_msg = "ERROR opening file '" + bitcode_path + "'\n";
193             return nullptr;
194         }
195     } else {
196         error_msg = "ERROR : file Extension is not the one expected (.fbc expected)\n";
197         return nullptr;
198     }
199 }
200 
writeInterpreterDSPFactoryToBitcodeFile(interpreter_dsp_factory * factory,const string & bitcode_path)201 EXPORT bool writeInterpreterDSPFactoryToBitcodeFile(interpreter_dsp_factory* factory, const string& bitcode_path)
202 {
203     LOCK_API
204     ofstream writer(bitcode_path.c_str());
205     if (writer.is_open()) {
206         factory->write(&writer, true);
207         return true;
208     } else {
209         return false;
210     }
211 }
212 
metadata(Meta * meta)213 EXPORT void interpreter_dsp::metadata(Meta* meta)
214 {
215     fDSP->metadata(meta);
216 }
217 
clone()218 EXPORT interpreter_dsp* interpreter_dsp::clone()
219 {
220     return fFactory->createDSPInstance();
221 }
222 
getSampleRate()223 EXPORT int interpreter_dsp::getSampleRate()
224 {
225     return fDSP->getSampleRate();
226 }
227 
getNumInputs()228 EXPORT int interpreter_dsp::getNumInputs()
229 {
230     return fDSP->getNumInputs();
231 }
232 
getNumOutputs()233 int EXPORT interpreter_dsp::getNumOutputs()
234 {
235     return fDSP->getNumOutputs();
236 }
237 
init(int sample_rate)238 EXPORT void interpreter_dsp::init(int sample_rate)
239 {
240     fDSP->init(sample_rate);
241 }
242 
instanceInit(int sample_rate)243 EXPORT void interpreter_dsp::instanceInit(int sample_rate)
244 {
245     fDSP->instanceInit(sample_rate);
246 }
247 
instanceConstants(int sample_rate)248 EXPORT void interpreter_dsp::instanceConstants(int sample_rate)
249 {
250     fDSP->instanceConstants(sample_rate);
251 }
252 
instanceResetUserInterface()253 EXPORT void interpreter_dsp::instanceResetUserInterface()
254 {
255     fDSP->instanceResetUserInterface();
256 }
257 
instanceClear()258 EXPORT void interpreter_dsp::instanceClear()
259 {
260     fDSP->instanceClear();
261 }
262 
buildUserInterface(UI * ui_interface)263 EXPORT void interpreter_dsp::buildUserInterface(UI* ui_interface)
264 {
265     UITemplate glue(ui_interface);
266     fDSP->buildUserInterface(&glue);
267 }
268 
compute(int count,FAUSTFLOAT ** input,FAUSTFLOAT ** output)269 EXPORT void interpreter_dsp::compute(int count, FAUSTFLOAT** input, FAUSTFLOAT** output)
270 {
271     fDSP->compute(count, input, output);
272 }
273