@@ -320,6 +320,7 @@ struct BraidsSettingItem : MenuItem { | |||
} | |||
void step() override { | |||
rightText = (*setting == onValue) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
@@ -330,6 +331,7 @@ struct BraidsLowCpuItem : MenuItem { | |||
} | |||
void step() override { | |||
rightText = (braids->lowCpu) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
@@ -121,6 +121,7 @@ BranchesWidget::BranchesWidget() { | |||
addChild(createLight<SmallLight<GreenRedLight>>(Vec(40, 325), module, Branches::STATE2_POS_LIGHT)); | |||
} | |||
struct BranchesModeItem : MenuItem { | |||
Branches *branches; | |||
int channel; | |||
@@ -129,9 +130,11 @@ struct BranchesModeItem : MenuItem { | |||
} | |||
void step() override { | |||
rightText = branches->mode[channel] ? "Toggle" : "Latch"; | |||
MenuItem::step(); | |||
} | |||
}; | |||
Menu *BranchesWidget::createContextMenu() { | |||
Menu *menu = ModuleWidget::createContextMenu(); | |||
@@ -139,6 +142,7 @@ Menu *BranchesWidget::createContextMenu() { | |||
assert(branches); | |||
menu->pushChild(construct<MenuLabel>()); | |||
menu->pushChild(construct<MenuLabel>(&MenuEntry::text, "Channels")); | |||
menu->pushChild(construct<BranchesModeItem>(&MenuEntry::text, "Channel 1 mode", &BranchesModeItem::branches, branches, &BranchesModeItem::channel, 0)); | |||
menu->pushChild(construct<BranchesModeItem>(&MenuEntry::text, "Channel 2 mode", &BranchesModeItem::branches, branches, &BranchesModeItem::channel, 1)); | |||
@@ -3,6 +3,7 @@ | |||
#include "dsp/samplerate.hpp" | |||
#include "dsp/ringbuffer.hpp" | |||
#include "dsp/digital.hpp" | |||
#include "dsp/vumeter.hpp" | |||
#include "clouds/dsp/granular_processor.h" | |||
@@ -63,8 +64,11 @@ struct Clouds : Module { | |||
SchmittTrigger freezeTrigger; | |||
bool freeze = false; | |||
SchmittTrigger modeTrigger; | |||
int modeIndex = 0; | |||
SchmittTrigger blendTrigger; | |||
int blendIndex = 0; | |||
clouds::PlaybackMode playback; | |||
int quality = 0; | |||
Clouds(); | |||
~Clouds(); | |||
@@ -72,7 +76,30 @@ struct Clouds : Module { | |||
void reset() override { | |||
freeze = false; | |||
modeIndex = 0; | |||
blendIndex = 0; | |||
playback = clouds::PLAYBACK_MODE_GRANULAR; | |||
quality = 0; | |||
} | |||
json_t *toJson() override { | |||
json_t *rootJ = json_object(); | |||
json_object_set_new(rootJ, "playback", json_integer((int) playback)); | |||
json_object_set_new(rootJ, "quality", json_integer(quality)); | |||
return rootJ; | |||
} | |||
void fromJson(json_t *rootJ) override { | |||
json_t *playbackJ = json_object_get(rootJ, "playback"); | |||
if (playbackJ) { | |||
playback = (clouds::PlaybackMode) json_integer_value(playbackJ); | |||
} | |||
json_t *qualityJ = json_object_get(rootJ, "quality"); | |||
if (qualityJ) { | |||
quality = json_integer_value(qualityJ); | |||
} | |||
} | |||
}; | |||
@@ -86,6 +113,7 @@ Clouds::Clouds() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||
memset(processor, 0, sizeof(*processor)); | |||
processor->Init(block_mem, memLen, block_ccm, ccmLen); | |||
reset(); | |||
} | |||
Clouds::~Clouds() { | |||
@@ -96,8 +124,8 @@ Clouds::~Clouds() { | |||
void Clouds::step() { | |||
// Get input | |||
Frame<2> inputFrame = {}; | |||
if (!inputBuffer.full()) { | |||
Frame<2> inputFrame; | |||
inputFrame.samples[0] = inputs[IN_L_INPUT].value * params[IN_GAIN_PARAM].value / 5.0; | |||
inputFrame.samples[1] = inputs[IN_R_INPUT].active ? inputs[IN_R_INPUT].value * params[IN_GAIN_PARAM].value / 5.0 : inputFrame.samples[0]; | |||
inputBuffer.push(inputFrame); | |||
@@ -106,8 +134,8 @@ void Clouds::step() { | |||
if (freezeTrigger.process(params[FREEZE_PARAM].value)) { | |||
freeze ^= true; | |||
} | |||
if (modeTrigger.process(params[MODE_PARAM].value)) { | |||
modeIndex = (modeIndex + 1) % 4; | |||
if (blendTrigger.process(params[MODE_PARAM].value)) { | |||
blendIndex = (blendIndex + 1) % 4; | |||
} | |||
// Trigger | |||
@@ -135,16 +163,14 @@ void Clouds::step() { | |||
} | |||
// Set up processor | |||
processor->set_num_channels(2); | |||
processor->set_low_fidelity(false); | |||
// TODO Support the other modes | |||
processor->set_playback_mode(clouds::PLAYBACK_MODE_GRANULAR); | |||
processor->set_playback_mode(playback); | |||
processor->set_quality(quality); | |||
processor->Prepare(); | |||
clouds::Parameters* p = processor->mutable_parameters(); | |||
clouds::Parameters *p = processor->mutable_parameters(); | |||
p->trigger = triggered; | |||
p->gate = triggered; | |||
p->freeze = freeze; | |||
p->freeze = freeze || (inputs[FREEZE_INPUT].value >= 1.0); | |||
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); | |||
@@ -153,6 +179,8 @@ void Clouds::step() { | |||
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; | |||
// TODO | |||
// Why doesn't dry audio get reverbed? | |||
p->reverb = params[REVERB_PARAM].value; | |||
clouds::ShortFrame output[32]; | |||
@@ -174,22 +202,31 @@ 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 | |||
Frame<2> outputFrame = {}; | |||
if (!outputBuffer.empty()) { | |||
Frame<2> outputFrame = outputBuffer.shift(); | |||
outputFrame = outputBuffer.shift(); | |||
outputs[OUT_L_OUTPUT].value = 5.0 * outputFrame.samples[0]; | |||
outputs[OUT_R_OUTPUT].value = 5.0 * outputFrame.samples[1]; | |||
} | |||
// Lights | |||
clouds::Parameters *p = processor->mutable_parameters(); | |||
VUMeter vuMeter; | |||
vuMeter.dBInterval = 6.0; | |||
Frame<2> lightFrame = p->freeze ? outputFrame : inputFrame; | |||
vuMeter.setValue(fmaxf(fabsf(lightFrame.samples[0]), fabsf(lightFrame.samples[1]))); | |||
lights[FREEZE_LIGHT].setBrightness(p->freeze ? 0.75 : 0.0); | |||
lights[MIX_GREEN_LIGHT].setBrightnessSmooth(vuMeter.getBrightness(3)); | |||
lights[PAN_GREEN_LIGHT].setBrightnessSmooth(vuMeter.getBrightness(2)); | |||
lights[FEEDBACK_GREEN_LIGHT].setBrightnessSmooth(vuMeter.getBrightness(1)); | |||
lights[REVERB_GREEN_LIGHT].setBrightness(0.0); | |||
lights[MIX_RED_LIGHT].setBrightness(0.0); | |||
lights[PAN_RED_LIGHT].setBrightness(0.0); | |||
lights[FEEDBACK_RED_LIGHT].setBrightnessSmooth(vuMeter.getBrightness(1)); | |||
lights[REVERB_RED_LIGHT].setBrightnessSmooth(vuMeter.getBrightness(0)); | |||
} | |||
@@ -260,37 +297,78 @@ CloudsWidget::CloudsWidget() { | |||
void CloudsWidget::step() { | |||
Clouds *module = dynamic_cast<Clouds*>(this->module); | |||
blendParam->visible = (module->modeIndex == 0); | |||
spreadParam->visible = (module->modeIndex == 1); | |||
feedbackParam->visible = (module->modeIndex == 2); | |||
reverbParam->visible = (module->modeIndex == 3); | |||
blendParam->visible = (module->blendIndex == 0); | |||
spreadParam->visible = (module->blendIndex == 1); | |||
feedbackParam->visible = (module->blendIndex == 2); | |||
reverbParam->visible = (module->blendIndex == 3); | |||
ModuleWidget::step(); | |||
} | |||
struct CloudsModeItem : MenuItem { | |||
struct CloudsBlendItem : MenuItem { | |||
Clouds *module; | |||
int blendIndex; | |||
void onAction(EventAction &e) override { | |||
module->blendIndex = blendIndex; | |||
} | |||
void step() override { | |||
rightText = (module->blendIndex == blendIndex) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
struct CloudsPlaybackItem : MenuItem { | |||
Clouds *module; | |||
clouds::PlaybackMode playback; | |||
void onAction(EventAction &e) override { | |||
module->playback = playback; | |||
} | |||
void step() override { | |||
rightText = (module->playback == playback) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
struct CloudsQualityItem : MenuItem { | |||
Clouds *module; | |||
int modeIndex; | |||
int quality; | |||
void onAction(EventAction &e) override { | |||
module->modeIndex = modeIndex; | |||
module->quality = quality; | |||
} | |||
void step() override { | |||
rightText = (module->modeIndex == modeIndex) ? "✔" : ""; | |||
rightText = (module->quality == quality) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
Menu *CloudsWidget::createContextMenu() { | |||
Menu *menu = ModuleWidget::createContextMenu(); | |||
Clouds *module = dynamic_cast<Clouds*>(this->module); | |||
menu->pushChild(construct<MenuLabel>()); | |||
menu->pushChild(construct<MenuLabel>(&MenuEntry::text, "Blend knob")); | |||
menu->pushChild(construct<CloudsModeItem>(&MenuEntry::text, "Wet/dry", &CloudsModeItem::module, module, &CloudsModeItem::modeIndex, 0)); | |||
menu->pushChild(construct<CloudsModeItem>(&MenuEntry::text, "Spread", &CloudsModeItem::module, module, &CloudsModeItem::modeIndex, 1)); | |||
menu->pushChild(construct<CloudsModeItem>(&MenuEntry::text, "Feedback", &CloudsModeItem::module, module, &CloudsModeItem::modeIndex, 2)); | |||
menu->pushChild(construct<CloudsModeItem>(&MenuEntry::text, "Reverb", &CloudsModeItem::module, module, &CloudsModeItem::modeIndex, 3)); | |||
menu->pushChild(construct<CloudsBlendItem>(&MenuEntry::text, "Wet/dry", &CloudsBlendItem::module, module, &CloudsBlendItem::blendIndex, 0)); | |||
menu->pushChild(construct<CloudsBlendItem>(&MenuEntry::text, "Spread", &CloudsBlendItem::module, module, &CloudsBlendItem::blendIndex, 1)); | |||
menu->pushChild(construct<CloudsBlendItem>(&MenuEntry::text, "Feedback", &CloudsBlendItem::module, module, &CloudsBlendItem::blendIndex, 2)); | |||
menu->pushChild(construct<CloudsBlendItem>(&MenuEntry::text, "Reverb", &CloudsBlendItem::module, module, &CloudsBlendItem::blendIndex, 3)); | |||
menu->pushChild(construct<MenuLabel>()); | |||
menu->pushChild(construct<MenuLabel>(&MenuEntry::text, "Alternative mode")); | |||
menu->pushChild(construct<CloudsPlaybackItem>(&MenuEntry::text, "Granular", &CloudsPlaybackItem::module, module, &CloudsPlaybackItem::playback, clouds::PLAYBACK_MODE_GRANULAR)); | |||
menu->pushChild(construct<CloudsPlaybackItem>(&MenuEntry::text, "Pitch-shifter/time-stretcher", &CloudsPlaybackItem::module, module, &CloudsPlaybackItem::playback, clouds::PLAYBACK_MODE_STRETCH)); | |||
menu->pushChild(construct<CloudsPlaybackItem>(&MenuEntry::text, "Looping delay", &CloudsPlaybackItem::module, module, &CloudsPlaybackItem::playback, clouds::PLAYBACK_MODE_LOOPING_DELAY)); | |||
menu->pushChild(construct<CloudsPlaybackItem>(&MenuEntry::text, "Spectral madness", &CloudsPlaybackItem::module, module, &CloudsPlaybackItem::playback, clouds::PLAYBACK_MODE_SPECTRAL)); | |||
menu->pushChild(construct<MenuLabel>()); | |||
menu->pushChild(construct<MenuLabel>(&MenuEntry::text, "Quality")); | |||
menu->pushChild(construct<CloudsQualityItem>(&MenuEntry::text, "1s 32kHz 16-bit stereo", &CloudsQualityItem::module, module, &CloudsQualityItem::quality, 0)); | |||
menu->pushChild(construct<CloudsQualityItem>(&MenuEntry::text, "2s 32kHz 16-bit mono", &CloudsQualityItem::module, module, &CloudsQualityItem::quality, 1)); | |||
menu->pushChild(construct<CloudsQualityItem>(&MenuEntry::text, "4s 16kHz 8-bit µ-law stereo", &CloudsQualityItem::module, module, &CloudsQualityItem::quality, 2)); | |||
menu->pushChild(construct<CloudsQualityItem>(&MenuEntry::text, "8s 16kHz 8-bit µ-law mono", &CloudsQualityItem::module, module, &CloudsQualityItem::quality, 3)); | |||
return menu; | |||
} |
@@ -199,7 +199,7 @@ void Elements::step() { | |||
} | |||
// Set lights | |||
lights[GATE_LIGHT].setBrightness(performance.gate ? 0.5 : 0.0); | |||
lights[GATE_LIGHT].setBrightness(performance.gate ? 0.75 : 0.0); | |||
lights[EXCITER_LIGHT].setBrightness(part->exciter_level()); | |||
lights[RESONATOR_LIGHT].setBrightness(part->resonator_level()); | |||
} | |||
@@ -286,10 +286,14 @@ ElementsWidget::ElementsWidget() { | |||
addParam(createParam<CKD6>(Vec(36, 116), module, Elements::PLAY_PARAM, 0.0, 1.0, 0.0)); | |||
ModuleLightWidget *gateLight = createLight<YellowLight>(Vec(36+3, 116+3), module, Elements::GATE_LIGHT); | |||
gateLight->bgColor = COLOR_BLACK_TRANSPARENT; | |||
gateLight->box.size = Vec(28-6, 28-6); | |||
addChild(gateLight); | |||
struct GateLight : YellowLight { | |||
GateLight() { | |||
box.size = Vec(28-6, 28-6); | |||
bgColor = COLOR_BLACK_TRANSPARENT; | |||
} | |||
}; | |||
addChild(createLight<GateLight>(Vec(36+3, 116+3), module, Elements::GATE_LIGHT)); | |||
addChild(createLight<MediumLight<GreenLight>>(Vec(184, 165), module, Elements::EXCITER_LIGHT)); | |||
addChild(createLight<MediumLight<RedLight>>(Vec(395, 165), module, Elements::RESONATOR_LIGHT)); | |||
} | |||
@@ -302,6 +306,7 @@ struct ElementsModalItem : MenuItem { | |||
} | |||
void step() override { | |||
rightText = (elements->getModel() == model) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
@@ -311,7 +316,7 @@ Menu *ElementsWidget::createContextMenu() { | |||
Elements *elements = dynamic_cast<Elements*>(module); | |||
assert(elements); | |||
menu->pushChild(construct<MenuLabel>()); | |||
menu->pushChild(construct<MenuEntry>()); | |||
menu->pushChild(construct<MenuLabel>(&MenuEntry::text, "Alternative models")); | |||
menu->pushChild(construct<ElementsModalItem>(&MenuEntry::text, "Original", &ElementsModalItem::elements, elements, &ElementsModalItem::model, 0)); | |||
menu->pushChild(construct<ElementsModalItem>(&MenuEntry::text, "Non-linear string", &ElementsModalItem::elements, elements, &ElementsModalItem::model, 1)); | |||
@@ -50,7 +50,6 @@ struct Frames : Module { | |||
SchmittTrigger addTrigger; | |||
SchmittTrigger delTrigger; | |||
bool clearKeyframes = false; | |||
Frames(); | |||
void step() override; | |||
@@ -71,7 +70,14 @@ struct Frames : Module { | |||
} | |||
json_object_set_new(rootJ, "keyframes", keyframesJ); | |||
// TODO Channel settings | |||
json_t *channelsJ = json_array(); | |||
for (int i = 0; i < 4; i++) { | |||
json_t *channelJ = json_object(); | |||
json_object_set_new(channelJ, "curve", json_integer((int) keyframer.mutable_settings(i)->easing_curve)); | |||
json_object_set_new(channelJ, "response", json_integer(keyframer.mutable_settings(i)->response)); | |||
json_array_append_new(channelsJ, channelJ); | |||
} | |||
json_object_set_new(rootJ, "channels", channelsJ); | |||
return rootJ; | |||
} | |||
@@ -95,7 +101,18 @@ struct Frames : Module { | |||
} | |||
} | |||
// TODO Channel settings | |||
json_t *channelsJ = json_object_get(rootJ, "channels"); | |||
if (channelsJ) { | |||
for (int i = 0; i < 4; i++) { | |||
json_t *channelJ = json_array_get(channelsJ, i); | |||
if (channelJ) { | |||
json_t *curveJ = json_object_get(channelJ, "curve"); | |||
keyframer.mutable_settings(i)->easing_curve = (frames::EasingCurve) json_integer_value(curveJ); | |||
json_t *responseJ = json_object_get(channelJ, "response"); | |||
keyframer.mutable_settings(i)->response = json_integer_value(responseJ); | |||
} | |||
} | |||
} | |||
} | |||
void reset() override { | |||
@@ -323,9 +340,11 @@ struct FramesCurveItem : MenuItem { | |||
} | |||
void step() override { | |||
rightText = (frames->keyframer.mutable_settings(channel)->easing_curve == curve) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
struct FramesResponseItem : MenuItem { | |||
Frames *frames; | |||
uint8_t channel; | |||
@@ -335,9 +354,11 @@ struct FramesResponseItem : MenuItem { | |||
} | |||
void step() override { | |||
rightText = (frames->keyframer.mutable_settings(channel)->response = response) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
struct FramesChannelSettingsItem : MenuItem { | |||
Frames *frames; | |||
uint8_t channel; | |||
@@ -361,6 +382,7 @@ struct FramesChannelSettingsItem : MenuItem { | |||
} | |||
}; | |||
struct FramesClearItem : MenuItem { | |||
Frames *frames; | |||
void onAction(EventAction &e) override { | |||
@@ -368,6 +390,7 @@ struct FramesClearItem : MenuItem { | |||
} | |||
}; | |||
struct FramesModeItem : MenuItem { | |||
Frames *frames; | |||
bool poly_lfo_mode; | |||
@@ -376,6 +399,7 @@ struct FramesModeItem : MenuItem { | |||
} | |||
void step() override { | |||
rightText = (frames->poly_lfo_mode == poly_lfo_mode) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
@@ -60,11 +60,11 @@ struct Rings : Module { | |||
rings::Strummer strummer; | |||
bool strum = false; | |||
bool lastStrum = false; | |||
SchmittTrigger polyphonyTrigger; | |||
SchmittTrigger modelTrigger; | |||
int polyphonyMode = 0; | |||
int model = 0; | |||
rings::ResonatorModel model = rings::RESONATOR_MODEL_MODAL; | |||
bool easterEgg = false; | |||
Rings(); | |||
@@ -74,7 +74,7 @@ struct Rings : Module { | |||
json_t *rootJ = json_object(); | |||
json_object_set_new(rootJ, "polyphony", json_integer(polyphonyMode)); | |||
json_object_set_new(rootJ, "model", json_integer(model)); | |||
json_object_set_new(rootJ, "model", json_integer((int) model)); | |||
json_object_set_new(rootJ, "easterEgg", json_boolean(easterEgg)); | |||
return rootJ; | |||
@@ -88,7 +88,7 @@ struct Rings : Module { | |||
json_t *modelJ = json_object_get(rootJ, "model"); | |||
if (modelJ) { | |||
model = json_integer_value(modelJ); | |||
model = (rings::ResonatorModel) json_integer_value(modelJ); | |||
} | |||
json_t *easterEggJ = json_object_get(rootJ, "easterEgg"); | |||
@@ -99,12 +99,12 @@ struct Rings : Module { | |||
void reset() override { | |||
polyphonyMode = 0; | |||
model = 0; | |||
model = rings::RESONATOR_MODEL_MODAL; | |||
} | |||
void randomize() override { | |||
polyphonyMode = randomu32() % 3; | |||
model = randomu32() % 3; | |||
model = (rings::ResonatorModel) (randomu32() % 3); | |||
} | |||
}; | |||
@@ -144,10 +144,11 @@ void Rings::step() { | |||
lights[POLYPHONY_RED_LIGHT].value = (polyphonyMode == 1 || polyphonyMode == 2) ? 1.0 : 0.0; | |||
if (modelTrigger.process(params[RESONATOR_PARAM].value)) { | |||
model = (model + 1) % 3; | |||
model = (rings::ResonatorModel) ((model + 1) % 3); | |||
} | |||
lights[RESONATOR_GREEN_LIGHT].value = (model == 0 || model == 1) ? 1.0 : 0.0; | |||
lights[RESONATOR_RED_LIGHT].value = (model == 1 || model == 2) ? 1.0 : 0.0; | |||
int modelColor = model % 3; | |||
lights[RESONATOR_GREEN_LIGHT].value = (modelColor == 0 || modelColor == 1) ? 1.0 : 0.0; | |||
lights[RESONATOR_RED_LIGHT].value = (modelColor == 1 || modelColor == 2) ? 1.0 : 0.0; | |||
// Render frames | |||
if (outputBuffer.empty()) { | |||
@@ -161,11 +162,15 @@ void Rings::step() { | |||
inputBuffer.startIncr(inLen); | |||
} | |||
// Polyphony / model | |||
int polyphony = 1<<polyphonyMode; | |||
// Polyphony | |||
int polyphony = 1 << polyphonyMode; | |||
if (part.polyphony() != polyphony) | |||
part.set_polyphony(polyphony); | |||
part.set_model((rings::ResonatorModel)model); | |||
// Model | |||
if (easterEgg) | |||
string_synth.set_fx((rings::FxType) model); | |||
else | |||
part.set_model(model); | |||
// Patch | |||
rings::Patch patch; | |||
@@ -288,11 +293,23 @@ RingsWidget::RingsWidget() { | |||
addOutput(createOutput<PJ301MPort>(Vec(131, 316), module, Rings::ODD_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(169, 316), module, Rings::EVEN_OUTPUT)); | |||
addChild(createLight<SmallLight<GreenRedLight>>(Vec(38, 43.8), module, Rings::POLYPHONY_GREEN_LIGHT)); | |||
addChild(createLight<SmallLight<GreenRedLight>>(Vec(163, 43.8), module, Rings::RESONATOR_GREEN_LIGHT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(37, 43), module, Rings::POLYPHONY_GREEN_LIGHT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(162, 43), module, Rings::RESONATOR_GREEN_LIGHT)); | |||
} | |||
struct RingsModelItem : MenuItem { | |||
Rings *rings; | |||
rings::ResonatorModel model; | |||
void onAction(EventAction &e) override { | |||
rings->model = model; | |||
} | |||
void step() override { | |||
rightText = (rings->model == model) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
struct RingsEasterEggItem : MenuItem { | |||
Rings *rings; | |||
void onAction(EventAction &e) override { | |||
@@ -300,6 +317,7 @@ struct RingsEasterEggItem : MenuItem { | |||
} | |||
void step() override { | |||
rightText = (rings->easterEgg) ? "✔" : ""; | |||
MenuItem::step(); | |||
} | |||
}; | |||
@@ -309,7 +327,16 @@ Menu *RingsWidget::createContextMenu() { | |||
Rings *rings = dynamic_cast<Rings*>(module); | |||
assert(rings); | |||
menu->pushChild(construct<MenuLabel>()); | |||
menu->pushChild(construct<MenuEntry>()); | |||
menu->pushChild(construct<MenuLabel>(&MenuLabel::text, "Resonator")); | |||
menu->pushChild(construct<RingsModelItem>(&MenuEntry::text, "Modal resonator", &RingsModelItem::rings, rings, &RingsModelItem::model, rings::RESONATOR_MODEL_MODAL)); | |||
menu->pushChild(construct<RingsModelItem>(&MenuEntry::text, "Sympathetic strings", &RingsModelItem::rings, rings, &RingsModelItem::model, rings::RESONATOR_MODEL_SYMPATHETIC_STRING)); | |||
menu->pushChild(construct<RingsModelItem>(&MenuEntry::text, "Modulated/inharmonic string", &RingsModelItem::rings, rings, &RingsModelItem::model, rings::RESONATOR_MODEL_STRING)); | |||
menu->pushChild(construct<RingsModelItem>(&MenuEntry::text, "FM voice", &RingsModelItem::rings, rings, &RingsModelItem::model, rings::RESONATOR_MODEL_FM_VOICE)); | |||
menu->pushChild(construct<RingsModelItem>(&MenuEntry::text, "Quantized sympathetic strings", &RingsModelItem::rings, rings, &RingsModelItem::model, rings::RESONATOR_MODEL_SYMPATHETIC_STRING_QUANTIZED)); | |||
menu->pushChild(construct<RingsModelItem>(&MenuEntry::text, "Reverb string", &RingsModelItem::rings, rings, &RingsModelItem::model, rings::RESONATOR_MODEL_STRING_AND_REVERB)); | |||
menu->pushChild(construct<MenuEntry>()); | |||
menu->pushChild(construct<RingsEasterEggItem>(&MenuEntry::text, "Disastrous Peace", &RingsEasterEggItem::rings, rings)); | |||
return menu; |
@@ -56,6 +56,17 @@ struct Tides : Module { | |||
Tides(); | |||
void step() override; | |||
void reset() override { | |||
generator.set_range(tides::GENERATOR_RANGE_MEDIUM); | |||
generator.set_mode(tides::GENERATOR_MODE_LOOPING); | |||
} | |||
void randomize() override { | |||
generator.set_range((tides::GeneratorRange) (randomu32() % 3)); | |||
generator.set_mode((tides::GeneratorMode) (randomu32() % 3)); | |||
} | |||
json_t *toJson() override { | |||
json_t *rootJ = json_object(); | |||
@@ -76,16 +87,6 @@ struct Tides : Module { | |||
generator.set_range((tides::GeneratorRange) json_integer_value(rangeJ)); | |||
} | |||
} | |||
void reset() override { | |||
generator.set_range(tides::GENERATOR_RANGE_MEDIUM); | |||
generator.set_mode(tides::GENERATOR_MODE_LOOPING); | |||
} | |||
void randomize() override { | |||
generator.set_range((tides::GeneratorRange) (randomu32() % 3)); | |||
generator.set_mode((tides::GeneratorMode) (randomu32() % 3)); | |||
} | |||
}; | |||
@@ -227,9 +228,9 @@ TidesWidget::TidesWidget() { | |||
addOutput(createOutput<PJ301MPort>(Vec(128, 316), module, Tides::UNI_OUTPUT)); | |||
addOutput(createOutput<PJ301MPort>(Vec(164, 316), module, Tides::BI_OUTPUT)); | |||
addChild(createLight<SmallLight<GreenRedLight>>(Vec(57, 62), module, Tides::MODE_GREEN_LIGHT)); | |||
addChild(createLight<SmallLight<GreenRedLight>>(Vec(57, 83), module, Tides::PHASE_GREEN_LIGHT)); | |||
addChild(createLight<SmallLight<GreenRedLight>>(Vec(57, 103), module, Tides::RANGE_GREEN_LIGHT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(56, 61), module, Tides::MODE_GREEN_LIGHT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(56, 82), module, Tides::PHASE_GREEN_LIGHT)); | |||
addChild(createLight<MediumLight<GreenRedLight>>(Vec(56, 102), module, Tides::RANGE_GREEN_LIGHT)); | |||
} | |||