|
|
@@ -1,13 +1,14 @@ |
|
|
|
#include "AudibleInstruments.hpp" |
|
|
|
#include "dsp/digital.hpp" |
|
|
|
// #include "stages/chain_state.h" |
|
|
|
#include "stages/segment_generator.h" |
|
|
|
#include "stages/oscillator.h" |
|
|
|
|
|
|
|
|
|
|
|
// Must match io_buffer.h |
|
|
|
static const int NUM_CHANNELS = 6; |
|
|
|
static const int BLOCK_SIZE = 8; |
|
|
|
|
|
|
|
|
|
|
|
struct SineOscillator { |
|
|
|
float phase = 0.f; |
|
|
|
|
|
|
@@ -29,8 +30,8 @@ struct SineOscillator { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
struct LongPressButton { |
|
|
|
|
|
|
|
struct LongPressButton { |
|
|
|
enum Events { |
|
|
|
NO_PRESS, |
|
|
|
SHORT_PRESS, |
|
|
@@ -40,8 +41,8 @@ struct LongPressButton { |
|
|
|
float pressedTime = 0.f; |
|
|
|
BooleanTrigger trigger; |
|
|
|
|
|
|
|
Events step(Param& param) { |
|
|
|
auto result = NO_PRESS; |
|
|
|
Events step(Param ¶m) { |
|
|
|
Events result = NO_PRESS; |
|
|
|
|
|
|
|
bool pressed = param.value > 0.f; |
|
|
|
if (pressed && pressedTime >= 0.f) { |
|
|
@@ -64,10 +65,10 @@ struct LongPressButton { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
struct GroupBuilder { |
|
|
|
|
|
|
|
struct GroupBuilder { |
|
|
|
GroupBuilder() { |
|
|
|
for (size_t i = 0; i < NUM_CHANNELS; i += 1) { |
|
|
|
for (size_t i = 0; i < NUM_CHANNELS; i++) { |
|
|
|
groupSize[i] = 0; |
|
|
|
} |
|
|
|
} |
|
|
@@ -80,16 +81,17 @@ struct GroupBuilder { |
|
|
|
isPatched = false; |
|
|
|
size_t activeGroup = 0; |
|
|
|
|
|
|
|
for (int i = count-1; i >= 0; i -= 1) { |
|
|
|
auto patched = (*inputs)[first + i].active; |
|
|
|
for (int i = count - 1; i >= 0; i -= 1) { |
|
|
|
bool patched = (*inputs)[first + i].active; |
|
|
|
|
|
|
|
activeGroup += 1; |
|
|
|
activeGroup++; |
|
|
|
if (!patched) { |
|
|
|
changed = changed || groupSize[i] != 0; |
|
|
|
changed = changed || (groupSize[i] != 0); |
|
|
|
groupSize[i] = 0; |
|
|
|
} else if (patched) { |
|
|
|
} |
|
|
|
else if (patched) { |
|
|
|
isPatched = true; |
|
|
|
changed = changed || groupSize[i] != activeGroup; |
|
|
|
changed = changed || (groupSize[i] != activeGroup); |
|
|
|
groupSize[i] = activeGroup; |
|
|
|
activeGroup = 0; |
|
|
|
} |
|
|
@@ -102,7 +104,7 @@ struct GroupBuilder { |
|
|
|
int group = 0; |
|
|
|
int currentGroupSize = 0; |
|
|
|
|
|
|
|
for (int i = 0; i < NUM_CHANNELS; i += 1) { |
|
|
|
for (int i = 0; i < NUM_CHANNELS; i++) { |
|
|
|
if (currentGroupSize <= 0) { |
|
|
|
currentGroupSize = max(1, groupSize[i]); |
|
|
|
group = i; |
|
|
@@ -136,7 +138,7 @@ 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 |
|
|
|
}; |
|
|
@@ -145,9 +147,7 @@ struct Stages : Module { |
|
|
|
bool configuration_changed[NUM_CHANNELS]; |
|
|
|
stages::SegmentGenerator segment_generator[NUM_CHANNELS]; |
|
|
|
SineOscillator oscillator[NUM_CHANNELS]; |
|
|
|
bool abloop; |
|
|
|
// stages::ChainState chain_state; |
|
|
|
// stages::Settings settings; |
|
|
|
bool abLoop; |
|
|
|
|
|
|
|
// Buttons |
|
|
|
LongPressButton typeButtons[NUM_CHANNELS]; |
|
|
@@ -160,14 +160,11 @@ struct Stages : Module { |
|
|
|
GroupBuilder groupBuilder; |
|
|
|
|
|
|
|
Stages() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { |
|
|
|
// chain_state.Init(NULL, NULL); |
|
|
|
onReset(); |
|
|
|
} |
|
|
|
|
|
|
|
void onReset() override { |
|
|
|
stages::kSampleRate = engineGetSampleRate(); |
|
|
|
|
|
|
|
abloop = false; |
|
|
|
abLoop = false; |
|
|
|
|
|
|
|
for (size_t i = 0; i < NUM_CHANNELS; ++i) { |
|
|
|
segment_generator[i].Init(); |
|
|
@@ -176,6 +173,8 @@ struct Stages : Module { |
|
|
|
configurations[i].loop = false; |
|
|
|
configuration_changed[i] = true; |
|
|
|
} |
|
|
|
|
|
|
|
onSampleRateChange(); |
|
|
|
} |
|
|
|
|
|
|
|
json_t *toJson() override { |
|
|
@@ -226,16 +225,15 @@ struct Stages : Module { |
|
|
|
} |
|
|
|
|
|
|
|
// See if the group associations have changed since the last group |
|
|
|
auto groups_changed = groupBuilder.buildGroups(&inputs, GATE_INPUTS, NUM_CHANNELS); |
|
|
|
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;) { |
|
|
|
|
|
|
|
// Check if the config needs applying to the segment generator for this group |
|
|
|
bool segment_changed = groups_changed; |
|
|
|
int numberOfLoops = 0; |
|
|
|
for (int j = 0; j < max(1, groupBuilder.groupSize[i]); j += 1) { |
|
|
|
for (int j = 0; j < max(1, groupBuilder.groupSize[i]); j++) { |
|
|
|
numberOfLoops += configurations[i + j].loop ? 1 : 0; |
|
|
|
segment_changed |= configuration_changed[i + j]; |
|
|
|
configuration_changed[i + j] = false; |
|
|
@@ -243,7 +241,7 @@ struct Stages : Module { |
|
|
|
|
|
|
|
if (segment_changed) { |
|
|
|
if (numberOfLoops > 2) { |
|
|
|
for (int j = 0; j < max(1, groupBuilder.groupSize[i]); j += 1) { |
|
|
|
for (int j = 0; j < max(1, groupBuilder.groupSize[i]); j++) { |
|
|
|
configurations[i + j].loop = false; |
|
|
|
} |
|
|
|
} |
|
|
@@ -251,7 +249,7 @@ struct Stages : Module { |
|
|
|
} |
|
|
|
|
|
|
|
// Set the segment parameters on the generator we're about to process |
|
|
|
for (int j = 0; j < segment_generator[i].num_segments(); j += 1) { |
|
|
|
for (int j = 0; j < segment_generator[i].num_segments(); j++) { |
|
|
|
segment_generator[i].set_segment_parameters(j, primaries[i + j], secondaries[i + j]); |
|
|
|
} |
|
|
|
|
|
|
@@ -260,8 +258,8 @@ struct Stages : Module { |
|
|
|
// Set the outputs for the active segment in each output sample |
|
|
|
// All outputs also go to the first segment |
|
|
|
for (int j = 0; j < BLOCK_SIZE; j++) { |
|
|
|
for (int k = 1; k < segment_generator[i].num_segments(); k += 1) { |
|
|
|
envelopeBuffer[i + k][j] = k == out[j].segment ? 1- out[j].phase : 0.f; |
|
|
|
for (int k = 1; k < segment_generator[i].num_segments(); k++) { |
|
|
|
envelopeBuffer[i + k][j] = k == out[j].segment ? 1 - out[j].phase : 0.f; |
|
|
|
} |
|
|
|
envelopeBuffer[i][j] = out[j].value; |
|
|
|
} |
|
|
@@ -286,21 +284,21 @@ struct Stages : Module { |
|
|
|
// See how many loop items we have |
|
|
|
int loopitems = 0; |
|
|
|
|
|
|
|
for (size_t j = 0; j < groupBuilder.groupSize[group]; j += 1) { |
|
|
|
for (size_t j = 0; j < groupBuilder.groupSize[group]; j++) { |
|
|
|
loopitems += configurations[group + j].loop ? 1 : 0; |
|
|
|
} |
|
|
|
|
|
|
|
// If we've got too many loop items, clear down to the one loop |
|
|
|
if ((abloop && loopitems > 2) || (!abloop && loopitems > 1)) { |
|
|
|
for (size_t j = 0; j < groupBuilder.groupSize[group]; j += 1) { |
|
|
|
if ((abLoop && loopitems > 2) || (!abLoop && loopitems > 1)) { |
|
|
|
for (size_t j = 0; j < groupBuilder.groupSize[group]; j++) { |
|
|
|
configurations[group + j].loop = (group + (int)j) == i; |
|
|
|
} |
|
|
|
loopitems = 1; |
|
|
|
} |
|
|
|
|
|
|
|
// Turn abloop off if we've got 2 or more loops |
|
|
|
// Turn abLoop off if we've got 2 or more loops |
|
|
|
if (loopitems >= 2) { |
|
|
|
abloop = false; |
|
|
|
abLoop = false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -344,19 +342,20 @@ struct Stages : Module { |
|
|
|
currentGroupSize -= 1; |
|
|
|
|
|
|
|
loopcount += configurations[i].loop ? 1 : 0; |
|
|
|
auto flashlevel = 1.f; |
|
|
|
float flashlevel = 1.f; |
|
|
|
|
|
|
|
if (!configurations[i].loop) { |
|
|
|
oscillator[i].step(0.f); // move the oscillator on to keep the lights in sync |
|
|
|
} else if (configurations[i].loop && loopcount == 1) { |
|
|
|
} |
|
|
|
else if (configurations[i].loop && loopcount == 1) { |
|
|
|
flashlevel = abs(oscillator[i].step(0.f)); |
|
|
|
} else { |
|
|
|
} |
|
|
|
else { |
|
|
|
flashlevel = abs(oscillator[i].step(0.25f)); |
|
|
|
} |
|
|
|
|
|
|
|
lights[TYPE_LIGHTS + i*2 + 0].setBrightness((configurations[i].type == 0 || configurations[i].type == 1) * flashlevel); |
|
|
|
lights[TYPE_LIGHTS + i*2 + 1].setBrightness((configurations[i].type == 1 || configurations[i].type == 2) * flashlevel); |
|
|
|
|
|
|
|
lights[TYPE_LIGHTS + i * 2 + 0].setBrightness((configurations[i].type == 0 || configurations[i].type == 1) * flashlevel); |
|
|
|
lights[TYPE_LIGHTS + i * 2 + 1].setBrightness((configurations[i].type == 1 || configurations[i].type == 2) * flashlevel); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
@@ -410,12 +409,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)); |
|
|
@@ -430,14 +429,14 @@ struct StagesWidget : ModuleWidget { |
|
|
|
struct ABLoopItem : MenuItem { |
|
|
|
Stages *module; |
|
|
|
void onAction(EventAction &e) override { |
|
|
|
module->abloop = true; |
|
|
|
module->abLoop = true; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
menu->addChild(MenuEntry::create()); |
|
|
|
ABLoopItem *abloopItem = MenuItem::create<ABLoopItem>("Set A/B Loop", CHECKMARK(module->abloop)); |
|
|
|
abloopItem->module = module; |
|
|
|
menu->addChild(abloopItem); |
|
|
|
ABLoopItem *abLoopItem = MenuItem::create<ABLoopItem>("Set A/B Loop", CHECKMARK(module->abLoop)); |
|
|
|
abLoopItem->module = module; |
|
|
|
menu->addChild(abLoopItem); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|