|
- #include "plugin.hpp"
- #include "marbles/random/random_generator.h"
- #include "marbles/random/random_stream.h"
- #include "marbles/random/t_generator.h"
- #include "marbles/random/x_y_generator.h"
- #include "marbles/note_filter.h"
-
-
- static const int BLOCK_SIZE = 5;
-
-
- static const marbles::Scale preset_scales[6] = {
- // C major
- {
- 1.0f,
- 12,
- {
- { 0.0000f, 255 }, // C
- { 0.0833f, 16 }, // C#
- { 0.1667f, 96 }, // D
- { 0.2500f, 24 }, // D#
- { 0.3333f, 128 }, // E
- { 0.4167f, 64 }, // F
- { 0.5000f, 8 }, // F#
- { 0.5833f, 192 }, // G
- { 0.6667f, 16 }, // G#
- { 0.7500f, 96 }, // A
- { 0.8333f, 24 }, // A#
- { 0.9167f, 128 }, // B
- }
- },
-
- // C minor
- {
- 1.0f,
- 12,
- {
- { 0.0000f, 255 }, // C
- { 0.0833f, 16 }, // C#
- { 0.1667f, 96 }, // D
- { 0.2500f, 128 }, // Eb
- { 0.3333f, 8 }, // E
- { 0.4167f, 64 }, // F
- { 0.5000f, 4 }, // F#
- { 0.5833f, 192 }, // G
- { 0.6667f, 16 }, // G#
- { 0.7500f, 96 }, // A
- { 0.8333f, 128 }, // Bb
- { 0.9167f, 16 }, // B
- }
- },
-
- // Pentatonic
- {
- 1.0f,
- 12,
- {
- { 0.0000f, 255 }, // C
- { 0.0833f, 4 }, // C#
- { 0.1667f, 96 }, // D
- { 0.2500f, 4 }, // Eb
- { 0.3333f, 4 }, // E
- { 0.4167f, 140 }, // F
- { 0.5000f, 4 }, // F#
- { 0.5833f, 192 }, // G
- { 0.6667f, 4 }, // G#
- { 0.7500f, 96 }, // A
- { 0.8333f, 4 }, // Bb
- { 0.9167f, 4 }, // B
- }
- },
-
- // Pelog
- {
- 1.0f,
- 7,
- {
- { 0.0000f, 255 }, // C
- { 0.1275f, 128 }, // Db+
- { 0.2625f, 32 }, // Eb-
- { 0.4600f, 8 }, // F#-
- { 0.5883f, 192 }, // G
- { 0.7067f, 64 }, // Ab
- { 0.8817f, 16 }, // Bb+
- }
- },
-
- // Raag Bhairav That
- {
- 1.0f,
- 12,
- {
- { 0.0000f, 255 }, // ** Sa
- { 0.0752f, 128 }, // ** Komal Re
- { 0.1699f, 4 }, // Re
- { 0.2630f, 4 }, // Komal Ga
- { 0.3219f, 128 }, // ** Ga
- { 0.4150f, 64 }, // ** Ma
- { 0.4918f, 4 }, // Tivre Ma
- { 0.5850f, 192 }, // ** Pa
- { 0.6601f, 64 }, // ** Komal Dha
- { 0.7549f, 4 }, // Dha
- { 0.8479f, 4 }, // Komal Ni
- { 0.9069f, 64 }, // ** Ni
- }
- },
-
- // Raag Shri
- {
- 1.0f,
- 12,
- {
- { 0.0000f, 255 }, // ** Sa
- { 0.0752f, 4 }, // Komal Re
- { 0.1699f, 128 }, // ** Re
- { 0.2630f, 64 }, // ** Komal Ga
- { 0.3219f, 4 }, // Ga
- { 0.4150f, 128 }, // ** Ma
- { 0.4918f, 4 }, // Tivre Ma
- { 0.5850f, 192 }, // ** Pa
- { 0.6601f, 4 }, // Komal Dha
- { 0.7549f, 64 }, // ** Dha
- { 0.8479f, 128 }, // ** Komal Ni
- { 0.9069f, 4 }, // Ni
- }
- },
- };
-
- static const marbles::Ratio y_divider_ratios[] = {
- { 1, 64 },
- { 1, 48 },
- { 1, 32 },
- { 1, 24 },
- { 1, 16 },
- { 1, 12 },
- { 1, 8 },
- { 1, 6 },
- { 1, 4 },
- { 1, 3 },
- { 1, 2 },
- { 1, 1 },
- };
-
- struct Marbles : Module {
- enum ParamIds {
- T_DEJA_VU_PARAM,
- X_DEJA_VU_PARAM,
- DEJA_VU_PARAM,
- T_RATE_PARAM,
- X_SPREAD_PARAM,
- T_MODE_PARAM,
- X_MODE_PARAM,
- DEJA_VU_LENGTH_PARAM,
- T_BIAS_PARAM,
- X_BIAS_PARAM,
- T_RANGE_PARAM,
- X_RANGE_PARAM,
- EXTERNAL_PARAM,
- T_JITTER_PARAM,
- X_STEPS_PARAM,
- Y_RATE_PARAM,
- Y_SPREAD_PARAM,
- Y_BIAS_PARAM,
- Y_STEPS_PARAM,
- GATE_BIAS_PARAM,
- GATE_JITTER_PARAM,
- NUM_PARAMS
- };
- enum InputIds {
- T_BIAS_INPUT,
- X_BIAS_INPUT,
- T_CLOCK_INPUT,
- T_RATE_INPUT,
- T_JITTER_INPUT,
- DEJA_VU_INPUT,
- X_STEPS_INPUT,
- X_SPREAD_INPUT,
- X_CLOCK_INPUT,
- NUM_INPUTS
- };
- enum OutputIds {
- T1_OUTPUT,
- T2_OUTPUT,
- T3_OUTPUT,
- Y_OUTPUT,
- X1_OUTPUT,
- X2_OUTPUT,
- X3_OUTPUT,
- NUM_OUTPUTS
- };
- enum LightIds {
- T_DEJA_VU_LIGHT,
- X_DEJA_VU_LIGHT,
- ENUMS(T_MODE_LIGHTS, 2),
- ENUMS(X_MODE_LIGHTS, 2),
- ENUMS(T_RANGE_LIGHTS, 2),
- ENUMS(X_RANGE_LIGHTS, 2),
- EXTERNAL_LIGHT,
- T1_LIGHT,
- T2_LIGHT,
- T3_LIGHT,
- Y_LIGHT,
- X1_LIGHT,
- X2_LIGHT,
- X3_LIGHT,
- NUM_LIGHTS
- };
-
- marbles::RandomGenerator random_generator;
- marbles::RandomStream random_stream;
- marbles::TGenerator t_generator;
- marbles::XYGenerator xy_generator;
- marbles::NoteFilter note_filter;
-
- // State
- dsp::BooleanTrigger tDejaVuTrigger;
- dsp::BooleanTrigger xDejaVuTrigger;
- dsp::BooleanTrigger tModeTrigger;
- dsp::BooleanTrigger xModeTrigger;
- dsp::BooleanTrigger tRangeTrigger;
- dsp::BooleanTrigger xRangeTrigger;
- dsp::BooleanTrigger externalTrigger;
- bool t_deja_vu;
- bool x_deja_vu;
- int t_mode;
- int x_mode;
- int t_range;
- int x_range;
- bool external;
- int x_scale;
- int y_divider_index;
- int x_clock_source_internal;
- int edit_mode;
-
- // Buffers
- stmlib::GateFlags t_clocks[BLOCK_SIZE] = {};
- stmlib::GateFlags last_t_clock = 0;
- stmlib::GateFlags xy_clocks[BLOCK_SIZE] = {};
- stmlib::GateFlags last_xy_clock = 0;
- float ramp_master[BLOCK_SIZE] = {};
- float ramp_external[BLOCK_SIZE] = {};
- float ramp_slave[2][BLOCK_SIZE] = {};
- bool gates[BLOCK_SIZE * 2] = {};
- float voltages[BLOCK_SIZE * 4] = {};
- int blockIndex = 0;
-
- Marbles() {
- config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
- configParam(T_DEJA_VU_PARAM, 0.0, 1.0, 0.0, "t deja vu");
- configParam(X_DEJA_VU_PARAM, 0.0, 1.0, 0.0, "X deja vu");
- configParam(DEJA_VU_PARAM, 0.0, 1.0, 0.5, "Deja vu probability");
- configParam(T_RATE_PARAM, -1.0, 1.0, 0.0, "Clock rate");
- configParam(X_SPREAD_PARAM, 0.0, 1.0, 0.5, "Probability distribution");
- configParam(T_MODE_PARAM, 0.0, 1.0, 0.0, "t mode");
- configParam(X_MODE_PARAM, 0.0, 1.0, 0.0, "X mode");
- configParam(DEJA_VU_LENGTH_PARAM, 0.0, 1.0, 0.0, "Loop length");
- configParam(T_BIAS_PARAM, 0.0, 1.0, 0.5, "Gate bias");
- configParam(X_BIAS_PARAM, 0.0, 1.0, 0.5, "Distribution bias");
- configParam(T_RANGE_PARAM, 0.0, 1.0, 0.0, "Clock range mode");
- configParam(X_RANGE_PARAM, 0.0, 1.0, 0.0, "Output voltage range mode");
- configParam(EXTERNAL_PARAM, 0.0, 1.0, 0.0, "External processing mode");
- configParam(T_JITTER_PARAM, 0.0, 1.0, 0.0, "Randomness amount");
- configParam(X_STEPS_PARAM, 0.0, 1.0, 0.5, "Smoothness");
-
- configParam(Y_RATE_PARAM, 0.0, 1.0, 4.5 / LENGTHOF(y_divider_ratios), "Clock divide");
- configParam(Y_SPREAD_PARAM, 0.0, 1.0, 0.5, "Probability distribution");
- configParam(Y_BIAS_PARAM, 0.0, 1.0, 0.5, "Voltage offset");
- configParam(Y_STEPS_PARAM, 0.0, 1.0, 0.0, "Smoothness");
-
- configParam(GATE_BIAS_PARAM, 0.0, 1.0, 0.5, "Gate length");
- configParam(GATE_JITTER_PARAM, 0.0, 1.0, 0.0, "Gate length randomness");
-
- random_generator.Init(1);
- random_stream.Init(&random_generator);
- note_filter.Init();
- onSampleRateChange();
- onReset();
- }
-
- void onReset() override {
- t_deja_vu = false;
- x_deja_vu = false;
- t_mode = 0;
- x_mode = 0;
- t_range = 1;
- x_range = 1;
- external = false;
- x_scale = 0;
- y_divider_index = 4;
- x_clock_source_internal = 0;
- edit_mode = 0;
- }
-
- void onRandomize() override {
- t_mode = random::u32() % 3;
- x_mode = random::u32() % 3;
- t_range = random::u32() % 3;
- x_range = random::u32() % 3;
- }
-
- void onSampleRateChange() override {
- float sampleRate = APP->engine->getSampleRate();
- t_generator.Init(&random_stream, sampleRate);
- xy_generator.Init(&random_stream, sampleRate);
-
- // Set scales
- for (int i = 0; i < 6; i++) {
- xy_generator.LoadScale(i, preset_scales[i]);
- }
- }
-
- json_t* dataToJson() override {
- json_t* rootJ = json_object();
-
- json_object_set_new(rootJ, "t_deja_vu", json_boolean(t_deja_vu));
- json_object_set_new(rootJ, "x_deja_vu", json_boolean(x_deja_vu));
- json_object_set_new(rootJ, "t_mode", json_integer(t_mode));
- json_object_set_new(rootJ, "x_mode", json_integer(x_mode));
- json_object_set_new(rootJ, "t_range", json_integer(t_range));
- json_object_set_new(rootJ, "x_range", json_integer(x_range));
- json_object_set_new(rootJ, "external", json_boolean(external));
- json_object_set_new(rootJ, "x_scale", json_integer(x_scale));
- json_object_set_new(rootJ, "y_divider_index", json_integer(y_divider_index));
- json_object_set_new(rootJ, "x_clock_source_internal", json_integer(x_clock_source_internal));
- json_object_set_new(rootJ, "edit_mode", json_integer(edit_mode));
-
- return rootJ;
- }
-
- void dataFromJson(json_t* rootJ) override {
- json_t* t_deja_vuJ = json_object_get(rootJ, "t_deja_vu");
- if (t_deja_vuJ)
- t_deja_vu = json_boolean_value(t_deja_vuJ);
-
- json_t* x_deja_vuJ = json_object_get(rootJ, "x_deja_vu");
- if (x_deja_vuJ)
- x_deja_vu = json_boolean_value(x_deja_vuJ);
-
- json_t* t_modeJ = json_object_get(rootJ, "t_mode");
- if (t_modeJ)
- t_mode = json_integer_value(t_modeJ);
-
- json_t* x_modeJ = json_object_get(rootJ, "x_mode");
- if (x_modeJ)
- x_mode = json_integer_value(x_modeJ);
-
- json_t* t_rangeJ = json_object_get(rootJ, "t_range");
- if (t_rangeJ)
- t_range = json_integer_value(t_rangeJ);
-
- json_t* x_rangeJ = json_object_get(rootJ, "x_range");
- if (x_rangeJ)
- x_range = json_integer_value(x_rangeJ);
-
- json_t* externalJ = json_object_get(rootJ, "external");
- if (externalJ)
- external = json_boolean_value(externalJ);
-
- json_t* x_scaleJ = json_object_get(rootJ, "x_scale");
- if (x_scaleJ)
- x_scale = json_integer_value(x_scaleJ);
-
- json_t* y_divider_indexJ = json_object_get(rootJ, "y_divider_index");
- if (y_divider_indexJ)
- y_divider_index = json_integer_value(y_divider_indexJ);
-
- json_t* x_clock_source_internalJ = json_object_get(rootJ, "x_clock_source_internal");
- if (x_clock_source_internalJ)
- x_clock_source_internal = json_integer_value(x_clock_source_internalJ);
-
- json_t* edit_modeJ = json_object_get(rootJ, "edit_mode");
- if (edit_modeJ)
- edit_mode = json_boolean_value(edit_modeJ);
- }
-
- void process(const ProcessArgs& args) override {
- // Buttons
- if (tDejaVuTrigger.process(params[T_DEJA_VU_PARAM].getValue() <= 0.f)) {
- t_deja_vu = !t_deja_vu;
- }
- if (xDejaVuTrigger.process(params[X_DEJA_VU_PARAM].getValue() <= 0.f)) {
- x_deja_vu = !x_deja_vu;
- }
- if (tModeTrigger.process(params[T_MODE_PARAM].getValue() <= 0.f)) {
- t_mode = (t_mode + 1) % 3;
- }
- if (xModeTrigger.process(params[X_MODE_PARAM].getValue() <= 0.f)) {
- x_mode = (x_mode + 1) % 3;
- }
- if (tRangeTrigger.process(params[T_RANGE_PARAM].getValue() <= 0.f)) {
- t_range = (t_range + 1) % 3;
- }
- if (xRangeTrigger.process(params[X_RANGE_PARAM].getValue() <= 0.f)) {
- x_range = (x_range + 1) % 3;
- }
- if (externalTrigger.process(params[EXTERNAL_PARAM].getValue() <= 0.f)) {
- external = !external;
- }
-
- // Clocks
- bool t_gate = (inputs[T_CLOCK_INPUT].getVoltage() >= 1.7f);
- last_t_clock = stmlib::ExtractGateFlags(last_t_clock, t_gate);
- t_clocks[blockIndex] = last_t_clock;
-
- bool x_gate = (inputs[X_CLOCK_INPUT].getVoltage() >= 1.7f);
- last_xy_clock = stmlib::ExtractGateFlags(last_xy_clock, x_gate);
- xy_clocks[blockIndex] = last_xy_clock;
-
- // Process block
- if (++blockIndex >= BLOCK_SIZE) {
- blockIndex = 0;
- stepBlock();
- }
-
- // Lights and outputs
-
- lights[T_DEJA_VU_LIGHT].setBrightness(t_deja_vu);
- lights[X_DEJA_VU_LIGHT].setBrightness(x_deja_vu);
-
- lights[T_MODE_LIGHTS + 0].setBrightness(t_mode == 0 || t_mode == 1);
- lights[T_MODE_LIGHTS + 1].setBrightness(t_mode == 1 || t_mode == 2);
-
- lights[X_MODE_LIGHTS + 0].setBrightness(x_mode == 0 || x_mode == 1);
- lights[X_MODE_LIGHTS + 1].setBrightness(x_mode == 1 || x_mode == 2);
-
- lights[T_RANGE_LIGHTS + 0].setBrightness(t_range == 0 || t_range == 1);
- lights[T_RANGE_LIGHTS + 1].setBrightness(t_range == 1 || t_range == 2);
-
- lights[X_RANGE_LIGHTS + 0].setBrightness(x_range == 0 || x_range == 1);
- lights[X_RANGE_LIGHTS + 1].setBrightness(x_range == 1 || x_range == 2);
-
- lights[EXTERNAL_LIGHT].setBrightness(external);
-
- outputs[T1_OUTPUT].setVoltage(gates[blockIndex * 2 + 0] ? 10.f : 0.f);
- lights[T1_LIGHT].setSmoothBrightness(gates[blockIndex * 2 + 0], args.sampleTime);
- outputs[T2_OUTPUT].setVoltage((ramp_master[blockIndex] < 0.5f) ? 10.f : 0.f);
- lights[T2_LIGHT].setSmoothBrightness(ramp_master[blockIndex] < 0.5f, args.sampleTime);
- outputs[T3_OUTPUT].setVoltage(gates[blockIndex * 2 + 1] ? 10.f : 0.f);
- lights[T3_LIGHT].setSmoothBrightness(gates[blockIndex * 2 + 1], args.sampleTime);
-
- outputs[X1_OUTPUT].setVoltage(voltages[blockIndex * 4 + 0]);
- lights[X1_LIGHT].setSmoothBrightness(voltages[blockIndex * 4 + 0], args.sampleTime);
- outputs[X2_OUTPUT].setVoltage(voltages[blockIndex * 4 + 1]);
- lights[X2_LIGHT].setSmoothBrightness(voltages[blockIndex * 4 + 1], args.sampleTime);
- outputs[X3_OUTPUT].setVoltage(voltages[blockIndex * 4 + 2]);
- lights[X3_LIGHT].setSmoothBrightness(voltages[blockIndex * 4 + 2], args.sampleTime);
- outputs[Y_OUTPUT].setVoltage(voltages[blockIndex * 4 + 3]);
- lights[Y_LIGHT].setSmoothBrightness(voltages[blockIndex * 4 + 3], args.sampleTime);
- }
-
- void stepBlock() {
- // Ramps
-
- marbles::Ramps ramps;
- ramps.master = ramp_master;
- ramps.external = ramp_external;
- ramps.slave[0] = ramp_slave[0];
- ramps.slave[1] = ramp_slave[1];
-
- float deja_vu = clamp(params[DEJA_VU_PARAM].getValue() + inputs[DEJA_VU_INPUT].getVoltage() / 5.f, 0.f, 1.f);
- static const int loop_length[] = {
- 1, 1, 1, 2, 2,
- 2, 2, 2, 3, 3,
- 3, 3, 4, 4, 4,
- 4, 4, 5, 5, 6,
- 6, 6, 7, 7, 8,
- 8, 8, 10, 10, 12,
- 12, 12, 14, 14, 16,
- 16
- };
- float deja_vu_length_index = params[DEJA_VU_LENGTH_PARAM].getValue() * (LENGTHOF(loop_length) - 1);
- int deja_vu_length = loop_length[(int) roundf(deja_vu_length_index)];
-
- // Set up TGenerator
-
- bool t_external_clock = inputs[T_CLOCK_INPUT].isConnected();
-
- t_generator.set_model((marbles::TGeneratorModel) t_mode);
- t_generator.set_range((marbles::TGeneratorRange) t_range);
- float t_rate = 60.f * (params[T_RATE_PARAM].getValue() + inputs[T_RATE_INPUT].getVoltage() / 5.f);
- t_generator.set_rate(t_rate);
- float t_bias = clamp(params[T_BIAS_PARAM].getValue() + inputs[T_BIAS_INPUT].getVoltage() / 5.f, 0.f, 1.f);
- t_generator.set_bias(t_bias);
- float t_jitter = clamp(params[T_JITTER_PARAM].getValue() + inputs[T_JITTER_INPUT].getVoltage() / 5.f, 0.f, 1.f);
- t_generator.set_jitter(t_jitter);
- t_generator.set_deja_vu(t_deja_vu ? deja_vu : 0.f);
- t_generator.set_length(deja_vu_length);
- t_generator.set_pulse_width_mean(params[GATE_BIAS_PARAM].getValue());
- t_generator.set_pulse_width_std(params[GATE_JITTER_PARAM].getValue());
-
- t_generator.Process(t_external_clock, t_clocks, ramps, gates, BLOCK_SIZE);
-
- // Set up XYGenerator
-
- marbles::ClockSource x_clock_source = (marbles::ClockSource) x_clock_source_internal;
- if (inputs[X_CLOCK_INPUT].isConnected())
- x_clock_source = marbles::CLOCK_SOURCE_EXTERNAL;
-
- marbles::GroupSettings x;
- x.control_mode = (marbles::ControlMode) x_mode;
- x.voltage_range = (marbles::VoltageRange) x_range;
- // TODO Fix the scaling
- float note_cv = 0.5f * (params[X_SPREAD_PARAM].getValue() + inputs[X_SPREAD_INPUT].getVoltage() / 5.f);
- float u = note_filter.Process(0.5f * (note_cv + 1.f));
- x.register_mode = external;
- x.register_value = u;
-
- float x_spread = clamp(params[X_SPREAD_PARAM].getValue() + inputs[X_SPREAD_INPUT].getVoltage() / 5.f, 0.f, 1.f);
- x.spread = x_spread;
- float x_bias = clamp(params[X_BIAS_PARAM].getValue() + inputs[X_BIAS_INPUT].getVoltage() / 5.f, 0.f, 1.f);
- x.bias = x_bias;
- float x_steps = clamp(params[X_STEPS_PARAM].getValue() + inputs[X_STEPS_INPUT].getVoltage() / 5.f, 0.f, 1.f);
- x.steps = x_steps;
- x.deja_vu = x_deja_vu ? deja_vu : 0.f;
- x.length = deja_vu_length;
- x.ratio.p = 1;
- x.ratio.q = 1;
- x.scale_index = x_scale;
-
- marbles::GroupSettings y;
- y.control_mode = marbles::CONTROL_MODE_IDENTICAL;
- y.voltage_range = marbles::VOLTAGE_RANGE_FULL;
- y.register_mode = false;
- y.register_value = 0.0f;
- y.spread = params[Y_SPREAD_PARAM].getValue();
- y.bias = params[Y_BIAS_PARAM].getValue();
- y.steps = params[Y_STEPS_PARAM].getValue();
- y.deja_vu = 0.0f;
- y.length = 1;
-
- uint index = (uint) (params[Y_RATE_PARAM].getValue() * LENGTHOF(y_divider_ratios));
- if (index < LENGTHOF(y_divider_ratios))
- y_divider_index = index;
- y.ratio = y_divider_ratios[y_divider_index];
- y.scale_index = x_scale;
-
- xy_generator.Process(x_clock_source, x, y, xy_clocks, ramps, voltages, BLOCK_SIZE);
- }
- };
-
-
- template <typename BASE>
- struct CKD6Light : BASE {
- CKD6Light() {
- this->box.size = Vec(22, 22);
- }
- };
-
-
- struct MarblesWidget : ModuleWidget {
- ParamWidget* yRateParam;
- ParamWidget* ySpreadParam;
- ParamWidget* yBiasParam;
- ParamWidget* yStepsParam;
-
- ParamWidget* gateBiasParam;
- ParamWidget* gateJitterParam;
-
- MarblesWidget(Marbles* module) {
- setModule(module);
- setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Marbles.svg")));
-
- addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0)));
- addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0)));
- addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
- addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
-
- addParam(createParamCentered<CKD6>(mm2px(Vec(16.545, 17.794)), module, Marbles::T_DEJA_VU_PARAM));
- addParam(createParamCentered<CKD6>(mm2px(Vec(74.845, 17.794)), module, Marbles::X_DEJA_VU_PARAM));
- addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(45.695, 22.244)), module, Marbles::DEJA_VU_PARAM));
- addParam(createParamCentered<Rogan3PSWhite>(mm2px(Vec(23.467, 35.264)), module, Marbles::T_RATE_PARAM));
- addParam(createParamCentered<Rogan3PSWhite>(mm2px(Vec(67.945, 35.243)), module, Marbles::X_SPREAD_PARAM));
- addParam(createParamCentered<TL1105>(mm2px(Vec(6.945, 38.794)), module, Marbles::T_MODE_PARAM));
- addParam(createParamCentered<TL1105>(mm2px(Vec(84.445, 38.793)), module, Marbles::X_MODE_PARAM));
- addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(45.695, 51.144)), module, Marbles::DEJA_VU_LENGTH_PARAM));
- addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(9.545, 58.394)), module, Marbles::T_BIAS_PARAM));
- addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(81.844, 58.394)), module, Marbles::X_BIAS_PARAM));
- addParam(createParamCentered<TL1105>(mm2px(Vec(26.644, 59.694)), module, Marbles::T_RANGE_PARAM));
- addParam(createParamCentered<TL1105>(mm2px(Vec(64.744, 59.694)), module, Marbles::X_RANGE_PARAM));
- addParam(createParamCentered<TL1105>(mm2px(Vec(45.694, 67.294)), module, Marbles::EXTERNAL_PARAM));
- addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(31.544, 73.694)), module, Marbles::T_JITTER_PARAM));
- addParam(createParamCentered<Rogan2PSWhite>(mm2px(Vec(59.845, 73.694)), module, Marbles::X_STEPS_PARAM));
-
- // Knobs for Y generator edit mode
- yRateParam = createParamCentered<Rogan3PSGreen>(mm2px(Vec(23.467, 35.264)), module, Marbles::Y_RATE_PARAM);
- addParam(yRateParam);
- ySpreadParam = createParamCentered<Rogan3PSGreen>(mm2px(Vec(67.945, 35.243)), module, Marbles::Y_SPREAD_PARAM);
- addParam(ySpreadParam);
- yBiasParam = createParamCentered<Rogan2PSGreen>(mm2px(Vec(81.844, 58.394)), module, Marbles::Y_BIAS_PARAM);
- addParam(yBiasParam);
- yStepsParam = createParamCentered<Rogan2PSGreen>(mm2px(Vec(59.845, 73.694)), module, Marbles::Y_STEPS_PARAM);
- addParam(yStepsParam);
-
- // Make colored knobs not visible in module browser
- yRateParam->visible = false;
- ySpreadParam->visible = false;
- yBiasParam->visible = false;
- yStepsParam->visible = false;
-
- // Knobs for gate edit mode
- gateBiasParam = createParamCentered<Rogan2PSRed>(mm2px(Vec(9.545, 58.394)), module, Marbles::GATE_BIAS_PARAM);
- addParam(gateBiasParam);
- gateJitterParam = createParamCentered<Rogan2PSRed>(mm2px(Vec(31.544, 73.694)), module, Marbles::GATE_JITTER_PARAM);
- addParam(gateJitterParam);
-
- // Make colored knobs not visible in module browser
- gateBiasParam->visible = false;
- gateJitterParam->visible = false;
-
- addInput(createInputCentered<PJ301MPort>(mm2px(Vec(9.545, 81.944)), module, Marbles::T_BIAS_INPUT));
- addInput(createInputCentered<PJ301MPort>(mm2px(Vec(81.844, 81.944)), module, Marbles::X_BIAS_INPUT));
- addInput(createInputCentered<PJ301MPort>(mm2px(Vec(9.545, 96.544)), module, Marbles::T_CLOCK_INPUT));
- addInput(createInputCentered<PJ301MPort>(mm2px(Vec(21.595, 96.544)), module, Marbles::T_RATE_INPUT));
- addInput(createInputCentered<PJ301MPort>(mm2px(Vec(33.644, 96.544)), module, Marbles::T_JITTER_INPUT));
- addInput(createInputCentered<PJ301MPort>(mm2px(Vec(45.695, 96.544)), module, Marbles::DEJA_VU_INPUT));
- addInput(createInputCentered<PJ301MPort>(mm2px(Vec(57.745, 96.544)), module, Marbles::X_STEPS_INPUT));
- addInput(createInputCentered<PJ301MPort>(mm2px(Vec(69.795, 96.544)), module, Marbles::X_SPREAD_INPUT));
- addInput(createInputCentered<PJ301MPort>(mm2px(Vec(81.844, 96.544)), module, Marbles::X_CLOCK_INPUT));
-
- addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(9.545, 111.144)), module, Marbles::T1_OUTPUT));
- addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(21.595, 111.144)), module, Marbles::T2_OUTPUT));
- addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(33.644, 111.144)), module, Marbles::T3_OUTPUT));
- addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(45.695, 111.144)), module, Marbles::Y_OUTPUT));
- addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(57.745, 111.144)), module, Marbles::X1_OUTPUT));
- addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(69.795, 111.144)), module, Marbles::X2_OUTPUT));
- addOutput(createOutputCentered<PJ301MPort>(mm2px(Vec(81.844, 111.144)), module, Marbles::X3_OUTPUT));
-
- addChild(createLightCentered<CKD6Light<GreenLight>>(mm2px(Vec(16.545, 17.794)), module, Marbles::T_DEJA_VU_LIGHT));
- addChild(createLightCentered<CKD6Light<GreenLight>>(mm2px(Vec(74.845, 17.794)), module, Marbles::X_DEJA_VU_LIGHT));
- addChild(createLightCentered<MediumLight<GreenRedLight>>(mm2px(Vec(6.944, 29.894)), module, Marbles::T_MODE_LIGHTS));
- addChild(createLightCentered<MediumLight<GreenRedLight>>(mm2px(Vec(84.444, 29.894)), module, Marbles::X_MODE_LIGHTS));
- addChild(createLightCentered<MediumLight<GreenRedLight>>(mm2px(Vec(26.644, 53.994)), module, Marbles::T_RANGE_LIGHTS));
- addChild(createLightCentered<MediumLight<GreenRedLight>>(mm2px(Vec(64.744, 53.994)), module, Marbles::X_RANGE_LIGHTS));
- addChild(createLightCentered<MediumLight<GreenLight>>(mm2px(Vec(45.695, 76.194)), module, Marbles::EXTERNAL_LIGHT));
- addChild(createLightCentered<MediumLight<GreenLight>>(mm2px(Vec(6.044, 104.794)), module, Marbles::T1_LIGHT));
- addChild(createLightCentered<MediumLight<GreenLight>>(mm2px(Vec(18.094, 104.794)), module, Marbles::T2_LIGHT));
- addChild(createLightCentered<MediumLight<GreenLight>>(mm2px(Vec(30.145, 104.794)), module, Marbles::T3_LIGHT));
- addChild(createLightCentered<MediumLight<GreenLight>>(mm2px(Vec(42.194, 104.794)), module, Marbles::Y_LIGHT));
- addChild(createLightCentered<MediumLight<GreenLight>>(mm2px(Vec(54.244, 104.794)), module, Marbles::X1_LIGHT));
- addChild(createLightCentered<MediumLight<GreenLight>>(mm2px(Vec(66.294, 104.794)), module, Marbles::X2_LIGHT));
- addChild(createLightCentered<MediumLight<GreenLight>>(mm2px(Vec(78.344, 104.794)), module, Marbles::X3_LIGHT));
- }
-
- void step() override {
- Marbles *module = dynamic_cast<Marbles *>(this->module);
-
- if (module) {
- yRateParam->visible = (module->edit_mode == 1);
- ySpreadParam->visible = (module->edit_mode == 1);
- yBiasParam->visible = (module->edit_mode == 1);
- yStepsParam->visible = (module->edit_mode == 1);
-
- gateBiasParam->visible = (module->edit_mode == 2);
- gateJitterParam->visible = (module->edit_mode == 2);
- }
-
- ModuleWidget::step();
- }
-
- void appendContextMenu(Menu* menu) override {
- Marbles* module = dynamic_cast<Marbles*>(this->module);
-
- struct ScaleItem : MenuItem {
- Marbles* module;
- int scale;
- void onAction(const event::Action& e) override {
- module->x_scale = scale;
- }
- };
-
- menu->addChild(new MenuSeparator);
- menu->addChild(createMenuLabel("Scales"));
- const std::string scaleLabels[] = {
- "Major",
- "Minor",
- "Pentatonic",
- "Pelog",
- "Raag Bhairav That",
- "Raag Shri",
- };
- for (int i = 0; i < (int) LENGTHOF(scaleLabels); i++) {
- ScaleItem* item = createMenuItem<ScaleItem>(scaleLabels[i], CHECKMARK(module->x_scale == i));
- item->module = module;
- item->scale = i;
- menu->addChild(item);
- }
-
- struct XClockSourceInternal : MenuItem {
- Marbles* module;
- int source;
- void onAction(const event::Action& e) override {
- module->x_clock_source_internal = source;
- }
- };
-
- menu->addChild(new MenuSeparator);
- menu->addChild(createMenuLabel("Internal X clock source"));
- const std::string sourceLabels[] = {
- "T₁ → X₁, T₂ → X₂, T₃ → X₃",
- "T₁ → X₁, X₂, X₃",
- "T₂ → X₁, X₂, X₃",
- "T₃ → X₁, X₂, X₃",
- };
- for (int i = 0; i < (int) LENGTHOF(sourceLabels); i++) {
- XClockSourceInternal* item = createMenuItem<XClockSourceInternal>(sourceLabels[i], CHECKMARK(module->x_clock_source_internal == i));
- item->module = module;
- item->source = i;
- menu->addChild(item);
- }
-
- struct YDividerIndexItem : MenuItem {
- Marbles* module;
- int index;
- void onAction(const event::Action& e) override {
- module->y_divider_index = index;
- module->params[module->Y_RATE_PARAM].setValue(index / LENGTHOF(y_divider_ratios));
- }
- };
-
- struct YDividerItem : MenuItem {
- Marbles* module;
- Menu* createChildMenu() override {
- Menu* menu = new Menu();
- const std::string yDividerRatioLabels[] = {
- "1/64",
- "1/48",
- "1/32",
- "1/24",
- "1/16",
- "1/12",
- "1/8",
- "1/6",
- "1/4",
- "1/3",
- "1/2",
- "1",
- };
- for (int i = 0; i < (int) LENGTHOF(yDividerRatioLabels); i++) {
- YDividerIndexItem* item = createMenuItem<YDividerIndexItem>(yDividerRatioLabels[i], CHECKMARK(module->y_divider_index == i));
- item->module = module;
- item->index = i;
- menu->addChild(item);
- }
- return menu;
- }
- };
-
- menu->addChild(new MenuSeparator);
- YDividerItem* yDividerItem = createMenuItem<YDividerItem>("Y divider ratio");
- yDividerItem->module = module;
- menu->addChild(yDividerItem);
-
- struct MarblesEditModeItem : MenuItem {
- Marbles *module;
- int editMode;
- void onAction(const event::Action& e) override {
- module->edit_mode = editMode;
- }
- void step() override {
- rightText = (module->edit_mode == editMode) ? "✔" : "";
- MenuItem::step();
- }
- };
-
- menu->addChild(new MenuSeparator);
- menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Edit Mode"));
-
- menu->addChild(construct<MarblesEditModeItem>(&MenuItem::text, "Default", &MarblesEditModeItem::module, module, &MarblesEditModeItem::editMode, 0));
- menu->addChild(construct<MarblesEditModeItem>(&MenuItem::text, "Y generator", &MarblesEditModeItem::module, module, &MarblesEditModeItem::editMode, 1));
- menu->addChild(construct<MarblesEditModeItem>(&MenuItem::text, "Gate", &MarblesEditModeItem::module, module, &MarblesEditModeItem::editMode, 2));
- }
- };
-
-
- Model* modelMarbles = createModel<Marbles, MarblesWidget>("Marbles");
|