From 632bc3fee7ffabef299cf7567a2bb0a92001d908 Mon Sep 17 00:00:00 2001 From: trian-gles <69212477+trian-gles@users.noreply.github.com> Date: Wed, 3 Jul 2024 12:41:37 +0200 Subject: [PATCH] working UI --- example.maxpat | 234 + lfogui.html | 84 + lfogui.js | 166 + react-dom.js | 29924 +++++++++++++++++++++++++++++++++++++++++++++++ react.js | 3343 ++++++ 5 files changed, 33751 insertions(+) create mode 100644 example.maxpat create mode 100644 lfogui.html create mode 100644 lfogui.js create mode 100644 react-dom.js create mode 100644 react.js diff --git a/example.maxpat b/example.maxpat new file mode 100644 index 0000000..2593b7a --- /dev/null +++ b/example.maxpat @@ -0,0 +1,234 @@ +{ + "patcher" : { + "fileversion" : 1, + "appversion" : { + "major" : 8, + "minor" : 6, + "revision" : 2, + "architecture" : "x64", + "modernui" : 1 + } +, + "classnamespace" : "box", + "rect" : [ 134.0, 134.0, 922.0, 715.0 ], + "bglocked" : 0, + "openinpresentation" : 0, + "default_fontsize" : 12.0, + "default_fontface" : 0, + "default_fontname" : "Arial", + "gridonopen" : 1, + "gridsize" : [ 15.0, 15.0 ], + "gridsnaponopen" : 1, + "objectsnaponopen" : 1, + "statusbarvisible" : 2, + "toolbarvisible" : 1, + "lefttoolbarpinned" : 0, + "toptoolbarpinned" : 0, + "righttoolbarpinned" : 0, + "bottomtoolbarpinned" : 0, + "toolbars_unpinned_last_save" : 0, + "tallnewobj" : 0, + "boxanimatetime" : 200, + "enablehscroll" : 1, + "enablevscroll" : 1, + "devicewidth" : 0.0, + "description" : "", + "digest" : "", + "tags" : "", + "style" : "", + "subpatcher_template" : "", + "assistshowspatchername" : 0, + "boxes" : [ { + "box" : { + "id" : "obj-6", + "linecount" : 2, + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 488.0, 6.0, 150.0, 34.0 ], + "text" : "required due to the asynchronous operation" + } + + } +, { + "box" : { + "id" : "obj-3", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 493.0, 42.0, 55.0, 22.0 ], + "text" : "del 1000" + } + + } +, { + "box" : { + "id" : "obj-45", + "maxclass" : "comment", + "numinlets" : 1, + "numoutlets" : 0, + "patching_rect" : [ 681.0, 43.0, 150.0, 20.0 ], + "text" : "Storage for the matrix" + } + + } +, { + "box" : { + "id" : "obj-20", + "maxclass" : "newobj", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "bang" ], + "patching_rect" : [ 217.0, 6.0, 58.0, 22.0 ], + "text" : "loadbang" + } + + } +, { + "box" : { + "id" : "obj-14", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 575.0, 69.0, 39.0, 22.0 ], + "text" : "dump" + } + + } +, { + "box" : { + "data" : { + "foo" : { + "lfos" : [ "0.2", "1", "3" ], + "matrix" : [ [ "90", "10", "48" ], [ "5", "3", "251" ], [ "-61", "8", "98" ] ], + "paramNames" : [ "carrierFreq", "modFreq", "modDepth" ] + } + + } +, + "id" : "obj-4", + "maxclass" : "newobj", + "numinlets" : 2, + "numoutlets" : 5, + "outlettype" : [ "dictionary", "", "", "", "" ], + "patching_rect" : [ 681.0, 69.0, 159.0, 22.0 ], + "saved_object_attributes" : { + "embed" : 1, + "legacy" : 0, + "parameter_enable" : 0, + "parameter_mappable" : 0 + } +, + "text" : "dict localStorage @embed 1" + } + + } +, { + "box" : { + "id" : "obj-13", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 493.0, 69.0, 51.0, 22.0 ], + "text" : "load foo" + } + + } +, { + "box" : { + "id" : "obj-12", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 426.0, 69.0, 54.0, 22.0 ], + "text" : "save foo" + } + + } +, { + "box" : { + "id" : "obj-18", + "maxclass" : "message", + "numinlets" : 2, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 217.0, 69.0, 106.0, 22.0 ], + "text" : "readfile lfogui.html" + } + + } +, { + "box" : { + "id" : "obj-2", + "maxclass" : "jweb", + "numinlets" : 1, + "numoutlets" : 1, + "outlettype" : [ "" ], + "patching_rect" : [ 443.0, 124.0, 428.0, 246.0 ], + "rendermode" : 0, + "url" : "file://lfogui.html" + } + + } + ], + "lines" : [ { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "source" : [ "obj-12", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "source" : [ "obj-13", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "source" : [ "obj-14", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-2", 0 ], + "source" : [ "obj-18", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-18", 0 ], + "order" : 1, + "source" : [ "obj-20", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-3", 0 ], + "order" : 0, + "source" : [ "obj-20", 0 ] + } + + } +, { + "patchline" : { + "destination" : [ "obj-13", 0 ], + "source" : [ "obj-3", 0 ] + } + + } + ], + "dependency_cache" : [ ], + "autosave" : 0 + } + +} diff --git a/lfogui.html b/lfogui.html new file mode 100644 index 0000000..1e11878 --- /dev/null +++ b/lfogui.html @@ -0,0 +1,84 @@ + + + + + + + + + + +
+ + + + + + + + diff --git a/lfogui.js b/lfogui.js new file mode 100644 index 0000000..0ec67df --- /dev/null +++ b/lfogui.js @@ -0,0 +1,166 @@ +// const { createElement } = require("./react"); + +const log = console.log; +// const log = window.max.outlet; + +const e = React.createElement; + +let lfos = []; +const MAXLFOS = 20; + +const SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square"]; +const PARAMOPTIONS = ["attenuation", "melody_scope"]; + + + +function DropDown(props) { + return e('select', {type: "number", onChange: props.onChange, value: props.value}, + ...props.options.map((item) => Option(item))); +} + +function ListItem(child){ + return e('li', null, child) +} + +function NumberBox(props){ + return e('input', {type: "number", onChange: props.onChange, value: props.value}, null); +} + +function Option(str){ + return e("option", null, str); +} + +function ControlType(){ + return e('select', {className: 'control-type'}, Option("LFO")); +} + +function LfoShape(){ + return e('select', {className: 'lfo-shape'}, Option("Sine"), Option("SawUp"), Option("SawDown"), Option("Tri"), Option("Square")); +} + +function ParamName(){ + return e('select', {className: 'param-name'}, Option("djParam"), Option("melody_scope")); +} + +function LfoRow(props){ + let content = e('ul', {className: 'lfo-item'}, + ListItem(ControlType()), + ListItem(DropDown({onChange: props.setShape, value:props.shape, options: SHAPETYPES})), + ListItem(DropDown({onChange: props.setDjParam, value: props.djParam, options: PARAMOPTIONS})), + ListItem(e(NumberBox, {onChange:props.setFreq, value:props.freq}, null)), + ListItem(e(NumberBox, {onChange:props.setAmp, value:props.amp}, null)), + ListItem(e(NumberBox, {onChange:props.setPhase, value:props.phase}, null)), + ListItem(e(Button, {text:'+', onClick: props.addLfo}, null)), + ListItem(e(Button, {text:'-', onClick: props.removeLfo}, null)) + ); + if (props.visible){ + return content + } + ; + + +} + +function Button(props){ + return e('button', {onClick: props.onClick}, props.text); +} + +function MasterLfoHandler(){ + + let initVisArr = Array(MAXLFOS).fill(false); + initVisArr[0] = true; + const [visibleArr, setVisibleArr] = React.useState(initVisArr); + + const [shapeArr, setShapeArr] = React.useState(Array(MAXLFOS).fill('Sine')); + const [djParamArr, setDjParamArr] = React.useState(Array(MAXLFOS).fill('djParam')); + + const [freqArr, setFreqArr] = React.useState(Array(MAXLFOS).fill('1')); + const [ampArr, setAmpArr] = React.useState(Array(MAXLFOS).fill('1')); + const [phaseArr, setPhaseArr] = React.useState(Array(MAXLFOS).fill('0')); + + const allArrays = [visibleArr, shapeArr, djParamArr, freqArr, ampArr, phaseArr]; + const allSetters = [setVisibleArr, setShapeArr, setDjParamArr, setFreqArr, setAmpArr, setPhaseArr]; + const blankVals = [true, 'Sine', '1', '1', '0']; + + + createParamChanger = (arr, setArr, index) => { + return (event) => { + let newArr = arr.slice(); + newArr[index] = event.target.value; + setArr(newArr); + log(`${index} ${event.target.value}`); + } + } + + + + + log("Rendering") + let contents = [] + for (var i = 0; i { + if (id < MAXLFOS - 1){ + if (visibleArr[id + 1]){ + // need to delete the empty item to make room + let emptyIndex = visibleArr.findIndex((item) => !item); + if (emptyIndex != -1){ + log(emptyIndex); + log(id + 1); + + for (var j = 0; j < allArrays.length; j++){ + + let array = allArrays[j]; + console.log(array); + // remove from all arrays + array.splice(emptyIndex, 1); + + // add empty item at opened index + array.splice(id + 1, 0, blankVals[j]); + allSetters[j](array); + console.log(array); + + } + } + + log(allArrays); + } + + let newArr = visibleArr.slice(); + newArr[id + 1] = true; + setVisibleArr(newArr); + + } + }, + removeLfo: () => { + let newArr = visibleArr.slice(); + newArr[id] = false; + setVisibleArr(newArr); + } + + }, + null)); + } + + return e('div', null, ...contents); +} + + + + +const root = ReactDOM.createRoot(document.getElementById('lfo-container')); +root.render(e(MasterLfoHandler, null, null)); \ No newline at end of file diff --git a/react-dom.js b/react-dom.js new file mode 100644 index 0000000..00404dd --- /dev/null +++ b/react-dom.js @@ -0,0 +1,29924 @@ +/** + * @license React + * react-dom.development.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : + typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) : + (global = global || self, factory(global.ReactDOM = {}, global.React)); + }(this, (function (exports, React) { 'use strict'; + + var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + + var suppressWarning = false; + function setSuppressWarning(newSuppressWarning) { + { + suppressWarning = newSuppressWarning; + } + } // In DEV, calls to console.warn and console.error get replaced + // by calls to these methods by a Babel plugin. + // + // In PROD (or in packages without access to React internals), + // they are left as they are instead. + + function warn(format) { + { + if (!suppressWarning) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + printWarning('warn', format, args); + } + } + } + function error(format) { + { + if (!suppressWarning) { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + + printWarning('error', format, args); + } + } + } + + function printWarning(level, format, args) { + // When changing this logic, you might want to also + // update consoleWithStackDev.www.js as well. + { + var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; + var stack = ReactDebugCurrentFrame.getStackAddendum(); + + if (stack !== '') { + format += '%s'; + args = args.concat([stack]); + } // eslint-disable-next-line react-internal/safe-string-coercion + + + var argsWithFormat = args.map(function (item) { + return String(item); + }); // Careful: RN currently depends on this prefix + + argsWithFormat.unshift('Warning: ' + format); // We intentionally don't use spread (or .apply) directly because it + // breaks IE9: https://github.com/facebook/react/issues/13610 + // eslint-disable-next-line react-internal/no-production-logging + + Function.prototype.apply.call(console[level], console, argsWithFormat); + } + } + + var FunctionComponent = 0; + var ClassComponent = 1; + var IndeterminateComponent = 2; // Before we know whether it is function or class + + var HostRoot = 3; // Root of a host tree. Could be nested inside another node. + + var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. + + var HostComponent = 5; + var HostText = 6; + var Fragment = 7; + var Mode = 8; + var ContextConsumer = 9; + var ContextProvider = 10; + var ForwardRef = 11; + var Profiler = 12; + var SuspenseComponent = 13; + var MemoComponent = 14; + var SimpleMemoComponent = 15; + var LazyComponent = 16; + var IncompleteClassComponent = 17; + var DehydratedFragment = 18; + var SuspenseListComponent = 19; + var ScopeComponent = 21; + var OffscreenComponent = 22; + var LegacyHiddenComponent = 23; + var CacheComponent = 24; + var TracingMarkerComponent = 25; + + // ----------------------------------------------------------------------------- + + var enableClientRenderFallbackOnTextMismatch = true; // TODO: Need to review this code one more time before landing + // the react-reconciler package. + + var enableNewReconciler = false; // Support legacy Primer support on internal FB www + + var enableLazyContextPropagation = false; // FB-only usage. The new API has different semantics. + + var enableLegacyHidden = false; // Enables unstable_avoidThisFallback feature in Fiber + + var enableSuspenseAvoidThisFallback = false; // Enables unstable_avoidThisFallback feature in Fizz + // React DOM Chopping Block + // + // Similar to main Chopping Block but only flags related to React DOM. These are + // grouped because we will likely batch all of them into a single major release. + // ----------------------------------------------------------------------------- + // Disable support for comment nodes as React DOM containers. Already disabled + // in open source, but www codebase still relies on it. Need to remove. + + var disableCommentsAsDOMContainers = true; // Disable javascript: URL strings in href for XSS protection. + // and client rendering, mostly to allow JSX attributes to apply to the custom + // element's object properties instead of only HTML attributes. + // https://github.com/facebook/react/issues/11347 + + var enableCustomElementPropertySupport = false; // Disables children for