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.

556 lines
16KB

  1. #include "Walk2.hpp"
  2. #define ZOOM_OUT_KEY "zoom_out"
  3. #define GRID_KEY "grid"
  4. #define COLOR_KEY "color"
  5. void Walk2::onReset() {
  6. _jumpTrigger.reset();
  7. _modulationStep = modulationSteps;
  8. }
  9. void Walk2::onSampleRateChange() {
  10. _modulationStep = modulationSteps;
  11. _historySteps = (historySeconds * engineGetSampleRate()) / historyPoints;
  12. }
  13. json_t* Walk2::toJson() {
  14. json_t* root = json_object();
  15. json_object_set_new(root, ZOOM_OUT_KEY, json_boolean(_zoomOut));
  16. json_object_set_new(root, GRID_KEY, json_boolean(_drawGrid));
  17. json_object_set_new(root, COLOR_KEY, json_integer(_traceColor));
  18. return root;
  19. }
  20. void Walk2::fromJson(json_t* root) {
  21. json_t* zo = json_object_get(root, ZOOM_OUT_KEY);
  22. if (zo) {
  23. _zoomOut = json_is_true(zo);
  24. }
  25. json_t* g = json_object_get(root, GRID_KEY);
  26. if (g) {
  27. _drawGrid = json_is_true(g);
  28. }
  29. json_t* c = json_object_get(root, COLOR_KEY);
  30. if (c) {
  31. _traceColor = (TraceColor)json_integer_value(c);
  32. }
  33. }
  34. inline float scaleRate(float rate) {
  35. return 0.2f * powf(rate, 5.0f);
  36. }
  37. void Walk2::step() {
  38. ++_modulationStep;
  39. if (_modulationStep >= modulationSteps) {
  40. _modulationStep = 0;
  41. float sampleRate = engineGetSampleRate();
  42. float rateX = params[RATE_X_PARAM].value;
  43. if (inputs[RATE_X_INPUT].active) {
  44. rateX *= clamp(inputs[RATE_X_INPUT].value / 10.0f, 0.0f, 1.0f);
  45. }
  46. rateX = scaleRate(rateX);
  47. _walkX.setParams(sampleRate, rateX);
  48. _slewX.setParams(sampleRate, std::max((1.0f - rateX) * 100.0f, 0.0f), 10.0f);
  49. _offsetX = params[OFFSET_X_PARAM].value;
  50. if (inputs[OFFSET_X_INPUT].active) {
  51. _offsetX *= clamp(inputs[OFFSET_X_INPUT].value / 5.0f, -1.0f, 1.0f);
  52. }
  53. _offsetX *= 5.0f;
  54. _scaleX = params[SCALE_X_PARAM].value;
  55. if (inputs[SCALE_X_INPUT].active) {
  56. _scaleX *= clamp(inputs[SCALE_X_INPUT].value / 10.0f, 0.0f, 1.0f);
  57. }
  58. float rateY = params[RATE_Y_PARAM].value;
  59. if (inputs[RATE_Y_INPUT].active) {
  60. rateY *= clamp(inputs[RATE_Y_INPUT].value / 10.0f, 0.0f, 1.0f);
  61. }
  62. rateY = scaleRate(rateY);
  63. _walkY.setParams(sampleRate, rateY);
  64. _slewY.setParams(sampleRate, std::max((1.0f - rateY) * 100.0f, 0.0f), 10.0f);
  65. _offsetY = params[OFFSET_Y_PARAM].value;
  66. if (inputs[OFFSET_Y_INPUT].active) {
  67. _offsetY *= clamp(inputs[OFFSET_Y_INPUT].value / 5.0f, -1.0f, 1.0f);
  68. }
  69. _offsetY *= 5.0f;
  70. _scaleY = params[SCALE_Y_PARAM].value;
  71. if (inputs[SCALE_Y_INPUT].active) {
  72. _scaleY *= clamp(inputs[SCALE_Y_INPUT].value / 10.0f, 0.0f, 1.0f);
  73. }
  74. }
  75. Vec* jumpTo = _jumpTo;
  76. if (jumpTo != NULL) {
  77. _jumpTo = NULL;
  78. _walkX.tell(jumpTo->x);
  79. _walkY.tell(jumpTo->y);
  80. delete jumpTo;
  81. }
  82. else if (_jumpTrigger.process(inputs[JUMP_INPUT].value)) {
  83. _walkX.jump();
  84. _walkY.jump();
  85. }
  86. float outX = _slewX.next(_walkX.next());
  87. outX *= _scaleX;
  88. outX += _offsetX;
  89. outputs[OUT_X_OUTPUT].value = outX;
  90. float outY = _slewY.next(_walkY.next());
  91. outY *= _scaleY;
  92. outY += _offsetY;
  93. outputs[OUT_Y_OUTPUT].value = outY;
  94. outputs[DISTANCE_OUTPUT].value = sqrtf(outX*outX + outY*outY) * 0.707107f; // scaling constant is 10 / squrt(200)
  95. if (_historyStep == 0) {
  96. _outsX.push(outX);
  97. _outsY.push(outY);
  98. }
  99. ++_historyStep;
  100. _historyStep %= _historySteps;
  101. }
  102. struct Walk2Display : TransparentWidget {
  103. const int _insetAround = 4;
  104. const NVGcolor _axisColor = nvgRGBA(0xff, 0xff, 0xff, 0x70);
  105. const NVGcolor _defaultTraceColor = nvgRGBA(0x00, 0xff, 0x00, 0xee);
  106. Walk2* _module;
  107. const Vec _size;
  108. const Vec _drawSize;
  109. int _midX, _midY;
  110. std::shared_ptr<Font> _font;
  111. NVGcolor _traceColor = _defaultTraceColor;
  112. Walk2Display(
  113. Walk2* module,
  114. Vec size
  115. )
  116. : _module(module)
  117. , _size(size)
  118. , _drawSize(2 * (_size.x - 2 * _insetAround), 2 * (_size.y - 2 * _insetAround))
  119. , _midX(_insetAround + _drawSize.x/2)
  120. , _midY(_insetAround + _drawSize.y/2)
  121. , _font(Font::load(assetPlugin(plugin, "res/fonts/inconsolata.ttf")))
  122. {
  123. }
  124. void onMouseDown(EventMouseDown& e) override {
  125. if (
  126. e.pos.x > _insetAround &&
  127. e.pos.x < _size.x - _insetAround &&
  128. e.pos.y > _insetAround &&
  129. e.pos.y < _size.y - _insetAround
  130. ) {
  131. float x = 20.0f * ((e.pos.x - _insetAround) / (float)_drawSize.x);
  132. x -= 5.0f;
  133. float y = 20.0f * ((e.pos.y - _insetAround) / (float)_drawSize.y);
  134. y = 5.0f - y;
  135. _module->_jumpTo = new Vec(x, y);
  136. }
  137. }
  138. void draw(NVGcontext* vg) override {
  139. switch (_module->_traceColor) {
  140. case Walk2::ORANGE_TRACE_COLOR: {
  141. _traceColor = nvgRGBA(0xff, 0x80, 0x00, 0xee);
  142. break;
  143. }
  144. case Walk2::RED_TRACE_COLOR: {
  145. _traceColor = nvgRGBA(0xff, 0x00, 0x00, 0xee);
  146. break;
  147. }
  148. case Walk2::BLUE_TRACE_COLOR: {
  149. _traceColor = nvgRGBA(0x00, 0xdd, 0xff, 0xee);
  150. break;
  151. }
  152. case Walk2::GREEN_TRACE_COLOR:
  153. default: {
  154. _traceColor = _defaultTraceColor;
  155. }
  156. }
  157. drawBackground(vg);
  158. float strokeWidth = std::max(1.0f, 3 - RACK_PLUGIN_UI_RACKSCENE->zoomWidget->zoom);
  159. nvgSave(vg);
  160. nvgScissor(vg, _insetAround, _insetAround, _drawSize.x / 2, _drawSize.y / 2);
  161. if (_module->_zoomOut) {
  162. nvgScale(vg, 0.5f, 0.5f);
  163. strokeWidth *= 2.0f;
  164. }
  165. else {
  166. float tx = 1.0f + (clamp(_module->_offsetX, -5.0f, 5.0f) / 5.0f);
  167. tx *= -_drawSize.x / 4;
  168. float ty = 1.0f - (clamp(_module->_offsetY, -5.0f, 5.0f) / 5.0f);
  169. ty *= -_drawSize.y / 4;
  170. nvgTranslate(vg, tx, ty);
  171. }
  172. drawAxes(vg, strokeWidth);
  173. drawTrace(vg, _traceColor, _module->_outsX, _module->_outsY);
  174. nvgRestore(vg);
  175. }
  176. void drawBackground(NVGcontext* vg) {
  177. nvgSave(vg);
  178. nvgBeginPath(vg);
  179. nvgRect(vg, 0, 0, _size.x, _size.y);
  180. nvgFillColor(vg, nvgRGBA(0x00, 0x00, 0x00, 0xff));
  181. nvgFill(vg);
  182. nvgStrokeColor(vg, nvgRGBA(0xc0, 0xc0, 0xc0, 0xff));
  183. nvgStroke(vg);
  184. nvgRestore(vg);
  185. }
  186. void drawAxes(NVGcontext* vg, float strokeWidth) {
  187. const float shortTick = 4.0f;
  188. const float longTick = 8.0f;
  189. float dot = 0.5f * strokeWidth;
  190. nvgSave(vg);
  191. nvgStrokeColor(vg, _axisColor);
  192. nvgStrokeWidth(vg, strokeWidth);
  193. nvgBeginPath(vg);
  194. nvgMoveTo(vg, _insetAround, _midY);
  195. nvgLineTo(vg, _insetAround + _drawSize.x, _midY);
  196. nvgStroke(vg);
  197. nvgBeginPath(vg);
  198. nvgMoveTo(vg, _midX, _insetAround);
  199. nvgLineTo(vg, _midX, _insetAround + _drawSize.y);
  200. nvgStroke(vg);
  201. for (int i = 1; i <= 10; ++i) {
  202. float tick = i % 5 == 0 ? longTick : shortTick;
  203. float x = (i * 0.1f) * 0.5f * _drawSize.x;
  204. nvgBeginPath(vg);
  205. nvgMoveTo(vg, _midX + x, _midY - tick);
  206. nvgLineTo(vg, _midX + x, _midY + tick);
  207. nvgStroke(vg);
  208. nvgBeginPath(vg);
  209. nvgMoveTo(vg, _midX - x, _midY - tick);
  210. nvgLineTo(vg, _midX - x, _midY + tick);
  211. nvgStroke(vg);
  212. float y = (i * 0.1f) * 0.5f * _drawSize.y;
  213. nvgBeginPath(vg);
  214. nvgMoveTo(vg, _midX - tick, _midY + y);
  215. nvgLineTo(vg, _midX + tick, _midY + y);
  216. nvgStroke(vg);
  217. nvgBeginPath(vg);
  218. nvgMoveTo(vg, _midX - tick, _midY - y);
  219. nvgLineTo(vg, _midX + tick, _midY - y);
  220. nvgStroke(vg);
  221. if (_module->_drawGrid) {
  222. for (int j = 1; j <= 10; ++j) {
  223. float y = (j * 0.1f) * 0.5f * _drawSize.y;
  224. nvgBeginPath(vg);
  225. nvgMoveTo(vg, _midX + x - dot, _midY + y);
  226. nvgLineTo(vg, _midX + x + dot, _midY + y);
  227. nvgStroke(vg);
  228. nvgBeginPath(vg);
  229. nvgMoveTo(vg, _midX - x - dot, _midY + y);
  230. nvgLineTo(vg, _midX - x + dot, _midY + y);
  231. nvgStroke(vg);
  232. nvgBeginPath(vg);
  233. nvgMoveTo(vg, _midX - x - dot, _midY - y);
  234. nvgLineTo(vg, _midX - x + dot, _midY - y);
  235. nvgStroke(vg);
  236. nvgBeginPath(vg);
  237. nvgMoveTo(vg, _midX + x - dot, _midY - y);
  238. nvgLineTo(vg, _midX + x + dot, _midY - y);
  239. nvgStroke(vg);
  240. }
  241. }
  242. }
  243. if (_module->_drawGrid) {
  244. const float tick = shortTick;
  245. {
  246. float x = _midX - _drawSize.x / 4;
  247. float y = _midY - _drawSize.y / 4;
  248. nvgBeginPath(vg);
  249. nvgMoveTo(vg, x - tick, y);
  250. nvgLineTo(vg, x + tick, y);
  251. nvgStroke(vg);
  252. nvgBeginPath(vg);
  253. nvgMoveTo(vg, x, y - tick);
  254. nvgLineTo(vg, x, y + tick);
  255. nvgStroke(vg);
  256. }
  257. {
  258. float x = _midX + _drawSize.x / 4;
  259. float y = _midY - _drawSize.y / 4;
  260. nvgBeginPath(vg);
  261. nvgMoveTo(vg, x - tick, y);
  262. nvgLineTo(vg, x + tick, y);
  263. nvgStroke(vg);
  264. nvgBeginPath(vg);
  265. nvgMoveTo(vg, x, y - tick);
  266. nvgLineTo(vg, x, y + tick);
  267. nvgStroke(vg);
  268. }
  269. {
  270. float x = _midX + _drawSize.x / 4;
  271. float y = _midY + _drawSize.y / 4;
  272. nvgBeginPath(vg);
  273. nvgMoveTo(vg, x - tick, y);
  274. nvgLineTo(vg, x + tick, y);
  275. nvgStroke(vg);
  276. nvgBeginPath(vg);
  277. nvgMoveTo(vg, x, y - tick);
  278. nvgLineTo(vg, x, y + tick);
  279. nvgStroke(vg);
  280. }
  281. {
  282. float x = _midX - _drawSize.x / 4;
  283. float y = _midY + _drawSize.y / 4;
  284. nvgBeginPath(vg);
  285. nvgMoveTo(vg, x - tick, y);
  286. nvgLineTo(vg, x + tick, y);
  287. nvgStroke(vg);
  288. nvgBeginPath(vg);
  289. nvgMoveTo(vg, x, y - tick);
  290. nvgLineTo(vg, x, y + tick);
  291. nvgStroke(vg);
  292. }
  293. }
  294. nvgRestore(vg);
  295. }
  296. void drawTrace(NVGcontext* vg, NVGcolor color, HistoryBuffer<float>& x, HistoryBuffer<float>& y) {
  297. nvgSave(vg);
  298. // nvgGlobalCompositeOperation(vg, NVG_LIGHTER);
  299. // int n = _module->historyPoints;
  300. // float beginRadius = std::max(1.0f, 2.0f - gRackScene->zoomWidget->zoom);
  301. // float endRadius = std::max(0.01f, 0.8f - gRackScene->zoomWidget->zoom);
  302. // float radiusStep = (beginRadius - endRadius) / (float)n;
  303. // float radius = beginRadius;
  304. // float alphaStep = (color.a - 0.1f) / (float)n;
  305. // for (int i = 0; i < n; ++i) {
  306. // nvgBeginPath(vg);
  307. // nvgCircle(vg, cvToPixel(_midX, _drawSize.x, x.value(i)), cvToPixel(_midY, _drawSize.y, y.value(i)), radius);
  308. // nvgStrokeColor(vg, color);
  309. // nvgFillColor(vg, color);
  310. // nvgStroke(vg);
  311. // nvgFill(vg);
  312. // radius -= radiusStep;
  313. // color.a -= alphaStep;
  314. // }
  315. int n = _module->historyPoints;
  316. float beginWidth = std::max(1.0f, 4.0f - RACK_PLUGIN_UI_RACKSCENE->zoomWidget->zoom);
  317. float endWidth = std::max(0.5f, 2.0f - RACK_PLUGIN_UI_RACKSCENE->zoomWidget->zoom);
  318. if (_module->_zoomOut) {
  319. beginWidth *= 2.0f;
  320. endWidth *= 2.0f;
  321. }
  322. float widthStep = (beginWidth - endWidth) / (float)n;
  323. float width = endWidth;
  324. float endAlpha = 0.1f;
  325. float alphaStep = (color.a - endAlpha) / (float)n;
  326. color.a = endAlpha;
  327. for (int i = n - 1; i > 0; --i) {
  328. nvgBeginPath(vg);
  329. nvgMoveTo(vg, cvToPixelX(_midX, _drawSize.x, x.value(i - 1)), cvToPixelY(_midY, _drawSize.y, y.value(i - 1)));
  330. nvgLineTo(vg, cvToPixelX(_midX, _drawSize.x, x.value(i)), cvToPixelY(_midY, _drawSize.y, y.value(i)));
  331. nvgStrokeWidth(vg, width);
  332. nvgStrokeColor(vg, color);
  333. nvgStroke(vg);
  334. width += widthStep;
  335. color.a += alphaStep;
  336. }
  337. nvgBeginPath(vg);
  338. nvgCircle(vg, cvToPixelX(_midX, _drawSize.x, x.value(0)), cvToPixelY(_midY, _drawSize.y, y.value(0)), 0.5f * width);
  339. nvgStrokeColor(vg, color);
  340. nvgFillColor(vg, color);
  341. nvgStroke(vg);
  342. nvgFill(vg);
  343. nvgRestore(vg);
  344. }
  345. inline float cvToPixelX(float mid, float extent, float cv) {
  346. return mid + 0.05f * extent * cv;
  347. }
  348. inline float cvToPixelY(float mid, float extent, float cv) {
  349. return mid - 0.05f * extent * cv;
  350. }
  351. };
  352. struct ZoomOutMenuItem : MenuItem {
  353. Walk2* _module;
  354. const bool _zoomOut;
  355. ZoomOutMenuItem(Walk2* module, const char* label, bool zoomOut)
  356. : _module(module)
  357. , _zoomOut(zoomOut)
  358. {
  359. this->text = label;
  360. }
  361. void onAction(EventAction &e) override {
  362. _module->_zoomOut = _zoomOut;
  363. }
  364. void step() override {
  365. rightText = _module->_zoomOut == _zoomOut ? "?" : "";
  366. }
  367. };
  368. struct GridMenuItem : MenuItem {
  369. Walk2* _module;
  370. GridMenuItem(Walk2* module, const char* label) : _module(module) {
  371. this->text = label;
  372. }
  373. void onAction(EventAction &e) override {
  374. _module->_drawGrid = !_module->_drawGrid;
  375. }
  376. void step() override {
  377. rightText = _module->_drawGrid ? "?" : "";
  378. }
  379. };
  380. struct ColorMenuItem : MenuItem {
  381. Walk2* _module;
  382. const Walk2::TraceColor _color;
  383. ColorMenuItem(Walk2* module, const char* label, Walk2::TraceColor color)
  384. : _module(module)
  385. , _color(color)
  386. {
  387. this->text = label;
  388. }
  389. void onAction(EventAction &e) override {
  390. _module->_traceColor = _color;
  391. }
  392. void step() override {
  393. rightText = _module->_traceColor == _color ? "?" : "";
  394. }
  395. };
  396. struct Walk2Widget : ModuleWidget {
  397. static constexpr int hp = 14;
  398. Walk2Widget(Walk2* module) : ModuleWidget(module) {
  399. box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT);
  400. {
  401. SVGPanel *panel = new SVGPanel();
  402. panel->box.size = box.size;
  403. panel->setBackground(SVG::load(assetPlugin(plugin, "res/Walk2.svg")));
  404. addChild(panel);
  405. }
  406. {
  407. auto inset = Vec(10, 25);
  408. int dim = box.size.x - 2*inset.x;
  409. auto size = Vec(dim, dim);
  410. auto display = new Walk2Display(module, size);
  411. display->box.pos = inset;
  412. display->box.size = size;
  413. addChild(display);
  414. }
  415. addChild(Widget::create<ScrewSilver>(Vec(15, 0)));
  416. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 0)));
  417. addChild(Widget::create<ScrewSilver>(Vec(15, 365)));
  418. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 30, 365)));
  419. // generated by svg_widgets.rb
  420. auto rateXParamPosition = Vec(28.0, 240.0);
  421. auto rateYParamPosition = Vec(151.5, 240.0);
  422. auto offsetXParamPosition = Vec(75.0, 234.0);
  423. auto offsetYParamPosition = Vec(119.0, 234.0);
  424. auto scaleXParamPosition = Vec(75.0, 262.5);
  425. auto scaleYParamPosition = Vec(119.0, 262.5);
  426. auto offsetXInputPosition = Vec(10.5, 284.0);
  427. auto scaleXInputPosition = Vec(41.5, 284.0);
  428. auto rateXInputPosition = Vec(10.5, 323.0);
  429. auto offsetYInputPosition = Vec(145.5, 284.0);
  430. auto scaleYInputPosition = Vec(176.5, 284.0);
  431. auto rateYInputPosition = Vec(145.5, 323.0);
  432. auto jumpInputPosition = Vec(78.0, 303.0);
  433. auto outXOutputPosition = Vec(41.5, 323.0);
  434. auto outYOutputPosition = Vec(176.5, 323.0);
  435. auto distanceOutputPosition = Vec(109.0, 303.0);
  436. // end generated by svg_widgets.rb
  437. addParam(ParamWidget::create<Knob29>(rateXParamPosition, module, Walk2::RATE_X_PARAM, 0.0, 1.0, 0.1));
  438. addParam(ParamWidget::create<Knob29>(rateYParamPosition, module, Walk2::RATE_Y_PARAM, 0.0, 1.0, 0.1));
  439. addParam(ParamWidget::create<Knob16>(offsetXParamPosition, module, Walk2::OFFSET_X_PARAM, -1.0, 1.0, 0.0));
  440. addParam(ParamWidget::create<Knob16>(offsetYParamPosition, module, Walk2::OFFSET_Y_PARAM, -1.0, 1.0, 0.0));
  441. addParam(ParamWidget::create<Knob16>(scaleXParamPosition, module, Walk2::SCALE_X_PARAM, 0.0, 1.0, 1.0));
  442. addParam(ParamWidget::create<Knob16>(scaleYParamPosition, module, Walk2::SCALE_Y_PARAM, 0.0, 1.0, 1.0));
  443. addInput(Port::create<Port24>(offsetXInputPosition, Port::INPUT, module, Walk2::OFFSET_X_INPUT));
  444. addInput(Port::create<Port24>(scaleXInputPosition, Port::INPUT, module, Walk2::SCALE_X_INPUT));
  445. addInput(Port::create<Port24>(rateXInputPosition, Port::INPUT, module, Walk2::RATE_X_INPUT));
  446. addInput(Port::create<Port24>(offsetYInputPosition, Port::INPUT, module, Walk2::OFFSET_Y_INPUT));
  447. addInput(Port::create<Port24>(scaleYInputPosition, Port::INPUT, module, Walk2::SCALE_Y_INPUT));
  448. addInput(Port::create<Port24>(rateYInputPosition, Port::INPUT, module, Walk2::RATE_Y_INPUT));
  449. addInput(Port::create<Port24>(jumpInputPosition, Port::INPUT, module, Walk2::JUMP_INPUT));
  450. addOutput(Port::create<Port24>(outXOutputPosition, Port::OUTPUT, module, Walk2::OUT_X_OUTPUT));
  451. addOutput(Port::create<Port24>(outYOutputPosition, Port::OUTPUT, module, Walk2::OUT_Y_OUTPUT));
  452. addOutput(Port::create<Port24>(distanceOutputPosition, Port::OUTPUT, module, Walk2::DISTANCE_OUTPUT));
  453. }
  454. void appendContextMenu(Menu* menu) override {
  455. Walk2* w = dynamic_cast<Walk2*>(module);
  456. assert(w);
  457. menu->addChild(new MenuLabel());
  458. menu->addChild(new ZoomOutMenuItem(w, "Display range: +/-5V", false));
  459. menu->addChild(new ZoomOutMenuItem(w, "Display range: +/-10V", true));
  460. menu->addChild(new MenuLabel());
  461. menu->addChild(new GridMenuItem(w, "Show grid"));
  462. menu->addChild(new MenuLabel());
  463. menu->addChild(new ColorMenuItem(w, "Trace color: green", Walk2::GREEN_TRACE_COLOR));
  464. menu->addChild(new ColorMenuItem(w, "Trace color: orange", Walk2::ORANGE_TRACE_COLOR));
  465. menu->addChild(new ColorMenuItem(w, "Trace color: red", Walk2::RED_TRACE_COLOR));
  466. menu->addChild(new ColorMenuItem(w, "Trace color: blue", Walk2::BLUE_TRACE_COLOR));
  467. }
  468. };
  469. RACK_PLUGIN_MODEL_INIT(Bogaudio, Walk2) {
  470. Model* modelWalk2 = createModel<Walk2, Walk2Widget>("Bogaudio-Walk2", "Walk2", "");
  471. return modelWalk2;
  472. }