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.

417 lines
16KB

  1. #include "plugin.hpp"
  2. #include "elements/dsp/part.h"
  3. struct Elements : Module {
  4. enum ParamIds {
  5. CONTOUR_PARAM,
  6. BOW_PARAM,
  7. BLOW_PARAM,
  8. STRIKE_PARAM,
  9. COARSE_PARAM,
  10. FINE_PARAM,
  11. FM_PARAM,
  12. FLOW_PARAM,
  13. MALLET_PARAM,
  14. GEOMETRY_PARAM,
  15. BRIGHTNESS_PARAM,
  16. BOW_TIMBRE_PARAM,
  17. BLOW_TIMBRE_PARAM,
  18. STRIKE_TIMBRE_PARAM,
  19. DAMPING_PARAM,
  20. POSITION_PARAM,
  21. SPACE_PARAM,
  22. BOW_TIMBRE_MOD_PARAM,
  23. FLOW_MOD_PARAM,
  24. BLOW_TIMBRE_MOD_PARAM,
  25. MALLET_MOD_PARAM,
  26. STRIKE_TIMBRE_MOD_PARAM,
  27. DAMPING_MOD_PARAM,
  28. GEOMETRY_MOD_PARAM,
  29. POSITION_MOD_PARAM,
  30. BRIGHTNESS_MOD_PARAM,
  31. SPACE_MOD_PARAM,
  32. PLAY_PARAM,
  33. NUM_PARAMS
  34. };
  35. enum InputIds {
  36. NOTE_INPUT,
  37. FM_INPUT,
  38. GATE_INPUT,
  39. STRENGTH_INPUT,
  40. BLOW_INPUT,
  41. STRIKE_INPUT,
  42. BOW_TIMBRE_MOD_INPUT,
  43. FLOW_MOD_INPUT,
  44. BLOW_TIMBRE_MOD_INPUT,
  45. MALLET_MOD_INPUT,
  46. STRIKE_TIMBRE_MOD_INPUT,
  47. DAMPING_MOD_INPUT,
  48. GEOMETRY_MOD_INPUT,
  49. POSITION_MOD_INPUT,
  50. BRIGHTNESS_MOD_INPUT,
  51. SPACE_MOD_INPUT,
  52. NUM_INPUTS
  53. };
  54. enum OutputIds {
  55. AUX_OUTPUT,
  56. MAIN_OUTPUT,
  57. NUM_OUTPUTS
  58. };
  59. enum LightIds {
  60. GATE_LIGHT,
  61. EXCITER_LIGHT,
  62. RESONATOR_LIGHT,
  63. NUM_LIGHTS
  64. };
  65. dsp::SampleRateConverter<16 * 2> inputSrc;
  66. dsp::SampleRateConverter<16 * 2> outputSrc;
  67. dsp::DoubleRingBuffer<dsp::Frame<16 * 2>, 256> inputBuffer;
  68. dsp::DoubleRingBuffer<dsp::Frame<16 * 2>, 256> outputBuffer;
  69. uint16_t reverb_buffers[16][32768] = {};
  70. elements::Part* parts[16];
  71. Elements() {
  72. config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
  73. configParam(CONTOUR_PARAM, 0.0, 1.0, 1.0, "Envelope contour");
  74. configParam(BOW_PARAM, 0.0, 1.0, 0.0, "Bow exciter");
  75. configParam(BLOW_PARAM, 0.0, 1.0, 0.0, "Blow exciter");
  76. configParam(STRIKE_PARAM, 0.0, 1.0, 0.5, "Percussive noise amount");
  77. configParam(COARSE_PARAM, -30.0, 30.0, 0.0, "Coarse frequency adjustment");
  78. configParam(FINE_PARAM, -2.0, 2.0, 0.0, "Fine frequency adjustment");
  79. configParam(FM_PARAM, -1.0, 1.0, 0.0, "FM input attenuverter");
  80. configParam(FLOW_PARAM, 0.0, 1.0, 0.5, "Air flow noise color");
  81. configParam(MALLET_PARAM, 0.0, 1.0, 0.5, "Percussive noise type");
  82. configParam(GEOMETRY_PARAM, 0.0, 1.0, 0.5, "Resonator geometry");
  83. configParam(BRIGHTNESS_PARAM, 0.0, 1.0, 0.5, "Brightness");
  84. configParam(BOW_TIMBRE_PARAM, 0.0, 1.0, 0.5, "Bow timbre");
  85. configParam(BLOW_TIMBRE_PARAM, 0.0, 1.0, 0.5, "Blow timbre");
  86. configParam(STRIKE_TIMBRE_PARAM, 0.0, 1.0, 0.5, "Strike timbre");
  87. configParam(DAMPING_PARAM, 0.0, 1.0, 0.5, "Energy dissipation speed");
  88. configParam(POSITION_PARAM, 0.0, 1.0, 0.5, "Excitation position");
  89. configParam(SPACE_PARAM, 0.0, 2.0, 0.0, "Reverb space");
  90. configParam(BOW_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0, "Bow timbre CV");
  91. configParam(FLOW_MOD_PARAM, -1.0, 1.0, 0.0, "Air flow noise CV");
  92. configParam(BLOW_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0, "Blow timbre CV");
  93. configParam(MALLET_MOD_PARAM, -1.0, 1.0, 0.0, "Percussive noise CV");
  94. configParam(STRIKE_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0, "Strike timbre CV");
  95. configParam(DAMPING_MOD_PARAM, -1.0, 1.0, 0.0, "Energy dissipation speed CV");
  96. configParam(GEOMETRY_MOD_PARAM, -1.0, 1.0, 0.0, "Resonator geometry CV");
  97. configParam(POSITION_MOD_PARAM, -1.0, 1.0, 0.0, "Excitation position CV");
  98. configParam(BRIGHTNESS_MOD_PARAM, -1.0, 1.0, 0.0, "Brightness CV");
  99. configParam(SPACE_MOD_PARAM, -2.0, 2.0, 0.0, "Reverb space CV");
  100. configButton(PLAY_PARAM, "Play");
  101. configInput(NOTE_INPUT, "Pitch (1V/oct)");
  102. configInput(FM_INPUT, "FM");
  103. configInput(GATE_INPUT, "Gate");
  104. configInput(STRENGTH_INPUT, "Strength");
  105. configInput(BLOW_INPUT, "External blow");
  106. configInput(STRIKE_INPUT, "External strike");
  107. configInput(BOW_TIMBRE_MOD_INPUT, "Bow timbre");
  108. configInput(FLOW_MOD_INPUT, "Air flow noise");
  109. configInput(BLOW_TIMBRE_MOD_INPUT, "Blow timbre");
  110. configInput(MALLET_MOD_INPUT, "Percussive noise");
  111. configInput(STRIKE_TIMBRE_MOD_INPUT, "Strike timbre");
  112. configInput(DAMPING_MOD_INPUT, "Energy dissipation speed");
  113. configInput(GEOMETRY_MOD_INPUT, "Resonator geometry");
  114. configInput(POSITION_MOD_INPUT, "Excitation position");
  115. configInput(BRIGHTNESS_MOD_INPUT, "Brightness");
  116. configInput(SPACE_MOD_INPUT, "Reverb space");
  117. configOutput(AUX_OUTPUT, "Left");
  118. configOutput(MAIN_OUTPUT, "Right");
  119. configBypass(BLOW_INPUT, AUX_OUTPUT);
  120. configBypass(STRIKE_INPUT, MAIN_OUTPUT);
  121. for (int c = 0; c < 16; c++) {
  122. parts[c] = new elements::Part();
  123. // In the Mutable Instruments code, Part doesn't initialize itself, so zero it here.
  124. std::memset(parts[c], 0, sizeof(*parts[c]));
  125. parts[c]->Init(reverb_buffers[c]);
  126. // Just some random numbers
  127. uint32_t seed[3] = {1, 2, 3};
  128. parts[c]->Seed(seed, 3);
  129. }
  130. }
  131. ~Elements() {
  132. for (int c = 0; c < 16; c++) {
  133. delete parts[c];
  134. }
  135. }
  136. void onReset() override {
  137. setModel(0);
  138. }
  139. void process(const ProcessArgs& args) override {
  140. int channels = std::max(inputs[NOTE_INPUT].getChannels(), 1);
  141. // Get input
  142. if (!inputBuffer.full()) {
  143. dsp::Frame<16 * 2> inputFrame = {};
  144. for (int c = 0; c < channels; c++) {
  145. inputFrame.samples[c * 2 + 0] = inputs[BLOW_INPUT].getPolyVoltage(c) / 5.0;
  146. inputFrame.samples[c * 2 + 1] = inputs[STRIKE_INPUT].getPolyVoltage(c) / 5.0;
  147. }
  148. inputBuffer.push(inputFrame);
  149. }
  150. // Generate output if output buffer is empty
  151. if (outputBuffer.empty()) {
  152. // blow[channel][bufferIndex]
  153. float blow[16][16] = {};
  154. float strike[16][16] = {};
  155. // Convert input buffer
  156. {
  157. inputSrc.setRates(args.sampleRate, 32000);
  158. inputSrc.setChannels(channels * 2);
  159. int inLen = inputBuffer.size();
  160. int outLen = 16;
  161. dsp::Frame<16 * 2> inputFrames[outLen];
  162. inputSrc.process(inputBuffer.startData(), &inLen, inputFrames, &outLen);
  163. inputBuffer.startIncr(inLen);
  164. for (int c = 0; c < channels; c++) {
  165. for (int i = 0; i < outLen; i++) {
  166. blow[c][i] = inputFrames[i].samples[c * 2 + 0];
  167. strike[c][i] = inputFrames[i].samples[c * 2 + 1];
  168. }
  169. }
  170. }
  171. // Process channels
  172. // main[channel][bufferIndex]
  173. float main[16][16];
  174. float aux[16][16];
  175. float gateLight = 0.f;
  176. float exciterLight = 0.f;
  177. float resonatorLight = 0.f;
  178. for (int c = 0; c < channels; c++) {
  179. // Set patch from parameters
  180. elements::Patch* p = parts[c]->mutable_patch();
  181. p->exciter_envelope_shape = params[CONTOUR_PARAM].getValue();
  182. p->exciter_bow_level = params[BOW_PARAM].getValue();
  183. p->exciter_blow_level = params[BLOW_PARAM].getValue();
  184. p->exciter_strike_level = params[STRIKE_PARAM].getValue();
  185. #define BIND(_p, _m, _i) clamp(params[_p].getValue() + 3.3f * dsp::quadraticBipolar(params[_m].getValue()) * inputs[_i].getPolyVoltage(c) / 5.f, 0.f, 0.9995f)
  186. p->exciter_bow_timbre = BIND(BOW_TIMBRE_PARAM, BOW_TIMBRE_MOD_PARAM, BOW_TIMBRE_MOD_INPUT);
  187. p->exciter_blow_meta = BIND(FLOW_PARAM, FLOW_MOD_PARAM, FLOW_MOD_INPUT);
  188. p->exciter_blow_timbre = BIND(BLOW_TIMBRE_PARAM, BLOW_TIMBRE_MOD_PARAM, BLOW_TIMBRE_MOD_INPUT);
  189. p->exciter_strike_meta = BIND(MALLET_PARAM, MALLET_MOD_PARAM, MALLET_MOD_INPUT);
  190. p->exciter_strike_timbre = BIND(STRIKE_TIMBRE_PARAM, STRIKE_TIMBRE_MOD_PARAM, STRIKE_TIMBRE_MOD_INPUT);
  191. p->resonator_geometry = BIND(GEOMETRY_PARAM, GEOMETRY_MOD_PARAM, GEOMETRY_MOD_INPUT);
  192. p->resonator_brightness = BIND(BRIGHTNESS_PARAM, BRIGHTNESS_MOD_PARAM, BRIGHTNESS_MOD_INPUT);
  193. p->resonator_damping = BIND(DAMPING_PARAM, DAMPING_MOD_PARAM, DAMPING_MOD_INPUT);
  194. p->resonator_position = BIND(POSITION_PARAM, POSITION_MOD_PARAM, POSITION_MOD_INPUT);
  195. p->space = clamp(params[SPACE_PARAM].getValue() + params[SPACE_MOD_PARAM].getValue() * inputs[SPACE_MOD_INPUT].getPolyVoltage(c) / 5.f, 0.f, 2.f);
  196. // Get performance inputs
  197. elements::PerformanceState performance;
  198. performance.note = 12.f * inputs[NOTE_INPUT].getVoltage(c) + std::round(params[COARSE_PARAM].getValue()) + params[FINE_PARAM].getValue() + 69.f;
  199. performance.modulation = 3.3f * dsp::quarticBipolar(params[FM_PARAM].getValue()) * 49.5f * inputs[FM_INPUT].getPolyVoltage(c) / 5.f;
  200. performance.gate = params[PLAY_PARAM].getValue() >= 1.f || inputs[GATE_INPUT].getPolyVoltage(c) >= 1.f;
  201. performance.strength = clamp(1.f - inputs[STRENGTH_INPUT].getPolyVoltage(c) / 5.f, 0.f, 1.f);
  202. // Generate audio
  203. parts[c]->Process(performance, blow[c], strike[c], main[c], aux[c], 16);
  204. // Set lights based on first poly channel
  205. gateLight = std::max(gateLight, performance.gate ? 0.75f : 0.f);
  206. exciterLight = std::max(exciterLight, parts[c]->exciter_level());
  207. resonatorLight = std::max(resonatorLight, parts[c]->resonator_level());
  208. }
  209. // Set lights
  210. lights[GATE_LIGHT].setBrightness(gateLight);
  211. lights[EXCITER_LIGHT].setBrightness(exciterLight);
  212. lights[RESONATOR_LIGHT].setBrightness(resonatorLight);
  213. // Convert output buffer
  214. {
  215. dsp::Frame<16 * 2> outputFrames[16];
  216. for (int c = 0; c < channels; c++) {
  217. for (int i = 0; i < 16; i++) {
  218. outputFrames[i].samples[c * 2 + 0] = main[c][i];
  219. outputFrames[i].samples[c * 2 + 1] = aux[c][i];
  220. }
  221. }
  222. outputSrc.setRates(32000, args.sampleRate);
  223. outputSrc.setChannels(channels * 2);
  224. int inLen = 16;
  225. int outLen = outputBuffer.capacity();
  226. outputSrc.process(outputFrames, &inLen, outputBuffer.endData(), &outLen);
  227. outputBuffer.endIncr(outLen);
  228. }
  229. }
  230. // Set output
  231. if (!outputBuffer.empty()) {
  232. dsp::Frame<16 * 2> outputFrame = outputBuffer.shift();
  233. for (int c = 0; c < channels; c++) {
  234. outputs[AUX_OUTPUT].setVoltage(5.f * outputFrame.samples[c * 2 + 0], c);
  235. outputs[MAIN_OUTPUT].setVoltage(5.f * outputFrame.samples[c * 2 + 1], c);
  236. }
  237. }
  238. outputs[AUX_OUTPUT].setChannels(channels);
  239. outputs[MAIN_OUTPUT].setChannels(channels);
  240. }
  241. json_t* dataToJson() override {
  242. json_t* rootJ = json_object();
  243. json_object_set_new(rootJ, "model", json_integer(getModel()));
  244. return rootJ;
  245. }
  246. void dataFromJson(json_t* rootJ) override {
  247. json_t* modelJ = json_object_get(rootJ, "model");
  248. if (modelJ) {
  249. setModel(json_integer_value(modelJ));
  250. }
  251. }
  252. int getModel() {
  253. // Use the first channel's Part as the reference model
  254. if (parts[0]->easter_egg())
  255. return -1;
  256. return (int) parts[0]->resonator_model();
  257. }
  258. /** Sets the resonator model.
  259. -1 means easter egg (Ominous voice)
  260. */
  261. void setModel(int model) {
  262. if (model < 0) {
  263. for (int c = 0; c < 16; c++) {
  264. parts[c]->set_easter_egg(true);
  265. }
  266. }
  267. else {
  268. for (int c = 0; c < 16; c++) {
  269. parts[c]->set_easter_egg(false);
  270. parts[c]->set_resonator_model((elements::ResonatorModel) model);
  271. }
  272. }
  273. }
  274. };
  275. struct ElementsWidget : ModuleWidget {
  276. ElementsWidget(Elements* module) {
  277. setModule(module);
  278. setPanel(Svg::load(asset::plugin(pluginInstance, "res/Elements.svg")));
  279. addChild(createWidget<ScrewSilver>(Vec(15, 0)));
  280. addChild(createWidget<ScrewSilver>(Vec(480, 0)));
  281. addChild(createWidget<ScrewSilver>(Vec(15, 365)));
  282. addChild(createWidget<ScrewSilver>(Vec(480, 365)));
  283. addParam(createParam<Rogan1PSWhite>(Vec(28, 42), module, Elements::CONTOUR_PARAM));
  284. addParam(createParam<Rogan1PSWhite>(Vec(99, 42), module, Elements::BOW_PARAM));
  285. addParam(createParam<Rogan1PSRed>(Vec(169, 42), module, Elements::BLOW_PARAM));
  286. addParam(createParam<Rogan1PSGreen>(Vec(239, 42), module, Elements::STRIKE_PARAM));
  287. addParam(createParam<Rogan1PSWhite>(Vec(310, 42), module, Elements::COARSE_PARAM));
  288. addParam(createParam<Rogan1PSWhite>(Vec(381, 42), module, Elements::FINE_PARAM));
  289. addParam(createParam<Rogan1PSWhite>(Vec(451, 42), module, Elements::FM_PARAM));
  290. addParam(createParam<Rogan3PSRed>(Vec(115, 116), module, Elements::FLOW_PARAM));
  291. addParam(createParam<Rogan3PSGreen>(Vec(212, 116), module, Elements::MALLET_PARAM));
  292. addParam(createParam<Rogan3PSWhite>(Vec(326, 116), module, Elements::GEOMETRY_PARAM));
  293. addParam(createParam<Rogan3PSWhite>(Vec(423, 116), module, Elements::BRIGHTNESS_PARAM));
  294. addParam(createParam<Rogan1PSWhite>(Vec(99, 202), module, Elements::BOW_TIMBRE_PARAM));
  295. addParam(createParam<Rogan1PSRed>(Vec(170, 202), module, Elements::BLOW_TIMBRE_PARAM));
  296. addParam(createParam<Rogan1PSGreen>(Vec(239, 202), module, Elements::STRIKE_TIMBRE_PARAM));
  297. addParam(createParam<Rogan1PSWhite>(Vec(310, 202), module, Elements::DAMPING_PARAM));
  298. addParam(createParam<Rogan1PSWhite>(Vec(380, 202), module, Elements::POSITION_PARAM));
  299. addParam(createParam<Rogan1PSWhite>(Vec(451, 202), module, Elements::SPACE_PARAM));
  300. addParam(createParam<Trimpot>(Vec(104.5, 273), module, Elements::BOW_TIMBRE_MOD_PARAM));
  301. addParam(createParam<Trimpot>(Vec(142.5, 273), module, Elements::FLOW_MOD_PARAM));
  302. addParam(createParam<Trimpot>(Vec(181.5, 273), module, Elements::BLOW_TIMBRE_MOD_PARAM));
  303. addParam(createParam<Trimpot>(Vec(219.5, 273), module, Elements::MALLET_MOD_PARAM));
  304. addParam(createParam<Trimpot>(Vec(257.5, 273), module, Elements::STRIKE_TIMBRE_MOD_PARAM));
  305. addParam(createParam<Trimpot>(Vec(315.5, 273), module, Elements::DAMPING_MOD_PARAM));
  306. addParam(createParam<Trimpot>(Vec(354.5, 273), module, Elements::GEOMETRY_MOD_PARAM));
  307. addParam(createParam<Trimpot>(Vec(392.5, 273), module, Elements::POSITION_MOD_PARAM));
  308. addParam(createParam<Trimpot>(Vec(430.5, 273), module, Elements::BRIGHTNESS_MOD_PARAM));
  309. addParam(createParam<Trimpot>(Vec(469.5, 273), module, Elements::SPACE_MOD_PARAM));
  310. addInput(createInput<PJ301MPort>(Vec(20, 178), module, Elements::NOTE_INPUT));
  311. addInput(createInput<PJ301MPort>(Vec(55, 178), module, Elements::FM_INPUT));
  312. addInput(createInput<PJ301MPort>(Vec(20, 224), module, Elements::GATE_INPUT));
  313. addInput(createInput<PJ301MPort>(Vec(55, 224), module, Elements::STRENGTH_INPUT));
  314. addInput(createInput<PJ301MPort>(Vec(20, 270), module, Elements::BLOW_INPUT));
  315. addInput(createInput<PJ301MPort>(Vec(55, 270), module, Elements::STRIKE_INPUT));
  316. addOutput(createOutput<PJ301MPort>(Vec(20, 316), module, Elements::AUX_OUTPUT));
  317. addOutput(createOutput<PJ301MPort>(Vec(55, 316), module, Elements::MAIN_OUTPUT));
  318. addInput(createInput<PJ301MPort>(Vec(101, 316), module, Elements::BOW_TIMBRE_MOD_INPUT));
  319. addInput(createInput<PJ301MPort>(Vec(139, 316), module, Elements::FLOW_MOD_INPUT));
  320. addInput(createInput<PJ301MPort>(Vec(178, 316), module, Elements::BLOW_TIMBRE_MOD_INPUT));
  321. addInput(createInput<PJ301MPort>(Vec(216, 316), module, Elements::MALLET_MOD_INPUT));
  322. addInput(createInput<PJ301MPort>(Vec(254, 316), module, Elements::STRIKE_TIMBRE_MOD_INPUT));
  323. addInput(createInput<PJ301MPort>(Vec(312, 316), module, Elements::DAMPING_MOD_INPUT));
  324. addInput(createInput<PJ301MPort>(Vec(350, 316), module, Elements::GEOMETRY_MOD_INPUT));
  325. addInput(createInput<PJ301MPort>(Vec(389, 316), module, Elements::POSITION_MOD_INPUT));
  326. addInput(createInput<PJ301MPort>(Vec(427, 316), module, Elements::BRIGHTNESS_MOD_INPUT));
  327. addInput(createInput<PJ301MPort>(Vec(466, 316), module, Elements::SPACE_MOD_INPUT));
  328. addParam(createParam<CKD6>(Vec(36, 116), module, Elements::PLAY_PARAM));
  329. struct GateLight : YellowLight {
  330. GateLight() {
  331. box.size = Vec(28 - 6, 28 - 6);
  332. bgColor = color::BLACK_TRANSPARENT;
  333. }
  334. };
  335. addChild(createLight<GateLight>(Vec(36 + 3, 116 + 3), module, Elements::GATE_LIGHT));
  336. addChild(createLight<MediumLight<GreenLight>>(Vec(184, 165), module, Elements::EXCITER_LIGHT));
  337. addChild(createLight<MediumLight<RedLight>>(Vec(395, 165), module, Elements::RESONATOR_LIGHT));
  338. }
  339. void appendContextMenu(Menu* menu) override {
  340. Elements* module = dynamic_cast<Elements*>(this->module);
  341. assert(module);
  342. menu->addChild(new MenuSeparator);
  343. menu->addChild(createMenuLabel("Models"));
  344. static const std::vector<std::string> modelLabels = {
  345. "Original",
  346. "Non-linear string",
  347. "Chords",
  348. "Ominous voice",
  349. };
  350. for (int i = 0; i < 4; i++) {
  351. menu->addChild(createCheckMenuItem(modelLabels[i], "",
  352. [=]() {return module->getModel() == i;},
  353. [=]() {module->setModel(i);}
  354. ));
  355. }
  356. }
  357. };
  358. Model* modelElements = createModel<Elements, ElementsWidget>("Elements");