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.

321 lines
10KB

  1. #include "dBiz.hpp"
  2. #include "dsp/functions.hpp"
  3. namespace rack_plugin_dBiz {
  4. struct sinebank {
  5. float deltaTime = 1.0 / engineGetSampleRate();
  6. float phase = 0.0;
  7. float freq;
  8. float pitch;
  9. float pitchSlew = 0.0;
  10. int pitchSlewIndex = 0;
  11. //void setPitch(float pitchKnob, float pitchCv)
  12. void setPitch(float pitchKnob, float pitchCv)
  13. {
  14. // Compute frequency
  15. pitch = pitchKnob;
  16. // Apply pitch slew
  17. const float pitchSlewAmount = 3.0;
  18. pitch += pitchSlew * pitchSlewAmount;
  19. pitch += pitchCv;
  20. // Note C3
  21. freq = 261.626 * powf(2.0, pitch / 12.0);
  22. // Accumulate the phase
  23. phase += freq * deltaTime;
  24. if (phase >= 1.0)
  25. phase -= 1.0;
  26. }
  27. void setFreq(float freq2)
  28. {
  29. // Accumulate the phase
  30. phase += freq2 * deltaTime;
  31. if (phase >= 1.0)
  32. phase -= 1.0;
  33. }
  34. float light()
  35. {
  36. return sinf(2 * M_PI * phase);
  37. }
  38. };
  39. ///////// inspired to Tutorial Module!!
  40. struct DAOSC : Module {
  41. enum ParamIds
  42. {
  43. A_PITCH_PARAM,
  44. A_FINE_PARAM,
  45. A_FOLD_PARAM,
  46. A_DRIVE_PARAM,
  47. //A_MODE_PARAM,
  48. A_SAW_PARAM,
  49. A_SQUARE_PARAM,
  50. A_FM_PARAM,
  51. B_PITCH_PARAM,
  52. B_FINE_PARAM,
  53. B_FOLD_PARAM,
  54. B_DRIVE_PARAM,
  55. //B_MODE_PARAM,
  56. B_SAW_PARAM,
  57. B_SQUARE_PARAM,
  58. B_FM_PARAM,
  59. NUM_PARAMS
  60. };
  61. enum InputIds
  62. {
  63. A_FM_INPUT,
  64. A_SAW_INPUT,
  65. A_SQUARE_INPUT,
  66. A_PITCH_INPUT,
  67. A_FOLD_INPUT,
  68. A_DRIVE_INPUT,
  69. //A_OFF_INPUT,
  70. B_FM_INPUT,
  71. B_SAW_INPUT,
  72. B_SQUARE_INPUT,
  73. B_PITCH_INPUT,
  74. B_DRIVE_INPUT,
  75. B_FOLD_INPUT,
  76. //B_OFF_INPUT,
  77. NUM_INPUTS
  78. };
  79. enum OutputIds
  80. {
  81. A_OUTPUT,
  82. B_OUTPUT,
  83. SUM_OUTPUT,
  84. NUM_OUTPUTS
  85. };
  86. enum LightIds {
  87. NUM_LIGHTS
  88. };
  89. float phase = 0.0;
  90. float blinkPhase = 0.0;
  91. sinebank osc_a;
  92. sinebank a_harmonic[20]={};
  93. sinebank a_harmonicq[20] = {};
  94. sinebank osc_b;
  95. sinebank b_harmonic[20] = {};
  96. sinebank b_harmonicq[20] = {};
  97. DAOSC() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {}
  98. void step() override;
  99. };
  100. void DAOSC::step() {
  101. int a_harm = round(params[A_SAW_PARAM].value+clamp(inputs[A_SAW_INPUT].value, 0.0f, 19.0f));
  102. int a_harmq = round(params[A_SQUARE_PARAM].value+clamp(inputs[A_SQUARE_INPUT].value, 0.0f, 19.0f));
  103. int b_harm = round(params[B_SAW_PARAM].value + clamp(inputs[B_SAW_INPUT].value, 0.0f, 19.0f));
  104. int b_harmq = round(params[B_SQUARE_PARAM].value + clamp(inputs[B_SQUARE_INPUT].value, 0.0f, 19.0f));
  105. if(a_harm >20) a_harm = 20;
  106. if(a_harmq>20) a_harmq = 20;
  107. if(b_harm >20) b_harm = 20;
  108. if(b_harmq>20) b_harmq = 20;
  109. float a_harmsum = 0.0;
  110. float a_harmsumq = 0.0;
  111. float b_harmsum = 0.0;
  112. float b_harmsumq = 0.0;
  113. float a_pitchCv = 12.0 * inputs[A_PITCH_INPUT].value;
  114. float b_pitchCv = 12.0 * inputs[B_PITCH_INPUT].value;
  115. float a_pitchFine = 3.0 * quadraticBipolar(params[A_FINE_PARAM].value);
  116. float b_pitchFine = 3.0 * quadraticBipolar(params[B_FINE_PARAM].value);
  117. if (inputs[A_FM_INPUT].active)
  118. {
  119. a_pitchCv += quadraticBipolar(params[A_FM_PARAM].value) * 12.0 * inputs[A_FM_INPUT].value;
  120. }
  121. if (inputs[B_FM_INPUT].active)
  122. {
  123. b_pitchCv += quadraticBipolar(params[B_FM_PARAM].value) * 12.0 * inputs[B_FM_INPUT].value;
  124. }
  125. osc_a.setPitch(params[A_PITCH_PARAM].value, a_pitchFine + a_pitchCv);
  126. osc_b.setPitch(params[B_PITCH_PARAM].value, b_pitchFine + b_pitchCv);
  127. for (int i = 1; i < a_harm; i++)
  128. {
  129. a_harmonic[i].setFreq((i*2)*osc_a.freq);
  130. a_harmsum += a_harmonic[i].light()*3.0/i;
  131. }
  132. for (int i = 1; i < a_harmq; i++)
  133. {
  134. a_harmonicq[i].setFreq(((i * 2) + 1) * osc_a.freq);
  135. a_harmsumq += a_harmonicq[i].light() * 3.0/ i;
  136. }
  137. for (int i = 1; i < b_harm; i++)
  138. {
  139. b_harmonic[i].setFreq((i * 2) * osc_b.freq);
  140. b_harmsum += b_harmonic[i].light() * 3.0/ i;
  141. }
  142. for (int i = 1; i < b_harmq; i++)
  143. {
  144. b_harmonicq[i].setFreq(((i * 2) + 1) * osc_b.freq);
  145. b_harmsumq += b_harmonicq[i].light() * 3.0 / i;
  146. }
  147. //////////////// Contrast - Thx to Michael Hetrick!!!
  148. ////////////////A
  149. float a_inputf = 3.0 * osc_a.light() + a_harmsum + a_harmsumq;
  150. float b_inputf = 3.0 * osc_b.light() + b_harmsum + b_harmsumq;
  151. a_inputf = clamp(a_inputf, -6.0f, 6.0f) * 0.2f;
  152. b_inputf = clamp(b_inputf, -6.0f, 6.0f) * 0.2f;
  153. float a_contrast = params[A_FOLD_PARAM].value + clamp(inputs[A_FOLD_INPUT].value, 0.0f, 6.0f);
  154. float b_contrast = params[B_FOLD_PARAM].value + clamp(inputs[B_FOLD_INPUT].value, 0.0f, 6.0f);
  155. a_contrast = clamp(a_contrast, 0.0f, 6.0f) * 0.2f;
  156. b_contrast = clamp(b_contrast, 0.0f, 6.0f) * 0.2f;
  157. const float a_factor1 = a_inputf * 1.57143;
  158. const float a_factor2 = sinf(a_inputf * 6.28571) * a_contrast;
  159. const float b_factor1 = b_inputf * 1.57143;
  160. const float b_factor2 = sinf(b_inputf * 6.28571) * b_contrast;
  161. float a_outputf = sinf(a_factor1 + a_factor2);
  162. a_outputf *= 6.0f;
  163. float b_outputf = sinf(b_factor1 + b_factor2);
  164. b_outputf *= 6.0f;
  165. //////////////////////////Wave shape - Thx to Michael Hetrick!!!
  166. float a_inputd = a_outputf;
  167. float b_inputd = b_outputf;
  168. a_inputd = clamp(a_inputd, -5.0f, 5.0f) * 0.2f;
  169. b_inputd = clamp(b_inputd, -5.0f, 5.0f) * 0.2f;
  170. float a_shape = params[A_DRIVE_PARAM].value + clamp(inputs[A_DRIVE_INPUT].value, -5.0f, 5.0f);
  171. a_shape = clamp(a_shape, -5.0f, 5.0f) * 0.2f;
  172. a_shape *= 0.99f;
  173. float b_shape = params[B_DRIVE_PARAM].value + clamp(inputs[B_DRIVE_INPUT].value, -5.0f, 5.0f);
  174. b_shape = clamp(b_shape, -5.0f, 5.0f) * 0.2f;
  175. b_shape *= 0.99f;
  176. const float a_shapeB = (1.0 - a_shape) / (1.0 + a_shape);
  177. const float a_shapeA = (4.0 * a_shape) / ((1.0 - a_shape) * (1.0 + a_shape));
  178. const float b_shapeB = (1.0 - b_shape) / (1.0 + b_shape);
  179. const float b_shapeA = (4.0 * b_shape) / ((1.0 - b_shape) * (1.0 + b_shape));
  180. float a_outputd = a_inputd * (a_shapeA + a_shapeB);
  181. float b_outputd = b_inputd * (b_shapeA + b_shapeB);
  182. a_outputd = a_outputd / ((std::abs(a_inputd) * a_shapeA) + a_shapeB);
  183. b_outputd = b_outputd / ((std::abs(b_inputd) * b_shapeA) + b_shapeB);
  184. b_outputd *= 1.0f;
  185. ////////////////////////////////////////////////////////
  186. outputs[A_OUTPUT].value = 3.0 * a_outputd;
  187. outputs[B_OUTPUT].value = 3.0 * b_outputd;
  188. outputs[SUM_OUTPUT].value = 3.0 * (a_outputd + b_outputd) / 2;
  189. }
  190. struct DAOSCWidget : ModuleWidget
  191. {
  192. DAOSCWidget(DAOSC *module) : ModuleWidget(module)
  193. {
  194. box.size = Vec(13 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT);
  195. {
  196. SVGPanel *panel = new SVGPanel();
  197. panel->box.size = box.size;
  198. panel->setBackground(SVG::load(assetPlugin(plugin, "res/DAOSC.svg")));
  199. addChild(panel);
  200. }
  201. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  202. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 0)));
  203. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  204. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 365)));
  205. int knob=42;
  206. int jack=30;
  207. float mid = 97.5;
  208. int top = 20;
  209. int down = 50;
  210. // addParam(ParamWidget::create<CKSS>(Vec(off * 2 + 18, 30), module, DAOSC::A_MODE_PARAM, 0.0, 1.0, 0.0));
  211. // addParam(ParamWidget::create<CKSS>(Vec(off * 3 + 18, 30), module, DAOSC::B_MODE_PARAM, 0.0, 1.0, 0.0));
  212. addParam(ParamWidget::create<LRoundWhy>(Vec(box.size.x-mid-50, top), module, DAOSC::A_PITCH_PARAM, -54.0, 54.0, 0.0));
  213. addParam(ParamWidget::create<RoundWhy>(Vec(box.size.x-mid-knob*2 - 10, top), module, DAOSC::A_FINE_PARAM, -1.0, 1.0, 0.0));
  214. addParam(ParamWidget::create<RoundWhy>(Vec(box.size.x - mid - knob * 1 , top + knob + 35), module, DAOSC::A_FM_PARAM, 0.0, 1.0, 0.0));
  215. addParam(ParamWidget::create<RoundAzz>(Vec(box.size.x - mid - knob * 2 - 5, top + knob + 5), module, DAOSC::A_FOLD_PARAM, 0.0, 5.0, 0.0));
  216. addParam(ParamWidget::create<RoundRed>(Vec(box.size.x - mid - knob * 2 - 5, 125), module, DAOSC::A_DRIVE_PARAM, -5.0, 5.0, 0.0));
  217. addParam(ParamWidget::create<RoundWhy>(Vec(box.size.x-mid-knob, 157), module, DAOSC::A_SQUARE_PARAM, 1.0, 20.0, 1.0));
  218. addParam(ParamWidget::create<RoundWhy>(Vec(box.size.x-mid-knob*2, 177), module, DAOSC::A_SAW_PARAM, 1.0, 20.0, 1.0));
  219. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid-jack-5, 160+down), Port::INPUT, module, DAOSC::A_FM_INPUT));
  220. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid-jack-5, 190+down), Port::INPUT, module, DAOSC::A_PITCH_INPUT));
  221. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid-jack*2-5, 190+down), Port::INPUT, module, DAOSC::A_FOLD_INPUT));
  222. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid-jack*3-5, 190+down), Port::INPUT, module, DAOSC::A_DRIVE_INPUT));
  223. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid-jack*2-5, 230+down), Port::INPUT, module, DAOSC::A_SAW_INPUT));
  224. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid-jack*3-5, 230+down), Port::INPUT, module, DAOSC::A_SQUARE_INPUT));
  225. addOutput(Port::create<PJ301MOPort>(Vec(box.size.x - mid-jack-5, 230+down), Port::OUTPUT, module, DAOSC::A_OUTPUT));
  226. addParam(ParamWidget::create<LRoundWhy>(Vec(box.size.x-mid+5, top), module, DAOSC::B_PITCH_PARAM, -54.0, 54.0, 0.0));
  227. addParam(ParamWidget::create<RoundWhy>(Vec(box.size.x-mid+5+knob+10, top), module, DAOSC::B_FINE_PARAM, -1.0, 1.0, 0.0));
  228. addParam(ParamWidget::create<RoundWhy>(Vec(box.size.x - mid + 5, top + knob+35), module, DAOSC::B_FM_PARAM, 0.0, 1.0, 0.0));
  229. addParam(ParamWidget::create<RoundAzz>(Vec(box.size.x - mid + 10 + knob, top + knob + 5), module, DAOSC::B_FOLD_PARAM, 0.0, 5.0, 0.0));
  230. addParam(ParamWidget::create<RoundRed>(Vec(box.size.x - mid + 10 + knob, 125), module, DAOSC::B_DRIVE_PARAM, -5.0, 5.0, 0.0));
  231. addParam(ParamWidget::create<RoundWhy>(Vec(box.size.x-mid+5, 157), module, DAOSC::B_SQUARE_PARAM, 1.0, 20.0, 1.0));
  232. addParam(ParamWidget::create<RoundWhy>(Vec(box.size.x-mid+5+knob, 177), module, DAOSC::B_SAW_PARAM, 1.0, 20.0, 1.0));
  233. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid+10, 160+down), Port::INPUT, module, DAOSC::B_FM_INPUT));
  234. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid+10, 190+down), Port::INPUT, module, DAOSC::B_PITCH_INPUT));
  235. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid+10+jack, 190+down), Port::INPUT, module, DAOSC::B_FOLD_INPUT));
  236. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid+10+jack*2, 190+down), Port::INPUT, module, DAOSC::B_DRIVE_INPUT));
  237. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid+10+jack, 230+down), Port::INPUT, module, DAOSC::B_SAW_INPUT));
  238. addInput(Port::create<PJ301MIPort>(Vec(box.size.x-mid+10+jack*2, 230+down), Port::INPUT, module, DAOSC::B_SQUARE_INPUT));
  239. addOutput(Port::create<PJ301MOPort>(Vec(box.size.x - mid+10, 230+down), Port::OUTPUT, module, DAOSC::B_OUTPUT));
  240. addOutput(Port::create<PJ301MOPort>(Vec(box.size.x - mid-12.5, 265+down), Port::OUTPUT, module, DAOSC::SUM_OUTPUT));
  241. }
  242. };
  243. } // namespace rack_plugin_dBiz
  244. using namespace rack_plugin_dBiz;
  245. RACK_PLUGIN_MODEL_INIT(dBiz, DAOSC) {
  246. Model *modelDAOSC = Model::create<DAOSC, DAOSCWidget>("dBiz", "DAOSC", "DAOSC", OSCILLATOR_TAG);
  247. return modelDAOSC;
  248. }