| @@ -11,7 +11,7 @@ static const int PORT_MAX_CHANNELS = 16; | |||
| struct Port { | |||
| /** Voltage of the port */ | |||
| /** Voltage of the port. */ | |||
| union { | |||
| /** Unstable API. Use set/getVoltage() instead. */ | |||
| float voltages[PORT_MAX_CHANNELS] = {}; | |||
| @@ -25,7 +25,7 @@ struct Port { | |||
| uint8_t channels = 1; | |||
| /** Unstable API. Use isConnected() instead. */ | |||
| bool active; | |||
| /** For rendering plug lights on cables | |||
| /** For rendering plug lights on cables. | |||
| Green for positive, red for negative, and blue for polyphonic | |||
| */ | |||
| Light plugLights[3]; | |||
| @@ -34,16 +34,19 @@ struct Port { | |||
| 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) { | |||
| 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) { | |||
| 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) { | |||
| 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) { | |||
| float opacity = settings::cableOpacity; | |||
| 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; | |||
| 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; | |||
| } | |||
| // 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(); | |||
| @@ -38,16 +38,11 @@ void PortWidget::step() { | |||
| return; | |||
| 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); | |||
| } | |||
| @@ -10,8 +10,8 @@ void Cable::step() { | |||
| Input *input = &inputModule->inputs[inputId]; | |||
| // Match number of polyphonic channels to output port | |||
| 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]; | |||
| } | |||
| } | |||
| @@ -61,12 +61,12 @@ struct Barrier { | |||
| return; | |||
| std::unique_lock<std::mutex> lock(mutex); | |||
| count++; | |||
| if (count >= total) { | |||
| count = 0; | |||
| cv.notify_all(); | |||
| if (count < total) { | |||
| cv.wait(lock); | |||
| } | |||
| else { | |||
| cv.wait(lock); | |||
| count = 0; | |||
| cv.notify_all(); | |||
| } | |||
| } | |||
| }; | |||
| @@ -82,11 +82,11 @@ struct SpinBarrier { | |||
| void wait() { | |||
| count++; | |||
| if (count >= total) { | |||
| count = 0; | |||
| if (count < total) { | |||
| while (count > 0) {} | |||
| } | |||
| else { | |||
| while (count > 0) {} | |||
| count = 0; | |||
| } | |||
| } | |||
| }; | |||
| @@ -159,6 +159,9 @@ Engine::Engine() { | |||
| internal->sampleRate = sampleRate; | |||
| internal->sampleTime = 1 / sampleRate; | |||
| internal->sampleRateRequested = sampleRate; | |||
| internal->engineBarrier.total = 1; | |||
| internal->workerBarrier.total = 1; | |||
| } | |||
| Engine::~Engine() { | |||
| @@ -209,6 +212,11 @@ static void Engine_stepModules(Engine *engine, int id) { | |||
| for (int i = id; i < modulesLen; i += threadCount) { | |||
| Module *module = internal->modules[i]; | |||
| if (!module->bypass) { | |||
| for (Output &output : module->outputs) { | |||
| // Reset output channels without clearing channel voltages | |||
| output.channels = 1; | |||
| } | |||
| // Step module | |||
| if (settings::powerMeter) { | |||
| auto startTime = std::chrono::high_resolution_clock::now(); | |||
| @@ -225,6 +233,11 @@ static void Engine_stepModules(Engine *engine, int id) { | |||
| module->step(); | |||
| } | |||
| } | |||
| else { | |||
| for (Output &output : module->outputs) { | |||
| output.setChannels(0); | |||
| } | |||
| } | |||
| // Iterate ports and step plug lights | |||
| for (Input &input : module->inputs) { | |||