Browse Source

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

tags/v1.0.0
Andrew Belt 5 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 {
/** Returns the value if a cable is plugged in, otherwise returns the given default value */
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 {
/** The mean-square of the brightness */
float value = 0.f;
float getBrightness();

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

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

/** 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.
*/
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 {
/** Voltage of the port */
union {
/** Accessing this directly is deprecated.
Use getVoltage() and setVoltage() instead
*/
float value;
float values[PORT_MAX_CHANNELS] = {};
/** DEPRECATED. Use getVoltage() and setVoltage() instead. */
float value;
};
/** Number of polyphonic 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) {
return values[channel];
@@ -45,6 +48,12 @@ struct Port {
int getChannels() {
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;
for (int i = 0; i < 16; i++) {
if (!outputs[CC_OUTPUT + i].active)
if (!outputs[CC_OUTPUT + i].isActive())
continue;

int cc = learnedCcs[i];


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

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

float thickness = 5;
if (cable && cable->outputModule) {
// Increase thickness if output port is polyphonic
Output *output = &cable->outputModule->outputs[cable->outputId];
if (output->channels != 1) {
if (output->channels > 1) {
// Increase thickness if output port is polyphonic
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();


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

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

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);
}


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

// Iterate ports and step plug lights
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) {
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();
}

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

void Engine::removeCable(Cable *cable) {
@@ -328,11 +302,11 @@ void Engine::removeCable(Cable *cable) {
// Check that the cable is already added
auto it = std::find(cables.begin(), cables.end(), cable);
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
cables.erase(it);
Engine_updateActive(this);
// Remove ID
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