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
12KB

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