Browse Source

Merge branch 'Rcomian-v0.6' into v0.6

tags/v1.0.1
Andrew Belt 6 years ago
parent
commit
ed0c44cb69
4 changed files with 265 additions and 57 deletions
  1. +1
    -1
      eurorack
  2. +11
    -10
      res/Stages.svg
  3. +1
    -1
      src/AudibleInstruments.cpp
  4. +252
    -45
      src/Stages.cpp

+ 1
- 1
eurorack

@@ -1 +1 @@
Subproject commit e9aac2ab705e7b7e902b43a1bbd9e01d25cd42a2
Subproject commit 2bd5cdf9598ebf720da33b60e0bc5e2dad4215d3

+ 11
- 10
res/Stages.svg View File

@@ -10,9 +10,9 @@
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="70.887665mm"
width="71.120003mm"
height="128.5889mm"
viewBox="0 0 70.887665 128.5889"
viewBox="0 0 71.120003 128.5889"
version="1.1"
id="svg1428"
inkscape:version="0.92.2 2405546, 2018-03-11"
@@ -1173,11 +1173,11 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="191.99827"
inkscape:cy="232.47187"
inkscape:zoom="5.6"
inkscape:cx="149.63939"
inkscape:cy="511.43702"
inkscape:document-units="mm"
inkscape:current-layer="layer2"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
@@ -1186,7 +1186,7 @@
inkscape:window-width="1600"
inkscape:window-height="882"
inkscape:window-x="0"
inkscape:window-y="18"
inkscape:window-y="27"
inkscape:window-maximized="0"
inkscape:snap-bbox="true"
inkscape:snap-bbox-midpoints="false"
@@ -1194,7 +1194,8 @@
inkscape:snap-page="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:bbox-paths="true" />
inkscape:bbox-paths="true"
units="mm" />
<metadata
id="metadata1425">
<rdf:RDF>
@@ -1213,11 +1214,11 @@
id="layer1"
transform="translate(0.04409722,-168.45588)">
<rect
style="display:inline;fill:#e6e6e6;stroke-width:0.36505559"
style="display:inline;fill:#e6e6e6;stroke-width:0.36565334"
y="168.45589"
x="-0.044097219"
height="128.58888"
width="70.887665"
width="71.120003"
id="background" />
<path
inkscape:connector-curvature="0"


+ 1
- 1
src/AudibleInstruments.cpp View File

@@ -23,6 +23,6 @@ void init(rack::Plugin *p) {
p->addModel(modelVeils);
p->addModel(modelFrames);
// p->addModel(modelPeaks);
// p->addModel(modelStages);
p->addModel(modelMarbles);
p->addModel(modelStages);
}

+ 252
- 45
src/Stages.cpp View File

@@ -1,6 +1,5 @@
#include "AudibleInstruments.hpp"
#include "dsp/digital.hpp"
// #include "stages/chain_state.h"
#include "stages/segment_generator.h"
#include "stages/oscillator.h"

@@ -9,6 +8,114 @@
static const int NUM_CHANNELS = 6;
static const int BLOCK_SIZE = 8;

struct LongPressButton {
enum Events {
NO_PRESS,
SHORT_PRESS,
LONG_PRESS
};

float pressedTime = 0.f;
BooleanTrigger trigger;

Events step(Param &param) {
Events result = NO_PRESS;

bool pressed = param.value > 0.f;
if (pressed && pressedTime >= 0.f) {
pressedTime += engineGetSampleTime();
if (pressedTime >= 1.f) {
pressedTime = -1.f;
result = LONG_PRESS;
}
}

// Check if released
if (trigger.process(!pressed)) {
if (pressedTime >= 0.f) {
result = SHORT_PRESS;
}
pressedTime = 0.f;
}

return result;
}
};

struct GroupInfo {
int first_segment = 0;
int segment_count = 0;
bool gated = false;
};

struct GroupBuilder {

GroupInfo groups[NUM_CHANNELS];
int groupCount = 0;

bool buildGroups(std::vector<Input> *gateInputs, size_t first, size_t count) {
bool any_gates = false;

GroupInfo nextGroups[NUM_CHANNELS];

int currentGroup = 0;
for (int i = 0; i < NUM_CHANNELS; i++) {
bool gated = (*gateInputs)[first + i].active;

if (!any_gates) {
if (!gated) {
// No gates at all yet, segments are all single segment groups
nextGroups[currentGroup].first_segment = i;
nextGroups[currentGroup].segment_count = 1;
nextGroups[currentGroup].gated = false;
currentGroup++;
}
else {
// first gate, current group is start of a segment group
any_gates = true;
nextGroups[currentGroup].first_segment = i;
nextGroups[currentGroup].segment_count = 1;
nextGroups[currentGroup].gated = true;
currentGroup++;
}
}
else {
if (!gated) {
// We've had a gate, this ungated segment is part of the previous group
nextGroups[currentGroup-1].segment_count++;
}
else {
// This gated input indicates the start of the next group
nextGroups[currentGroup].first_segment = i;
nextGroups[currentGroup].segment_count = 1;
nextGroups[currentGroup].gated = true;
currentGroup++;
}
}
}

bool changed = false;

if (currentGroup != groupCount) {
changed = true;
groupCount = currentGroup;
}

for (int i = 0; i < groupCount; i++) {
if (nextGroups[i].segment_count != groups[i].segment_count ||
nextGroups[i].gated != groups[i].gated ||
nextGroups[i].first_segment != groups[i].first_segment) {
changed = true;
}

groups[i].first_segment = nextGroups[i].first_segment;
groups[i].segment_count = nextGroups[i].segment_count;
groups[i].gated = nextGroups[i].gated;
}

return changed;
}
};

struct Stages : Module {
enum ParamIds {
@@ -27,40 +134,41 @@ struct Stages : Module {
NUM_OUTPUTS
};
enum LightIds {
ENUMS(TYPE_LIGHTS, NUM_CHANNELS*2),
ENUMS(TYPE_LIGHTS, NUM_CHANNELS * 2),
ENUMS(ENVELOPE_LIGHTS, NUM_CHANNELS),
NUM_LIGHTS
};

stages::segment::Configuration configurations[NUM_CHANNELS];
bool configuration_changed[NUM_CHANNELS];
stages::SegmentGenerator segment_generator[NUM_CHANNELS];
stages::Oscillator oscillator[NUM_CHANNELS];
// stages::ChainState chain_state;
// stages::Settings settings;
float lightOscillatorPhase;

// Buttons
BooleanTrigger typeTriggers[NUM_CHANNELS];
float pressedTime = 0.f;
LongPressButton typeButtons[NUM_CHANNELS];

// Buffers
float envelopeBuffer[NUM_CHANNELS][BLOCK_SIZE] = {};
stmlib::GateFlags last_gate_flags[NUM_CHANNELS] = {};
stmlib::GateFlags gate_flags[NUM_CHANNELS][BLOCK_SIZE] = {};
int blockIndex = 0;
GroupBuilder groupBuilder;

Stages() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
// chain_state.Init(NULL, NULL);
onReset();
}

void onReset() override {
for (size_t i = 0; i < NUM_CHANNELS; ++i) {
segment_generator[i].Init();
oscillator[i].Init();

configurations[i].type = stages::segment::TYPE_RAMP;
configurations[i].loop = false;
configuration_changed[i] = true;
}

lightOscillatorPhase = 0.f;
onSampleRateChange();
}

json_t *toJson() override {
@@ -94,49 +202,127 @@ struct Stages : Module {
}
}

void onSampleRateChange() override {
for (int i = 0; i < NUM_CHANNELS; i++) {
segment_generator[i].SetSampleRate(engineGetSampleRate());
}
}

void stepBlock() {
// Get parameters
float primaries[NUM_CHANNELS];
float secondaries[NUM_CHANNELS];
for (int i = 0; i < NUM_CHANNELS; i++) {
primaries[i] = clamp(params[LEVEL_PARAMS + i].value + inputs[LEVEL_INPUTS].value / 8.f, 0.f, 1.f);
primaries[i] = clamp(params[LEVEL_PARAMS + i].value + inputs[LEVEL_INPUTS + i].value / 8.f, 0.f, 1.f);
secondaries[i] = params[SHAPE_PARAMS + i].value;
}

// // Get patched state
// for (int i = 0; i < NUM_CHANNELS; i++) {
// bool p = inputs[GATE_INPUTS + i].active;
// if (p != patched[i])
// dirty_configurations[i] = true;
// patched[i] = p;
// }
// See if the group associations have changed since the last group
bool groups_changed = groupBuilder.buildGroups(&inputs, GATE_INPUTS, NUM_CHANNELS);

// Process block
stages::SegmentGenerator::Output out[BLOCK_SIZE] = {};
for (int i = 0; i < NUM_CHANNELS; i++) {
bool led_state = segment_generator[i].Process(gate_flags[i], out, BLOCK_SIZE);
for (int i = 0; i < groupBuilder.groupCount; i++) {
GroupInfo &group = groupBuilder.groups[i];

// Check if the config needs applying to the segment generator for this group
bool apply_config = groups_changed;
int numberOfLoopsInGroup = 0;
for (int j = 0; j < group.segment_count; j++) {
int segment = group.first_segment + j;
numberOfLoopsInGroup += configurations[segment].loop ? 1 : 0;
apply_config |= configuration_changed[segment];
configuration_changed[segment] = false;
}

if (numberOfLoopsInGroup > 2) {
// Too many segments are looping, turn them all off
apply_config = true;
for (int j = 0; j < group.segment_count; j++) {
configurations[group.first_segment + j].loop = false;
}
}

if (apply_config) {
segment_generator[i].Configure(group.gated, &configurations[group.first_segment], group.segment_count);
}

// Set the segment parameters on the generator we're about to process
for (int j = 0; j < group.segment_count; j++) {
segment_generator[i].set_segment_parameters(j, primaries[group.first_segment + j], secondaries[group.first_segment + j]);
}

segment_generator[i].Process(gate_flags[group.first_segment], out, BLOCK_SIZE);

for (int j = 0; j < BLOCK_SIZE; j++) {
envelopeBuffer[i][j] = out[j].value;
for (int k = 1; k < group.segment_count; k++) {
int segment = group.first_segment + k;
if (k == out[j].segment) {
// Set the phase output for the active segment
envelopeBuffer[segment][j] = 1.f - out[j].phase;
}
else {
// Non active segments have 0.f output
envelopeBuffer[segment][j] = 0.f;
}
}
// First group segment gets the actual output
envelopeBuffer[group.first_segment][j] = out[j].value;
}
}
}

void toggleMode(int i) {
configurations[i].type = (stages::segment::Type) ((configurations[i].type + 1) % 3);
configuration_changed[i] = true;
}

void toggleLoop(int segment) {
configuration_changed[segment] = true;
configurations[segment].loop = !configurations[segment].loop;

// ensure that we don't have too many looping segments in the group
if (configurations[segment].loop) {
int segment_count = 0;
for (int i = 0; i < groupBuilder.groupCount; i++) {
segment_count += groupBuilder.groups[i].segment_count;

if (segment_count > segment) {
GroupInfo &group = groupBuilder.groups[i];

// See how many loop items we have
int numberOfLoopsInGroup = 0;

for (int j = 0; j < group.segment_count; j++) {
numberOfLoopsInGroup += configurations[group.first_segment + j].loop ? 1 : 0;
}

// If we've got too many loop items, clear down to the one looping segment
if (numberOfLoopsInGroup > 2) {
for (int j = 0; j < group.segment_count; j++) {
configurations[group.first_segment + j].loop = (group.first_segment + j) == segment;
}
}

break;
}
}
}
}

void step() override {
// Oscillate flashing the type lights
lightOscillatorPhase += 0.5f * engineGetSampleTime();
if (lightOscillatorPhase >= 1.0f)
lightOscillatorPhase -= 1.0f;

// Buttons
for (int i = 0; i < NUM_CHANNELS; i++) {
bool pressed = params[TYPE_PARAMS + i].value > 0.f;
if (pressed) {
pressedTime += engineGetSampleTime();
}
// Check if released
if (typeTriggers[i].process(!pressed)) {
if (pressedTime >= 1.f) {
configurations[i].loop = !configurations[i].loop;
}
else {
configurations[i].type = (stages::segment::Type) ((configurations[i].type + 1) % 3);
}
pressedTime = 0.f;
switch (typeButtons[i].step(params[TYPE_PARAMS + i])) {
default:
case LongPressButton::NO_PRESS: break;
case LongPressButton::SHORT_PRESS: toggleMode(i); break;
case LongPressButton::LONG_PRESS: toggleLoop(i); break;
}
}

@@ -154,13 +340,34 @@ struct Stages : Module {
}

// Output
for (int i = 0; i < NUM_CHANNELS; i++) {
float envelope = envelopeBuffer[i][blockIndex];
outputs[ENVELOPE_OUTPUTS + i].value = envelope * 10.f;
lights[ENVELOPE_LIGHTS + i].setBrightnessSmooth(envelope);
for (int i = 0; i < groupBuilder.groupCount; i++) {
GroupInfo &group = groupBuilder.groups[i];

int numberOfLoopsInGroup = 0;
for (int j = 0; j < group.segment_count; j++) {
int segment = group.first_segment + j;

float envelope = envelopeBuffer[segment][blockIndex];
outputs[ENVELOPE_OUTPUTS + segment].value = envelope * 8.f;
lights[ENVELOPE_LIGHTS + segment].setBrightnessSmooth(envelope);

numberOfLoopsInGroup += configurations[segment].loop ? 1 : 0;
float flashlevel = 1.f;

lights[TYPE_LIGHTS + i*2 + 0].setBrightness(configurations[i].type == 0 || configurations[i].type == 1);
lights[TYPE_LIGHTS + i*2 + 1].setBrightness(configurations[i].type == 1 || configurations[i].type == 2);
if (configurations[segment].loop && numberOfLoopsInGroup == 1) {
flashlevel = abs(sinf(2.0f * M_PI * lightOscillatorPhase));
}
else if (configurations[segment].loop && numberOfLoopsInGroup > 1) {
float advancedPhase = lightOscillatorPhase + 0.25f;
if (advancedPhase > 1.0f)
advancedPhase -= 1.0f;

flashlevel = abs(sinf(2.0f * M_PI * advancedPhase));
}

lights[TYPE_LIGHTS + segment * 2 + 0].setBrightness((configurations[segment].type == 0 || configurations[segment].type == 1) * flashlevel);
lights[TYPE_LIGHTS + segment * 2 + 1].setBrightness((configurations[segment].type == 1 || configurations[segment].type == 2) * flashlevel);
}
}
}
};
@@ -214,12 +421,12 @@ struct StagesWidget : ModuleWidget {
addOutput(Port::create<PJ301MPort>(mm2px(Vec(48.48943, 106.95203)), Port::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 4));
addOutput(Port::create<PJ301MPort>(mm2px(Vec(59.92921, 106.95203)), Port::OUTPUT, module, Stages::ENVELOPE_OUTPUTS + 5));

addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(5.27737, 26.74447)), module, Stages::TYPE_LIGHTS + 0*2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(16.73784, 26.74447)), module, Stages::TYPE_LIGHTS + 1*2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(28.1783, 26.74447)), module, Stages::TYPE_LIGHTS + 2*2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(39.61877, 26.74447)), module, Stages::TYPE_LIGHTS + 3*2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(51.07923, 26.74447)), module, Stages::TYPE_LIGHTS + 4*2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(62.51971, 26.74447)), module, Stages::TYPE_LIGHTS + 5*2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(5.27737, 26.74447)), module, Stages::TYPE_LIGHTS + 0 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(16.73784, 26.74447)), module, Stages::TYPE_LIGHTS + 1 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(28.1783, 26.74447)), module, Stages::TYPE_LIGHTS + 2 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(39.61877, 26.74447)), module, Stages::TYPE_LIGHTS + 3 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(51.07923, 26.74447)), module, Stages::TYPE_LIGHTS + 4 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenRedLight>>(mm2px(Vec(62.51971, 26.74447)), module, Stages::TYPE_LIGHTS + 5 * 2));
addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(mm2px(Vec(2.29462, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 0));
addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(mm2px(Vec(13.73509, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 1));
addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(mm2px(Vec(25.17556, 103.19253)), module, Stages::ENVELOPE_LIGHTS + 2));


Loading…
Cancel
Save