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.

428 lines
15KB

  1. #include "AudibleInstruments.hpp"
  2. #include <string.h>
  3. #include "frames/keyframer.h"
  4. #include "frames/poly_lfo.h"
  5. #include "dsp/digital.hpp"
  6. struct Frames : Module {
  7. enum ParamIds {
  8. GAIN1_PARAM,
  9. GAIN2_PARAM,
  10. GAIN3_PARAM,
  11. GAIN4_PARAM,
  12. ADD_PARAM,
  13. DEL_PARAM,
  14. FRAME_PARAM,
  15. MODULATION_PARAM,
  16. OFFSET_PARAM,
  17. NUM_PARAMS
  18. };
  19. enum InputIds {
  20. ALL_INPUT,
  21. IN1_INPUT,
  22. IN2_INPUT,
  23. IN3_INPUT,
  24. IN4_INPUT,
  25. FRAME_INPUT,
  26. NUM_INPUTS
  27. };
  28. enum OutputIds {
  29. MIX_OUTPUT,
  30. OUT1_OUTPUT,
  31. OUT2_OUTPUT,
  32. OUT3_OUTPUT,
  33. OUT4_OUTPUT,
  34. FRAME_STEP_OUTPUT,
  35. NUM_OUTPUTS
  36. };
  37. enum LightIds {
  38. GAIN1_LIGHT,
  39. EDIT_LIGHT = GAIN1_LIGHT + 4,
  40. FRAME_LIGHT,
  41. NUM_LIGHTS = FRAME_LIGHT + 3
  42. };
  43. frames::Keyframer keyframer;
  44. frames::PolyLfo poly_lfo;
  45. bool poly_lfo_mode = false;
  46. uint16_t lastControls[4] = {};
  47. SchmittTrigger addTrigger;
  48. SchmittTrigger delTrigger;
  49. Frames();
  50. void step() override;
  51. json_t *toJson() override {
  52. json_t *rootJ = json_object();
  53. json_object_set_new(rootJ, "polyLfo", json_boolean(poly_lfo_mode));
  54. json_t *keyframesJ = json_array();
  55. for (int i = 0; i < keyframer.num_keyframes(); i++) {
  56. json_t *keyframeJ = json_array();
  57. frames::Keyframe *keyframe = keyframer.mutable_keyframe(i);
  58. json_array_append_new(keyframeJ, json_integer(keyframe->timestamp));
  59. for (int k = 0; k < 4; k++) {
  60. json_array_append_new(keyframeJ, json_integer(keyframe->values[k]));
  61. }
  62. json_array_append_new(keyframesJ, keyframeJ);
  63. }
  64. json_object_set_new(rootJ, "keyframes", keyframesJ);
  65. json_t *channelsJ = json_array();
  66. for (int i = 0; i < 4; i++) {
  67. json_t *channelJ = json_object();
  68. json_object_set_new(channelJ, "curve", json_integer((int) keyframer.mutable_settings(i)->easing_curve));
  69. json_object_set_new(channelJ, "response", json_integer(keyframer.mutable_settings(i)->response));
  70. json_array_append_new(channelsJ, channelJ);
  71. }
  72. json_object_set_new(rootJ, "channels", channelsJ);
  73. return rootJ;
  74. }
  75. void fromJson(json_t *rootJ) override {
  76. json_t *polyLfoJ = json_object_get(rootJ, "polyLfo");
  77. if (polyLfoJ)
  78. poly_lfo_mode = json_boolean_value(polyLfoJ);
  79. json_t *keyframesJ = json_object_get(rootJ, "keyframes");
  80. if (keyframesJ) {
  81. json_t *keyframeJ;
  82. size_t i;
  83. json_array_foreach(keyframesJ, i, keyframeJ) {
  84. uint16_t timestamp = json_integer_value(json_array_get(keyframeJ, 0));
  85. uint16_t values[4];
  86. for (int k = 0; k < 4; k++) {
  87. values[k] = json_integer_value(json_array_get(keyframeJ, k + 1));
  88. }
  89. keyframer.AddKeyframe(timestamp, values);
  90. }
  91. }
  92. json_t *channelsJ = json_object_get(rootJ, "channels");
  93. if (channelsJ) {
  94. for (int i = 0; i < 4; i++) {
  95. json_t *channelJ = json_array_get(channelsJ, i);
  96. if (channelJ) {
  97. json_t *curveJ = json_object_get(channelJ, "curve");
  98. if (curveJ)
  99. keyframer.mutable_settings(i)->easing_curve = (frames::EasingCurve) json_integer_value(curveJ);
  100. json_t *responseJ = json_object_get(channelJ, "response");
  101. if (responseJ)
  102. keyframer.mutable_settings(i)->response = json_integer_value(responseJ);
  103. }
  104. }
  105. }
  106. }
  107. void onReset() override {
  108. poly_lfo_mode = false;
  109. keyframer.Clear();
  110. for (int i = 0; i < 4; i++) {
  111. keyframer.mutable_settings(i)->easing_curve = frames::EASING_CURVE_LINEAR;
  112. keyframer.mutable_settings(i)->response = 0;
  113. }
  114. }
  115. void onRandomize() override {
  116. // TODO
  117. // Maybe something useful should go in here?
  118. }
  119. };
  120. Frames::Frames() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  121. memset(&keyframer, 0, sizeof(keyframer));
  122. keyframer.Init();
  123. memset(&poly_lfo, 0, sizeof(poly_lfo));
  124. poly_lfo.Init();
  125. onReset();
  126. }
  127. void Frames::step() {
  128. // Set gain and timestamp knobs
  129. uint16_t controls[4];
  130. for (int i = 0; i < 4; i++) {
  131. controls[i] = params[GAIN1_PARAM + i].value * 65535.0;
  132. }
  133. int32_t timestamp = params[FRAME_PARAM].value * 65535.0;
  134. int32_t timestampMod = timestamp + params[MODULATION_PARAM].value * inputs[FRAME_INPUT].value / 10.0 * 65535.0;
  135. timestamp = clamp(timestamp, 0, 65535);
  136. timestampMod = clamp(timestampMod, 0, 65535);
  137. int16_t nearestIndex = -1;
  138. if (!poly_lfo_mode) {
  139. nearestIndex = keyframer.FindNearestKeyframe(timestamp, 2048);
  140. }
  141. // Render, handle buttons
  142. if (poly_lfo_mode) {
  143. if (controls[0] != lastControls[0])
  144. poly_lfo.set_shape(controls[0]);
  145. if (controls[1] != lastControls[1])
  146. poly_lfo.set_shape_spread(controls[1]);
  147. if (controls[2] != lastControls[2])
  148. poly_lfo.set_spread(controls[2]);
  149. if (controls[3] != lastControls[3])
  150. poly_lfo.set_coupling(controls[3]);
  151. poly_lfo.Render(timestampMod);
  152. }
  153. else {
  154. for (int i = 0; i < 4; i++) {
  155. if (controls[i] != lastControls[i]) {
  156. // Update recently moved control
  157. if (keyframer.num_keyframes() == 0) {
  158. keyframer.set_immediate(i, controls[i]);
  159. }
  160. if (nearestIndex >= 0) {
  161. frames::Keyframe *nearestKeyframe = keyframer.mutable_keyframe(nearestIndex);
  162. nearestKeyframe->values[i] = controls[i];
  163. }
  164. }
  165. }
  166. if (addTrigger.process(params[ADD_PARAM].value)) {
  167. if (nearestIndex < 0) {
  168. keyframer.AddKeyframe(timestamp, controls);
  169. }
  170. }
  171. if (delTrigger.process(params[DEL_PARAM].value)) {
  172. if (nearestIndex >= 0) {
  173. int32_t nearestTimestamp = keyframer.keyframe(nearestIndex).timestamp;
  174. keyframer.RemoveKeyframe(nearestTimestamp);
  175. }
  176. }
  177. keyframer.Evaluate(timestampMod);
  178. }
  179. // Get gains
  180. float gains[4];
  181. for (int i = 0; i < 4; i++) {
  182. if (poly_lfo_mode) {
  183. // gains[i] = poly_lfo.level(i) / 255.0;
  184. gains[i] = poly_lfo.level16(i) / 65535.0;
  185. }
  186. else {
  187. float lin = keyframer.level(i) / 65535.0;
  188. gains[i] = lin;
  189. }
  190. // Simulate SSM2164
  191. if (keyframer.mutable_settings(i)->response > 0) {
  192. const float expBase = 200.0;
  193. float expGain = rescale(powf(expBase, gains[i]), 1.0f, expBase, 0.0f, 1.0f);
  194. gains[i] = crossfade(gains[i], expGain, keyframer.mutable_settings(i)->response / 255.0f);
  195. }
  196. }
  197. // Update last controls
  198. for (int i = 0; i < 4; i++) {
  199. lastControls[i] = controls[i];
  200. }
  201. // Get inputs
  202. float all = ((int)params[OFFSET_PARAM].value == 1) ? 10.0 : 0.0;
  203. if (inputs[ALL_INPUT].active) {
  204. all = inputs[ALL_INPUT].value;
  205. }
  206. float ins[4];
  207. for (int i = 0; i < 4; i++) {
  208. ins[i] = inputs[IN1_INPUT + i].normalize(all) * gains[i];
  209. }
  210. // Set outputs
  211. float mix = 0.0;
  212. for (int i = 0; i < 4; i++) {
  213. if (outputs[OUT1_OUTPUT + i].active) {
  214. outputs[OUT1_OUTPUT + i].value = ins[i];
  215. }
  216. else {
  217. mix += ins[i];
  218. }
  219. }
  220. outputs[MIX_OUTPUT].value = clamp(mix / 2.0, -10.0f, 10.0f);
  221. // Set lights
  222. for (int i = 0; i < 4; i++) {
  223. lights[GAIN1_LIGHT + i].setBrightness(gains[i]);
  224. }
  225. if (poly_lfo_mode) {
  226. lights[EDIT_LIGHT].value = (poly_lfo.level(0) > 128 ? 1.0 : 0.0);
  227. }
  228. else {
  229. lights[EDIT_LIGHT].value = (nearestIndex >= 0 ? 1.0 : 0.0);
  230. }
  231. // Set frame light colors
  232. const uint8_t *colors;
  233. if (poly_lfo_mode) {
  234. colors = poly_lfo.color();
  235. }
  236. else {
  237. colors = keyframer.color();
  238. }
  239. for (int i = 0; i < 3; i++) {
  240. float c = colors[i] / 255.0;
  241. c = 1.0 - (1.0 - c) * 1.25;
  242. lights[FRAME_LIGHT + i].setBrightness(c);
  243. }
  244. }
  245. struct CKSSRot : SVGSwitch, ToggleSwitch {
  246. CKSSRot() {
  247. addFrame(SVG::load(assetPlugin(plugin, "res/CKSS_rot_0.svg")));
  248. addFrame(SVG::load(assetPlugin(plugin, "res/CKSS_rot_1.svg")));
  249. sw->wrap();
  250. box.size = sw->box.size;
  251. }
  252. };
  253. struct FramesWidget : ModuleWidget {
  254. FramesWidget(Frames *module) : ModuleWidget(module) {
  255. setPanel(SVG::load(assetPlugin(plugin, "res/Frames.svg")));
  256. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  257. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 0)));
  258. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  259. addChild(Widget::create<ScrewSilver>(Vec(box.size.x-30, 365)));
  260. addParam(ParamWidget::create<Rogan1PSWhite>(Vec(14, 52), module, Frames::GAIN1_PARAM, 0.0, 1.0, 0.0));
  261. addParam(ParamWidget::create<Rogan1PSWhite>(Vec(81, 52), module, Frames::GAIN2_PARAM, 0.0, 1.0, 0.0));
  262. addParam(ParamWidget::create<Rogan1PSWhite>(Vec(149, 52), module, Frames::GAIN3_PARAM, 0.0, 1.0, 0.0));
  263. addParam(ParamWidget::create<Rogan1PSWhite>(Vec(216, 52), module, Frames::GAIN4_PARAM, 0.0, 1.0, 0.0));
  264. addParam(ParamWidget::create<Rogan6PSWhite>(Vec(89, 115), module, Frames::FRAME_PARAM, 0.0, 1.0, 0.0));
  265. addParam(ParamWidget::create<Rogan1PSGreen>(Vec(208, 141), module, Frames::MODULATION_PARAM, -1.0, 1.0, 0.0));
  266. addParam(ParamWidget::create<CKD6>(Vec(19, 123), module, Frames::ADD_PARAM, 0.0, 1.0, 0.0));
  267. addParam(ParamWidget::create<CKD6>(Vec(19, 172), module, Frames::DEL_PARAM, 0.0, 1.0, 0.0));
  268. addParam(ParamWidget::create<CKSSRot>(Vec(18, 239), module, Frames::OFFSET_PARAM, 0.0, 1.0, 0.0));
  269. addInput(Port::create<PJ301MPort>(Vec(16, 273), Port::INPUT, module, Frames::ALL_INPUT));
  270. addInput(Port::create<PJ301MPort>(Vec(59, 273), Port::INPUT, module, Frames::IN1_INPUT));
  271. addInput(Port::create<PJ301MPort>(Vec(102, 273), Port::INPUT, module, Frames::IN2_INPUT));
  272. addInput(Port::create<PJ301MPort>(Vec(145, 273), Port::INPUT, module, Frames::IN3_INPUT));
  273. addInput(Port::create<PJ301MPort>(Vec(188, 273), Port::INPUT, module, Frames::IN4_INPUT));
  274. addInput(Port::create<PJ301MPort>(Vec(231, 273), Port::INPUT, module, Frames::FRAME_INPUT));
  275. addOutput(Port::create<PJ301MPort>(Vec(16, 315), Port::OUTPUT, module, Frames::MIX_OUTPUT));
  276. addOutput(Port::create<PJ301MPort>(Vec(59, 315), Port::OUTPUT, module, Frames::OUT1_OUTPUT));
  277. addOutput(Port::create<PJ301MPort>(Vec(102, 315), Port::OUTPUT, module, Frames::OUT2_OUTPUT));
  278. addOutput(Port::create<PJ301MPort>(Vec(145, 315), Port::OUTPUT, module, Frames::OUT3_OUTPUT));
  279. addOutput(Port::create<PJ301MPort>(Vec(188, 315), Port::OUTPUT, module, Frames::OUT4_OUTPUT));
  280. addOutput(Port::create<PJ301MPort>(Vec(231, 315), Port::OUTPUT, module, Frames::FRAME_STEP_OUTPUT));
  281. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(Vec(30, 101), module, Frames::GAIN1_LIGHT + 0));
  282. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(Vec(97, 101), module, Frames::GAIN1_LIGHT + 1));
  283. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(Vec(165, 101), module, Frames::GAIN1_LIGHT + 2));
  284. addChild(ModuleLightWidget::create<SmallLight<GreenLight>>(Vec(232, 101), module, Frames::GAIN1_LIGHT + 3));
  285. addChild(ModuleLightWidget::create<MediumLight<GreenLight>>(Vec(61, 155), module, Frames::EDIT_LIGHT));
  286. struct FrameLight : RedGreenBlueLight {
  287. FrameLight() {
  288. box.size = Vec(71, 71);
  289. }
  290. };
  291. addChild(ModuleLightWidget::create<FrameLight>(Vec(100, 126), module, Frames::FRAME_LIGHT));
  292. }
  293. void appendContextMenu(Menu *menu) override {
  294. Frames *frames = dynamic_cast<Frames*>(module);
  295. assert(frames);
  296. struct FramesCurveItem : MenuItem {
  297. Frames *frames;
  298. uint8_t channel;
  299. frames::EasingCurve curve;
  300. void onAction(EventAction &e) override {
  301. frames->keyframer.mutable_settings(channel)->easing_curve = curve;
  302. }
  303. void step() override {
  304. rightText = (frames->keyframer.mutable_settings(channel)->easing_curve == curve) ? "✔" : "";
  305. MenuItem::step();
  306. }
  307. };
  308. struct FramesResponseItem : MenuItem {
  309. Frames *frames;
  310. uint8_t channel;
  311. uint8_t response;
  312. void onAction(EventAction &e) override {
  313. frames->keyframer.mutable_settings(channel)->response = response;
  314. }
  315. void step() override {
  316. rightText = (frames->keyframer.mutable_settings(channel)->response == response) ? "✔" : "";
  317. MenuItem::step();
  318. }
  319. };
  320. struct FramesChannelSettingsItem : MenuItem {
  321. Frames *frames;
  322. uint8_t channel;
  323. Menu *createChildMenu() override {
  324. Menu *menu = new Menu();
  325. menu->addChild(construct<MenuLabel>(&MenuLabel::text, stringf("Channel %d", channel + 1)));
  326. menu->addChild(construct<MenuLabel>());
  327. menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Interpolation Curve"));
  328. menu->addChild(construct<FramesCurveItem>(&MenuItem::text, "Step", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_STEP));
  329. menu->addChild(construct<FramesCurveItem>(&MenuItem::text, "Linear", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_LINEAR));
  330. menu->addChild(construct<FramesCurveItem>(&MenuItem::text, "Accelerating", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_IN_QUARTIC));
  331. menu->addChild(construct<FramesCurveItem>(&MenuItem::text, "Decelerating", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_OUT_QUARTIC));
  332. menu->addChild(construct<FramesCurveItem>(&MenuItem::text, "Smooth Departure/Arrival", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_SINE));
  333. menu->addChild(construct<FramesCurveItem>(&MenuItem::text, "Bouncing", &FramesCurveItem::frames, frames, &FramesCurveItem::channel, channel, &FramesCurveItem::curve, frames::EASING_CURVE_BOUNCE));
  334. menu->addChild(construct<MenuLabel>());
  335. menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Response Curve"));
  336. menu->addChild(construct<FramesResponseItem>(&MenuItem::text, "Linear", &FramesResponseItem::frames, frames, &FramesResponseItem::channel, channel, &FramesResponseItem::response, 0));
  337. menu->addChild(construct<FramesResponseItem>(&MenuItem::text, "Exponential", &FramesResponseItem::frames, frames, &FramesResponseItem::channel, channel, &FramesResponseItem::response, 255));
  338. return menu;
  339. }
  340. };
  341. struct FramesClearItem : MenuItem {
  342. Frames *frames;
  343. void onAction(EventAction &e) override {
  344. frames->keyframer.Clear();
  345. }
  346. };
  347. struct FramesModeItem : MenuItem {
  348. Frames *frames;
  349. bool poly_lfo_mode;
  350. void onAction(EventAction &e) override {
  351. frames->poly_lfo_mode = poly_lfo_mode;
  352. }
  353. void step() override {
  354. rightText = (frames->poly_lfo_mode == poly_lfo_mode) ? "✔" : "";
  355. MenuItem::step();
  356. }
  357. };
  358. menu->addChild(construct<MenuLabel>());
  359. menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Channel Settings"));
  360. for (int i = 0; i < 4; i++) {
  361. menu->addChild(construct<FramesChannelSettingsItem>(&MenuItem::text, stringf("Channel %d", i + 1), &FramesChannelSettingsItem::frames, frames, &FramesChannelSettingsItem::channel, i));
  362. }
  363. menu->addChild(construct<FramesClearItem>(&MenuItem::text, "Clear Keyframes", &FramesClearItem::frames, frames));
  364. menu->addChild(construct<MenuLabel>());
  365. menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Mode"));
  366. menu->addChild(construct<FramesModeItem>(&MenuItem::text, "Keyframer", &FramesModeItem::frames, frames, &FramesModeItem::poly_lfo_mode, false));
  367. menu->addChild(construct<FramesModeItem>(&MenuItem::text, "Poly LFO", &FramesModeItem::frames, frames, &FramesModeItem::poly_lfo_mode, true));
  368. }
  369. };
  370. Model *modelFrames = Model::create<Frames, FramesWidget>("Audible Instruments", "Frames", "Keyframer/Mixer", MIXER_TAG, ATTENUATOR_TAG, LFO_TAG);