| @@ -30,6 +30,7 @@ struct Engine { | |||
| void removeModule(Module *module); | |||
| void resetModule(Module *module); | |||
| void randomizeModule(Module *module); | |||
| void bypassModule(Module *module, bool bypass); | |||
| /** Does not transfer pointer ownership */ | |||
| void addCable(Cable *cable); | |||
| void removeCable(Cable *cable); | |||
| @@ -37,16 +37,16 @@ struct Port { | |||
| return voltages[channel]; | |||
| } | |||
| /** Returns the voltage if a cable is plugged in, otherwise returns the given normal voltage */ | |||
| float getNormalVoltage(float normalVoltage, int channel = 0) { | |||
| return isConnected() ? getVoltage(channel) : normalVoltage; | |||
| } | |||
| /** Returns the voltage if there are enough channels, otherwise returns the first voltage (channel 0) */ | |||
| /** Returns the voltage if `channel` is a valid channel, otherwise returns the first voltage (channel 0) */ | |||
| float getPolyVoltage(int channel) { | |||
| return (channel < channels) ? getVoltage(channel) : getVoltage(0); | |||
| } | |||
| /** Returns the voltage if a cable is connected, otherwise returns the given normal voltage */ | |||
| float getNormalVoltage(float normalVoltage, int channel = 0) { | |||
| return isConnected() ? getVoltage(channel) : normalVoltage; | |||
| } | |||
| float getNormalPolyVoltage(float normalVoltage, int channel) { | |||
| return isConnected() ? getPolyVoltage(channel) : normalVoltage; | |||
| } | |||
| @@ -221,7 +221,7 @@ void CableWidget::draw(NVGcontext *vg) { | |||
| } | |||
| float thickness = 5; | |||
| if (cable->outputModule) { | |||
| if (isComplete()) { | |||
| Output *output = &cable->outputModule->outputs[cable->outputId]; | |||
| if (output->channels > 1) { | |||
| // Increase thickness if output port is polyphonic | |||
| @@ -246,7 +246,7 @@ void CableWidget::drawPlugs(NVGcontext *vg) { | |||
| // Draw plug if the cable is on top, or if the cable is incomplete | |||
| if (!isComplete() || app()->scene->rackWidget->getTopCable(outputPort) == this) { | |||
| drawPlug(vg, outputPos, color); | |||
| if (outputPort) { | |||
| if (isComplete()) { | |||
| // Draw plug light | |||
| nvgSave(vg); | |||
| nvgTranslate(vg, outputPos.x - 4, outputPos.y - 4); | |||
| @@ -257,7 +257,7 @@ void CableWidget::drawPlugs(NVGcontext *vg) { | |||
| if (!isComplete() || app()->scene->rackWidget->getTopCable(inputPort) == this) { | |||
| drawPlug(vg, inputPos, color); | |||
| if (inputPort) { | |||
| if (isComplete()) { | |||
| nvgSave(vg); | |||
| nvgTranslate(vg, inputPos.x - 4, inputPos.y - 4); | |||
| inputPort->plugLight->draw(vg); | |||
| @@ -117,22 +117,7 @@ static void Engine_step(Engine *engine) { | |||
| // Iterate modules | |||
| for (Module *module : engine->modules) { | |||
| if (module->bypass) { | |||
| // Bypass module | |||
| for (Output &output : module->outputs) { | |||
| // This also zeros all voltages | |||
| output.setChannels(0); | |||
| } | |||
| if (settings::powerMeter) { | |||
| module->cpuTime = 0.f; | |||
| } | |||
| } | |||
| else { | |||
| // Set all outputs to 1 channel so that modules are forced to specify 0 or >2 channels every frame | |||
| for (Output &output : module->outputs) { | |||
| // Don't use Port::setChannels() so we maintain all previous voltages | |||
| output.channels = 1; | |||
| } | |||
| if (!module->bypass) { | |||
| // Step module | |||
| if (settings::powerMeter) { | |||
| auto startTime = std::chrono::high_resolution_clock::now(); | |||
| @@ -263,6 +248,7 @@ void Engine::resetModule(Module *module) { | |||
| assert(module); | |||
| VIPLock vipLock(internal->vipMutex); | |||
| std::lock_guard<std::mutex> lock(internal->mutex); | |||
| module->reset(); | |||
| } | |||
| @@ -270,9 +256,31 @@ void Engine::randomizeModule(Module *module) { | |||
| assert(module); | |||
| VIPLock vipLock(internal->vipMutex); | |||
| std::lock_guard<std::mutex> lock(internal->mutex); | |||
| module->randomize(); | |||
| } | |||
| void Engine::bypassModule(Module *module, bool bypass) { | |||
| assert(module); | |||
| VIPLock vipLock(internal->vipMutex); | |||
| std::lock_guard<std::mutex> lock(internal->mutex); | |||
| if (bypass) { | |||
| for (Output &output : module->outputs) { | |||
| // This also zeros all voltages | |||
| output.setChannels(0); | |||
| } | |||
| module->cpuTime = 0.f; | |||
| } | |||
| else { | |||
| // Set all outputs to 1 channel | |||
| for (Output &output : module->outputs) { | |||
| // Don't use Port::setChannels() so we maintain all previous voltages | |||
| output.channels = 1; | |||
| } | |||
| } | |||
| module->bypass = bypass; | |||
| } | |||
| static void Engine_updateConnected(Engine *engine) { | |||
| // Set everything to unconnected | |||
| for (Module *module : engine->modules) { | |||
| @@ -2,6 +2,7 @@ | |||
| #include "app.hpp" | |||
| #include "app/Scene.hpp" | |||
| #include "engine/Cable.hpp" | |||
| #include "engine/Engine.hpp" | |||
| namespace rack { | |||
| @@ -80,13 +81,13 @@ void ModuleMove::redo() { | |||
| void ModuleBypass::undo() { | |||
| ModuleWidget *mw = app()->scene->rackWidget->getModule(moduleId); | |||
| assert(mw); | |||
| mw->module->bypass = !bypass; | |||
| app()->engine->bypassModule(mw->module, !bypass); | |||
| } | |||
| void ModuleBypass::redo() { | |||
| ModuleWidget *mw = app()->scene->rackWidget->getModule(moduleId); | |||
| assert(mw); | |||
| mw->module->bypass = bypass; | |||
| app()->engine->bypassModule(mw->module, bypass); | |||
| } | |||