#include "Nohmad.hpp" #include #include #include namespace rack_plugin_Nohmad { struct NoiseGenerator { std::mt19937 rng; std::uniform_real_distribution uniform; NoiseGenerator() : uniform(-1.0f, 1.0f) { rng.seed(std::random_device()()); } float white() { return uniform(rng); } }; struct PinkFilter { float b0, b1, b2, b3, b4, b5, b6; // Coefficients float y; // Out void process(float x) { b0 = 0.99886f * b0 + x * 0.0555179f; b1 = 0.99332f * b1 + x * 0.0750759f; b2 = 0.96900f * b2 + x * 0.1538520f; b3 = 0.86650f * b3 + x * 0.3104856f; b4 = 0.55000f * b4 + x * 0.5329522f; b5 = -0.7616f * b5 - x * 0.0168980f; y = b0 + b1 + b2 + b3 + b4 + b5 + b6 + x * 0.5362f; b6 = x * 0.115926f; } float pink() { return y; } }; struct NotchFilter { float freq, bandwidth; // Params float a0, a1, a2, b1, b2; // Coefficients float x1, x2; // In float y1, y2; // out void setFreq(float value) { freq = value; computeCoefficients(); } void setBandwidth(float value) { bandwidth = value; computeCoefficients(); } void process(float x) { float y = a0 * x + a1 * x1 + a2 * x2 + b1 * y1 + b2 * y2; x2 = x1; x1 = x; y2 = y1; y1 = y; } float notch() { return y1; } void computeCoefficients() { float c2pf = cos(2.0f * M_PI * freq); float r = 1.0f - 3.0f * bandwidth; float r2 = r * r; float k = (1.0f - (2.0f * r * c2pf) + r2) / (2.0f - 2.0f * c2pf); a0 = k; a1 = -2.0f * k * c2pf; a2 = k; b1 = 2.0f * r * c2pf; b2 = -r2; } }; struct Noise : Module { enum ParamIds { QUANTA_PARAM, NUM_PARAMS }; enum InputIds { NUM_INPUTS }; enum OutputIds { WHITE_OUTPUT, PINK_OUTPUT, RED_OUTPUT, GREY_OUTPUT, BLUE_OUTPUT, PURPLE_OUTPUT, QUANTA_OUTPUT, NUM_OUTPUTS }; NoiseGenerator noise; PinkFilter pinkFilter; RCFilter redFilter; NotchFilter greyFilter; RCFilter blueFilter; RCFilter purpleFilter; Noise() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) { redFilter.setCutoff(441.0f / engineGetSampleRate()); purpleFilter.setCutoff(44100.0f / engineGetSampleRate()); blueFilter.setCutoff(44100.0f / engineGetSampleRate()); greyFilter.setFreq(1000.0f / engineGetSampleRate()); greyFilter.setBandwidth(0.3f); } void step() override; }; void Noise::step() { float white = noise.white(); if (outputs[PINK_OUTPUT].active || outputs[BLUE_OUTPUT].active || outputs[GREY_OUTPUT].active) { pinkFilter.process(white); } if (outputs[WHITE_OUTPUT].active) { outputs[WHITE_OUTPUT].value = 5.0f * white; } if (outputs[RED_OUTPUT].active) { redFilter.process(white); outputs[RED_OUTPUT].value = 5.0f * clamp(7.8f * redFilter.lowpass(), -1.0f, 1.0f); } if (outputs[PINK_OUTPUT].active) { outputs[PINK_OUTPUT].value = 5.0f * clamp(0.18f * pinkFilter.pink(), -1.0f, 1.0f); } if (outputs[GREY_OUTPUT].active) { greyFilter.process(pinkFilter.pink() * 0.034); outputs[GREY_OUTPUT].value = 5.0f * clamp(0.23f * (pinkFilter.pink() * 0.5f + greyFilter.notch() * 0.5f), -1.0f, 1.0f); } if (outputs[BLUE_OUTPUT].active) { blueFilter.process(pinkFilter.pink()); outputs[BLUE_OUTPUT].value = 5.0f * clamp(0.64f * blueFilter.highpass(), -1.0f, 1.0f); } if (outputs[PURPLE_OUTPUT].active) { purpleFilter.process(white); outputs[PURPLE_OUTPUT].value = 5.0f * clamp(0.82f * purpleFilter.highpass(), -1.0f, 1.0f); } if (outputs[QUANTA_OUTPUT].active) { outputs[QUANTA_OUTPUT].value = abs(white) <= params[QUANTA_PARAM].value ? 5.0f * sgn(white) : 0.0f; } } struct MiniTrimpot : Trimpot { MiniTrimpot() { box.size = Vec(12, 12); } }; struct NoiseWidget : ModuleWidget { NoiseWidget(Noise *module); }; NoiseWidget::NoiseWidget(Noise *module) : ModuleWidget(module) { box.size = Vec(15 * 3, 380); { SVGPanel *panel = new SVGPanel(); panel->box.size = box.size; panel->setBackground(SVG::load(assetPlugin(plugin, "res/Noise.svg"))); addChild(panel); } addOutput(Port::create(Vec(10.5, 55), Port::OUTPUT, module, Noise::WHITE_OUTPUT)); addOutput(Port::create(Vec(10.5, 101), Port::OUTPUT, module, Noise::PINK_OUTPUT)); addOutput(Port::create(Vec(10.5, 150), Port::OUTPUT, module, Noise::RED_OUTPUT)); addOutput(Port::create(Vec(10.5, 199), Port::OUTPUT, module, Noise::GREY_OUTPUT)); addOutput(Port::create(Vec(10.5, 247), Port::OUTPUT, module, Noise::BLUE_OUTPUT)); addOutput(Port::create(Vec(10.5, 295), Port::OUTPUT, module, Noise::PURPLE_OUTPUT)); addOutput(Port::create(Vec(10.5, 343), Port::OUTPUT, module, Noise::QUANTA_OUTPUT)); addParam(ParamWidget::create(Vec(30, 365), module, Noise::QUANTA_PARAM, 0.0f, 1.0f, 0.066f)); } } // namespace rack_plugin_Nohmad using namespace rack_plugin_Nohmad; RACK_PLUGIN_MODEL_INIT(Nohmad, Noise) { Model *modelNoise = Model::create("Nohmad", "Noise", "Noise", NOISE_TAG); return modelNoise; }