|
|
@@ -54,13 +54,13 @@ struct Braids : Module { |
|
|
|
configInput(COLOR_INPUT, "Color"); |
|
|
|
configOutput(OUT_OUTPUT, "Audio"); |
|
|
|
|
|
|
|
memset(&osc, 0, sizeof(osc)); |
|
|
|
std::memset(&osc, 0, sizeof(osc)); |
|
|
|
osc.Init(); |
|
|
|
memset(&jitter_source, 0, sizeof(jitter_source)); |
|
|
|
std::memset(&jitter_source, 0, sizeof(jitter_source)); |
|
|
|
jitter_source.Init(); |
|
|
|
memset(&ws, 0, sizeof(ws)); |
|
|
|
std::memset(&ws, 0, sizeof(ws)); |
|
|
|
ws.Init(0x0000); |
|
|
|
memset(&settings, 0, sizeof(settings)); |
|
|
|
std::memset(&settings, 0, sizeof(settings)); |
|
|
|
|
|
|
|
// List of supported settings |
|
|
|
settings.meta_modulation = 0; |
|
|
@@ -81,9 +81,9 @@ struct Braids : Module { |
|
|
|
float fm = params[FM_PARAM].getValue() * inputs[FM_INPUT].getVoltage(); |
|
|
|
|
|
|
|
// Set shape |
|
|
|
int shape = roundf(params[SHAPE_PARAM].getValue() * braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META); |
|
|
|
int shape = std::round(params[SHAPE_PARAM].getValue() * braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META); |
|
|
|
if (settings.meta_modulation) { |
|
|
|
shape += roundf(fm / 10.0 * braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META); |
|
|
|
shape += std::round(fm / 10.0 * braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META); |
|
|
|
} |
|
|
|
settings.shape = clamp(shape, 0, braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META); |
|
|
|
|
|
|
@@ -102,7 +102,7 @@ struct Braids : Module { |
|
|
|
if (!settings.meta_modulation) |
|
|
|
pitchV += fm; |
|
|
|
if (lowCpu) |
|
|
|
pitchV += log2f(96000.f * args.sampleTime); |
|
|
|
pitchV += std::log2(96000.f * args.sampleTime); |
|
|
|
int32_t pitch = (pitchV * 12.0 + 60) * 128; |
|
|
|
pitch += jitter_source.Render(settings.vco_drift); |
|
|
|
pitch = clamp(pitch, 0, 16383); |
|
|
@@ -184,62 +184,73 @@ struct Braids : Module { |
|
|
|
lowCpu = json_boolean_value(lowCpuJ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
int getShapeParam() { |
|
|
|
return std::round(params[SHAPE_PARAM].getValue() * braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META); |
|
|
|
} |
|
|
|
void setShapeParam(int shape) { |
|
|
|
params[SHAPE_PARAM].setValue(shape / (float) braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct ShapeInfo { |
|
|
|
std::string code; |
|
|
|
std::string label; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static const char* algo_values[] = { |
|
|
|
"CSAW", |
|
|
|
"/\\-_", |
|
|
|
"//-_", |
|
|
|
"FOLD", |
|
|
|
"uuuu", |
|
|
|
"SUB-", |
|
|
|
"SUB/", |
|
|
|
"SYN-", |
|
|
|
"SYN/", |
|
|
|
"//x3", |
|
|
|
"-_x3", |
|
|
|
"/\\x3", |
|
|
|
"SIx3", |
|
|
|
"RING", |
|
|
|
"////", |
|
|
|
"//uu", |
|
|
|
"TOY*", |
|
|
|
"ZLPF", |
|
|
|
"ZPKF", |
|
|
|
"ZBPF", |
|
|
|
"ZHPF", |
|
|
|
"VOSM", |
|
|
|
"VOWL", |
|
|
|
"VFOF", |
|
|
|
"HARM", |
|
|
|
"FM ", |
|
|
|
"FBFM", |
|
|
|
"WTFM", |
|
|
|
"PLUK", |
|
|
|
"BOWD", |
|
|
|
"BLOW", |
|
|
|
"FLUT", |
|
|
|
"BELL", |
|
|
|
"DRUM", |
|
|
|
"KICK", |
|
|
|
"CYMB", |
|
|
|
"SNAR", |
|
|
|
"WTBL", |
|
|
|
"WMAP", |
|
|
|
"WLIN", |
|
|
|
"WTx4", |
|
|
|
"NOIS", |
|
|
|
"TWNQ", |
|
|
|
"CLKN", |
|
|
|
"CLOU", |
|
|
|
"PRTC", |
|
|
|
"QPSK", |
|
|
|
" ", |
|
|
|
static const std::vector<ShapeInfo> SHAPE_INFOS = { |
|
|
|
{"CSAW", "Quirky sawtooth"}, |
|
|
|
{"/\\-_", "Triangle to saw"}, |
|
|
|
{"//-_", "Sawtooth wave with dephasing"}, |
|
|
|
{"FOLD", "Wavefolded sine/triangle"}, |
|
|
|
{"uuuu", "Buzz"}, |
|
|
|
{"SUB-", "Square sub"}, |
|
|
|
{"SUB/", "Saw sub"}, |
|
|
|
{"SYN-", "Square sync"}, |
|
|
|
{"SYN/", "Saw sync"}, |
|
|
|
{"//x3", "Triple saw"}, |
|
|
|
{"-_x3", "Triple square"}, |
|
|
|
{"/\\x3", "Triple triangle"}, |
|
|
|
{"SIx3", "Triple sine"}, |
|
|
|
{"RING", "Triple ring mod"}, |
|
|
|
{"////", "Saw swarm"}, |
|
|
|
{"//uu", "Saw comb"}, |
|
|
|
{"TOY*", "Circuit-bent toy"}, |
|
|
|
{"ZLPF", "Low-pass filtered waveform"}, |
|
|
|
{"ZPKF", "Peak filtered waveform"}, |
|
|
|
{"ZBPF", "Band-pass filtered waveform"}, |
|
|
|
{"ZHPF", "High-pass filtered waveform"}, |
|
|
|
{"VOSM", "VOSIM formant"}, |
|
|
|
{"VOWL", "Speech synthesis"}, |
|
|
|
{"VFOF", "FOF speech synthesis"}, |
|
|
|
{"HARM", "12 sine harmonics"}, |
|
|
|
{"FM ", "2-operator phase-modulation"}, |
|
|
|
{"FBFM", "2-operator phase-modulation with feedback"}, |
|
|
|
{"WTFM", "2-operator phase-modulation with chaotic feedback"}, |
|
|
|
{"PLUK", "Plucked string"}, |
|
|
|
{"BOWD", "Bowed string"}, |
|
|
|
{"BLOW", "Blown reed"}, |
|
|
|
{"FLUT", "Flute"}, |
|
|
|
{"BELL", "Bell"}, |
|
|
|
{"DRUM", "Drum"}, |
|
|
|
{"KICK", "Kick drum circuit simulation"}, |
|
|
|
{"CYMB", "Cymbal"}, |
|
|
|
{"SNAR", "Snare"}, |
|
|
|
{"WTBL", "Wavetable"}, |
|
|
|
{"WMAP", "2D wavetable"}, |
|
|
|
{"WLIN", "1D wavetable"}, |
|
|
|
{"WTx4", "4-voice paraphonic 1D wavetable"}, |
|
|
|
{"NOIS", "Filtered noise"}, |
|
|
|
{"TWNQ", "Twin peaks noise"}, |
|
|
|
{"CLKN", "Clocked noise"}, |
|
|
|
{"CLOU", "Granular cloud"}, |
|
|
|
{"PRTC", "Particle noise"}, |
|
|
|
{"QPSK", "Digital modulation"}, |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct BraidsDisplay : TransparentWidget { |
|
|
|
Braids* module; |
|
|
|
std::shared_ptr<Font> font; |
|
|
@@ -271,35 +282,10 @@ struct BraidsDisplay : TransparentWidget { |
|
|
|
Vec textPos = Vec(11, 47); |
|
|
|
NVGcolor textColor = nvgRGB(0xaf, 0xd2, 0x2c); |
|
|
|
nvgFillColor(args.vg, nvgTransRGBA(textColor, 16)); |
|
|
|
// Background of all segments |
|
|
|
nvgText(args.vg, textPos.x, textPos.y, "~~~~", NULL); |
|
|
|
nvgFillColor(args.vg, textColor); |
|
|
|
nvgText(args.vg, textPos.x, textPos.y, algo_values[shape], NULL); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct BraidsSettingItem : MenuItem { |
|
|
|
uint8_t* setting = NULL; |
|
|
|
uint8_t offValue = 0; |
|
|
|
uint8_t onValue = 1; |
|
|
|
void onAction(const event::Action& e) override { |
|
|
|
// Toggle setting |
|
|
|
*setting = (*setting == onValue) ? offValue : onValue; |
|
|
|
} |
|
|
|
void step() override { |
|
|
|
rightText = (*setting == onValue) ? "✔" : ""; |
|
|
|
MenuItem::step(); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
struct BraidsLowCpuItem : MenuItem { |
|
|
|
Braids* braids; |
|
|
|
void onAction(const event::Action& e) override { |
|
|
|
braids->lowCpu = !braids->lowCpu; |
|
|
|
} |
|
|
|
void step() override { |
|
|
|
rightText = (braids->lowCpu) ? "✔" : ""; |
|
|
|
MenuItem::step(); |
|
|
|
nvgText(args.vg, textPos.x, textPos.y, SHAPE_INFOS[shape].code.c_str(), NULL); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
@@ -309,14 +295,6 @@ struct BraidsWidget : ModuleWidget { |
|
|
|
setModule(module); |
|
|
|
setPanel(Svg::load(asset::plugin(pluginInstance, "res/Braids.svg"))); |
|
|
|
|
|
|
|
{ |
|
|
|
BraidsDisplay* display = new BraidsDisplay(); |
|
|
|
display->box.pos = Vec(14, 53); |
|
|
|
display->box.size = Vec(148, 56); |
|
|
|
display->module = module; |
|
|
|
addChild(display); |
|
|
|
} |
|
|
|
|
|
|
|
addChild(createWidget<ScrewSilver>(Vec(15, 0))); |
|
|
|
addChild(createWidget<ScrewSilver>(Vec(210, 0))); |
|
|
|
addChild(createWidget<ScrewSilver>(Vec(15, 365))); |
|
|
@@ -338,6 +316,12 @@ struct BraidsWidget : ModuleWidget { |
|
|
|
addInput(createInput<PJ301MPort>(Vec(122, 316), module, Braids::TIMBRE_INPUT)); |
|
|
|
addInput(createInput<PJ301MPort>(Vec(160, 316), module, Braids::COLOR_INPUT)); |
|
|
|
addOutput(createOutput<PJ301MPort>(Vec(205, 316), module, Braids::OUT_OUTPUT)); |
|
|
|
|
|
|
|
BraidsDisplay* display = new BraidsDisplay(); |
|
|
|
display->box.pos = Vec(14, 53); |
|
|
|
display->box.size = Vec(148, 56); |
|
|
|
display->module = module; |
|
|
|
addChild(display); |
|
|
|
} |
|
|
|
|
|
|
|
void appendContextMenu(Menu* menu) override { |
|
|
@@ -345,6 +329,15 @@ struct BraidsWidget : ModuleWidget { |
|
|
|
|
|
|
|
menu->addChild(new MenuSeparator); |
|
|
|
|
|
|
|
std::vector<std::string> shapeLabels; |
|
|
|
for (const ShapeInfo& s : SHAPE_INFOS) { |
|
|
|
shapeLabels.push_back(s.label + " (" + s.code + ")"); |
|
|
|
} |
|
|
|
menu->addChild(createIndexSubmenuItem("Model", shapeLabels, |
|
|
|
[=]() {return module->getShapeParam();}, |
|
|
|
[=](int i) {module->setShapeParam(i);} |
|
|
|
)); |
|
|
|
|
|
|
|
menu->addChild(createBoolPtrMenuItem("FM CV selects model (META)", &module->settings.meta_modulation)); |
|
|
|
|
|
|
|
menu->addChild(createBoolMenuItem("Pitch drift (DRFT)", |
|
|
|