#include #include "AudibleInstruments.hpp" #include "dsp.hpp" #include "braids/macro_oscillator.h" struct Braids : Module { enum ParamIds { FINE_PARAM, COARSE_PARAM, FM_PARAM, TIMBRE_PARAM, MODULATION_PARAM, COLOR_PARAM, SHAPE_PARAM, NUM_PARAMS }; enum InputIds { TRIG_INPUT, PITCH_INPUT, FM_INPUT, TIMBRE_INPUT, COLOR_INPUT, NUM_INPUTS }; enum OutputIds { OUT_OUTPUT, NUM_OUTPUTS }; braids::MacroOscillator *osc; SampleRateConverter<1> src; DoubleRingBuffer, 256> outputBuffer; bool lastTrig = false; Braids(); ~Braids(); void step(); void setShape(int shape); }; Braids::Braids() { params.resize(NUM_PARAMS); inputs.resize(NUM_INPUTS); outputs.resize(NUM_OUTPUTS); osc = new braids::MacroOscillator(); memset(osc, 0, sizeof(*osc)); osc->Init(); } Braids::~Braids() { delete osc; } void Braids::step() { // Trigger bool trig = getf(inputs[TRIG_INPUT]) >= 1.0; if (!lastTrig && trig) { osc->Strike(); } lastTrig = trig; // Render frames if (outputBuffer.empty()) { // Set shape int shape = roundf(params[SHAPE_PARAM]); osc->set_shape((braids::MacroOscillatorShape) shape); // Set timbre/modulation float timbre = params[TIMBRE_PARAM] + params[MODULATION_PARAM] * getf(inputs[TIMBRE_INPUT]) / 5.0; float modulation = params[COLOR_PARAM] + getf(inputs[COLOR_INPUT]) / 5.0; int16_t param1 = mapf(clampf(timbre, 0.0, 1.0), 0.0, 1.0, 0, INT16_MAX); int16_t param2 = mapf(clampf(modulation, 0.0, 1.0), 0.0, 1.0, 0, INT16_MAX); osc->set_parameters(param1, param2); // Set pitch float pitch = getf(inputs[PITCH_INPUT]) + params[COARSE_PARAM] + params[FINE_PARAM] / 12.0 + params[FM_PARAM] * getf(inputs[FM_INPUT]); int16_t p = clampf((pitch * 12.0 + 60) * 128, 0, INT16_MAX); osc->set_pitch(p); // TODO: add a sync input buffer (must be sample rate converted) uint8_t sync_buffer[24] = {}; int16_t render_buffer[24]; osc->Render(sync_buffer, render_buffer, 24); // Sample rate convert Frame<1> in[24]; for (int i = 0; i < 24; i++) { in[i].samples[0] = render_buffer[i] / 32768.0; } src.setRatio(gSampleRate / 96000.0); int inLen = 24; int outLen = outputBuffer.capacity(); src.process(in, &inLen, outputBuffer.endData(), &outLen); outputBuffer.endIncr(outLen); } // Output if (!outputBuffer.empty()) { Frame<1> f = outputBuffer.shift(); setf(outputs[OUT_OUTPUT], 5.0 * f.samples[0]); } } static const char *algo_values[] = { "CSAW", "/\\-_", "//-_", "FOLD", "uuuu", "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", " ", }; struct BraidsDisplay : TransparentWidget { float *value; std::shared_ptr font; BraidsDisplay() { font = Font::load("plugins/AudibleInstruments/res/hdad-segment14-1.002/Segment14.ttf"); } void draw(NVGcontext *vg) { int shape = roundf(getf(value)); // Background NVGcolor backgroundColor = nvgRGB(0x38, 0x38, 0x38); NVGcolor borderColor = nvgRGB(0x10, 0x10, 0x10); nvgBeginPath(vg); nvgRoundedRect(vg, 0.0, 0.0, box.size.x, box.size.y, 5.0); nvgFillColor(vg, backgroundColor); nvgFill(vg); nvgStrokeWidth(vg, 1.0); nvgStrokeColor(vg, borderColor); nvgStroke(vg); nvgFontSize(vg, 36); nvgFontFaceId(vg, font->handle); nvgTextLetterSpacing(vg, 2.5); Vec textPos = Vec(10, 48); NVGcolor textColor = nvgRGB(0xaf, 0xd2, 0x2c); nvgFillColor(vg, nvgTransRGBA(textColor, 16)); nvgText(vg, textPos.x, textPos.y, "~~~~", NULL); nvgFillColor(vg, textColor); nvgText(vg, textPos.x, textPos.y, algo_values[shape], NULL); } }; BraidsWidget::BraidsWidget() { Braids *module = new Braids(); setModule(module); box.size = Vec(15*16, 380); { Panel *panel = new LightPanel(); panel->backgroundImage = Image::load("plugins/AudibleInstruments/res/Braids.png"); panel->box.size = box.size; addChild(panel); } { BraidsDisplay *display = new BraidsDisplay(); display->box.pos = Vec(14, 53); display->box.size = Vec(148, 56); display->value = &module->params[Braids::SHAPE_PARAM]; addChild(display); } addChild(createScrew(Vec(15, 0))); addChild(createScrew(Vec(210, 0))); addChild(createScrew(Vec(15, 365))); addChild(createScrew(Vec(210, 365))); addParam(createParam(Vec(177, 60), module, Braids::SHAPE_PARAM, 0.0, braids::MACRO_OSC_SHAPE_LAST-2, 0.0)); addParam(createParam(Vec(20, 139), module, Braids::FINE_PARAM, -1.0, 1.0, 0.0)); addParam(createParam(Vec(98, 139), module, Braids::COARSE_PARAM, -2.0, 2.0, 0.0)); addParam(createParam(Vec(177, 139), module, Braids::FM_PARAM, -1.0, 1.0, 0.0)); addParam(createParam(Vec(20, 218), module, Braids::TIMBRE_PARAM, 0.0, 1.0, 0.5)); addParam(createParam(Vec(98, 218), module, Braids::MODULATION_PARAM, -1.0, 1.0, 0.0)); addParam(createParam(Vec(177, 218), module, Braids::COLOR_PARAM, 0.0, 1.0, 0.5)); addInput(createInput(Vec(7, 313), module, Braids::TRIG_INPUT)); addInput(createInput(Vec(45, 313), module, Braids::PITCH_INPUT)); addInput(createInput(Vec(82, 313), module, Braids::FM_INPUT)); addInput(createInput(Vec(120, 313), module, Braids::TIMBRE_INPUT)); addInput(createInput(Vec(157, 313), module, Braids::COLOR_INPUT)); addOutput(createOutput(Vec(202, 313), module, Braids::OUT_OUTPUT)); }