| @@ -11,7 +11,7 @@ static const int PORT_MAX_CHANNELS = 16; | |||||
| struct Port { | struct Port { | ||||
| /** Voltage of the port */ | |||||
| /** Voltage of the port. */ | |||||
| union { | union { | ||||
| /** Unstable API. Use set/getVoltage() instead. */ | /** Unstable API. Use set/getVoltage() instead. */ | ||||
| float voltages[PORT_MAX_CHANNELS] = {}; | float voltages[PORT_MAX_CHANNELS] = {}; | ||||
| @@ -25,7 +25,7 @@ struct Port { | |||||
| uint8_t channels = 1; | uint8_t channels = 1; | ||||
| /** Unstable API. Use isConnected() instead. */ | /** Unstable API. Use isConnected() instead. */ | ||||
| bool active; | bool active; | ||||
| /** For rendering plug lights on cables | |||||
| /** For rendering plug lights on cables. | |||||
| Green for positive, red for negative, and blue for polyphonic | Green for positive, red for negative, and blue for polyphonic | ||||
| */ | */ | ||||
| Light plugLights[3]; | Light plugLights[3]; | ||||
| @@ -34,16 +34,19 @@ struct Port { | |||||
| voltages[channel] = voltage; | voltages[channel] = voltage; | ||||
| } | } | ||||
| /** Returns the voltage of the given channel. | |||||
| Because of proper bookkeeping, all channels higher than the input port's number of channels should be 0V. | |||||
| */ | |||||
| float getVoltage(int channel = 0) { | float getVoltage(int channel = 0) { | ||||
| return voltages[channel]; | return voltages[channel]; | ||||
| } | } | ||||
| /** Returns the voltage if `channel` is a valid channel, otherwise returns the first voltage (channel 0) */ | |||||
| /** Returns the given channel's voltage if the port is polyphonic, otherwise returns the first voltage (channel 0). */ | |||||
| float getPolyVoltage(int channel) { | float getPolyVoltage(int channel) { | ||||
| return (channel < channels) ? getVoltage(channel) : getVoltage(0); | |||||
| return (channels == 1) ? getVoltage(channel) : getVoltage(0); | |||||
| } | } | ||||
| /** Returns the voltage if a cable is connected, otherwise returns the given normal voltage */ | |||||
| /** Returns the voltage if a cable is connected, otherwise returns the given normal voltage. */ | |||||
| float getNormalVoltage(float normalVoltage, int channel = 0) { | float getNormalVoltage(float normalVoltage, int channel = 0) { | ||||
| return isConnected() ? getVoltage(channel) : normalVoltage; | return isConnected() ? getVoltage(channel) : normalVoltage; | ||||
| } | } | ||||
| @@ -209,28 +209,27 @@ void CableWidget::fromJson(json_t *rootJ, const std::map<int, ModuleWidget*> &mo | |||||
| void CableWidget::draw(const widget::DrawContext &ctx) { | void CableWidget::draw(const widget::DrawContext &ctx) { | ||||
| float opacity = settings::cableOpacity; | float opacity = settings::cableOpacity; | ||||
| float tension = settings::cableTension; | float tension = settings::cableTension; | ||||
| if (!isComplete()) { | |||||
| // Draw opaque if the cable is incomplete | |||||
| opacity = 1.0; | |||||
| } | |||||
| else { | |||||
| // Draw opaque if mouse is hovering over a connected port | |||||
| if (outputPort->hovered || inputPort->hovered) | |||||
| opacity = 1.0; | |||||
| } | |||||
| float thickness = 5; | float thickness = 5; | ||||
| if (isComplete()) { | if (isComplete()) { | ||||
| Output *output = &cable->outputModule->outputs[cable->outputId]; | |||||
| if (output->channels > 1) { | |||||
| // Increase thickness if output port is polyphonic | |||||
| Input *input = &cable->inputModule->inputs[cable->inputId]; | |||||
| // Draw opaque if mouse is hovering over a connected port | |||||
| if (input->channels > 1) { | |||||
| // Increase thickness if input port is polyphonic | |||||
| thickness = 8; | thickness = 8; | ||||
| } | } | ||||
| // else if (output->channels == 0) { | |||||
| // // Draw translucent cable if not active (i.e. 0 channels) | |||||
| // opacity *= 0.5; | |||||
| // } | |||||
| if (outputPort->hovered || inputPort->hovered) { | |||||
| opacity = 1.0; | |||||
| } | |||||
| else if (input->channels == 0) { | |||||
| // Draw translucent cable if not active (i.e. 0 channels) | |||||
| opacity *= 0.25; | |||||
| } | |||||
| } | |||||
| else { | |||||
| // Draw opaque if the cable is incomplete | |||||
| opacity = 1.0; | |||||
| } | } | ||||
| math::Vec outputPos = getOutputPos(); | math::Vec outputPos = getOutputPos(); | ||||
| @@ -38,16 +38,11 @@ void PortWidget::step() { | |||||
| return; | return; | ||||
| std::vector<float> values(3); | std::vector<float> values(3); | ||||
| // Input and Outputs are not virtual, so we can't cast to Port to make this less redundant. | |||||
| if (type == OUTPUT) { | |||||
| values[0] = module->outputs[portId].plugLights[0].getBrightness(); | |||||
| values[1] = module->outputs[portId].plugLights[1].getBrightness(); | |||||
| values[2] = module->outputs[portId].plugLights[2].getBrightness(); | |||||
| } | |||||
| else { | |||||
| values[0] = module->inputs[portId].plugLights[0].getBrightness(); | |||||
| values[1] = module->inputs[portId].plugLights[1].getBrightness(); | |||||
| values[2] = module->inputs[portId].plugLights[2].getBrightness(); | |||||
| for (int i = 0; i < 3; i++) { | |||||
| if (type == OUTPUT) | |||||
| values[i] = module->outputs[portId].plugLights[i].getBrightness(); | |||||
| else | |||||
| values[i] = module->inputs[portId].plugLights[i].getBrightness(); | |||||
| } | } | ||||
| plugLight->setBrightnesses(values); | plugLight->setBrightnesses(values); | ||||
| } | } | ||||
| @@ -10,8 +10,8 @@ void Cable::step() { | |||||
| Input *input = &inputModule->inputs[inputId]; | Input *input = &inputModule->inputs[inputId]; | ||||
| // Match number of polyphonic channels to output port | // Match number of polyphonic channels to output port | ||||
| input->channels = output->channels; | input->channels = output->channels; | ||||
| // Copy voltages from output to input | |||||
| for (int i = 0; i < output->channels; i++) { | |||||
| // Copy all voltages from output to input | |||||
| for (int i = 0; i < PORT_MAX_CHANNELS; i++) { | |||||
| input->voltages[i] = output->voltages[i]; | input->voltages[i] = output->voltages[i]; | ||||
| } | } | ||||
| } | } | ||||
| @@ -61,12 +61,12 @@ struct Barrier { | |||||
| return; | return; | ||||
| std::unique_lock<std::mutex> lock(mutex); | std::unique_lock<std::mutex> lock(mutex); | ||||
| count++; | count++; | ||||
| if (count >= total) { | |||||
| count = 0; | |||||
| cv.notify_all(); | |||||
| if (count < total) { | |||||
| cv.wait(lock); | |||||
| } | } | ||||
| else { | else { | ||||
| cv.wait(lock); | |||||
| count = 0; | |||||
| cv.notify_all(); | |||||
| } | } | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -82,11 +82,11 @@ struct SpinBarrier { | |||||
| void wait() { | void wait() { | ||||
| count++; | count++; | ||||
| if (count >= total) { | |||||
| count = 0; | |||||
| if (count < total) { | |||||
| while (count > 0) {} | |||||
| } | } | ||||
| else { | else { | ||||
| while (count > 0) {} | |||||
| count = 0; | |||||
| } | } | ||||
| } | } | ||||
| }; | }; | ||||
| @@ -159,6 +159,9 @@ Engine::Engine() { | |||||
| internal->sampleRate = sampleRate; | internal->sampleRate = sampleRate; | ||||
| internal->sampleTime = 1 / sampleRate; | internal->sampleTime = 1 / sampleRate; | ||||
| internal->sampleRateRequested = sampleRate; | internal->sampleRateRequested = sampleRate; | ||||
| internal->engineBarrier.total = 1; | |||||
| internal->workerBarrier.total = 1; | |||||
| } | } | ||||
| Engine::~Engine() { | Engine::~Engine() { | ||||
| @@ -209,6 +212,11 @@ static void Engine_stepModules(Engine *engine, int id) { | |||||
| for (int i = id; i < modulesLen; i += threadCount) { | for (int i = id; i < modulesLen; i += threadCount) { | ||||
| Module *module = internal->modules[i]; | Module *module = internal->modules[i]; | ||||
| if (!module->bypass) { | if (!module->bypass) { | ||||
| for (Output &output : module->outputs) { | |||||
| // Reset output channels without clearing channel voltages | |||||
| output.channels = 1; | |||||
| } | |||||
| // Step module | // Step module | ||||
| if (settings::powerMeter) { | if (settings::powerMeter) { | ||||
| auto startTime = std::chrono::high_resolution_clock::now(); | auto startTime = std::chrono::high_resolution_clock::now(); | ||||
| @@ -225,6 +233,11 @@ static void Engine_stepModules(Engine *engine, int id) { | |||||
| module->step(); | module->step(); | ||||
| } | } | ||||
| } | } | ||||
| else { | |||||
| for (Output &output : module->outputs) { | |||||
| output.setChannels(0); | |||||
| } | |||||
| } | |||||
| // Iterate ports and step plug lights | // Iterate ports and step plug lights | ||||
| for (Input &input : module->inputs) { | for (Input &input : module->inputs) { | ||||