diff --git a/res/Clouds.png b/res/Clouds.png index 7836a7e..979b40e 100644 Binary files a/res/Clouds.png and b/res/Clouds.png differ diff --git a/src/AudibleInstruments.hpp b/src/AudibleInstruments.hpp index 69bdd44..f8da3cc 100644 --- a/src/AudibleInstruments.hpp +++ b/src/AudibleInstruments.hpp @@ -33,7 +33,13 @@ struct StreamsWidget : ModuleWidget { }; struct CloudsWidget : ModuleWidget { + ParamWidget *blendParam; + ParamWidget *spreadParam; + ParamWidget *feedbackParam; + ParamWidget *reverbParam; CloudsWidget(); + void step() override; + Menu *createContextMenu() override; }; struct WarpsWidget : ModuleWidget { diff --git a/src/Clouds.cpp b/src/Clouds.cpp index 14adde2..e7fecd8 100644 --- a/src/Clouds.cpp +++ b/src/Clouds.cpp @@ -2,11 +2,15 @@ #include "AudibleInstruments.hpp" #include "dsp/samplerate.hpp" #include "dsp/ringbuffer.hpp" +#include "dsp/digital.hpp" #include "clouds/dsp/granular_processor.h" struct Clouds : Module { enum ParamIds { + FREEZE_PARAM, + MODE_PARAM, + LOAD_PARAM, POSITION_PARAM, SIZE_PARAM, PITCH_PARAM, @@ -14,6 +18,9 @@ struct Clouds : Module { DENSITY_PARAM, TEXTURE_PARAM, BLEND_PARAM, + SPREAD_PARAM, + FEEDBACK_PARAM, + REVERB_PARAM, NUM_PARAMS }; enum InputIds { @@ -34,6 +41,14 @@ struct Clouds : Module { OUT_R_OUTPUT, NUM_OUTPUTS }; + enum LightIds { + FREEZE_LIGHT, + MIX_GREEN_LIGHT, MIX_RED_LIGHT, + PAN_GREEN_LIGHT, PAN_RED_LIGHT, + FEEDBACK_GREEN_LIGHT, FEEDBACK_RED_LIGHT, + REVERB_GREEN_LIGHT, REVERB_RED_LIGHT, + NUM_LIGHTS + }; SampleRateConverter<2> inputSrc; SampleRateConverter<2> outputSrc; @@ -46,13 +61,23 @@ struct Clouds : Module { bool triggered = false; + SchmittTrigger freezeTrigger; + bool freeze = false; + SchmittTrigger modeTrigger; + int modeIndex = 0; + Clouds(); ~Clouds(); void step() override; + + void reset() override { + freeze = false; + modeIndex = 0; + } }; -Clouds::Clouds() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { +Clouds::Clouds() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { const int memLen = 118784; const int ccmLen = 65536 - 128; block_mem = new uint8_t[memLen](); @@ -78,6 +103,13 @@ void Clouds::step() { inputBuffer.push(inputFrame); } + if (freezeTrigger.process(params[FREEZE_PARAM].value)) { + freeze ^= true; + } + if (modeTrigger.process(params[MODE_PARAM].value)) { + modeIndex = (modeIndex + 1) % 4; + } + // Trigger if (inputs[TRIG_INPUT].value >= 1.0) { triggered = true; @@ -112,17 +144,16 @@ void Clouds::step() { clouds::Parameters* p = processor->mutable_parameters(); p->trigger = triggered; p->gate = triggered; - p->freeze = (inputs[FREEZE_INPUT].value >= 1.0); + p->freeze = freeze; p->position = clampf(params[POSITION_PARAM].value + inputs[POSITION_INPUT].value / 5.0, 0.0, 1.0); p->size = clampf(params[SIZE_PARAM].value + inputs[SIZE_INPUT].value / 5.0, 0.0, 1.0); p->pitch = clampf((params[PITCH_PARAM].value + inputs[PITCH_INPUT].value) * 12.0, -48.0, 48.0); p->density = clampf(params[DENSITY_PARAM].value + inputs[DENSITY_INPUT].value / 5.0, 0.0, 1.0); p->texture = clampf(params[TEXTURE_PARAM].value + inputs[TEXTURE_INPUT].value / 5.0, 0.0, 1.0); - float blend = clampf(params[BLEND_PARAM].value + inputs[BLEND_INPUT].value / 5.0, 0.0, 1.0); - p->dry_wet = blend; - p->stereo_spread = 0.0; - p->feedback = 0.0; - p->reverb = 0.0; + p->dry_wet = clampf(params[BLEND_PARAM].value + inputs[BLEND_INPUT].value / 5.0, 0.0, 1.0); + p->stereo_spread = params[SPREAD_PARAM].value; + p->feedback = params[FEEDBACK_PARAM].value; + p->reverb = params[REVERB_PARAM].value; clouds::ShortFrame output[32]; processor->Process(input, output, 32); @@ -143,6 +174,14 @@ void Clouds::step() { } triggered = false; + + // Lights + lights[FREEZE_LIGHT].value = freeze ? 1.0 : 0.0; + // TODO + lights[MIX_GREEN_LIGHT].value = 1.0; + lights[PAN_GREEN_LIGHT].value = 1.0; + lights[FEEDBACK_GREEN_LIGHT].value = 1.0; + lights[REVERB_GREEN_LIGHT].value = 1.0; } // Set output @@ -171,10 +210,6 @@ CloudsWidget::CloudsWidget() { addChild(createScrew(Vec(15, 365))); addChild(createScrew(Vec(240, 365))); - // TODO - // addParam(createParam(Vec(211, 51), module, Clouds::POSITION_PARAM, 0.0, 1.0, 0.5)); - // addParam(createParam(Vec(239, 51), module, Clouds::POSITION_PARAM, 0.0, 1.0, 0.5)); - addParam(createParam(Vec(27, 93), module, Clouds::POSITION_PARAM, 0.0, 1.0, 0.5)); addParam(createParam(Vec(108, 93), module, Clouds::SIZE_PARAM, 0.0, 1.0, 0.5)); addParam(createParam(Vec(190, 93), module, Clouds::PITCH_PARAM, -2.0, 2.0, 0.0)); @@ -182,7 +217,18 @@ CloudsWidget::CloudsWidget() { addParam(createParam(Vec(14, 180), module, Clouds::IN_GAIN_PARAM, 0.0, 1.0, 0.5)); addParam(createParam(Vec(81, 180), module, Clouds::DENSITY_PARAM, 0.0, 1.0, 0.5)); addParam(createParam(Vec(146, 180), module, Clouds::TEXTURE_PARAM, 0.0, 1.0, 0.5)); - addParam(createParam(Vec(213, 180), module, Clouds::BLEND_PARAM, 0.0, 1.0, 0.5)); + blendParam = createParam(Vec(213, 180), module, Clouds::BLEND_PARAM, 0.0, 1.0, 0.5); + addParam(blendParam); + spreadParam = createParam(Vec(213, 180), module, Clouds::SPREAD_PARAM, 0.0, 1.0, 0.0); + addParam(spreadParam); + feedbackParam = createParam(Vec(213, 180), module, Clouds::FEEDBACK_PARAM, 0.0, 1.0, 0.0); + addParam(feedbackParam); + reverbParam = createParam(Vec(213, 180), module, Clouds::REVERB_PARAM, 0.0, 1.0, 0.0); + addParam(reverbParam); + + addParam(createParam(Vec(12, 43), module, Clouds::FREEZE_PARAM, 0.0, 1.0, 0.0)); + addParam(createParam(Vec(211, 50), module, Clouds::MODE_PARAM, 0.0, 1.0, 0.0)); + addParam(createParam(Vec(239, 50), module, Clouds::LOAD_PARAM, 0.0, 1.0, 0.0)); addInput(createInput(Vec(15, 274), module, Clouds::FREEZE_INPUT)); addInput(createInput(Vec(58, 274), module, Clouds::TRIG_INPUT)); @@ -197,4 +243,54 @@ CloudsWidget::CloudsWidget() { addInput(createInput(Vec(144, 317), module, Clouds::TEXTURE_INPUT)); addOutput(createOutput(Vec(188, 317), module, Clouds::OUT_L_OUTPUT)); addOutput(createOutput(Vec(230, 317), module, Clouds::OUT_R_OUTPUT)); + + struct FreezeLight : YellowLight { + FreezeLight() { + box.size = Vec(28-6, 28-6); + bgColor = COLOR_BLACK_TRANSPARENT; + } + }; + addChild(createLight(Vec(12+3, 43+3), module, Clouds::FREEZE_LIGHT)); + addChild(createLight>(Vec(82.5, 53), module, Clouds::MIX_GREEN_LIGHT)); + addChild(createLight>(Vec(114.5, 53), module, Clouds::PAN_GREEN_LIGHT)); + addChild(createLight>(Vec(145.5, 53), module, Clouds::FEEDBACK_GREEN_LIGHT)); + addChild(createLight>(Vec(177.5, 53), module, Clouds::REVERB_GREEN_LIGHT)); +} + +void CloudsWidget::step() { + Clouds *module = dynamic_cast(this->module); + + blendParam->visible = (module->modeIndex == 0); + spreadParam->visible = (module->modeIndex == 1); + feedbackParam->visible = (module->modeIndex == 2); + reverbParam->visible = (module->modeIndex == 3); + + ModuleWidget::step(); +} + + +struct CloudsModeItem : MenuItem { + Clouds *module; + int modeIndex; + void onAction(EventAction &e) override { + module->modeIndex = modeIndex; + } + void step() override { + rightText = (module->modeIndex == modeIndex) ? "✔" : ""; + } +}; + +Menu *CloudsWidget::createContextMenu() { + Menu *menu = ModuleWidget::createContextMenu(); + + Clouds *module = dynamic_cast(this->module); + + menu->pushChild(construct()); + menu->pushChild(construct(&MenuEntry::text, "Blend knob")); + menu->pushChild(construct(&MenuEntry::text, "Wet/dry", &CloudsModeItem::module, module, &CloudsModeItem::modeIndex, 0)); + menu->pushChild(construct(&MenuEntry::text, "Spread", &CloudsModeItem::module, module, &CloudsModeItem::modeIndex, 1)); + menu->pushChild(construct(&MenuEntry::text, "Feedback", &CloudsModeItem::module, module, &CloudsModeItem::modeIndex, 2)); + menu->pushChild(construct(&MenuEntry::text, "Reverb", &CloudsModeItem::module, module, &CloudsModeItem::modeIndex, 3)); + + return menu; }