Browse Source

Merge Port::channels and Port::active concept. Add third Light to plug for polyphony.

tags/v1.0.0
Andrew Belt 6 years ago
parent
commit
d35de0b6f1
9 changed files with 93 additions and 80 deletions
  1. +1
    -1
      include/engine/Input.hpp
  2. +20
    -2
      include/engine/Light.hpp
  3. +17
    -8
      include/engine/Port.hpp
  4. +1
    -1
      src/Core/MIDI_CC.cpp
  5. +6
    -2
      src/app/CableWidget.cpp
  6. +7
    -3
      src/app/ModuleLightWidget.cpp
  7. +9
    -35
      src/engine/Engine.cpp
  8. +0
    -28
      src/engine/Light.cpp
  9. +32
    -0
      src/engine/Port.cpp

+ 1
- 1
include/engine/Input.hpp View File

@@ -9,7 +9,7 @@ namespace rack {
struct Input : Port { struct Input : Port {
/** Returns the value if a cable is plugged in, otherwise returns the given default value */ /** Returns the value if a cable is plugged in, otherwise returns the given default value */
float normalize(float normalVoltage, int channel = 0) { float normalize(float normalVoltage, int channel = 0) {
return active ? getVoltage(channel) : normalVoltage;
return isActive() ? getVoltage(channel) : normalVoltage;
} }
}; };




+ 20
- 2
include/engine/Light.hpp View File

@@ -6,15 +6,33 @@ namespace rack {




struct Light { struct Light {
/** The mean-square of the brightness */
float value = 0.f; float value = 0.f;
float getBrightness();

float getBrightness() {
return std::sqrt(value);
}

void setBrightness(float brightness) { void setBrightness(float brightness) {
value = (brightness > 0.f) ? std::pow(brightness, 2) : 0.f; value = (brightness > 0.f) ? std::pow(brightness, 2) : 0.f;
} }

/** Emulates slow fall (but immediate rise) of LED brightness. /** Emulates slow fall (but immediate rise) of LED brightness.
`frames` rescales the timestep. For example, if your module calls this method every 16 frames, use 16.f. `frames` rescales the timestep. For example, if your module calls this method every 16 frames, use 16.f.
*/ */
void setBrightnessSmooth(float brightness, float frames = 1.f);
void setBrightnessSmooth(float brightness, float frames = 1.f) {
float v = (brightness > 0.f) ? std::pow(brightness, 2) : 0.f;
if (v < value) {
// Fade out light with lambda = framerate
// Use 44.1k here to avoid the call to Engine::getSampleRate().
// This is close enough to look okay up to 96k
value += (v - value) * frames * 60.f / 44100.f;
}
else {
// Immediately illuminate light
value = v;
}
}
}; };






+ 17
- 8
include/engine/Port.hpp View File

@@ -12,19 +12,22 @@ static const int PORT_MAX_CHANNELS = 16;
struct Port { struct Port {
/** Voltage of the port */ /** Voltage of the port */
union { union {
/** Accessing this directly is deprecated.
Use getVoltage() and setVoltage() instead
*/
float value;
float values[PORT_MAX_CHANNELS] = {}; float values[PORT_MAX_CHANNELS] = {};
/** DEPRECATED. Use getVoltage() and setVoltage() instead. */
float value;
}; };
/** Number of polyphonic channels /** Number of polyphonic channels
May be 0 to PORT_MAX_CHANNELS. May be 0 to PORT_MAX_CHANNELS.
*/ */
int channels = 1;
/** Whether a cable is plugged in */
bool active = false;
Light plugLights[2];
union {
uint8_t channels = 1;
/** DEPRECATED. Use isActive() instead. */
bool active;
};
/** For rendering plug lights on cables
Green for positive, red for negative, and blue for polyphonic
*/
Light plugLights[3];


float getVoltage(int channel = 0) { float getVoltage(int channel = 0) {
return values[channel]; return values[channel];
@@ -45,6 +48,12 @@ struct Port {
int getChannels() { int getChannels() {
return channels; return channels;
} }

bool isActive() {
return channels;
}

void step();
}; };






+ 1
- 1
src/Core/MIDI_CC.cpp View File

@@ -47,7 +47,7 @@ struct MIDI_CC : Module {


float lambda = app()->engine->getSampleTime() * 100.f; float lambda = app()->engine->getSampleTime() * 100.f;
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
if (!outputs[CC_OUTPUT + i].active)
if (!outputs[CC_OUTPUT + i].isActive())
continue; continue;


int cc = learnedCcs[i]; int cc = learnedCcs[i];


+ 6
- 2
src/app/CableWidget.cpp View File

@@ -222,11 +222,15 @@ void CableWidget::draw(NVGcontext *vg) {


float thickness = 5; float thickness = 5;
if (cable && cable->outputModule) { if (cable && cable->outputModule) {
// Increase thickness if output port is polyphonic
Output *output = &cable->outputModule->outputs[cable->outputId]; Output *output = &cable->outputModule->outputs[cable->outputId];
if (output->channels != 1) {
if (output->channels > 1) {
// Increase thickness if output port is polyphonic
thickness = 7; thickness = 7;
} }
else if (output->channels == 0) {
// Draw translucent cable if not active (i.e. 0 channels)
nvgGlobalAlpha(vg, 0.5);
}
} }


math::Vec outputPos = getOutputPos(); math::Vec outputPos = getOutputPos();


+ 7
- 3
src/app/ModuleLightWidget.cpp View File

@@ -12,9 +12,13 @@ void ModuleLightWidget::step() {
std::vector<float> values(baseColors.size()); std::vector<float> values(baseColors.size());


for (size_t i = 0; i < baseColors.size(); i++) { for (size_t i = 0; i < baseColors.size(); i++) {
float value = module->lights[firstLightId + i].getBrightness();
value = math::clamp(value, 0.f, 1.f);
values[i] = value;
float brightness = module->lights[firstLightId + i].getBrightness();
if (!std::isfinite(brightness))
brightness = 0.f;
// Because LEDs are nonlinear, this seems to look more natural.
brightness = std::sqrt(brightness);
brightness = math::clamp(brightness, 0.f, 1.f);
values[i] = brightness;
} }
setValues(values); setValues(values);
} }


+ 9
- 35
src/engine/Engine.cpp View File

@@ -114,13 +114,14 @@ static void Engine_step(Engine *engine) {
} }
} }


float cpuLambda = engine->internal->sampleTime / 2.f;

// Iterate modules // Iterate modules
for (Module *module : engine->modules) { for (Module *module : engine->modules) {
if (module->bypass) { if (module->bypass) {
// Bypass module // Bypass module
for (Output &output : module->outputs) { for (Output &output : module->outputs) {
output.channels = 1;
output.setVoltage(0.f);
output.setChannels(0);
} }
module->cpuTime = 0.f; module->cpuTime = 0.f;
} }
@@ -134,8 +135,7 @@ static void Engine_step(Engine *engine) {
auto stopTime = std::chrono::high_resolution_clock::now(); auto stopTime = std::chrono::high_resolution_clock::now();
float cpuTime = std::chrono::duration<float>(stopTime - startTime).count(); float cpuTime = std::chrono::duration<float>(stopTime - startTime).count();
// Smooth cpu time // Smooth cpu time
float powerLambda = engine->internal->sampleTime / 2.f;
module->cpuTime += (cpuTime - module->cpuTime) * powerLambda;
module->cpuTime += (cpuTime - module->cpuTime) * cpuLambda;
} }
else { else {
module->step(); module->step();
@@ -144,18 +144,10 @@ static void Engine_step(Engine *engine) {


// Iterate ports and step plug lights // Iterate ports and step plug lights
for (Input &input : module->inputs) { for (Input &input : module->inputs) {
if (input.active) {
float value = input.value / 5.f;
input.plugLights[0].setBrightnessSmooth(value);
input.plugLights[1].setBrightnessSmooth(-value);
}
input.step();
} }
for (Output &output : module->outputs) { for (Output &output : module->outputs) {
if (output.active) {
float value = output.value / 5.f;
output.plugLights[0].setBrightnessSmooth(value);
output.plugLights[1].setBrightnessSmooth(-value);
}
output.step();
} }
} }


@@ -274,23 +266,6 @@ void Engine::randomizeModule(Module *module) {
module->randomize(); module->randomize();
} }


static void Engine_updateActive(Engine *engine) {
// Set everything to inactive
for (Module *module : engine->modules) {
for (Input &input : module->inputs) {
input.active = false;
}
for (Output &output : module->outputs) {
output.active = false;
}
}
// Set inputs/outputs to active
for (Cable *cable : engine->cables) {
cable->outputModule->outputs[cable->outputId].active = true;
cable->inputModule->inputs[cable->inputId].active = true;
}
}

void Engine::addCable(Cable *cable) { void Engine::addCable(Cable *cable) {
assert(cable); assert(cable);
VIPLock vipLock(internal->vipMutex); VIPLock vipLock(internal->vipMutex);
@@ -318,7 +293,6 @@ void Engine::addCable(Cable *cable) {
} }
// Add the cable // Add the cable
cables.push_back(cable); cables.push_back(cable);
Engine_updateActive(this);
} }


void Engine::removeCable(Cable *cable) { void Engine::removeCable(Cable *cable) {
@@ -328,11 +302,11 @@ void Engine::removeCable(Cable *cable) {
// Check that the cable is already added // Check that the cable is already added
auto it = std::find(cables.begin(), cables.end(), cable); auto it = std::find(cables.begin(), cables.end(), cable);
assert(it != cables.end()); assert(it != cables.end());
// Set input to 0V
cable->inputModule->inputs[cable->inputId].value = 0.f;
// Set input to inactive
Input &input = cable->inputModule->inputs[cable->inputId];
input.setChannels(0);
// Remove the cable // Remove the cable
cables.erase(it); cables.erase(it);
Engine_updateActive(this);
// Remove ID // Remove ID
cable->id = 0; cable->id = 0;
} }


+ 0
- 28
src/engine/Light.cpp View File

@@ -1,28 +0,0 @@
#include "engine/Light.hpp"
#include "engine/Engine.hpp"
#include "app.hpp"


namespace rack {


float Light::getBrightness() {
// LEDs are diodes, so don't allow reverse current.
// For some reason, instead of the RMS, the sqrt of RMS looks better
return std::pow(std::fmax(0.f, value), 0.25f);
}

void Light::setBrightnessSmooth(float brightness, float frames) {
float v = (brightness > 0.f) ? std::pow(brightness, 2) : 0.f;
if (v < value) {
// Fade out light with lambda = framerate
value += (v - value) * app()->engine->getSampleTime() * frames * 60.f;
}
else {
// Immediately illuminate light
value = v;
}
}


} // namespace rack

+ 32
- 0
src/engine/Port.cpp View File

@@ -0,0 +1,32 @@
#include "engine/Port.hpp"


namespace rack {


void Port::step() {
if (channels == 0) {
plugLights[0].setBrightness(0.f);
plugLights[1].setBrightness(0.f);
plugLights[2].setBrightness(0.f);
}
else if (channels == 1) {
float v = getVoltage() / 10.f;
plugLights[0].setBrightnessSmooth(v);
plugLights[1].setBrightnessSmooth(-v);
plugLights[2].setBrightness(0.f);
}
else {
float v2 = 0.f;
for (int c = 0; c < channels; c++) {
v2 += std::pow(getVoltage(c), 2);
}
float v = std::sqrt(v2) / 10.f;
plugLights[0].setBrightness(0.f);
plugLights[1].setBrightness(0.f);
plugLights[2].setBrightnessSmooth(v);
}
}


} // namespace rack

Loading…
Cancel
Save