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.

413 lines
16KB

  1. #include "plugin.hpp"
  2. #include "simd_mask.hpp"
  3. #include "PulseGenerator_4.hpp"
  4. #define MAX(a,b) a>b?a:b
  5. static simd::float_4 shapeDelta(simd::float_4 delta, simd::float_4 tau, float shape) {
  6. simd::float_4 lin = simd::sgn(delta) * 10.f / tau;
  7. if (shape < 0.f) {
  8. simd::float_4 log = simd::sgn(delta) * simd::float_4(40.f) / tau / (simd::fabs(delta) + simd::float_4(1.f));
  9. return crossfade_4(lin, log, -shape * 0.95f);
  10. }
  11. else {
  12. simd::float_4 exp = M_E * delta / tau;
  13. return crossfade_4(lin, exp, shape * 0.90f);
  14. }
  15. }
  16. struct Rampage : Module {
  17. enum ParamIds {
  18. RANGE_A_PARAM,
  19. RANGE_B_PARAM,
  20. SHAPE_A_PARAM,
  21. SHAPE_B_PARAM,
  22. TRIGG_A_PARAM,
  23. TRIGG_B_PARAM,
  24. RISE_A_PARAM,
  25. RISE_B_PARAM,
  26. FALL_A_PARAM,
  27. FALL_B_PARAM,
  28. CYCLE_A_PARAM,
  29. CYCLE_B_PARAM,
  30. BALANCE_PARAM,
  31. NUM_PARAMS
  32. };
  33. enum InputIds {
  34. IN_A_INPUT,
  35. IN_B_INPUT,
  36. TRIGG_A_INPUT,
  37. TRIGG_B_INPUT,
  38. RISE_CV_A_INPUT,
  39. RISE_CV_B_INPUT,
  40. FALL_CV_A_INPUT,
  41. FALL_CV_B_INPUT,
  42. EXP_CV_A_INPUT,
  43. EXP_CV_B_INPUT,
  44. CYCLE_A_INPUT,
  45. CYCLE_B_INPUT,
  46. NUM_INPUTS
  47. };
  48. enum OutputIds {
  49. RISING_A_OUTPUT,
  50. RISING_B_OUTPUT,
  51. FALLING_A_OUTPUT,
  52. FALLING_B_OUTPUT,
  53. EOC_A_OUTPUT,
  54. EOC_B_OUTPUT,
  55. OUT_A_OUTPUT,
  56. OUT_B_OUTPUT,
  57. COMPARATOR_OUTPUT,
  58. MIN_OUTPUT,
  59. MAX_OUTPUT,
  60. NUM_OUTPUTS
  61. };
  62. enum LightIds {
  63. COMPARATOR_LIGHT,
  64. MIN_LIGHT,
  65. MAX_LIGHT,
  66. OUT_A_LIGHT,
  67. OUT_B_LIGHT,
  68. RISING_A_LIGHT,
  69. RISING_B_LIGHT,
  70. FALLING_A_LIGHT,
  71. FALLING_B_LIGHT,
  72. NUM_LIGHTS
  73. };
  74. /*
  75. float out[2] = {};
  76. bool gate[2] = {};
  77. */
  78. simd::float_4 out[2][4];
  79. simd::float_4 gate[2][4]; // use simd __m128 logic instead of bool
  80. dsp::TSchmittTrigger<simd::float_4> trigger_4[2][4];
  81. PulseGenerator_4 endOfCyclePulse[2][4];
  82. ChannelMask channelMask;
  83. Rampage() {
  84. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  85. configParam(RANGE_A_PARAM, 0.0, 2.0, 0.0, "Ch 1 range");
  86. configParam(SHAPE_A_PARAM, -1.0, 1.0, 0.0, "Ch 1 shape");
  87. configParam(TRIGG_A_PARAM, 0.0, 1.0, 0.0, "Ch 1 trigger");
  88. configParam(RISE_A_PARAM, 0.0, 1.0, 0.0, "Ch 1 rise time");
  89. configParam(FALL_A_PARAM, 0.0, 1.0, 0.0, "Ch 1 fall time");
  90. configParam(CYCLE_A_PARAM, 0.0, 1.0, 0.0, "Ch 1 cycle");
  91. configParam(RANGE_B_PARAM, 0.0, 2.0, 0.0, "Ch 2 range");
  92. configParam(SHAPE_B_PARAM, -1.0, 1.0, 0.0, "Ch 2 shape");
  93. configParam(TRIGG_B_PARAM, 0.0, 1.0, 0.0, "Ch 2 trigger");
  94. configParam(RISE_B_PARAM, 0.0, 1.0, 0.0, "Ch 2 rise time");
  95. configParam(FALL_B_PARAM, 0.0, 1.0, 0.0, "Ch 2 fall time");
  96. configParam(CYCLE_B_PARAM, 0.0, 1.0, 0.0, "Ch 2 cycle");
  97. configParam(BALANCE_PARAM, 0.0, 1.0, 0.5, "Balance");
  98. memset(out, 0, sizeof(out));
  99. memset(gate, 0, sizeof(gate));
  100. }
  101. void process(const ProcessArgs &args) override {
  102. int channels_in[2];
  103. int channels_trig[2];
  104. int channels[2];
  105. // determine number of channels:
  106. for (int part=0; part<2; part++) {
  107. int tmp = inputs[IN_A_INPUT+part].getChannels();
  108. channels_in[part] = MAX(1,tmp);
  109. tmp = inputs[TRIGG_A_INPUT+part].getChannels();
  110. channels_trig[part] = MAX(1,tmp);
  111. channels[part] = MAX(channels_in[part], channels_trig[part]);
  112. outputs[OUT_A_OUTPUT+part].setChannels(channels[part]);
  113. outputs[RISING_A_OUTPUT+part].setChannels(channels[part]);
  114. outputs[FALLING_A_OUTPUT+part].setChannels(channels[part]);
  115. outputs[EOC_A_OUTPUT+part].setChannels(channels[part]);
  116. }
  117. int channels_max = MAX(channels[0], channels[1]);
  118. // loop over two parts of Rampage:
  119. for (int part = 0; part < 2; part++) {
  120. simd::float_4 in[4];
  121. simd::float_4 in_trig[4];
  122. simd::float_4 expCV[4] = {};
  123. simd::float_4 riseCV[4] = {};
  124. simd::float_4 fallCV[4] = {};
  125. simd::float_4 cycle[4] = {};
  126. float shape = params[SHAPE_A_PARAM + part].getValue();
  127. float minTime;
  128. switch ((int) params[RANGE_A_PARAM + part].getValue()) {
  129. case 0: minTime = 1e-2; break;
  130. case 1: minTime = 1e-3; break;
  131. default: minTime = 1e-1; break;
  132. }
  133. simd::float_4 param_rise = simd::float_4(params[RISE_A_PARAM + part].getValue());
  134. simd::float_4 param_fall = simd::float_4(params[FALL_A_PARAM + part].getValue());
  135. simd::float_4 param_trig = simd::float_4(params[TRIGG_A_PARAM + part].getValue() * 10.0f);
  136. simd::float_4 param_cycle = simd::float_4(params[CYCLE_A_PARAM + part].getValue() * 10.0f);
  137. if(inputs[IN_A_INPUT + part].isConnected()) {
  138. load_input(inputs[IN_A_INPUT + part], in, channels_in[part]);
  139. channelMask.apply_all(in, channels_in[part]);
  140. } else {
  141. memset(in, 0, sizeof(in));
  142. }
  143. if(inputs[TRIGG_A_INPUT + part].isConnected()) {
  144. load_input(inputs[TRIGG_A_INPUT + part], in_trig, channels_trig[part]);
  145. channelMask.apply_all(in_trig, channels_trig[part]);
  146. } else {
  147. memset(in_trig, 0, sizeof(in_trig));
  148. }
  149. for(int c=0; c<channels_trig[part]; c+=4) in_trig[c/4] = param_trig + in_trig[c/4]/2.0f;
  150. channelMask.apply_all(in_trig, channels_trig[part] );
  151. for(int c=0; c<channels[part]; c+=4) {
  152. simd::float_4 trig_mask = trigger_4[part][c/4].process(in_trig[c/4]);
  153. gate[part][c/4] = ifelse(trig_mask, simd::float_4::mask(), gate[part][c/4]);
  154. in[c/4] = ifelse(gate[part][c/4], simd::float_4(10.0f), in[c/4]);
  155. }
  156. if(inputs[EXP_CV_A_INPUT + part].isConnected()) {
  157. load_input(inputs[EXP_CV_A_INPUT + part], expCV, channels[part]);
  158. for(int c=0; c<channels[part]; c+=4) riseCV[c/4] *= -1.0f;
  159. }
  160. load_input(inputs[RISE_CV_A_INPUT + part], riseCV, channels[part]);
  161. for(int c=0; c<channels[part]; c+=4) {
  162. riseCV[c/4] += expCV[c/4];
  163. riseCV[c/4] *= 0.10f;
  164. riseCV[c/4] += param_rise;
  165. }
  166. load_input(inputs[FALL_CV_A_INPUT + part], fallCV, channels[part]);
  167. for(int c=0; c<channels[part]; c+=4) {
  168. fallCV[c/4] += expCV[c/4];
  169. fallCV[c/4] *= 0.10f;
  170. fallCV[c/4] += param_fall;
  171. }
  172. load_input(inputs[CYCLE_A_INPUT], cycle, channels[part]);
  173. // channelMask.apply_all(cycle, channels[part]);
  174. for(int c=0; c<channels[part]; c+=4) {
  175. cycle[c/4] += param_cycle;
  176. }
  177. channelMask.apply_all(cycle, channels[part]);
  178. for(int c=0; c<channels[part]; c+=4) {
  179. simd::float_4 delta = in[c/4] - out[part][c/4];
  180. simd::float_4 delta_gt_0 = delta > simd::float_4::zero();
  181. simd::float_4 delta_lt_0 = delta < simd::float_4::zero();
  182. simd::float_4 delta_eq_0 = ~(delta_lt_0|delta_gt_0);
  183. simd::float_4 rateCV = ifelse(delta_gt_0, riseCV[c/4], simd::float_4::zero());
  184. rateCV = ifelse(delta_lt_0, fallCV[c/4], rateCV);
  185. rateCV = clamp(rateCV, simd::float_4::zero(), simd::float_4(1.0f));
  186. simd::float_4 rate = minTime * simd::pow(2.0f, rateCV * 10.0f);
  187. out[part][c/4] += shapeDelta(delta, rate, shape) * args.sampleTime;
  188. simd::float_4 rising = (in[c/4] - out[part][c/4]) > simd::float_4( 1e-3);
  189. simd::float_4 falling = (in[c/4] - out[part][c/4]) < simd::float_4(-1e-3);
  190. simd::float_4 end_of_cycle = simd::andnot(falling,delta_lt_0);
  191. endOfCyclePulse[part][c/4].trigger(end_of_cycle, 1e-3);
  192. gate[part][c/4] = ifelse( simd::andnot(rising, delta_gt_0), simd::float_4::zero(), gate[part][c/4]);
  193. gate[part][c/4] = ifelse( end_of_cycle & (cycle[c/4]>=simd::float_4(4.0f)), simd::float_4::mask(), gate[part][c/4] );
  194. gate[part][c/4] = ifelse( delta_eq_0, simd::float_4::zero(), gate[part][c/4] );
  195. out[part][c/4] = ifelse( rising|falling, out[part][c/4], in[c/4] );
  196. simd::float_4 out_rising = ifelse(rising, simd::float_4(10.0f), simd::float_4::zero() );
  197. simd::float_4 out_falling = ifelse(falling, simd::float_4(10.0f), simd::float_4::zero() );
  198. simd::float_4 pulse = endOfCyclePulse[part][c/4].process(args.sampleTime);
  199. simd::float_4 out_EOC = ifelse(pulse, simd::float_4(10.f), simd::float_4::zero() );
  200. out[part][c/4].store(outputs[OUT_A_OUTPUT+part].getVoltages(c));
  201. out_rising.store( outputs[RISING_A_OUTPUT+part].getVoltages(c));
  202. out_falling.store(outputs[FALLING_A_OUTPUT+part].getVoltages(c));
  203. out_EOC.store(outputs[EOC_A_OUTPUT+part].getVoltages(c));
  204. } // for(int c, ...)
  205. if(channels[part] == 1) {
  206. lights[RISING_A_LIGHT + part].setSmoothBrightness(outputs[RISING_A_OUTPUT+part].getVoltage()/10.f, args.sampleTime);
  207. lights[FALLING_A_LIGHT + part].setSmoothBrightness(outputs[FALLING_A_OUTPUT+part].getVoltage()/10.f, args.sampleTime);
  208. lights[OUT_A_LIGHT + part].setSmoothBrightness(out[part][0].s[0] / 10.0, args.sampleTime);
  209. } else {
  210. lights[RISING_A_LIGHT + part].setSmoothBrightness(outputs[RISING_A_OUTPUT+part].getVoltageSum()/10.f, args.sampleTime);
  211. lights[FALLING_A_LIGHT + part].setSmoothBrightness(outputs[FALLING_A_OUTPUT+part].getVoltageSum()/10.f, args.sampleTime);
  212. lights[OUT_A_LIGHT + part].setSmoothBrightness(outputs[OUT_A_OUTPUT].getVoltageSum() / 10.0, args.sampleTime);
  213. }
  214. // Integrator
  215. // bool rising = false;
  216. // bool falling = false;
  217. /*
  218. if (delta > 0) {
  219. // Rise
  220. float riseCv = params[RISE_A_PARAM + c].getValue() - inputs[EXP_CV_A_INPUT + c].getVoltage() / 10.0 + inputs[RISE_CV_A_INPUT + c].getVoltage() / 10.0;
  221. riseCv = clamp(riseCv, 0.0f, 1.0f);
  222. float rise = minTime * std::pow(2.0, riseCv * 10.0);
  223. out[c] += shapeDelta(delta, rise, shape) * args.sampleTime;
  224. rising = (in - out[c] > 1e-3);
  225. if (!rising) {
  226. gate[c] = false;
  227. }
  228. }
  229. else if (delta < 0) {
  230. // Fall
  231. float fallCv = params[FALL_A_PARAM + c].getValue() - inputs[EXP_CV_A_INPUT + c].getVoltage() / 10.0 + inputs[FALL_CV_A_INPUT + c].getVoltage() / 10.0;
  232. fallCv = clamp(fallCv, 0.0f, 1.0f);
  233. float fall = minTime * std::pow(2.0, fallCv * 10.0);
  234. out[c] += shapeDelta(delta, fall, shape) * args.sampleTime;
  235. falling = (in - out[c] < -1e-3);
  236. if (!falling) {
  237. // End of cycle, check if we should turn the gate back on (cycle mode)
  238. endOfCyclePulse[c].trigger(1e-3);
  239. if (params[CYCLE_A_PARAM + c].getValue() * 10.0 + inputs[CYCLE_A_INPUT + c].getVoltage() >= 4.0) {
  240. gate[c] = true;
  241. }
  242. }
  243. }
  244. else {
  245. gate[c] = false;
  246. }
  247. if (!rising && !falling) {
  248. out[c] = in;
  249. }
  250. */
  251. // outputs[RISING_A_OUTPUT + part].setVoltage((rising ? 10.0 : 0.0));
  252. // outputs[FALLING_A_OUTPUT + part].setVoltage((falling ? 10.0 : 0.0));
  253. // lights[RISING_A_LIGHT + part].setSmoothBrightness(rising ? 1.0 : 0.0, args.sampleTime);
  254. // lights[FALLING_A_LIGHT + part].setSmoothBrightness(falling ? 1.0 : 0.0, args.sampleTime);
  255. // outputs[EOC_A_OUTPUT + part].setVoltage((endOfCyclePulse[c].process(args.sampleTime) ? 10.0 : 0.0));
  256. // outputs[OUT_A_OUTPUT + part].setVoltage(out[c]);
  257. // lights[OUT_A_LIGHT + part].setSmoothBrightness(out[c] / 10.0, args.sampleTime);
  258. } // for (int part, ... )
  259. // Logic
  260. float balance = params[BALANCE_PARAM].getValue();
  261. for(int c=0; c<channels_max; c+=4) {
  262. simd::float_4 a = out[0][c/4];
  263. simd::float_4 b = out[1][c/4];
  264. if (balance < 0.5)
  265. b *= 2.0 * balance;
  266. else if (balance > 0.5)
  267. a *= 2.0 * (1.0 - balance);
  268. simd::float_4 comp = ifelse( b>a, simd::float_4(10.0f), simd::float_4::zero() );
  269. simd::float_4 out_min = simd::fmin(a,b);
  270. simd::float_4 out_max = simd::fmax(a,b);
  271. comp.store(outputs[COMPARATOR_OUTPUT].getVoltages(c));
  272. out_min.store(outputs[MIN_OUTPUT].getVoltages(c));
  273. out_max.store(outputs[MAX_OUTPUT].getVoltages(c));
  274. }
  275. // Lights
  276. lights[COMPARATOR_LIGHT].setSmoothBrightness(outputs[COMPARATOR_OUTPUT].getVoltageSum() / 10.0, args.sampleTime);
  277. lights[MIN_LIGHT].setSmoothBrightness(outputs[MIN_OUTPUT].getVoltageSum() / 10.0, args.sampleTime);
  278. lights[MAX_LIGHT].setSmoothBrightness(outputs[MAX_OUTPUT].getVoltageSum() / 10.0, args.sampleTime);
  279. } // end process()
  280. };
  281. struct RampageWidget : ModuleWidget {
  282. RampageWidget(Rampage *module) {
  283. setModule(module);
  284. setPanel(APP->window->loadSvg(asset::plugin(pluginInstance, "res/Rampage.svg")));
  285. addChild(createWidget<Knurlie>(Vec(15, 0)));
  286. addChild(createWidget<Knurlie>(Vec(box.size.x-30, 0)));
  287. addChild(createWidget<Knurlie>(Vec(15, 365)));
  288. addChild(createWidget<Knurlie>(Vec(box.size.x-30, 365)));
  289. addParam(createParam<BefacoSwitch>(Vec(94, 32), module, Rampage::RANGE_A_PARAM));
  290. addParam(createParam<BefacoTinyKnob>(Vec(27, 90), module, Rampage::SHAPE_A_PARAM));
  291. addParam(createParam<BefacoPush>(Vec(72, 82), module, Rampage::TRIGG_A_PARAM));
  292. addParam(createParam<BefacoSlidePot>(Vec(16, 135), module, Rampage::RISE_A_PARAM));
  293. addParam(createParam<BefacoSlidePot>(Vec(57, 135), module, Rampage::FALL_A_PARAM));
  294. addParam(createParam<BefacoSwitch>(Vec(101, 238), module, Rampage::CYCLE_A_PARAM));
  295. addParam(createParam<BefacoSwitch>(Vec(147, 32), module, Rampage::RANGE_B_PARAM));
  296. addParam(createParam<BefacoTinyKnob>(Vec(217, 90), module, Rampage::SHAPE_B_PARAM));
  297. addParam(createParam<BefacoPush>(Vec(170, 82), module, Rampage::TRIGG_B_PARAM));
  298. addParam(createParam<BefacoSlidePot>(Vec(197, 135), module, Rampage::RISE_B_PARAM));
  299. addParam(createParam<BefacoSlidePot>(Vec(238, 135), module, Rampage::FALL_B_PARAM));
  300. addParam(createParam<BefacoSwitch>(Vec(141, 238), module, Rampage::CYCLE_B_PARAM));
  301. addParam(createParam<Davies1900hWhiteKnob>(Vec(117, 76), module, Rampage::BALANCE_PARAM));
  302. addInput(createInput<PJ301MPort>(Vec(14, 30), module, Rampage::IN_A_INPUT));
  303. addInput(createInput<PJ301MPort>(Vec(52, 37), module, Rampage::TRIGG_A_INPUT));
  304. addInput(createInput<PJ301MPort>(Vec(8, 268), module, Rampage::RISE_CV_A_INPUT));
  305. addInput(createInput<PJ301MPort>(Vec(67, 268), module, Rampage::FALL_CV_A_INPUT));
  306. addInput(createInput<PJ301MPort>(Vec(38, 297), module, Rampage::EXP_CV_A_INPUT));
  307. addInput(createInput<PJ301MPort>(Vec(102, 290), module, Rampage::CYCLE_A_INPUT));
  308. addInput(createInput<PJ301MPort>(Vec(229, 30), module, Rampage::IN_B_INPUT));
  309. addInput(createInput<PJ301MPort>(Vec(192, 37), module, Rampage::TRIGG_B_INPUT));
  310. addInput(createInput<PJ301MPort>(Vec(176, 268), module, Rampage::RISE_CV_B_INPUT));
  311. addInput(createInput<PJ301MPort>(Vec(237, 268), module, Rampage::FALL_CV_B_INPUT));
  312. addInput(createInput<PJ301MPort>(Vec(207, 297), module, Rampage::EXP_CV_B_INPUT));
  313. addInput(createInput<PJ301MPort>(Vec(143, 290), module, Rampage::CYCLE_B_INPUT));
  314. addOutput(createOutput<PJ301MPort>(Vec(8, 326), module, Rampage::RISING_A_OUTPUT));
  315. addOutput(createOutput<PJ301MPort>(Vec(68, 326), module, Rampage::FALLING_A_OUTPUT));
  316. addOutput(createOutput<PJ301MPort>(Vec(104, 326), module, Rampage::EOC_A_OUTPUT));
  317. addOutput(createOutput<PJ301MPort>(Vec(102, 195), module, Rampage::OUT_A_OUTPUT));
  318. addOutput(createOutput<PJ301MPort>(Vec(177, 326), module, Rampage::RISING_B_OUTPUT));
  319. addOutput(createOutput<PJ301MPort>(Vec(237, 326), module, Rampage::FALLING_B_OUTPUT));
  320. addOutput(createOutput<PJ301MPort>(Vec(140, 326), module, Rampage::EOC_B_OUTPUT));
  321. addOutput(createOutput<PJ301MPort>(Vec(142, 195), module, Rampage::OUT_B_OUTPUT));
  322. addOutput(createOutput<PJ301MPort>(Vec(122, 133), module, Rampage::COMPARATOR_OUTPUT));
  323. addOutput(createOutput<PJ301MPort>(Vec(89, 157), module, Rampage::MIN_OUTPUT));
  324. addOutput(createOutput<PJ301MPort>(Vec(155, 157), module, Rampage::MAX_OUTPUT));
  325. addChild(createLight<SmallLight<RedLight>>(Vec(132, 167), module, Rampage::COMPARATOR_LIGHT));
  326. addChild(createLight<SmallLight<RedLight>>(Vec(123, 174), module, Rampage::MIN_LIGHT));
  327. addChild(createLight<SmallLight<RedLight>>(Vec(141, 174), module, Rampage::MAX_LIGHT));
  328. addChild(createLight<SmallLight<RedLight>>(Vec(126, 185), module, Rampage::OUT_A_LIGHT));
  329. addChild(createLight<SmallLight<RedLight>>(Vec(138, 185), module, Rampage::OUT_B_LIGHT));
  330. addChild(createLight<SmallLight<RedLight>>(Vec(18, 312), module, Rampage::RISING_A_LIGHT));
  331. addChild(createLight<SmallLight<RedLight>>(Vec(78, 312), module, Rampage::FALLING_A_LIGHT));
  332. addChild(createLight<SmallLight<RedLight>>(Vec(187, 312), module, Rampage::RISING_B_LIGHT));
  333. addChild(createLight<SmallLight<RedLight>>(Vec(247, 312), module, Rampage::FALLING_B_LIGHT));
  334. }
  335. };
  336. Model *modelRampage = createModel<Rampage, RampageWidget>("Rampage");