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.

311 lines
11KB

  1. #include <string.h>
  2. #include "AudibleInstruments.hpp"
  3. #include "dsp.hpp"
  4. #include "elements/dsp/part.h"
  5. struct Elements : Module {
  6. enum ParamIds {
  7. CONTOUR_PARAM,
  8. BOW_PARAM,
  9. BLOW_PARAM,
  10. STRIKE_PARAM,
  11. COARSE_PARAM,
  12. FINE_PARAM,
  13. FM_PARAM,
  14. FLOW_PARAM,
  15. MALLET_PARAM,
  16. GEOMETRY_PARAM,
  17. BRIGHTNESS_PARAM,
  18. BOW_TIMBRE_PARAM,
  19. BLOW_TIMBRE_PARAM,
  20. STRIKE_TIMBRE_PARAM,
  21. DAMPING_PARAM,
  22. POSITION_PARAM,
  23. SPACE_PARAM,
  24. BOW_TIMBRE_MOD_PARAM,
  25. FLOW_MOD_PARAM,
  26. BLOW_TIMBRE_MOD_PARAM,
  27. MALLET_MOD_PARAM,
  28. STRIKE_TIMBRE_MOD_PARAM,
  29. DAMPING_MOD_PARAM,
  30. GEOMETRY_MOD_PARAM,
  31. POSITION_MOD_PARAM,
  32. BRIGHTNESS_MOD_PARAM,
  33. SPACE_MOD_PARAM,
  34. PLAY_PARAM,
  35. NUM_PARAMS
  36. };
  37. enum InputIds {
  38. NOTE_INPUT,
  39. FM_INPUT,
  40. GATE_INPUT,
  41. STRENGTH_INPUT,
  42. BLOW_INPUT,
  43. STRIKE_INPUT,
  44. BOW_TIMBRE_MOD_INPUT,
  45. FLOW_MOD_INPUT,
  46. BLOW_TIMBRE_MOD_INPUT,
  47. MALLET_MOD_INPUT,
  48. STRIKE_TIMBRE_MOD_INPUT,
  49. DAMPING_MOD_INPUT,
  50. GEOMETRY_MOD_INPUT,
  51. POSITION_MOD_INPUT,
  52. BRIGHTNESS_MOD_INPUT,
  53. SPACE_MOD_INPUT,
  54. NUM_INPUTS
  55. };
  56. enum OutputIds {
  57. AUX_OUTPUT,
  58. MAIN_OUTPUT,
  59. NUM_OUTPUTS
  60. };
  61. SampleRateConverter<2> inputSrc;
  62. SampleRateConverter<2> outputSrc;
  63. DoubleRingBuffer<Frame<2>, 256> inputBuffer;
  64. DoubleRingBuffer<Frame<2>, 256> outputBuffer;
  65. uint16_t reverb_buffer[32768] = {};
  66. elements::Part *part;
  67. float lights[2] = {};
  68. Elements();
  69. ~Elements();
  70. void step();
  71. json_t *toJson() {
  72. json_t *rootJ = json_object();
  73. json_object_set_new(rootJ, "model", json_integer(getModel()));
  74. return rootJ;
  75. }
  76. void fromJson(json_t *rootJ) {
  77. json_t *modelJ = json_object_get(rootJ, "model");
  78. if (modelJ) {
  79. setModel(json_integer_value(modelJ));
  80. }
  81. }
  82. int getModel() {
  83. return (int)part->resonator_model();
  84. }
  85. void setModel(int model) {
  86. part->set_resonator_model((elements::ResonatorModel)model);
  87. }
  88. };
  89. Elements::Elements() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
  90. part = new elements::Part();
  91. // In the Mutable Instruments code, Part doesn't initialize itself, so zero it here.
  92. memset(part, 0, sizeof(*part));
  93. part->Init(reverb_buffer);
  94. // Just some random numbers
  95. uint32_t seed[3] = {1, 2, 3};
  96. part->Seed(seed, 3);
  97. }
  98. Elements::~Elements() {
  99. delete part;
  100. }
  101. void Elements::step() {
  102. // Get input
  103. if (!inputBuffer.full()) {
  104. Frame<2> inputFrame;
  105. inputFrame.samples[0] = inputs[BLOW_INPUT].value / 5.0;
  106. inputFrame.samples[1] = inputs[STRIKE_INPUT].value / 5.0;
  107. inputBuffer.push(inputFrame);
  108. }
  109. // Render frames
  110. if (outputBuffer.empty()) {
  111. float blow[16] = {};
  112. float strike[16] = {};
  113. float main[16];
  114. float aux[16];
  115. // Convert input buffer
  116. {
  117. inputSrc.setRatio(32000.0 / gSampleRate);
  118. Frame<2> inputFrames[16];
  119. int inLen = inputBuffer.size();
  120. int outLen = 16;
  121. inputSrc.process(inputBuffer.startData(), &inLen, inputFrames, &outLen);
  122. inputBuffer.startIncr(inLen);
  123. for (int i = 0; i < outLen; i++) {
  124. blow[i] = inputFrames[i].samples[0];
  125. strike[i] = inputFrames[i].samples[1];
  126. }
  127. }
  128. // Set patch from parameters
  129. elements::Patch* p = part->mutable_patch();
  130. p->exciter_envelope_shape = params[CONTOUR_PARAM].value;
  131. p->exciter_bow_level = params[BOW_PARAM].value;
  132. p->exciter_blow_level = params[BLOW_PARAM].value;
  133. p->exciter_strike_level = params[STRIKE_PARAM].value;
  134. #define BIND(_p, _m, _i) clampf(params[_p].value + 3.3*quadraticBipolar(params[_m].value)*inputs[_i].value/5.0, 0.0, 0.9995)
  135. p->exciter_bow_timbre = BIND(BOW_TIMBRE_PARAM, BOW_TIMBRE_MOD_PARAM, BOW_TIMBRE_MOD_INPUT);
  136. p->exciter_blow_meta = BIND(FLOW_PARAM, FLOW_MOD_PARAM, FLOW_MOD_INPUT);
  137. p->exciter_blow_timbre = BIND(BLOW_TIMBRE_PARAM, BLOW_TIMBRE_MOD_PARAM, BLOW_TIMBRE_MOD_INPUT);
  138. p->exciter_strike_meta = BIND(MALLET_PARAM, MALLET_MOD_PARAM, MALLET_MOD_INPUT);
  139. p->exciter_strike_timbre = BIND(STRIKE_TIMBRE_PARAM, STRIKE_TIMBRE_MOD_PARAM, STRIKE_TIMBRE_MOD_INPUT);
  140. p->resonator_geometry = BIND(GEOMETRY_PARAM, GEOMETRY_MOD_PARAM, GEOMETRY_MOD_INPUT);
  141. p->resonator_brightness = BIND(BRIGHTNESS_PARAM, BRIGHTNESS_MOD_PARAM, BRIGHTNESS_MOD_INPUT);
  142. p->resonator_damping = BIND(DAMPING_PARAM, DAMPING_MOD_PARAM, DAMPING_MOD_INPUT);
  143. p->resonator_position = BIND(POSITION_PARAM, POSITION_MOD_PARAM, POSITION_MOD_INPUT);
  144. p->space = clampf(params[SPACE_PARAM].value + params[SPACE_MOD_PARAM].value*inputs[SPACE_MOD_INPUT].value/5.0, 0.0, 2.0);
  145. // Get performance inputs
  146. elements::PerformanceState performance;
  147. performance.note = 12.0*inputs[NOTE_INPUT].value + roundf(params[COARSE_PARAM].value) + params[FINE_PARAM].value + 69.0;
  148. performance.modulation = 3.3*quarticBipolar(params[FM_PARAM].value) * 49.5 * inputs[FM_INPUT].value/5.0;
  149. performance.gate = params[PLAY_PARAM].value >= 1.0 || inputs[GATE_INPUT].value >= 1.0;
  150. performance.strength = clampf(1.0 - inputs[STRENGTH_INPUT].value/5.0, 0.0, 1.0);
  151. // Generate audio
  152. part->Process(performance, blow, strike, main, aux, 16);
  153. // Convert output buffer
  154. {
  155. Frame<2> outputFrames[16];
  156. for (int i = 0; i < 16; i++) {
  157. outputFrames[i].samples[0] = main[i];
  158. outputFrames[i].samples[1] = aux[i];
  159. }
  160. outputSrc.setRatio(gSampleRate / 32000.0);
  161. int inLen = 16;
  162. int outLen = outputBuffer.capacity();
  163. outputSrc.process(outputFrames, &inLen, outputBuffer.endData(), &outLen);
  164. outputBuffer.endIncr(outLen);
  165. }
  166. // Set lights
  167. lights[0] = part->exciter_level();
  168. lights[1] = part->resonator_level();
  169. }
  170. // Set output
  171. if (!outputBuffer.empty()) {
  172. Frame<2> outputFrame = outputBuffer.shift();
  173. outputs[AUX_OUTPUT].value = 5.0 * outputFrame.samples[0];
  174. outputs[MAIN_OUTPUT].value = 5.0 * outputFrame.samples[1];
  175. }
  176. }
  177. ElementsWidget::ElementsWidget() {
  178. Elements *module = new Elements();
  179. setModule(module);
  180. box.size = Vec(15*34, 380);
  181. {
  182. Panel *panel = new LightPanel();
  183. panel->backgroundImage = Image::load(assetPlugin(plugin, "res/Elements.png"));
  184. panel->box.size = box.size;
  185. addChild(panel);
  186. }
  187. addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  188. addChild(createScrew<ScrewSilver>(Vec(480, 0)));
  189. addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  190. addChild(createScrew<ScrewSilver>(Vec(480, 365)));
  191. addParam(createParam<Rogan1PSWhite>(Vec(29, 43), module, Elements::CONTOUR_PARAM, 0.0, 1.0, 1.0));
  192. addParam(createParam<Rogan1PSWhite>(Vec(100, 43), module, Elements::BOW_PARAM, 0.0, 1.0, 0.0));
  193. addParam(createParam<Rogan1PSRed>(Vec(170, 43), module, Elements::BLOW_PARAM, 0.0, 1.0, 0.0));
  194. addParam(createParam<Rogan1PSGreen>(Vec(240, 43), module, Elements::STRIKE_PARAM, 0.0, 1.0, 0.5));
  195. addParam(createParam<Rogan1PSWhite>(Vec(311, 43), module, Elements::COARSE_PARAM, -30.0, 30.0, 0.0));
  196. addParam(createParam<Rogan1PSWhite>(Vec(382, 43), module, Elements::FINE_PARAM, -2.0, 2.0, 0.0));
  197. addParam(createParam<Rogan1PSWhite>(Vec(452, 43), module, Elements::FM_PARAM, -1.0, 1.0, 0.0));
  198. addParam(createParam<Rogan3PSRed>(Vec(116, 117), module, Elements::FLOW_PARAM, 0.0, 1.0, 0.5));
  199. addParam(createParam<Rogan3PSGreen>(Vec(213, 117), module, Elements::MALLET_PARAM, 0.0, 1.0, 0.5));
  200. addParam(createParam<Rogan3PSWhite>(Vec(327, 117), module, Elements::GEOMETRY_PARAM, 0.0, 1.0, 0.5));
  201. addParam(createParam<Rogan3PSWhite>(Vec(424, 117), module, Elements::BRIGHTNESS_PARAM, 0.0, 1.0, 0.5));
  202. addParam(createParam<Rogan1PSWhite>(Vec(100, 203), module, Elements::BOW_TIMBRE_PARAM, 0.0, 1.0, 0.5));
  203. addParam(createParam<Rogan1PSRed>(Vec(171, 203), module, Elements::BLOW_TIMBRE_PARAM, 0.0, 1.0, 0.5));
  204. addParam(createParam<Rogan1PSGreen>(Vec(240, 203), module, Elements::STRIKE_TIMBRE_PARAM, 0.0, 1.0, 0.5));
  205. addParam(createParam<Rogan1PSWhite>(Vec(311, 203), module, Elements::DAMPING_PARAM, 0.0, 1.0, 0.5));
  206. addParam(createParam<Rogan1PSWhite>(Vec(381, 203), module, Elements::POSITION_PARAM, 0.0, 1.0, 0.5));
  207. addParam(createParam<Rogan1PSWhite>(Vec(452, 203), module, Elements::SPACE_PARAM, 0.0, 2.0, 0.0));
  208. addParam(createParam<Trimpot>(Vec(104, 274), module, Elements::BOW_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0));
  209. addParam(createParam<Trimpot>(Vec(143, 274), module, Elements::FLOW_MOD_PARAM, -1.0, 1.0, 0.0));
  210. addParam(createParam<Trimpot>(Vec(181, 274), module, Elements::BLOW_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0));
  211. addParam(createParam<Trimpot>(Vec(220, 274), module, Elements::MALLET_MOD_PARAM, -1.0, 1.0, 0.0));
  212. addParam(createParam<Trimpot>(Vec(258, 274), module, Elements::STRIKE_TIMBRE_MOD_PARAM, -1.0, 1.0, 0.0));
  213. addParam(createParam<Trimpot>(Vec(316, 274), module, Elements::DAMPING_MOD_PARAM, -1.0, 1.0, 0.0));
  214. addParam(createParam<Trimpot>(Vec(354, 274), module, Elements::GEOMETRY_MOD_PARAM, -1.0, 1.0, 0.0));
  215. addParam(createParam<Trimpot>(Vec(393, 274), module, Elements::POSITION_MOD_PARAM, -1.0, 1.0, 0.0));
  216. addParam(createParam<Trimpot>(Vec(431, 274), module, Elements::BRIGHTNESS_MOD_PARAM, -1.0, 1.0, 0.0));
  217. addParam(createParam<Trimpot>(Vec(470, 274), module, Elements::SPACE_MOD_PARAM, -2.0, 2.0, 0.0));
  218. addInput(createInput<PJ3410Port>(Vec(16, 175), module, Elements::NOTE_INPUT));
  219. addInput(createInput<PJ3410Port>(Vec(52, 175), module, Elements::FM_INPUT));
  220. addInput(createInput<PJ3410Port>(Vec(16, 221), module, Elements::GATE_INPUT));
  221. addInput(createInput<PJ3410Port>(Vec(52, 221), module, Elements::STRENGTH_INPUT));
  222. addInput(createInput<PJ3410Port>(Vec(16, 267), module, Elements::BLOW_INPUT));
  223. addInput(createInput<PJ3410Port>(Vec(52, 267), module, Elements::STRIKE_INPUT));
  224. addOutput(createOutput<PJ3410Port>(Vec(16, 313), module, Elements::AUX_OUTPUT));
  225. addOutput(createOutput<PJ3410Port>(Vec(52, 313), module, Elements::MAIN_OUTPUT));
  226. addInput(createInput<PJ3410Port>(Vec(97, 313), module, Elements::BOW_TIMBRE_MOD_INPUT));
  227. addInput(createInput<PJ3410Port>(Vec(136, 313), module, Elements::FLOW_MOD_INPUT));
  228. addInput(createInput<PJ3410Port>(Vec(174, 313), module, Elements::BLOW_TIMBRE_MOD_INPUT));
  229. addInput(createInput<PJ3410Port>(Vec(213, 313), module, Elements::MALLET_MOD_INPUT));
  230. addInput(createInput<PJ3410Port>(Vec(251, 313), module, Elements::STRIKE_TIMBRE_MOD_INPUT));
  231. addInput(createInput<PJ3410Port>(Vec(309, 313), module, Elements::DAMPING_MOD_INPUT));
  232. addInput(createInput<PJ3410Port>(Vec(347, 313), module, Elements::GEOMETRY_MOD_INPUT));
  233. addInput(createInput<PJ3410Port>(Vec(386, 313), module, Elements::POSITION_MOD_INPUT));
  234. addInput(createInput<PJ3410Port>(Vec(424, 313), module, Elements::BRIGHTNESS_MOD_INPUT));
  235. addInput(createInput<PJ3410Port>(Vec(463, 313), module, Elements::SPACE_MOD_INPUT));
  236. addParam(createParam<CKD6>(Vec(36, 116), module, Elements::PLAY_PARAM, 0.0, 1.0, 0.0));
  237. addChild(createValueLight<MediumLight<GreenRedPolarityLight>>(Vec(184, 165), &module->lights[0]));
  238. addChild(createValueLight<MediumLight<GreenRedPolarityLight>>(Vec(395, 165), &module->lights[1]));
  239. }
  240. struct ElementsModalItem : MenuItem {
  241. Elements *elements;
  242. int model;
  243. void onAction() {
  244. elements->setModel(model);
  245. }
  246. void step() {
  247. rightText = (elements->getModel() == model) ? "✔" : "";
  248. }
  249. };
  250. Menu *ElementsWidget::createContextMenu() {
  251. Menu *menu = ModuleWidget::createContextMenu();
  252. Elements *elements = dynamic_cast<Elements*>(module);
  253. assert(elements);
  254. menu->pushChild(construct<MenuLabel>());
  255. menu->pushChild(construct<MenuLabel>(&MenuEntry::text, "Alternative Models"));
  256. menu->pushChild(construct<ElementsModalItem>(&MenuEntry::text, "Original", &ElementsModalItem::elements, elements, &ElementsModalItem::model, 0));
  257. menu->pushChild(construct<ElementsModalItem>(&MenuEntry::text, "Non-Linear String", &ElementsModalItem::elements, elements, &ElementsModalItem::model, 1));
  258. menu->pushChild(construct<ElementsModalItem>(&MenuEntry::text, "Chords", &ElementsModalItem::elements, elements, &ElementsModalItem::model, 2));
  259. return menu;
  260. }