| @@ -24,6 +24,9 @@ namespace engine { | |||||
| /** DSP processor instance for your module. */ | /** DSP processor instance for your module. */ | ||||
| struct Module { | struct Module { | ||||
| struct Internal; | |||||
| Internal* internal; | |||||
| plugin::Model* model = NULL; | plugin::Model* model = NULL; | ||||
| /** Unique ID for referring to the module in the engine. | /** Unique ID for referring to the module in the engine. | ||||
| Assigned when added to the engine. | Assigned when added to the engine. | ||||
| @@ -81,12 +84,6 @@ struct Module { | |||||
| }; | }; | ||||
| std::vector<BypassRoute> bypassRoutes; | std::vector<BypassRoute> bypassRoutes; | ||||
| /** Seconds spent in the process() method, with exponential smoothing. | |||||
| Only written when CPU timing is enabled, since time measurement is expensive. | |||||
| */ | |||||
| float cpuTime = 0.f; | |||||
| bool bypassed = false; | |||||
| /** Constructs a Module with no params, inputs, outputs, and lights. */ | /** Constructs a Module with no params, inputs, outputs, and lights. */ | ||||
| Module(); | Module(); | ||||
| /** Use config() instead. */ | /** Use config() instead. */ | ||||
| @@ -276,6 +273,10 @@ struct Module { | |||||
| virtual void onRandomize() {} | virtual void onRandomize() {} | ||||
| /** DEPRECATED. Override `onSampleRateChange(e)` instead. */ | /** DEPRECATED. Override `onSampleRateChange(e)` instead. */ | ||||
| virtual void onSampleRateChange() {} | virtual void onSampleRateChange() {} | ||||
| // private | |||||
| float& cpuTime(); | |||||
| bool& bypassed(); | |||||
| }; | }; | ||||
| @@ -299,7 +299,7 @@ ModuleWidget::~ModuleWidget() { | |||||
| void ModuleWidget::draw(const DrawArgs& args) { | void ModuleWidget::draw(const DrawArgs& args) { | ||||
| nvgScissor(args.vg, RECT_ARGS(args.clipBox)); | nvgScissor(args.vg, RECT_ARGS(args.clipBox)); | ||||
| if (module && module->bypassed) { | |||||
| if (module && module->bypassed()) { | |||||
| nvgGlobalAlpha(args.vg, 0.33); | nvgGlobalAlpha(args.vg, 0.33); | ||||
| } | } | ||||
| @@ -314,12 +314,12 @@ void ModuleWidget::draw(const DrawArgs& args) { | |||||
| nvgFillColor(args.vg, nvgRGBAf(0, 0, 0, 0.75)); | nvgFillColor(args.vg, nvgRGBAf(0, 0, 0, 0.75)); | ||||
| nvgFill(args.vg); | nvgFill(args.vg); | ||||
| float percent = module->cpuTime * APP->engine->getSampleRate() * 100; | |||||
| float microseconds = module->cpuTime * 1e6f; | |||||
| float percent = module->cpuTime() * APP->engine->getSampleRate() * 100; | |||||
| float microseconds = module->cpuTime() * 1e6f; | |||||
| std::string cpuText = string::f("%.1f%%\n%.2f μs", percent, microseconds); | std::string cpuText = string::f("%.1f%%\n%.2f μs", percent, microseconds); | ||||
| bndLabel(args.vg, 2.0, box.size.y - 34.0, INFINITY, INFINITY, -1, cpuText.c_str()); | bndLabel(args.vg, 2.0, box.size.y - 34.0, INFINITY, INFINITY, -1, cpuText.c_str()); | ||||
| float p = math::clamp(module->cpuTime / APP->engine->getSampleTime(), 0.f, 1.f); | |||||
| float p = math::clamp(module->cpuTime() / APP->engine->getSampleTime(), 0.f, 1.f); | |||||
| nvgBeginPath(args.vg); | nvgBeginPath(args.vg); | ||||
| nvgRect(args.vg, | nvgRect(args.vg, | ||||
| 0, (1.f - p) * box.size.y, | 0, (1.f - p) * box.size.y, | ||||
| @@ -835,12 +835,12 @@ void ModuleWidget::cloneAction() { | |||||
| void ModuleWidget::bypassAction() { | void ModuleWidget::bypassAction() { | ||||
| assert(module); | assert(module); | ||||
| APP->engine->bypassModule(module, !module->bypassed); | |||||
| APP->engine->bypassModule(module, !module->bypassed()); | |||||
| // history::ModuleBypass | // history::ModuleBypass | ||||
| history::ModuleBypass* h = new history::ModuleBypass; | history::ModuleBypass* h = new history::ModuleBypass; | ||||
| h->moduleId = module->id; | h->moduleId = module->id; | ||||
| h->bypassed = module->bypassed; | |||||
| h->bypassed = module->bypassed(); | |||||
| APP->history->push(h); | APP->history->push(h); | ||||
| } | } | ||||
| @@ -908,7 +908,7 @@ void ModuleWidget::createContextMenu() { | |||||
| ModuleBypassItem* bypassItem = new ModuleBypassItem; | ModuleBypassItem* bypassItem = new ModuleBypassItem; | ||||
| bypassItem->text = "Bypass"; | bypassItem->text = "Bypass"; | ||||
| bypassItem->rightText = RACK_MOD_CTRL_NAME "+E"; | bypassItem->rightText = RACK_MOD_CTRL_NAME "+E"; | ||||
| if (module && module->bypassed) | |||||
| if (module && module->bypassed()) | |||||
| bypassItem->rightText = CHECKMARK_STRING " " + bypassItem->rightText; | bypassItem->rightText = CHECKMARK_STRING " " + bypassItem->rightText; | ||||
| bypassItem->moduleWidget = this; | bypassItem->moduleWidget = this; | ||||
| menu->addChild(bypassItem); | menu->addChild(bypassItem); | ||||
| @@ -229,7 +229,7 @@ static void Engine_stepModulesWorker(Engine* that, int threadId) { | |||||
| } | } | ||||
| // Step module | // Step module | ||||
| if (!module->bypassed) | |||||
| if (!module->bypassed()) | |||||
| module->process(processArgs); | module->process(processArgs); | ||||
| else | else | ||||
| module->processBypass(processArgs); | module->processBypass(processArgs); | ||||
| @@ -241,7 +241,7 @@ static void Engine_stepModulesWorker(Engine* that, int threadId) { | |||||
| // Smooth CPU time | // Smooth CPU time | ||||
| const float cpuTau = 2.f /* seconds */; | const float cpuTau = 2.f /* seconds */; | ||||
| module->cpuTime += (duration - module->cpuTime) * processArgs.sampleTime / cpuTau; | |||||
| module->cpuTime() += (duration - module->cpuTime()) * processArgs.sampleTime / cpuTau; | |||||
| } | } | ||||
| // Iterate ports to step plug lights | // Iterate ports to step plug lights | ||||
| @@ -629,14 +629,14 @@ void Engine::randomizeModule(Module* module) { | |||||
| void Engine::bypassModule(Module* module, bool bypassed) { | void Engine::bypassModule(Module* module, bool bypassed) { | ||||
| std::lock_guard<std::recursive_mutex> lock(internal->mutex); | std::lock_guard<std::recursive_mutex> lock(internal->mutex); | ||||
| assert(module); | assert(module); | ||||
| if (module->bypassed == bypassed) | |||||
| if (module->bypassed() == bypassed) | |||||
| return; | return; | ||||
| // Clear outputs and set to 1 channel | // Clear outputs and set to 1 channel | ||||
| for (Output& output : module->outputs) { | for (Output& output : module->outputs) { | ||||
| // This zeros all voltages, but the channel is set to 1 if connected | // This zeros all voltages, but the channel is set to 1 if connected | ||||
| output.setChannels(0); | output.setChannels(0); | ||||
| } | } | ||||
| module->bypassed = bypassed; | |||||
| module->bypassed() = bypassed; | |||||
| // Trigger event | // Trigger event | ||||
| if (bypassed) { | if (bypassed) { | ||||
| Module::BypassEvent eBypass; | Module::BypassEvent eBypass; | ||||
| @@ -6,7 +6,16 @@ namespace rack { | |||||
| namespace engine { | namespace engine { | ||||
| struct Module::Internal { | |||||
| /** Seconds spent in the process() method, with exponential smoothing. | |||||
| Only written when CPU timing is enabled, since time measurement is expensive. | |||||
| */ | |||||
| float cpuTime = 0.f; | |||||
| bool bypassed = false; | |||||
| }; | |||||
| Module::Module() { | Module::Module() { | ||||
| internal = new Internal; | |||||
| } | } | ||||
| Module::~Module() { | Module::~Module() { | ||||
| @@ -22,6 +31,7 @@ Module::~Module() { | |||||
| if (outputInfo) | if (outputInfo) | ||||
| delete outputInfo; | delete outputInfo; | ||||
| } | } | ||||
| delete internal; | |||||
| } | } | ||||
| void Module::config(int numParams, int numInputs, int numOutputs, int numLights) { | void Module::config(int numParams, int numInputs, int numOutputs, int numLights) { | ||||
| @@ -92,8 +102,8 @@ json_t* Module::toJson() { | |||||
| json_object_set_new(rootJ, "params", paramsJ); | json_object_set_new(rootJ, "params", paramsJ); | ||||
| // bypassed | // bypassed | ||||
| if (bypassed) | |||||
| json_object_set_new(rootJ, "bypassed", json_boolean(bypassed)); | |||||
| if (internal->bypassed) | |||||
| json_object_set_new(rootJ, "bypassed", json_boolean(true)); | |||||
| // leftModuleId | // leftModuleId | ||||
| if (leftExpander.moduleId >= 0) | if (leftExpander.moduleId >= 0) | ||||
| @@ -192,7 +202,7 @@ void Module::fromJson(json_t* rootJ) { | |||||
| if (!bypassedJ) | if (!bypassedJ) | ||||
| bypassedJ = json_object_get(rootJ, "disabled"); | bypassedJ = json_object_get(rootJ, "disabled"); | ||||
| if (bypassedJ) | if (bypassedJ) | ||||
| bypassed = json_boolean_value(bypassedJ); | |||||
| internal->bypassed = json_boolean_value(bypassedJ); | |||||
| // These do not need to be deserialized, since the module positions will set them correctly when added to the rack. | // These do not need to be deserialized, since the module positions will set them correctly when added to the rack. | ||||
| // // leftModuleId | // // leftModuleId | ||||
| @@ -236,5 +246,15 @@ void Module::onRandomize(const RandomizeEvent& e) { | |||||
| } | } | ||||
| float& Module::cpuTime() { | |||||
| return internal->cpuTime; | |||||
| } | |||||
| bool& Module::bypassed() { | |||||
| return internal->bypassed; | |||||
| } | |||||
| } // namespace engine | } // namespace engine | ||||
| } // namespace rack | } // namespace rack | ||||