| @@ -29,6 +29,9 @@ | |||||
| #include <faust/gui/ValueConverter.h> | #include <faust/gui/ValueConverter.h> | ||||
| #include <iostream> | #include <iostream> | ||||
| #include <memory> | |||||
| using namespace std; | |||||
| #define kBufferSize 64 | #define kBufferSize 64 | ||||
| @@ -37,87 +40,42 @@ extern rack::Plugin* pluginInstance; | |||||
| // UI handler for switches, knobs and leds | // UI handler for switches, knobs and leds | ||||
| struct RackUI : public GenericUI | struct RackUI : public GenericUI | ||||
| { | { | ||||
| // 0|1 switches | |||||
| FAUSTFLOAT* fSwitches[NUM_ROWS]; | |||||
| // Knobs with [0..1] <==> [min..max] mapping and medata 'scale' handling | |||||
| ConverterZoneControl* fKnobs[NUM_ROWS]; | |||||
| // Leds | |||||
| FAUSTFLOAT* fLedRed[NUM_ROWS]; | |||||
| FAUSTFLOAT* fLedGreen[NUM_ROWS]; | |||||
| FAUSTFLOAT* fLedBlue[NUM_ROWS]; | |||||
| typedef function<void(ProcessBlock* block)> updateFunction; | |||||
| // Switch Leds | |||||
| FAUSTFLOAT* fSwitchRed[NUM_ROWS]; | |||||
| FAUSTFLOAT* fSwitchGreen[NUM_ROWS]; | |||||
| FAUSTFLOAT* fSwitchBlue[NUM_ROWS]; | |||||
| vector<ConverterZoneControl*> fConverters; | |||||
| vector<updateFunction> fUpdateFunIn; | |||||
| vector<updateFunction> fUpdateFunOut; | |||||
| string fKey, fValue, fScale; | |||||
| std::string fKey, fValue, fScale; | |||||
| void addItem(FAUSTFLOAT* table[NUM_ROWS], FAUSTFLOAT* zone, const std::string& value) | |||||
| int getIndex(const string& value) | |||||
| { | { | ||||
| try { | try { | ||||
| int index = std::stoi(value); | |||||
| int index = stoi(value); | |||||
| if (index >= 0 && index <= NUM_ROWS) { | if (index >= 0 && index <= NUM_ROWS) { | ||||
| table[index-1] = zone; | |||||
| return index; | |||||
| } else { | } else { | ||||
| std::cerr << "ERROR : incorrect '" << index << "' value !\n"; | |||||
| } | |||||
| } catch (std::invalid_argument& e) { | |||||
| std::cerr << "ERROR : " << e.what() << std::endl; | |||||
| } | |||||
| fValue = fKey = fScale = ""; | |||||
| } | |||||
| void addItemConverter(ConverterZoneControl* table[NUM_ROWS], FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max, const std::string& value) | |||||
| { | |||||
| try { | |||||
| int index = std::stoi(value); | |||||
| if (index >= 0 && index <= NUM_ROWS) { | |||||
| // Select appropriate converter according to scale mode | |||||
| if (fScale == "log") { | |||||
| table[index-1] = new ConverterZoneControl(zone, new LogValueConverter(0., 1., min, max)); | |||||
| } else if (fScale == "exp") { | |||||
| table[index-1] = new ConverterZoneControl(zone, new ExpValueConverter(0., 1., min, max)); | |||||
| } else { | |||||
| table[index-1] = new ConverterZoneControl(zone, new LinearValueConverter(0., 1., min, max)); | |||||
| } | |||||
| } else { | |||||
| std::cerr << "ERROR : incorrect '" << index << "' value !\n"; | |||||
| cerr << "ERROR : incorrect '" << index << "' value !\n"; | |||||
| return -1; | |||||
| } | } | ||||
| } catch (std::invalid_argument& e) { | |||||
| std::cerr << "ERROR : " << e.what() << std::endl; | |||||
| } | |||||
| fValue = fKey = fScale = ""; | |||||
| } | |||||
| RackUI() | |||||
| { | |||||
| fScale = "lin"; | |||||
| for (int i = 0; i < NUM_ROWS; i++) { | |||||
| fSwitches[i] = nullptr; | |||||
| fKnobs[i] = nullptr; | |||||
| fLedRed[i] = nullptr; | |||||
| fLedGreen[i] = nullptr; | |||||
| fLedBlue[i] = nullptr; | |||||
| fSwitchRed[i] = nullptr; | |||||
| fSwitchGreen[i] = nullptr; | |||||
| fSwitchBlue[i] = nullptr; | |||||
| } catch (invalid_argument& e) { | |||||
| cerr << "ERROR : " << e.what() << endl; | |||||
| return -1; | |||||
| } | } | ||||
| } | } | ||||
| RackUI():fScale("lin") | |||||
| {} | |||||
| virtual ~RackUI() | virtual ~RackUI() | ||||
| { | { | ||||
| for (int i = 0; i < NUM_ROWS; i++) { | |||||
| delete fKnobs[i]; | |||||
| } | |||||
| for (auto& it : fConverters) delete it; | |||||
| } | } | ||||
| void addButton(const char* label, FAUSTFLOAT* zone) | void addButton(const char* label, FAUSTFLOAT* zone) | ||||
| { | { | ||||
| if (fKey == "switch") { | |||||
| addItem(fSwitches, zone, fValue); | |||||
| int index = getIndex(fValue); | |||||
| if (fKey == "switch" && (index != -1)) { | |||||
| fUpdateFunIn.push_back([=] (ProcessBlock* block) { *zone = block->switches[index-1]; }); | |||||
| } | } | ||||
| } | } | ||||
| @@ -129,27 +87,39 @@ struct RackUI : public GenericUI | |||||
| { | { | ||||
| addNumEntry(label, zone, init, min, max, step); | addNumEntry(label, zone, init, min, max, step); | ||||
| } | } | ||||
| void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) | void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) | ||||
| { | { | ||||
| if (fKey == "knob") { | |||||
| addItemConverter(fKnobs, zone, min, max, fValue); | |||||
| int index = getIndex(fValue); | |||||
| if (fKey == "knob" && (index != -1)) { | |||||
| ConverterZoneControl* converter; | |||||
| if (fScale == "log") { | |||||
| converter = new ConverterZoneControl(zone, new LogValueConverter(0., 1., min, max)); | |||||
| } else if (fScale == "exp") { | |||||
| converter = new ConverterZoneControl(zone, new ExpValueConverter(0., 1., min, max)); | |||||
| } else { | |||||
| converter = new ConverterZoneControl(zone, new LinearValueConverter(0., 1., min, max)); | |||||
| } | |||||
| fUpdateFunIn.push_back([=] (ProcessBlock* block) { converter->update(block->knobs[index-1]); }); | |||||
| fConverters.push_back(converter); | |||||
| } | } | ||||
| } | } | ||||
| void addBarGraph(FAUSTFLOAT* zone) | void addBarGraph(FAUSTFLOAT* zone) | ||||
| { | { | ||||
| if (fKey == "led_red") { | |||||
| addItem(fLedRed, zone, fValue); | |||||
| } else if (fKey == "led_green") { | |||||
| addItem(fLedGreen, zone, fValue); | |||||
| } else if (fKey == "led_blue") { | |||||
| addItem(fLedBlue, zone, fValue); | |||||
| } else if (fKey == "switch_red") { | |||||
| addItem(fSwitchRed, zone, fValue); | |||||
| } else if (fKey == "switch_green") { | |||||
| addItem(fSwitchGreen, zone, fValue); | |||||
| } else if (fKey == "switch_blue") { | |||||
| addItem(fSwitchBlue, zone, fValue); | |||||
| int index = getIndex(fValue); | |||||
| if ((fKey == "led_red") && (index != -1)) { | |||||
| fUpdateFunOut.push_back([=] (ProcessBlock* block) { block->lights[index-1][0] = *zone; }); | |||||
| } else if ((fKey == "led_green") && (index != -1)) { | |||||
| fUpdateFunOut.push_back([=] (ProcessBlock* block) { block->lights[index-1][1] = *zone; }); | |||||
| } else if ((fKey == "led_blue") && (index != -1)) { | |||||
| fUpdateFunOut.push_back([=] (ProcessBlock* block) { block->lights[index-1][2] = *zone; }); | |||||
| } else if ((fKey == "switch_red") && (index != -1)) { | |||||
| fUpdateFunOut.push_back([=] (ProcessBlock* block) { block->switchLights[index-1][0] = *zone; }); | |||||
| } else if ((fKey == "switch_green") && (index != -1)) { | |||||
| fUpdateFunOut.push_back([=] (ProcessBlock* block) { block->switchLights[index-1][1] = *zone; }); | |||||
| } else if ((fKey == "switch_blue") && (index != -1)) { | |||||
| fUpdateFunOut.push_back([=] (ProcessBlock* block) { block->switchLights[index-1][2] = *zone; }); | |||||
| } | } | ||||
| } | } | ||||
| @@ -164,17 +134,11 @@ struct RackUI : public GenericUI | |||||
| void declare(FAUSTFLOAT* zone, const char* key, const char* val) | void declare(FAUSTFLOAT* zone, const char* key, const char* val) | ||||
| { | { | ||||
| if ((std::string(key) == "switch") | |||||
| || (std::string(key) == "knob") | |||||
| || (std::string(key) == "led_red") | |||||
| || (std::string(key) == "led_green") | |||||
| || (std::string(key) == "led_blue") | |||||
| || (std::string(key) == "switch_red") | |||||
| || (std::string(key) == "switch_green") | |||||
| || (std::string(key) == "switch_blue")) { | |||||
| static vector<string> keys = {"switch", "knob", "led_red", "led_green", "led_blue", "switch_red", "switch_green", "switch_blue"}; | |||||
| if (find(keys.begin(), keys.end(), key) != keys.end()) { | |||||
| fKey = key; | fKey = key; | ||||
| fValue = val; | fValue = val; | ||||
| } else if (std::string(key) == "scale") { | |||||
| } else if (string(key) == "scale") { | |||||
| fScale = val; | fScale = val; | ||||
| } | } | ||||
| } | } | ||||
| @@ -202,19 +166,19 @@ class FaustEngine : public ScriptEngine { | |||||
| deleteDSPFactory(fDSPFactory); | deleteDSPFactory(fDSPFactory); | ||||
| } | } | ||||
| std::string getEngineName() override | |||||
| string getEngineName() override | |||||
| { | { | ||||
| return "Faust"; | return "Faust"; | ||||
| } | } | ||||
| int run(const std::string& path, const std::string& script) override | |||||
| int run(const string& path, const string& script) override | |||||
| { | { | ||||
| #if defined ARCH_MAC | #if defined ARCH_MAC | ||||
| std::string temp_cache = "/private/var/tmp/VCV_" + generateSHA1(script); | |||||
| string temp_cache = "/private/var/tmp/VCV_" + generateSHA1(script); | |||||
| #else | #else | ||||
| std::string temp_cache = "" + generateSHA1(script); | |||||
| string temp_cache = "" + generateSHA1(script); | |||||
| #endif | #endif | ||||
| std::string error_msg; | |||||
| string error_msg; | |||||
| // Try to load the machine code cache | // Try to load the machine code cache | ||||
| fDSPFactory = readDSPFactoryFromMachineFile(temp_cache, "", error_msg); | fDSPFactory = readDSPFactoryFromMachineFile(temp_cache, "", error_msg); | ||||
| @@ -250,12 +214,12 @@ class FaustEngine : public ScriptEngine { | |||||
| // Prepare inputs/outputs | // Prepare inputs/outputs | ||||
| if (fDSP->getNumInputs() > NUM_ROWS) { | if (fDSP->getNumInputs() > NUM_ROWS) { | ||||
| display("ERROR: DSP has " + std::to_string(fDSP->getNumInputs()) + " inputs !"); | |||||
| display("ERROR: DSP has " + to_string(fDSP->getNumInputs()) + " inputs !"); | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| if (fDSP->getNumOutputs() > NUM_ROWS) { | if (fDSP->getNumOutputs() > NUM_ROWS) { | ||||
| display("ERROR: DSP has " + std::to_string(fDSP->getNumInputs()) + " outputs !"); | |||||
| display("ERROR: DSP has " + to_string(fDSP->getNumInputs()) + " outputs !"); | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| @@ -293,39 +257,13 @@ class FaustEngine : public ScriptEngine { | |||||
| } | } | ||||
| // Update inputs controllers | // Update inputs controllers | ||||
| for (int i = 0; i < NUM_ROWS; i++) { | |||||
| if (fRackUI.fSwitches[i]) { | |||||
| *fRackUI.fSwitches[i] = block->switches[i]; | |||||
| } | |||||
| if (fRackUI.fKnobs[i]) { | |||||
| fRackUI.fKnobs[i]->update(block->knobs[i]); | |||||
| } | |||||
| } | |||||
| for (auto& it : fRackUI.fUpdateFunIn) it(block); | |||||
| // Compute samples | // Compute samples | ||||
| fDSP->compute(kBufferSize, fInputs, fOutputs); | |||||
| fDSP->compute(block->bufferSize, fInputs, fOutputs); | |||||
| // Update output controllers | // Update output controllers | ||||
| for (int i = 0; i < NUM_ROWS; i++) { | |||||
| if (fRackUI.fLedRed[i]) { | |||||
| block->lights[i][0] = *fRackUI.fLedRed[i]; | |||||
| } | |||||
| if (fRackUI.fLedGreen[i]) { | |||||
| block->lights[i][1] = *fRackUI.fLedGreen[i]; | |||||
| } | |||||
| if (fRackUI.fLedBlue[i]) { | |||||
| block->lights[i][2] = *fRackUI.fLedBlue[i]; | |||||
| } | |||||
| if (fRackUI.fSwitchRed[i]) { | |||||
| block->switchLights[i][0] = *fRackUI.fSwitchRed[i]; | |||||
| } | |||||
| if (fRackUI.fSwitchGreen[i]) { | |||||
| block->switchLights[i][1] = *fRackUI.fSwitchGreen[i]; | |||||
| } | |||||
| if (fRackUI.fSwitchBlue[i]) { | |||||
| block->switchLights[i][2] = *fRackUI.fSwitchBlue[i]; | |||||
| } | |||||
| } | |||||
| for (auto& it : fRackUI.fUpdateFunOut) it(block); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -336,7 +274,7 @@ class FaustEngine : public ScriptEngine { | |||||
| FAUSTFLOAT** fInputs; | FAUSTFLOAT** fInputs; | ||||
| FAUSTFLOAT** fOutputs; | FAUSTFLOAT** fOutputs; | ||||
| RackUI fRackUI; | RackUI fRackUI; | ||||
| std::string fDSPLibraries; | |||||
| string fDSPLibraries; | |||||
| }; | }; | ||||
| __attribute__((constructor(1000))) | __attribute__((constructor(1000))) | ||||