working UI
This commit is contained in:
commit
632bc3fee7
234
example.maxpat
Normal file
234
example.maxpat
Normal file
@ -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
|
||||
}
|
||||
|
||||
}
|
84
lfogui.html
Normal file
84
lfogui.html
Normal file
@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<!--
|
||||
We start with a basic html 'page' that is the size of the jweb object,
|
||||
but has no scrollbars nor floating content.
|
||||
-->
|
||||
|
||||
<head>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
border: 0;
|
||||
overflow: hidden; /* Disable scrollbars */
|
||||
display: block; /* No floating content on sides */
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 30px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#matrix {
|
||||
background-color: aquamarine;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.numbox-unclicked {
|
||||
background-color: none;
|
||||
user-select: none;
|
||||
border: solid;
|
||||
font-size: 12vw;
|
||||
}
|
||||
|
||||
.numbox-clicked {
|
||||
background-color: pink;
|
||||
user-select: none;
|
||||
border : solid;
|
||||
font-size: 12vw;
|
||||
}
|
||||
|
||||
.param-input-label {
|
||||
width: 93%;
|
||||
font-size: 5vw;
|
||||
}
|
||||
|
||||
.lfo-input-label {
|
||||
width: 40%;
|
||||
font-size: 5vw;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="lfo-container"></div>
|
||||
|
||||
<script src="./react.js"></script>
|
||||
<script src="./react-dom.js"></script>
|
||||
<script src="./lfogui.js">
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
166
lfogui.js
Normal file
166
lfogui.js
Normal file
@ -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<MAXLFOS; i++){
|
||||
let id = i;
|
||||
contents.push(
|
||||
e(LfoRow, {
|
||||
shape: shapeArr[i],
|
||||
setShape: createParamChanger(shapeArr, setShapeArr, i),
|
||||
djParam: djParamArr[i],
|
||||
setDjParam: createParamChanger(djParamArr, setDjParamArr, i),
|
||||
|
||||
freq: freqArr[i],
|
||||
setFreq: createParamChanger(freqArr, setFreqArr, i),
|
||||
amp: ampArr[i],
|
||||
setAmp: createParamChanger(ampArr, setAmpArr, i),
|
||||
phase: phaseArr[i],
|
||||
setPhase: createParamChanger(phaseArr, setPhaseArr, i),
|
||||
visible: visibleArr[i],
|
||||
addLfo: () => {
|
||||
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));
|
29924
react-dom.js
vendored
Normal file
29924
react-dom.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user