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.

351 lines
9.3KB

  1. #include <string.h>
  2. #include "AudibleInstruments.hpp"
  3. #include "dsp/samplerate.hpp"
  4. #include "dsp/ringbuffer.hpp"
  5. #include "braids/macro_oscillator.h"
  6. #include "braids/vco_jitter_source.h"
  7. #include "braids/signature_waveshaper.h"
  8. struct Braids : Module {
  9. enum ParamIds {
  10. FINE_PARAM,
  11. COARSE_PARAM,
  12. FM_PARAM,
  13. TIMBRE_PARAM,
  14. MODULATION_PARAM,
  15. COLOR_PARAM,
  16. SHAPE_PARAM,
  17. NUM_PARAMS
  18. };
  19. enum InputIds {
  20. TRIG_INPUT,
  21. PITCH_INPUT,
  22. FM_INPUT,
  23. TIMBRE_INPUT,
  24. COLOR_INPUT,
  25. NUM_INPUTS
  26. };
  27. enum OutputIds {
  28. OUT_OUTPUT,
  29. NUM_OUTPUTS
  30. };
  31. braids::MacroOscillator osc;
  32. braids::SettingsData settings;
  33. braids::VcoJitterSource jitter_source;
  34. braids::SignatureWaveshaper ws;
  35. SampleRateConverter<1> src;
  36. DoubleRingBuffer<Frame<1>, 256> outputBuffer;
  37. bool lastTrig = false;
  38. bool lowCpu = false;
  39. Braids();
  40. void step() override;
  41. void setShape(int shape);
  42. json_t *toJson() override {
  43. json_t *rootJ = json_object();
  44. json_t *settingsJ = json_array();
  45. uint8_t *settingsArray = &settings.shape;
  46. for (int i = 0; i < 20; i++) {
  47. json_t *settingJ = json_integer(settingsArray[i]);
  48. json_array_insert_new(settingsJ, i, settingJ);
  49. }
  50. json_object_set_new(rootJ, "settings", settingsJ);
  51. json_t *lowCpuJ = json_boolean(lowCpu);
  52. json_object_set_new(rootJ, "lowCpu", lowCpuJ);
  53. return rootJ;
  54. }
  55. void fromJson(json_t *rootJ) override {
  56. json_t *settingsJ = json_object_get(rootJ, "settings");
  57. if (settingsJ) {
  58. uint8_t *settingsArray = &settings.shape;
  59. for (int i = 0; i < 20; i++) {
  60. json_t *settingJ = json_array_get(settingsJ, i);
  61. if (settingJ)
  62. settingsArray[i] = json_integer_value(settingJ);
  63. }
  64. }
  65. json_t *lowCpuJ = json_object_get(rootJ, "lowCpu");
  66. if (lowCpuJ) {
  67. lowCpu = json_boolean_value(lowCpuJ);
  68. }
  69. }
  70. };
  71. Braids::Braids() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS) {
  72. memset(&osc, 0, sizeof(osc));
  73. osc.Init();
  74. memset(&jitter_source, 0, sizeof(jitter_source));
  75. jitter_source.Init();
  76. memset(&ws, 0, sizeof(ws));
  77. ws.Init(0x0000);
  78. memset(&settings, 0, sizeof(settings));
  79. // List of supported settings
  80. settings.meta_modulation = 0;
  81. settings.vco_drift = 0;
  82. settings.signature = 255;
  83. }
  84. void Braids::step() {
  85. // Trigger
  86. bool trig = inputs[TRIG_INPUT].value >= 1.0;
  87. if (!lastTrig && trig) {
  88. osc.Strike();
  89. }
  90. lastTrig = trig;
  91. // Render frames
  92. if (outputBuffer.empty()) {
  93. float fm = params[FM_PARAM].value * inputs[FM_INPUT].value;
  94. // Set shape
  95. int shape = roundf(params[SHAPE_PARAM].value * braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META);
  96. if (settings.meta_modulation) {
  97. shape += roundf(fm / 10.0 * braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META);
  98. }
  99. settings.shape = clampi(shape, 0, braids::MACRO_OSC_SHAPE_LAST_ACCESSIBLE_FROM_META);
  100. // Setup oscillator from settings
  101. osc.set_shape((braids::MacroOscillatorShape) settings.shape);
  102. // Set timbre/modulation
  103. float timbre = params[TIMBRE_PARAM].value + params[MODULATION_PARAM].value * inputs[TIMBRE_INPUT].value / 5.0;
  104. float modulation = params[COLOR_PARAM].value + inputs[COLOR_INPUT].value / 5.0;
  105. int16_t param1 = rescalef(clampf(timbre, 0.0, 1.0), 0.0, 1.0, 0, INT16_MAX);
  106. int16_t param2 = rescalef(clampf(modulation, 0.0, 1.0), 0.0, 1.0, 0, INT16_MAX);
  107. osc.set_parameters(param1, param2);
  108. // Set pitch
  109. float pitchV = inputs[PITCH_INPUT].value + params[COARSE_PARAM].value + params[FINE_PARAM].value / 12.0;
  110. if (!settings.meta_modulation)
  111. pitchV += fm;
  112. if (lowCpu)
  113. pitchV += log2f(96000.0 / engineGetSampleRate());
  114. int32_t pitch = (pitchV * 12.0 + 60) * 128;
  115. pitch += jitter_source.Render(settings.vco_drift);
  116. pitch = clampi(pitch, 0, 16383);
  117. osc.set_pitch(pitch);
  118. // TODO: add a sync input buffer (must be sample rate converted)
  119. uint8_t sync_buffer[24] = {};
  120. int16_t render_buffer[24];
  121. osc.Render(sync_buffer, render_buffer, 24);
  122. // Signature waveshaping, decimation (not yet supported), and bit reduction (not yet supported)
  123. uint16_t signature = settings.signature * settings.signature * 4095;
  124. for (size_t i = 0; i < 24; i++) {
  125. const int16_t bit_mask = 0xffff;
  126. int16_t sample = render_buffer[i] & bit_mask;
  127. int16_t warped = ws.Transform(sample);
  128. render_buffer[i] = stmlib::Mix(sample, warped, signature);
  129. }
  130. if (lowCpu) {
  131. for (int i = 0; i < 24; i++) {
  132. Frame<1> f;
  133. f.samples[0] = render_buffer[i] / 32768.0;
  134. outputBuffer.push(f);
  135. }
  136. }
  137. else {
  138. // Sample rate convert
  139. Frame<1> in[24];
  140. for (int i = 0; i < 24; i++) {
  141. in[i].samples[0] = render_buffer[i] / 32768.0;
  142. }
  143. src.setRatio(engineGetSampleRate() / 96000.0);
  144. int inLen = 24;
  145. int outLen = outputBuffer.capacity();
  146. src.process(in, &inLen, outputBuffer.endData(), &outLen);
  147. outputBuffer.endIncr(outLen);
  148. }
  149. }
  150. // Output
  151. if (!outputBuffer.empty()) {
  152. Frame<1> f = outputBuffer.shift();
  153. outputs[OUT_OUTPUT].value = 5.0 * f.samples[0];
  154. }
  155. }
  156. static const char *algo_values[] = {
  157. "CSAW",
  158. "/\\-_",
  159. "//-_",
  160. "FOLD",
  161. "uuuu",
  162. "SUB-",
  163. "SUB/",
  164. "SYN-",
  165. "SYN/",
  166. "//x3",
  167. "-_x3",
  168. "/\\x3",
  169. "SIx3",
  170. "RING",
  171. "////",
  172. "//uu",
  173. "TOY*",
  174. "ZLPF",
  175. "ZPKF",
  176. "ZBPF",
  177. "ZHPF",
  178. "VOSM",
  179. "VOWL",
  180. "VFOF",
  181. "HARM",
  182. "FM ",
  183. "FBFM",
  184. "WTFM",
  185. "PLUK",
  186. "BOWD",
  187. "BLOW",
  188. "FLUT",
  189. "BELL",
  190. "DRUM",
  191. "KICK",
  192. "CYMB",
  193. "SNAR",
  194. "WTBL",
  195. "WMAP",
  196. "WLIN",
  197. "WTx4",
  198. "NOIS",
  199. "TWNQ",
  200. "CLKN",
  201. "CLOU",
  202. "PRTC",
  203. "QPSK",
  204. " ",
  205. };
  206. struct BraidsDisplay : TransparentWidget {
  207. Braids *module;
  208. std::shared_ptr<Font> font;
  209. BraidsDisplay() {
  210. font = Font::load(assetPlugin(plugin, "res/hdad-segment14-1.002/Segment14.ttf"));
  211. }
  212. void draw(NVGcontext *vg) override {
  213. int shape = module->settings.shape;
  214. // Background
  215. NVGcolor backgroundColor = nvgRGB(0x38, 0x38, 0x38);
  216. NVGcolor borderColor = nvgRGB(0x10, 0x10, 0x10);
  217. nvgBeginPath(vg);
  218. nvgRoundedRect(vg, 0.0, 0.0, box.size.x, box.size.y, 5.0);
  219. nvgFillColor(vg, backgroundColor);
  220. nvgFill(vg);
  221. nvgStrokeWidth(vg, 1.0);
  222. nvgStrokeColor(vg, borderColor);
  223. nvgStroke(vg);
  224. nvgFontSize(vg, 36);
  225. nvgFontFaceId(vg, font->handle);
  226. nvgTextLetterSpacing(vg, 2.5);
  227. Vec textPos = Vec(10, 48);
  228. NVGcolor textColor = nvgRGB(0xaf, 0xd2, 0x2c);
  229. nvgFillColor(vg, nvgTransRGBA(textColor, 16));
  230. nvgText(vg, textPos.x, textPos.y, "~~~~", NULL);
  231. nvgFillColor(vg, textColor);
  232. nvgText(vg, textPos.x, textPos.y, algo_values[shape], NULL);
  233. }
  234. };
  235. BraidsWidget::BraidsWidget() {
  236. Braids *module = new Braids();
  237. setModule(module);
  238. box.size = Vec(15*16, 380);
  239. {
  240. Panel *panel = new LightPanel();
  241. panel->backgroundImage = Image::load(assetPlugin(plugin, "res/Braids.png"));
  242. panel->box.size = box.size;
  243. addChild(panel);
  244. }
  245. {
  246. BraidsDisplay *display = new BraidsDisplay();
  247. display->box.pos = Vec(14, 53);
  248. display->box.size = Vec(148, 56);
  249. display->module = module;
  250. addChild(display);
  251. }
  252. addChild(createScrew<ScrewSilver>(Vec(15, 0)));
  253. addChild(createScrew<ScrewSilver>(Vec(210, 0)));
  254. addChild(createScrew<ScrewSilver>(Vec(15, 365)));
  255. addChild(createScrew<ScrewSilver>(Vec(210, 365)));
  256. addParam(createParam<Rogan2SGray>(Vec(176, 59), module, Braids::SHAPE_PARAM, 0.0, 1.0, 0.0));
  257. addParam(createParam<Rogan2PSWhite>(Vec(19, 138), module, Braids::FINE_PARAM, -1.0, 1.0, 0.0));
  258. addParam(createParam<Rogan2PSWhite>(Vec(97, 138), module, Braids::COARSE_PARAM, -2.0, 2.0, 0.0));
  259. addParam(createParam<Rogan2PSWhite>(Vec(176, 138), module, Braids::FM_PARAM, -1.0, 1.0, 0.0));
  260. addParam(createParam<Rogan2PSGreen>(Vec(19, 217), module, Braids::TIMBRE_PARAM, 0.0, 1.0, 0.5));
  261. addParam(createParam<Rogan2PSGreen>(Vec(97, 217), module, Braids::MODULATION_PARAM, -1.0, 1.0, 0.0));
  262. addParam(createParam<Rogan2PSRed>(Vec(176, 217), module, Braids::COLOR_PARAM, 0.0, 1.0, 0.5));
  263. addInput(createInput<PJ301MPort>(Vec(10, 316), module, Braids::TRIG_INPUT));
  264. addInput(createInput<PJ301MPort>(Vec(47, 316), module, Braids::PITCH_INPUT));
  265. addInput(createInput<PJ301MPort>(Vec(84, 316), module, Braids::FM_INPUT));
  266. addInput(createInput<PJ301MPort>(Vec(122, 316), module, Braids::TIMBRE_INPUT));
  267. addInput(createInput<PJ301MPort>(Vec(160, 316), module, Braids::COLOR_INPUT));
  268. addOutput(createOutput<PJ301MPort>(Vec(205, 316), module, Braids::OUT_OUTPUT));
  269. }
  270. struct BraidsSettingItem : MenuItem {
  271. uint8_t *setting = NULL;
  272. uint8_t offValue = 0;
  273. uint8_t onValue = 1;
  274. void onAction() override {
  275. // Toggle setting
  276. *setting = (*setting == onValue) ? offValue : onValue;
  277. }
  278. void step() override {
  279. rightText = (*setting == onValue) ? "✔" : "";
  280. }
  281. };
  282. struct BraidsLowCpuItem : MenuItem {
  283. Braids *braids;
  284. void onAction() override {
  285. braids->lowCpu = !braids->lowCpu;
  286. }
  287. void step() override {
  288. rightText = (braids->lowCpu) ? "✔" : "";
  289. }
  290. };
  291. Menu *BraidsWidget::createContextMenu() {
  292. Menu *menu = ModuleWidget::createContextMenu();
  293. Braids *braids = dynamic_cast<Braids*>(module);
  294. assert(braids);
  295. menu->pushChild(construct<MenuLabel>());
  296. menu->pushChild(construct<MenuLabel>(&MenuEntry::text, "Options"));
  297. menu->pushChild(construct<BraidsSettingItem>(&MenuEntry::text, "META", &BraidsSettingItem::setting, &braids->settings.meta_modulation));
  298. menu->pushChild(construct<BraidsSettingItem>(&MenuEntry::text, "DRFT", &BraidsSettingItem::setting, &braids->settings.vco_drift, &BraidsSettingItem::onValue, 4));
  299. menu->pushChild(construct<BraidsSettingItem>(&MenuEntry::text, "SIGN", &BraidsSettingItem::setting, &braids->settings.signature, &BraidsSettingItem::onValue, 4));
  300. menu->pushChild(construct<BraidsLowCpuItem>(&MenuEntry::text, "Low CPU", &BraidsLowCpuItem::braids, braids));
  301. return menu;
  302. }