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