You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
4.9KB

  1. #include "Nohmad.hpp"
  2. #include <dsp/filter.hpp>
  3. #include <random>
  4. #include <cmath>
  5. namespace rack_plugin_Nohmad {
  6. struct NoiseGenerator {
  7. std::mt19937 rng;
  8. std::uniform_real_distribution<float> uniform;
  9. NoiseGenerator() : uniform(-1.0f, 1.0f) {
  10. rng.seed(std::random_device()());
  11. }
  12. float white() {
  13. return uniform(rng);
  14. }
  15. };
  16. struct PinkFilter {
  17. float b0, b1, b2, b3, b4, b5, b6; // Coefficients
  18. float y; // Out
  19. void process(float x) {
  20. b0 = 0.99886f * b0 + x * 0.0555179f;
  21. b1 = 0.99332f * b1 + x * 0.0750759f;
  22. b2 = 0.96900f * b2 + x * 0.1538520f;
  23. b3 = 0.86650f * b3 + x * 0.3104856f;
  24. b4 = 0.55000f * b4 + x * 0.5329522f;
  25. b5 = -0.7616f * b5 - x * 0.0168980f;
  26. y = b0 + b1 + b2 + b3 + b4 + b5 + b6 + x * 0.5362f;
  27. b6 = x * 0.115926f;
  28. }
  29. float pink() {
  30. return y;
  31. }
  32. };
  33. struct NotchFilter {
  34. float freq, bandwidth; // Params
  35. float a0, a1, a2, b1, b2; // Coefficients
  36. float x1, x2; // In
  37. float y1, y2; // out
  38. void setFreq(float value) {
  39. freq = value;
  40. computeCoefficients();
  41. }
  42. void setBandwidth(float value) {
  43. bandwidth = value;
  44. computeCoefficients();
  45. }
  46. void process(float x) {
  47. float y = a0 * x + a1 * x1 + a2 * x2 + b1 * y1 + b2 * y2;
  48. x2 = x1;
  49. x1 = x;
  50. y2 = y1;
  51. y1 = y;
  52. }
  53. float notch() {
  54. return y1;
  55. }
  56. void computeCoefficients() {
  57. float c2pf = cos(2.0f * M_PI * freq);
  58. float r = 1.0f - 3.0f * bandwidth;
  59. float r2 = r * r;
  60. float k = (1.0f - (2.0f * r * c2pf) + r2) / (2.0f - 2.0f * c2pf);
  61. a0 = k;
  62. a1 = -2.0f * k * c2pf;
  63. a2 = k;
  64. b1 = 2.0f * r * c2pf;
  65. b2 = -r2;
  66. }
  67. };
  68. struct Noise : Module {
  69. enum ParamIds {
  70. QUANTA_PARAM,
  71. NUM_PARAMS
  72. };
  73. enum InputIds {
  74. NUM_INPUTS
  75. };
  76. enum OutputIds {
  77. WHITE_OUTPUT,
  78. PINK_OUTPUT,
  79. RED_OUTPUT,
  80. GREY_OUTPUT,
  81. BLUE_OUTPUT,
  82. PURPLE_OUTPUT,
  83. QUANTA_OUTPUT,
  84. NUM_OUTPUTS
  85. };
  86. NoiseGenerator noise;
  87. PinkFilter pinkFilter;
  88. RCFilter redFilter;
  89. NotchFilter greyFilter;
  90. RCFilter blueFilter;
  91. RCFilter purpleFilter;
  92. Noise() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
  93. redFilter.setCutoff(441.0f / engineGetSampleRate());
  94. purpleFilter.setCutoff(44100.0f / engineGetSampleRate());
  95. blueFilter.setCutoff(44100.0f / engineGetSampleRate());
  96. greyFilter.setFreq(1000.0f / engineGetSampleRate());
  97. greyFilter.setBandwidth(0.3f);
  98. }
  99. void step() override;
  100. };
  101. void Noise::step() {
  102. float white = noise.white();
  103. if (outputs[PINK_OUTPUT].active || outputs[BLUE_OUTPUT].active || outputs[GREY_OUTPUT].active) {
  104. pinkFilter.process(white);
  105. }
  106. if (outputs[WHITE_OUTPUT].active) {
  107. outputs[WHITE_OUTPUT].value = 5.0f * white;
  108. }
  109. if (outputs[RED_OUTPUT].active) {
  110. redFilter.process(white);
  111. outputs[RED_OUTPUT].value = 5.0f * clamp(7.8f * redFilter.lowpass(), -1.0f, 1.0f);
  112. }
  113. if (outputs[PINK_OUTPUT].active) {
  114. outputs[PINK_OUTPUT].value = 5.0f * clamp(0.18f * pinkFilter.pink(), -1.0f, 1.0f);
  115. }
  116. if (outputs[GREY_OUTPUT].active) {
  117. greyFilter.process(pinkFilter.pink() * 0.034);
  118. outputs[GREY_OUTPUT].value = 5.0f * clamp(0.23f * (pinkFilter.pink() * 0.5f + greyFilter.notch() * 0.5f), -1.0f, 1.0f);
  119. }
  120. if (outputs[BLUE_OUTPUT].active) {
  121. blueFilter.process(pinkFilter.pink());
  122. outputs[BLUE_OUTPUT].value = 5.0f * clamp(0.64f * blueFilter.highpass(), -1.0f, 1.0f);
  123. }
  124. if (outputs[PURPLE_OUTPUT].active) {
  125. purpleFilter.process(white);
  126. outputs[PURPLE_OUTPUT].value = 5.0f * clamp(0.82f * purpleFilter.highpass(), -1.0f, 1.0f);
  127. }
  128. if (outputs[QUANTA_OUTPUT].active) {
  129. outputs[QUANTA_OUTPUT].value = abs(white) <= params[QUANTA_PARAM].value ? 5.0f * sgn(white) : 0.0f;
  130. }
  131. }
  132. struct MiniTrimpot : Trimpot {
  133. MiniTrimpot() {
  134. box.size = Vec(12, 12);
  135. }
  136. };
  137. struct NoiseWidget : ModuleWidget {
  138. NoiseWidget(Noise *module);
  139. };
  140. NoiseWidget::NoiseWidget(Noise *module) : ModuleWidget(module) {
  141. box.size = Vec(15 * 3, 380);
  142. {
  143. SVGPanel *panel = new SVGPanel();
  144. panel->box.size = box.size;
  145. panel->setBackground(SVG::load(assetPlugin(plugin, "res/Noise.svg")));
  146. addChild(panel);
  147. }
  148. addOutput(Port::create<PJ301MPort>(Vec(10.5, 55), Port::OUTPUT, module, Noise::WHITE_OUTPUT));
  149. addOutput(Port::create<PJ301MPort>(Vec(10.5, 101), Port::OUTPUT, module, Noise::PINK_OUTPUT));
  150. addOutput(Port::create<PJ301MPort>(Vec(10.5, 150), Port::OUTPUT, module, Noise::RED_OUTPUT));
  151. addOutput(Port::create<PJ301MPort>(Vec(10.5, 199), Port::OUTPUT, module, Noise::GREY_OUTPUT));
  152. addOutput(Port::create<PJ301MPort>(Vec(10.5, 247), Port::OUTPUT, module, Noise::BLUE_OUTPUT));
  153. addOutput(Port::create<PJ301MPort>(Vec(10.5, 295), Port::OUTPUT, module, Noise::PURPLE_OUTPUT));
  154. addOutput(Port::create<PJ301MPort>(Vec(10.5, 343), Port::OUTPUT, module, Noise::QUANTA_OUTPUT));
  155. addParam(ParamWidget::create<MiniTrimpot>(Vec(30, 365), module, Noise::QUANTA_PARAM, 0.0f, 1.0f, 0.066f));
  156. }
  157. } // namespace rack_plugin_Nohmad
  158. using namespace rack_plugin_Nohmad;
  159. RACK_PLUGIN_MODEL_INIT(Nohmad, Noise) {
  160. Model *modelNoise = Model::create<Noise, NoiseWidget>("Nohmad", "Noise", "Noise", NOISE_TAG);
  161. return modelNoise;
  162. }