Compare commits
1 Commits
main
...
save-cente
Author | SHA1 | Date | |
---|---|---|---|
c3656f182c |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
.DS_Store
|
|
267
ModEnum.maxhelp
267
ModEnum.maxhelp
@ -1,267 +0,0 @@
|
|||||||
{
|
|
||||||
"patcher" : {
|
|
||||||
"fileversion" : 1,
|
|
||||||
"appversion" : {
|
|
||||||
"major" : 8,
|
|
||||||
"minor" : 6,
|
|
||||||
"revision" : 5,
|
|
||||||
"architecture" : "x64",
|
|
||||||
"modernui" : 1
|
|
||||||
}
|
|
||||||
,
|
|
||||||
"classnamespace" : "box",
|
|
||||||
"rect" : [ 347.0, 100.0, 1131.0, 790.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-12",
|
|
||||||
"maxclass" : "message",
|
|
||||||
"numinlets" : 2,
|
|
||||||
"numoutlets" : 1,
|
|
||||||
"outlettype" : [ "" ],
|
|
||||||
"patching_rect" : [ 29.113923668861389, 96.202530384063721, 42.0, 22.0 ],
|
|
||||||
"text" : "reload"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"box" : {
|
|
||||||
"id" : "obj-51",
|
|
||||||
"maxclass" : "newobj",
|
|
||||||
"numinlets" : 1,
|
|
||||||
"numoutlets" : 1,
|
|
||||||
"outlettype" : [ "" ],
|
|
||||||
"patching_rect" : [ 294.936704993247986, 112.658226370811462, 277.0, 22.0 ],
|
|
||||||
"saved_object_attributes" : {
|
|
||||||
"client_rect" : [ 0, 99, 1470, 922 ],
|
|
||||||
"parameter_enable" : 0,
|
|
||||||
"parameter_mappable" : 0,
|
|
||||||
"storage_rect" : [ 1282, 626, 1887, 1000 ]
|
|
||||||
}
|
|
||||||
,
|
|
||||||
"text" : "pattrstorage myStorage @savemode 3 @greedy 1",
|
|
||||||
"varname" : "myStorage"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"box" : {
|
|
||||||
"id" : "obj-10",
|
|
||||||
"maxclass" : "preset",
|
|
||||||
"numinlets" : 1,
|
|
||||||
"numoutlets" : 5,
|
|
||||||
"outlettype" : [ "preset", "int", "preset", "int", "" ],
|
|
||||||
"patching_rect" : [ 55.696201801300049, 24.05063259601593, 100.0, 40.0 ],
|
|
||||||
"pattrstorage" : "myStorage"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"box" : {
|
|
||||||
"id" : "obj-8",
|
|
||||||
"maxclass" : "message",
|
|
||||||
"numinlets" : 2,
|
|
||||||
"numoutlets" : 1,
|
|
||||||
"outlettype" : [ "" ],
|
|
||||||
"patching_rect" : [ 851.30120575428009, 786.0, 50.0, 22.0 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"box" : {
|
|
||||||
"id" : "obj-9",
|
|
||||||
"maxclass" : "message",
|
|
||||||
"numinlets" : 2,
|
|
||||||
"numoutlets" : 1,
|
|
||||||
"outlettype" : [ "" ],
|
|
||||||
"patching_rect" : [ 679.901205754280113, 786.0, 50.0, 22.0 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"box" : {
|
|
||||||
"id" : "obj-6",
|
|
||||||
"maxclass" : "message",
|
|
||||||
"numinlets" : 2,
|
|
||||||
"numoutlets" : 1,
|
|
||||||
"outlettype" : [ "" ],
|
|
||||||
"patching_rect" : [ 508.501205754280136, 786.0, 50.0, 22.0 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"box" : {
|
|
||||||
"id" : "obj-7",
|
|
||||||
"maxclass" : "message",
|
|
||||||
"numinlets" : 2,
|
|
||||||
"numoutlets" : 1,
|
|
||||||
"outlettype" : [ "" ],
|
|
||||||
"patching_rect" : [ 337.101205754280102, 786.0, 50.0, 22.0 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"box" : {
|
|
||||||
"id" : "obj-5",
|
|
||||||
"linecount" : 2,
|
|
||||||
"maxclass" : "message",
|
|
||||||
"numinlets" : 2,
|
|
||||||
"numoutlets" : 1,
|
|
||||||
"outlettype" : [ "" ],
|
|
||||||
"patching_rect" : [ 165.701205754280096, 786.0, 50.0, 35.0 ],
|
|
||||||
"text" : "stream 0.802"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"box" : {
|
|
||||||
"id" : "obj-3",
|
|
||||||
"linecount" : 4,
|
|
||||||
"maxclass" : "message",
|
|
||||||
"numinlets" : 2,
|
|
||||||
"numoutlets" : 1,
|
|
||||||
"outlettype" : [ "" ],
|
|
||||||
"patching_rect" : [ 46.0, 786.0, 50.0, 62.0 ],
|
|
||||||
"text" : "pulse_length 0.981862"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"box" : {
|
|
||||||
"bgmode" : 0,
|
|
||||||
"border" : 0,
|
|
||||||
"clickthrough" : 0,
|
|
||||||
"enablehscroll" : 0,
|
|
||||||
"enablevscroll" : 0,
|
|
||||||
"id" : "obj-1",
|
|
||||||
"lockeddragscroll" : 0,
|
|
||||||
"lockedsize" : 0,
|
|
||||||
"maxclass" : "bpatcher",
|
|
||||||
"name" : "ModEnum.maxpat",
|
|
||||||
"numinlets" : 1,
|
|
||||||
"numoutlets" : 6,
|
|
||||||
"offset" : [ 0.0, 0.0 ],
|
|
||||||
"outlettype" : [ "", "", "", "", "", "" ],
|
|
||||||
"patching_rect" : [ 25.30120575428009, 154.216873168945312, 876.0, 621.0 ],
|
|
||||||
"varname" : "ModEnum",
|
|
||||||
"viewvisibility" : 1
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"lines" : [ {
|
|
||||||
"patchline" : {
|
|
||||||
"destination" : [ "obj-3", 1 ],
|
|
||||||
"source" : [ "obj-1", 0 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"patchline" : {
|
|
||||||
"destination" : [ "obj-5", 1 ],
|
|
||||||
"source" : [ "obj-1", 1 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"patchline" : {
|
|
||||||
"destination" : [ "obj-6", 1 ],
|
|
||||||
"source" : [ "obj-1", 3 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"patchline" : {
|
|
||||||
"destination" : [ "obj-7", 1 ],
|
|
||||||
"source" : [ "obj-1", 2 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"patchline" : {
|
|
||||||
"destination" : [ "obj-8", 1 ],
|
|
||||||
"source" : [ "obj-1", 5 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"patchline" : {
|
|
||||||
"destination" : [ "obj-9", 1 ],
|
|
||||||
"source" : [ "obj-1", 4 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"patchline" : {
|
|
||||||
"destination" : [ "obj-12", 0 ],
|
|
||||||
"source" : [ "obj-10", 1 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"patchline" : {
|
|
||||||
"destination" : [ "obj-1", 0 ],
|
|
||||||
"source" : [ "obj-12", 0 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"parameters" : {
|
|
||||||
"obj-1::obj-25" : [ "dict", "dict", 0 ],
|
|
||||||
"parameterbanks" : {
|
|
||||||
"0" : {
|
|
||||||
"index" : 0,
|
|
||||||
"name" : "",
|
|
||||||
"parameters" : [ "-", "-", "-", "-", "-", "-", "-", "-" ]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
,
|
|
||||||
"inherited_shortname" : 1
|
|
||||||
}
|
|
||||||
,
|
|
||||||
"dependency_cache" : [ {
|
|
||||||
"name" : "ModEnum.maxpat",
|
|
||||||
"bootpath" : "~/Documents/Max 8/Library/max-mod-enum",
|
|
||||||
"patcherrelativepath" : ".",
|
|
||||||
"type" : "JSON",
|
|
||||||
"implicit" : 1
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"name" : "myStorage.json",
|
|
||||||
"bootpath" : "~/Documents/Max 8/Library/max-mod-enum",
|
|
||||||
"patcherrelativepath" : ".",
|
|
||||||
"type" : "JSON",
|
|
||||||
"implicit" : 1
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"autosave" : 0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
3570
ModEnum.maxpat
3570
ModEnum.maxpat
File diff suppressed because one or more lines are too long
21
common.js
21
common.js
@ -5,8 +5,7 @@ function isNumeric(str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function DropDown(props) {
|
function DropDown(props) {
|
||||||
let className = props.locked ? 'locked-component' : '';
|
return e('select', {type: "number", onChange: props.onChange, value: props.value},
|
||||||
return e('select', {className, type: "number", onChange: props.onChange, value: props.value},
|
|
||||||
...props.options.map((item) => Option(item)));
|
...props.options.map((item) => Option(item)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,13 +18,11 @@ function Label(text){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function NumberBox(props){
|
function NumberBox(props){
|
||||||
let extraClassName = props.locked ? ' locked-component' : '';
|
return e('input', {type: "number", onChange: props.onChange, step: props.step, value: props.value, className: props.className}, null);
|
||||||
return e('input', {type: "number", onChange: props.onChange, step: props.step, value: props.value, className: props.className + extraClassName}, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function TextBox(props){
|
function TextBox(props){
|
||||||
let className = props.locked ? 'locked-component' : '';
|
return e('input', {type: "text", value: props.value, onChange: props.onChange, id: props.id});
|
||||||
return e('input', {className, type: "text", value: props.value, onChange: props.onChange, id: props.id});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Option(str, value){
|
function Option(str, value){
|
||||||
@ -33,8 +30,7 @@ function Option(str, value){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Button(props){
|
function Button(props){
|
||||||
let className = props.locked ? 'locked-component' : '';
|
return e('button', {onClick: props.onClick}, props.text);
|
||||||
return e('button', {onClick: props.onClick, className}, props.text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Switch(props){
|
function Switch(props){
|
||||||
@ -43,20 +39,12 @@ function Switch(props){
|
|||||||
e('span', {className: 'slider round'}, null))
|
e('span', {className: 'slider round'}, null))
|
||||||
}
|
}
|
||||||
|
|
||||||
function SendSaveEvent(){
|
|
||||||
setTimeout(() => {
|
|
||||||
window.dispatchEvent(new CustomEvent('saveDict', {'detail' : "localStorage"}));
|
|
||||||
}, 50)
|
|
||||||
}
|
|
||||||
|
|
||||||
function CreateParamChanger(arr, setArr, index, postCB=() => {}, preCB=(val) => val){
|
function CreateParamChanger(arr, setArr, index, postCB=() => {}, preCB=(val) => val){
|
||||||
return (event) => {
|
return (event) => {
|
||||||
let newArr = arr.slice();
|
let newArr = arr.slice();
|
||||||
newArr[index] = preCB(event.target.value);
|
newArr[index] = preCB(event.target.value);
|
||||||
setArr(newArr);
|
setArr(newArr);
|
||||||
postCB();
|
postCB();
|
||||||
SendSaveEvent();
|
|
||||||
|
|
||||||
log(`${index} ${event.target.value}`);
|
log(`${index} ${event.target.value}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,7 +56,6 @@ function CreateMatrixParamChanger(matrix, setMatrix, i, j){
|
|||||||
});
|
});
|
||||||
newMatrix[i][j] = event.target.value;
|
newMatrix[i][j] = event.target.value;
|
||||||
setMatrix(newMatrix);
|
setMatrix(newMatrix);
|
||||||
SendSaveEvent();
|
|
||||||
log(`${i}, ${j} ${event.target.value}`);
|
log(`${i}, ${j} ${event.target.value}`);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
28
enums.js
28
enums.js
@ -4,18 +4,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
function DataCell(element) {
|
|
||||||
return e('td', null, element);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOT A REACT FUNCTIONAL COMPONENT. MERELY RETURNS AN ARRAY WHICH IS UNPACKED
|
// NOT A REACT FUNCTIONAL COMPONENT. MERELY RETURNS AN ARRAY WHICH IS UNPACKED
|
||||||
function EnumeratorItems(index, enumBreakPoints, setEnumBreakPoints, enumNames, setEnumNames, djParam, locked){
|
function EnumeratorItems(index, enumBreakPoints, setEnumBreakPoints, enumNames, setEnumNames, djParam){
|
||||||
let items = [];
|
let items = [];
|
||||||
for (let i = 0; i < MAXENUMPOINTS; i++){
|
for (let i = 0; i < MAXENUMPOINTS; i++){
|
||||||
|
|
||||||
items.push(DataCell(e(TextBox, {locked, onChange: CreateMatrixParamChanger(enumNames, setEnumNames, index, i), value: enumNames[index][i], id:`text-${djParam}-${enumNames[index][i]}`}, null)));
|
items.push(ListItem(e(TextBox, {onChange: CreateMatrixParamChanger(enumNames, setEnumNames, index, i), value: enumNames[index][i], id:`text-${djParam}-${enumNames[index][i]}`}, null)));
|
||||||
// Add 1 to make up for the lower enum bound
|
// Add 1 to make up for the lower enum bound
|
||||||
items.push(DataCell(e(NumberBox, {locked, onChange: CreateMatrixParamChanger(enumBreakPoints, setEnumBreakPoints, index, i + 1), value:enumBreakPoints[index][i + 1]}, null)));
|
items.push(ListItem(e(NumberBox, {onChange: CreateMatrixParamChanger(enumBreakPoints, setEnumBreakPoints, index, i + 1), value:enumBreakPoints[index][i + 1]}, null)));
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
@ -23,15 +19,15 @@ function EnumeratorItems(index, enumBreakPoints, setEnumBreakPoints, enumNames,
|
|||||||
function EnumeratorRow(props){
|
function EnumeratorRow(props){
|
||||||
let linkedText = props.linked ? "<- mods" : "";
|
let linkedText = props.linked ? "<- mods" : "";
|
||||||
|
|
||||||
let content = e('tr', {className: 'lfo-item', id: `${props.djParam}-enum-row`},
|
let content = e('ul', {className: 'lfo-item', id: `${props.djParam}-enum-row`},
|
||||||
DataCell(DropDown({locked:props.locked, onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})),
|
ListItem(DropDown({onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})),
|
||||||
DataCell(DropDown({locked:props.locked, onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})),
|
ListItem(DropDown({onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})),
|
||||||
DataCell(e(NumberBox, {locked:props.locked, onChange: props.setEnumItemCounts, step:1, value:props.enumItems, className: 'enum-count'}, null)),
|
ListItem(e(NumberBox, {onChange: props.setEnumItemCounts, step:1, value:props.enumItems, className: 'enum-count'}, null)),
|
||||||
DataCell(e(NumberBox, {locked:props.locked, onChange: CreateMatrixParamChanger(props.enumBreakPoints, props.setEnumBreakPoints, props.index, 0), value:props.enumBreakPoints[props.index][0], step:0.1}, null)),
|
ListItem(e(NumberBox, {onChange: CreateMatrixParamChanger(props.enumBreakPoints, props.setEnumBreakPoints, props.index, 0), value:props.enumBreakPoints[props.index][0], step:0.1}, null)),
|
||||||
...(EnumeratorItems(props.index, props.enumBreakPoints, props.setEnumBreakPoints, props.enumNames, props.setEnumNames, props.djParam, props.locked).slice(0, props.enumItems * 2)),
|
...(EnumeratorItems(props.index, props.enumBreakPoints, props.setEnumBreakPoints, props.enumNames, props.setEnumNames, props.djParam).slice(0, props.enumItems * 2)),
|
||||||
DataCell(e(Button, {locked:props.locked, text:'+', onClick: props.addEnum}, null)),
|
ListItem(e(Button, {text:'+', onClick: props.addEnum}, null)),
|
||||||
DataCell(e(Button, {locked:props.locked, text:'-', onClick: props.removeEnum}, null)),
|
ListItem(e(Button, {text:'-', onClick: props.removeEnum}, null)),
|
||||||
DataCell(e("div", {className:"linked"}, linkedText))
|
ListItem(e("div", {className:"linked"}, linkedText))
|
||||||
);
|
);
|
||||||
if (props.visible){
|
if (props.visible){
|
||||||
return content;
|
return content;
|
||||||
|
2680
example-with-dj.maxpat
Normal file
2680
example-with-dj.maxpat
Normal file
File diff suppressed because it is too large
Load Diff
3457
example.maxpat
3457
example.maxpat
File diff suppressed because one or more lines are too long
541
lfogui.css
541
lfogui.css
@ -1,378 +1,181 @@
|
|||||||
* {
|
|
||||||
--locked-color: #5fadbf;
|
|
||||||
--unlocked-color: #ff5153;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--background: white;
|
|
||||||
--active: royalblue;
|
|
||||||
--nonactive: rgb(205, 205, 205);
|
|
||||||
--alert: red;
|
|
||||||
--textcolor: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
|
|
||||||
|
|
||||||
html {
|
|
||||||
background-color: var(--background);
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: "Poppins", sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
border: 0;
|
border: 0;
|
||||||
overflow-x: scroll;
|
overflow: hidden; /* Disable scrollbars */
|
||||||
overflow-y: scroll;
|
display: block; /* No floating content on sides */
|
||||||
display: block;
|
}
|
||||||
/* No floating content on sides */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*navigation*/
|
ul {
|
||||||
.header {
|
list-style-type: none;
|
||||||
display: flex;
|
margin: 0;
|
||||||
flex-flow: row nowrap;
|
padding: 0;
|
||||||
justify-content: space-between;
|
overflow: hidden;
|
||||||
align-items: center;
|
background-color: #333333;
|
||||||
margin: 1em;
|
}
|
||||||
border-bottom: 1px solid var(--active);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header button {
|
li {
|
||||||
border: 1px solid var(--active);
|
float: left;
|
||||||
color: var(--active);
|
}
|
||||||
background-color: white;
|
|
||||||
padding: 4px;
|
|
||||||
text-align: center;
|
|
||||||
display: inline-block;
|
|
||||||
padding: 0.5em;
|
|
||||||
margin: 4px;
|
|
||||||
font-size: 0.9em;
|
|
||||||
min-width: 4.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
td button {
|
|
||||||
background-color: white;
|
|
||||||
color: var(--active);
|
|
||||||
border: 1px solid var(--active);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* :::::::::::::: SELECTING MODULATORS/ENUMERATORS */
|
|
||||||
|
|
||||||
.header button.highlighted-button {
|
|
||||||
color: var(--active);
|
|
||||||
border: 1px solid var(--active);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header button.unhighlighted-button {
|
|
||||||
color: var(--nonactive);
|
|
||||||
border: 1px solid var(--nonactive);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* table */
|
|
||||||
table {
|
|
||||||
margin: 1em;
|
|
||||||
padding: 0em;
|
|
||||||
border-collapse: collapse;
|
|
||||||
background-color: lightsteelblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* points datacells should have a min-width*/
|
|
||||||
.enum-count {
|
|
||||||
min-width: 5.6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
padding: 0.4em 0.3em;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
thead {
|
|
||||||
color: white;
|
|
||||||
background-color: var(--active);
|
|
||||||
}
|
|
||||||
|
|
||||||
tr,
|
|
||||||
td {
|
|
||||||
margin: 0em;
|
|
||||||
}
|
|
||||||
|
|
||||||
td:last-child {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* input types */
|
|
||||||
/* dropdown list */
|
|
||||||
select {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
option, select>* {
|
|
||||||
font-size: 0.8em !important;
|
|
||||||
padding: 0em !important;
|
|
||||||
margin: 0em !important;
|
|
||||||
min-height: 0em !important;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
option {
|
|
||||||
background-color: var(--active);
|
|
||||||
}
|
|
||||||
|
|
||||||
option:not(:checked) {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* input */
|
|
||||||
input,
|
|
||||||
select {
|
|
||||||
border: 1px solid var(--active);
|
|
||||||
color: var(--active);
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
line-height: 1.5em;
|
|
||||||
height: 1.5em;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
padding-left: 5px;
|
|
||||||
/*slight padding on left*/
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=number] {
|
|
||||||
width: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=text] {
|
|
||||||
width: 60px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timeInput {
|
|
||||||
width: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#matrix {
|
|
||||||
background-color: aquamarine;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.numbox-unclicked {
|
|
||||||
user-select: none;
|
|
||||||
border: solid;
|
|
||||||
font-size: 12vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
.numbox-clicked {
|
|
||||||
user-select: none;
|
|
||||||
border: solid;
|
|
||||||
font-size: 12vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
.param-input-label {
|
|
||||||
width: 93%;
|
|
||||||
font-size: 5vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lfo-input-label {
|
|
||||||
width: 40%;
|
|
||||||
font-size: 5vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The switch - the box around the slider */
|
|
||||||
.switch {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
width: 30px;
|
|
||||||
height: 17px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide default HTML checkbox */
|
|
||||||
.switch input {
|
|
||||||
opacity: 0;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The slider */
|
|
||||||
input[type="range"] {
|
|
||||||
appearance: none;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 6px;
|
|
||||||
background-color: white;
|
|
||||||
outline: none;
|
|
||||||
opacity: 0.7;
|
|
||||||
-webkit-transition: .2s;
|
|
||||||
transition: opacity .2s;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*slider knob*/
|
|
||||||
input[type="range"]::-webkit-slider-runnable-track {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
color: var(--active);
|
|
||||||
margin-top: -1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="range"]::-webkit-slider-thumb {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: var(--active);
|
|
||||||
box-shadow: -80px 0 0 80px var(--active);
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="range"]::-moz-range-progress {
|
|
||||||
background-color: var(--active);
|
|
||||||
}
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
background-color: aliceblue;
|
|
||||||
padding: 0 4px 0 4px;
|
|
||||||
margin: 0 2px 0 2px;
|
|
||||||
border-color: #333333;
|
|
||||||
border-width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.base-val {
|
|
||||||
border: none;
|
|
||||||
color: white;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 0.9em;
|
|
||||||
width: 50px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.linked {
|
|
||||||
color: red;
|
|
||||||
border-width: 1px;
|
|
||||||
width: 50px;
|
|
||||||
font-size: small;
|
|
||||||
margin-left: 2px;
|
|
||||||
margin-top: 5px;
|
|
||||||
display: none;
|
|
||||||
/*hide*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@keyframes pulse-animation {
|
input[type=number] {
|
||||||
0% {
|
width: 50px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text] {
|
||||||
|
width: 60px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeInput {
|
||||||
|
width: 80px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#matrix {
|
||||||
|
background-color: aquamarine;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.numbox-unclicked {
|
||||||
|
user-select: none;
|
||||||
|
border: solid;
|
||||||
|
font-size: 12vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.numbox-clicked {
|
||||||
|
user-select: none;
|
||||||
|
border : solid;
|
||||||
|
font-size: 12vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.param-input-label {
|
||||||
|
width: 93%;
|
||||||
|
font-size: 5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lfo-input-label {
|
||||||
|
width: 40%;
|
||||||
|
font-size: 5vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The switch - the box around the slider */
|
||||||
|
.switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 30px;
|
||||||
|
height: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide default HTML checkbox */
|
||||||
|
.switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The slider */
|
||||||
|
.slider {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: #ccc;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
height: 13px;
|
||||||
|
width: 13px;
|
||||||
|
left: 2px;
|
||||||
|
bottom: 2px;
|
||||||
|
background-color: white;
|
||||||
|
-webkit-transition: .4s;
|
||||||
|
transition: .4s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider {
|
||||||
|
background-color: #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus + .slider {
|
||||||
|
box-shadow: 0 0 1px #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked + .slider:before {
|
||||||
|
-webkit-transform: translateX(13px);
|
||||||
|
-ms-transform: translateX(13px);
|
||||||
|
transform: translateX(13px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Rounded sliders */
|
||||||
|
.slider.round {
|
||||||
|
border-radius: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider.round:before {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enum-count {
|
||||||
|
background-color: aquamarine;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
background-color: aliceblue;
|
||||||
|
padding: 0 4px 0 4px;
|
||||||
|
margin: 0 2px 0 2px;
|
||||||
|
border-color: #333333;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.base-val {
|
||||||
|
background-color: lightgray;
|
||||||
|
border-color: #333333;
|
||||||
|
border-width: 1px;
|
||||||
|
width: 50px;
|
||||||
|
margin-left: 2px;
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked {
|
||||||
|
color: red;
|
||||||
|
border-width: 1px;
|
||||||
|
width: 50px;
|
||||||
|
font-size: small;
|
||||||
|
margin-left: 2px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@keyframes pulse-animation {
|
||||||
|
0% {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
100% {
|
||||||
100% {
|
|
||||||
color: red;
|
color: red;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#pulse {
|
#pulse {
|
||||||
animation: pulse-animation 0.2s normal;
|
animation: pulse-animation 0.2s normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* :::::::::::::: LOCK CSS */
|
|
||||||
|
|
||||||
.locked-component {
|
|
||||||
pointer-events: none;
|
|
||||||
background-color: #333333;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Locked */
|
|
||||||
.lock {
|
|
||||||
margin-top: 14px;
|
|
||||||
width: 24px;
|
|
||||||
height: 21px;
|
|
||||||
border: 3px solid var(--locked-color);
|
|
||||||
border-radius: 5px;
|
|
||||||
position: relative;
|
|
||||||
cursor: pointer;
|
|
||||||
-webkit-transition: all 0.1s ease-in-out;
|
|
||||||
transition: all 0.1s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lock:after {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
background: var(--locked-color);
|
|
||||||
width: 3px;
|
|
||||||
height: 7px;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
margin: -3.5px 0 0 -2px;
|
|
||||||
-webkit-transition: all 0.1s ease-in-out;
|
|
||||||
transition: all 0.1s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lock:before {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
bottom: 100%;
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -8px;
|
|
||||||
border: 3px solid var(--locked-color);
|
|
||||||
border-top-right-radius: 50%;
|
|
||||||
border-top-left-radius: 50%;
|
|
||||||
border-bottom: 0;
|
|
||||||
-webkit-transition: all 0.1s ease-in-out;
|
|
||||||
transition: all 0.1s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Locked Hover */
|
|
||||||
.lock:hover:before {
|
|
||||||
height: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unlocked */
|
|
||||||
.unlocked {
|
|
||||||
transform: rotate(10deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.unlocked:before {
|
|
||||||
bottom: 130%;
|
|
||||||
left: 31%;
|
|
||||||
margin-left: -11.5px;
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.unlocked,
|
|
||||||
.unlocked:before {
|
|
||||||
border-color: var(--unlocked-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.unlocked:after {
|
|
||||||
background: var(--unlocked-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unlocked Hover */
|
|
||||||
.unlocked:hover {
|
|
||||||
transform: rotate(3deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.unlocked:hover:before {
|
|
||||||
height: 10px;
|
|
||||||
left: 40%;
|
|
||||||
bottom: 124%;
|
|
||||||
transform: rotate(-30deg);
|
|
||||||
}
|
|
22
lfogui.html
22
lfogui.html
@ -7,20 +7,22 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<link rel="stylesheet" href="./lfogui.css">
|
||||||
<link rel="stylesheet" href="./lfogui.css">
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="lfo-container"></div>
|
<div id="lfo-container"></div>
|
||||||
|
|
||||||
<script src="./react.js"></script>
|
<script src="./react.js"></script>
|
||||||
<script src="./react-dom.js"></script>
|
<script src="./react-dom.js"></script>
|
||||||
<script src="./moment.js"></script>
|
<script src="./moment.js"></script>
|
||||||
<script src="./common.js"></script>
|
<script src="./common.js"></script>
|
||||||
<script src="./enums.js"></script>
|
<script src="./enums.js"></script>
|
||||||
<script src="./modulators.js"></script>
|
<script src="./modulators.js"></script>
|
||||||
<script src="./lfogui.js"></script>
|
<script src="./lfogui.js">
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
410
lfogui.js
410
lfogui.js
@ -4,110 +4,55 @@ var log;
|
|||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
log = console.log;
|
log = console.log;
|
||||||
else
|
else
|
||||||
log = (msg) => { window.max.outlet("debug " + msg) };
|
log = (msg) => {window.max.outlet("debug " + msg)};
|
||||||
|
|
||||||
const e = React.createElement;
|
const e = React.createElement;
|
||||||
|
|
||||||
let lfos = [];
|
let lfos = [];
|
||||||
const MAXLFOS = 200;
|
const MAXLFOS = 20;
|
||||||
const MAXENUMS = 200;
|
const MAXENUMS = 20;
|
||||||
const MAXENUMPOINTS = 10;
|
const MAXENUMPOINTS = 10;
|
||||||
const MAXUSERDEFINED = 4;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const ViewModes = Object.freeze({
|
const ViewModes = Object.freeze({
|
||||||
MOD: 0,
|
MOD: 0,
|
||||||
ENUM: 1
|
ENUM: 1
|
||||||
});
|
|
||||||
|
|
||||||
const LockModes = Object.freeze({
|
|
||||||
UNLOCK: 0,
|
|
||||||
LOCK: 1
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var modPhases = Array(MAXLFOS).fill(0);
|
var modPhases = Array(MAXLFOS).fill(0);
|
||||||
var firstUpdateTime = Date.now();
|
var firstUpdateTime = Date.now();
|
||||||
|
|
||||||
const MODULATORLABELS = ["inst", "type", "shape", "param", "timebase", "min", "max", "phase", "center", "result", "", ""];
|
const MODULATORLABELS = ["inst", "-type-", "---shape---", "-------param-------", "--timebase--", "-min-", "-max", "-phase-", "center"];
|
||||||
const ENUMERATORLABELS = ["inst", "parameter", "# points"];
|
const ENUMERATORLABELS = ["inst", "---parameter---", "-# points-"];
|
||||||
|
|
||||||
|
|
||||||
function parseLfoTimeNonMusical(lfoTime) {
|
|
||||||
if (lfoTime.slice(-2) == "hz") {
|
|
||||||
return parseFloat(lfoTime.slice(0, -2));
|
|
||||||
}
|
|
||||||
else if (lfoTime.slice(-2) == "ms") {
|
|
||||||
return 1000 / parseFloat(lfoTime.slice(0, -2));
|
|
||||||
}
|
|
||||||
else if (lfoTime.slice(-1) == "s") {
|
|
||||||
return 1 / parseFloat(lfoTime.slice(0, -1));
|
|
||||||
}
|
|
||||||
else if ((lfoTime.match(/:/g) || []).length == 2) {
|
|
||||||
return 1 / moment.duration(lfoTime).asSeconds();
|
|
||||||
}
|
|
||||||
else if ((lfoTime.match(/\./g) || []).length == 2) {
|
|
||||||
return 0; // ignore musical timings
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function nnFreqToHzString(num) {
|
|
||||||
return `${num}hz`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function MasterLfoHandler() {
|
function MasterLfoHandler(){
|
||||||
|
|
||||||
let initVisArr = Array(MAXLFOS).fill(false);
|
let initVisArr = Array(MAXLFOS).fill(false);
|
||||||
initVisArr[0] = true;
|
initVisArr[0] = true;
|
||||||
|
|
||||||
const [viewMode, setViewMode] = React.useState(ViewModes.MOD);
|
const [viewMode, setViewMode] = React.useState(ViewModes.MOD);
|
||||||
|
const toggleViewMode = () => {
|
||||||
const [lockMode, setLockMode] = React.useState(LockModes.UNLOCK);
|
if (viewMode === ViewModes.MOD)
|
||||||
const toggleLockMode = () => {
|
setViewMode(ViewModes.ENUM);
|
||||||
if (lockMode === LockModes.UNLOCK)
|
|
||||||
setLockMode(LockModes.LOCK);
|
|
||||||
else
|
else
|
||||||
setLockMode(LockModes.UNLOCK);
|
setViewMode(ViewModes.MOD);
|
||||||
};
|
};
|
||||||
|
|
||||||
const [enabled, setEnabled] = React.useState(false);
|
|
||||||
const toggleEnabled = () => {
|
|
||||||
setEnabled(!enabled);
|
|
||||||
};
|
|
||||||
|
|
||||||
const displayIfEnabled = (content) => {
|
|
||||||
if (enabled)
|
|
||||||
return content
|
|
||||||
}
|
|
||||||
|
|
||||||
let toggleEnabledText = enabled ? `Hide \u{25BE}` : `Show \u{25B8}`;
|
|
||||||
|
|
||||||
/// MODULATOR ARRAYS
|
/// MODULATOR ARRAYS
|
||||||
let userDefinedWavesBase = [];
|
|
||||||
let userDefinedFunctionsBase = [];
|
|
||||||
let userDefinedTypesBase = [0, 0, 0, 0]; //0 = wave, 1 = function
|
|
||||||
|
|
||||||
for (let i = 0; i < MAXUSERDEFINED; i++) {
|
|
||||||
userDefinedWavesBase.push(Array(50).fill(0));
|
|
||||||
userDefinedFunctionsBase.push(Array(101).fill(0));
|
|
||||||
}
|
|
||||||
const [userDefinedWaves, setUserDefinedWaves] = React.useState(userDefinedWavesBase);
|
|
||||||
const [userDefinedFunctions, setUserDefinedFunctions] = React.useState(userDefinedFunctionsBase);
|
|
||||||
const [userDefinedTypes, setUserDefinedTypes] = React.useState(userDefinedTypesBase);
|
|
||||||
const [modVisibleArr, setModVisibleArr] = React.useState(initVisArr);
|
const [modVisibleArr, setModVisibleArr] = React.useState(initVisArr);
|
||||||
const [modTypeArr, setModTypeArr] = React.useState(Array(MAXLFOS).fill('LFO'));
|
|
||||||
const [modInstanceNumArr, setModInstanceNumArr] = React.useState(Array(MAXLFOS).fill('1'));
|
const [modInstanceNumArr, setModInstanceNumArr] = React.useState(Array(MAXLFOS).fill('1'));
|
||||||
|
|
||||||
const [modCenterVals, setModCenterVals] = React.useState({ '1': {}, '2': {}, '3': {}, '4': {}, '5': {}, '6': {}});
|
const [modCenterVals, setModCenterVals] = React.useState({'1':{}, '2':{}, '3':{}, '4':{}});
|
||||||
|
|
||||||
const [ticks, setTicks] = React.useState(0);
|
const [bpm, setBpm] = React.useState(100);
|
||||||
const [beatsInMeasure, setBeatsInMeasure] = React.useState(4);
|
const [beatsInMeasure, setBeatsInMeasure] = React.useState(4);
|
||||||
|
|
||||||
const [noiseTypeArr, setNoiseTypeArr] = React.useState(Array(MAXLFOS).fill('Sine Int.'));
|
|
||||||
const [shapeArr, setShapeArr] = React.useState(Array(MAXLFOS).fill('Sine'));
|
const [shapeArr, setShapeArr] = React.useState(Array(MAXLFOS).fill('Sine'));
|
||||||
const [djParamArr, setDjParamArr] = React.useState(Array(MAXLFOS).fill('NONE'));
|
const [djParamArr, setDjParamArr] = React.useState(Array(MAXLFOS).fill('NONE'));
|
||||||
|
|
||||||
@ -117,40 +62,35 @@ function MasterLfoHandler() {
|
|||||||
const [minArr, setMinArr] = React.useState(Array(MAXLFOS).fill('0'));
|
const [minArr, setMinArr] = React.useState(Array(MAXLFOS).fill('0'));
|
||||||
const [maxArr, setMaxArr] = React.useState(Array(MAXLFOS).fill('1'));
|
const [maxArr, setMaxArr] = React.useState(Array(MAXLFOS).fill('1'));
|
||||||
|
|
||||||
const [initPhaseArr, setInitPhaseArr] = React.useState(Array(MAXLFOS).fill('0'));
|
const [phaseArr, setPhaseArr] = React.useState(Array(MAXLFOS).fill('0'));
|
||||||
const [lastPhaseArr, setLastPhaseArr] = React.useState(Array(MAXLFOS).fill(0));
|
|
||||||
const [cachedNoiseValueArr1, setCachedNoiseValueArr1] = React.useState(Array(MAXLFOS).fill(0));
|
|
||||||
const [cachedNoiseValueArr2, setCachedNoiseValueArr2] = React.useState(Array(MAXLFOS).fill(0));
|
|
||||||
|
|
||||||
|
const allModArrays = [modVisibleArr, modInstanceNumArr, shapeArr, djParamArr, freqArr, minArr, maxArr, phaseArr];
|
||||||
|
const allModSetters = [setModVisibleArr, setModInstanceNumArr, setShapeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setPhaseArr];
|
||||||
const allModArrays = [modVisibleArr, modTypeArr, modInstanceNumArr, shapeArr, noiseTypeArr, djParamArr, freqArr, minArr, maxArr, initPhaseArr, lastPhaseArr, cachedNoiseValueArr1, cachedNoiseValueArr2];
|
const modBlankVals = [true, '1', SHAPETYPES[0], MODPARAMOPTIONS[0], '1hz', '0', '1', '0'];
|
||||||
const allModSetters = [setModVisibleArr, setModTypeArr, setModInstanceNumArr, setShapeArr, setNoiseTypeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setInitPhaseArr, setLastPhaseArr, setCachedNoiseValueArr1, setCachedNoiseValueArr2];
|
|
||||||
const modBlankVals = [true, 'LFO', '1', SHAPETYPES[0], NOISETYPES[0], MODPARAMOPTIONS[0], '1hz', '0', '1', '0', 0, 0, 0];
|
|
||||||
|
|
||||||
|
|
||||||
/// ENUMERATOR ARRAYS
|
/// ENUMERATOR ARRAYS
|
||||||
const [enumVisibleArr, setEnumVisibleArr] = React.useState(initVisArr);
|
const [enumVisibleArr, setEnumVisibleArr] = React.useState(initVisArr);
|
||||||
const [enumInstanceNumArr, setEnumInstanceNumArr] = React.useState(Array(MAXLFOS).fill('1'));
|
const [enumInstanceNumArr, setEnumInstanceNumArr] = React.useState(Array(MAXLFOS).fill('1'));
|
||||||
const [enumItemCounts, setEnumItemCounts] = React.useState(Array(MAXENUMPOINTS).fill('2'));
|
const [enumItemCounts, setEnumItemCounts] = React.useState(Array(MAXENUMPOINTS).fill('2'));
|
||||||
const [enumDjParamArr, setEnumDjParamArr] = React.useState(Array(MAXENUMPOINTS).fill('NONE'));
|
const [enumDjParamArr, setEnumDjParamArr] = React.useState(Array(MAXENUMPOINTS).fill('attenuation'));
|
||||||
|
|
||||||
let baseEnumBreakpoints = Array(MAXENUMS).fill(0).map(x => Array(MAXENUMPOINTS + 1).fill(0));
|
let baseEnumBreakpoints = Array(MAXENUMS).fill(0).map(x => Array(MAXENUMPOINTS+ 1).fill(0));
|
||||||
for (let i = 0; i < MAXENUMS; i++) {
|
for (let i = 0; i < MAXENUMS; i++){
|
||||||
for (let j = 0; j < MAXENUMPOINTS + 1; j++) {
|
for (let j=0; j < MAXENUMPOINTS + 1; j++){
|
||||||
baseEnumBreakpoints[i][j] = j - 0.5;
|
baseEnumBreakpoints[i][j] = j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const [enumBreakPoints, setEnumBreakPoints] = React.useState(baseEnumBreakpoints);
|
const [enumBreakPoints, setEnumBreakPoints] = React.useState(baseEnumBreakpoints);
|
||||||
|
|
||||||
const getBlankEnumBreakPointRow = () => {
|
const getBlankEnumBreakPointRow = () => {
|
||||||
let arr = []
|
let arr = []
|
||||||
for (let i = 0; i < MAXENUMPOINTS + 1; i++)
|
for (let i=0; i< MAXENUMPOINTS + 1; i++)
|
||||||
arr.push(i - 0.5)
|
arr.push(i)
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getBlankEnumNameRow = () => { return Array(MAXENUMPOINTS).fill('param') };
|
const getBlankEnumNameRow = () => {return Array(MAXENUMPOINTS).fill('param')};
|
||||||
|
|
||||||
let baseEnumNames = Array(MAXENUMS).fill(0).map(x => Array(MAXENUMPOINTS).fill('param'));
|
let baseEnumNames = Array(MAXENUMS).fill(0).map(x => Array(MAXENUMPOINTS).fill('param'));
|
||||||
const [enumNames, setEnumNames] = React.useState(baseEnumNames);
|
const [enumNames, setEnumNames] = React.useState(baseEnumNames);
|
||||||
@ -170,45 +110,51 @@ function MasterLfoHandler() {
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
function handleLoad(event) {
|
function handleLoad(event) {
|
||||||
|
|
||||||
window.max.getDict(event.detail, (dict) => {
|
window.max.getDict(event.detail, (dict) => {
|
||||||
|
|
||||||
for (let i = 0; i < dict.data.modArrays.length; i++) {
|
for (let i = 0; i<allModArrays.length; i++) {
|
||||||
allModSetters[i](dict.data.modArrays[i]);
|
allModSetters[i](dict.data.modArrays[i]);
|
||||||
}
|
}
|
||||||
for (let i = 0; i < allEnumArrays.length; i++) {
|
|
||||||
|
for (let i = 0; i<allEnumArrays.length; i++) {
|
||||||
allEnumArrSetters[i](dict.data.enumArrays[i]);
|
allEnumArrSetters[i](dict.data.enumArrays[i]);
|
||||||
}
|
}
|
||||||
for (let i = 0; i < allEnumMats.length; i++) {
|
|
||||||
|
for (let i = 0; i<allEnumMats.length; i++) {
|
||||||
allEnumMatSetters[i](dict.data.enumMats[i]);
|
allEnumMatSetters[i](dict.data.enumMats[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setModCenterVals(dict.data.modCenters);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSave(event) {
|
function handleSave(event) {
|
||||||
let data = {
|
let data = {
|
||||||
'modArrays': allModArrays,
|
'modArrays' : allModArrays,
|
||||||
'enumArrays': allEnumArrays,
|
'enumArrays' : allEnumArrays,
|
||||||
'enumMats': allEnumMats
|
'enumMats' : allEnumMats,
|
||||||
|
'modCenters': modCenterVals
|
||||||
}
|
}
|
||||||
window.max.setDict(event.detail, { "data": data });
|
window.max.setDict(event.detail, {"data" : data});
|
||||||
window.max.outlet("saved");
|
window.max.outlet("saved");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// only called internally by 1. Handler after modulator processing 2. LFO outputs
|
// only called internally by 1. Handler after modulator processing 2. LFO outputs
|
||||||
function handleEnum(event) {
|
function handleEnum(event){
|
||||||
let inst = event.detail[0];
|
let inst = event.detail[0];
|
||||||
let name = event.detail[1];
|
let name = event.detail[1];
|
||||||
let val = event.detail[2];
|
let val = event.detail[2];
|
||||||
|
|
||||||
// if none of the Enums use this param, then we output it
|
// if none of the Enums use this param, then we output it
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < MAXENUMS) {
|
while (i < MAXENUMS){
|
||||||
if (enumVisibleArr[i] && enumDjParamArr[i] == name && enumInstanceNumArr[i] == inst)
|
if (enumVisibleArr[i] && enumDjParamArr[i] == name && enumInstanceNumArr[i] == inst)
|
||||||
break;
|
break;
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
if (i == MAXENUMS) {
|
if (i == MAXENUMS){
|
||||||
window.max.outlet(inst + ' ' + name + ' ' + val);
|
window.max.outlet(inst + ' ' + name + ' ' + val);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -225,25 +171,25 @@ function MasterLfoHandler() {
|
|||||||
let val = event.detail[2];
|
let val = event.detail[2];
|
||||||
// CHECK FOR INDEX OF THIS NAME IN ENUM MATRIX, AND IF IT IS THERE DENUMERATE
|
// CHECK FOR INDEX OF THIS NAME IN ENUM MATRIX, AND IF IT IS THERE DENUMERATE
|
||||||
let index = -1;
|
let index = -1;
|
||||||
for (let i = 0; i < MAXENUMS; i++) {
|
for (let i = 0; i < MAXENUMS; i++){
|
||||||
if (enumDjParamArr[i] == name && enumInstanceNumArr[i] == inst)
|
if (enumDjParamArr[i] == name && enumInstanceNumArr[i] == inst)
|
||||||
index = i;
|
index = i;
|
||||||
}
|
}
|
||||||
if (index != -1) {
|
if (index != -1){
|
||||||
val = denumerate(val, enumItemCounts[index], enumBreakPoints[index], enumNames[index]);
|
val = denumerate(val, enumItemCounts[index], enumBreakPoints[index], enumNames[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if none of the LFOs use this param, then we send it straight to the enum
|
// if none of the LFOs use this param, then we send it straight to the enum
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < MAXLFOS) {
|
while (i < MAXLFOS){
|
||||||
if (modVisibleArr[i] && djParamArr[i] == name && modInstanceNumArr[i] == inst)
|
if (modVisibleArr[i] && djParamArr[i] == name && modInstanceNumArr[i] == inst)
|
||||||
break;
|
break;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (i == MAXLFOS) {
|
if (i == MAXLFOS){
|
||||||
|
|
||||||
window.dispatchEvent(new CustomEvent('enum', { 'detail': [inst, name, val] }));
|
window.dispatchEvent(new CustomEvent('enum', {'detail' : [inst, name, val]}));
|
||||||
}
|
}
|
||||||
|
|
||||||
modCenterVals[inst][name] = val;
|
modCenterVals[inst][name] = val;
|
||||||
@ -255,123 +201,40 @@ function MasterLfoHandler() {
|
|||||||
|
|
||||||
function handleTick(event) {
|
function handleTick(event) {
|
||||||
let time = (Date.now() - firstUpdateTime) / 1000;
|
let time = (Date.now() - firstUpdateTime) / 1000;
|
||||||
let noiseData = { lastPhaseArr, setLastPhaseArr, cachedNoiseValueArr1, setCachedNoiseValueArr1, cachedNoiseValueArr2, setCachedNoiseValueArr2, noiseTypeArr };
|
operateModulators(modVisibleArr, modInstanceNumArr, djParamArr, modCenterVals, freqArr, minArr, maxArr, shapeArr, phaseArr, time, bpm, beatsInMeasure);
|
||||||
operateModulators(modVisibleArr, modTypeArr, modInstanceNumArr, djParamArr, modCenterVals, freqArr, minArr, maxArr, shapeArr, initPhaseArr, noiseData, userDefinedWaves, userDefinedFunctions, userDefinedTypes, time, beatsInMeasure, ticks);
|
}
|
||||||
|
|
||||||
|
function handleBpm(event) {
|
||||||
|
setBpm(event.detail);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTimeSig(event) {
|
function handleTimeSig(event) {
|
||||||
setBeatsInMeasure(parseFloat(event.detail[0]) * parseFloat(event.detail[1]) / 4);
|
setBeatsInMeasure(parseFloat(event.detail[0]) * parseFloat(event.detail[1])/ 4);
|
||||||
}
|
|
||||||
|
|
||||||
function handleChangeUserWave(event) {
|
|
||||||
userDefinedWaves[event.detail.index] = event.detail.points;
|
|
||||||
setUserDefinedWaves(userDefinedWaves);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleChangeUserFunction(event) {
|
|
||||||
userDefinedFunctions[event.detail.index] = event.detail.points;
|
|
||||||
setUserDefinedFunctions(userDefinedFunctions);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleChangeUserDefinedType(event) {
|
|
||||||
userDefinedTypes[event.detail.index - 1] = event.detail.type;
|
|
||||||
setUserDefinedTypes(userDefinedTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMaxTicks(event) {
|
|
||||||
setTicks(event.detail);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setNN(event) {
|
|
||||||
|
|
||||||
for (let i = 0; i < MAXLFOS; i++) {
|
|
||||||
freqArr[i] = nnFreqToHzString(event.detail[i]);
|
|
||||||
}
|
|
||||||
setFreqArr(freqArr)
|
|
||||||
|
|
||||||
for (let i = MAXLFOS; i < MAXLFOS * 2; i++) {
|
|
||||||
minArr[i - MAXLFOS] = event.detail[i];
|
|
||||||
}
|
|
||||||
setMinArr(minArr);
|
|
||||||
|
|
||||||
for (let i = MAXLFOS * 2; i < MAXLFOS * 3; i++) {
|
|
||||||
maxArr[i - MAXLFOS * 2] = event.detail[i];
|
|
||||||
}
|
|
||||||
setMaxArr(maxArr);
|
|
||||||
|
|
||||||
for (let i = MAXLFOS * 3; i < MAXLFOS * 4; i++) {
|
|
||||||
initPhaseArr[i - MAXLFOS * 3] = parseFloat(event.detail[i]);
|
|
||||||
|
|
||||||
}
|
|
||||||
setInitPhaseArr(initPhaseArr);
|
|
||||||
|
|
||||||
for (let i = MAXLFOS * 4; i < MAXLFOS * 5; i++) {
|
|
||||||
let index = i - MAXLFOS * 4;
|
|
||||||
let inst = modInstanceNumArr[index];
|
|
||||||
let param = djParamArr[index];
|
|
||||||
modCenterVals[inst][param] = parseFloat(event.detail[i]);
|
|
||||||
|
|
||||||
}
|
|
||||||
setModCenterVals(modCenterVals);
|
|
||||||
|
|
||||||
rerender(!render); // BAD! SHOULD NOT BE DOING THIS!
|
|
||||||
}
|
|
||||||
|
|
||||||
function dumpNN(event) {
|
|
||||||
let allNNData = [];
|
|
||||||
freqArr.forEach(element => {
|
|
||||||
allNNData.push(parseLfoTimeNonMusical(element));
|
|
||||||
});
|
|
||||||
allNNData = allNNData.concat(minArr);
|
|
||||||
allNNData = allNNData.concat(maxArr);
|
|
||||||
allNNData = allNNData.concat(initPhaseArr);
|
|
||||||
|
|
||||||
let lfoMatchedCenterVals = [];
|
|
||||||
for (let i = 0; i < MAXLFOS; i++) {
|
|
||||||
let inst = modInstanceNumArr[i];
|
|
||||||
let param = djParamArr[i];
|
|
||||||
lfoMatchedCenterVals.push(modCenterVals[inst][param]);
|
|
||||||
if (!lfoMatchedCenterVals[i])
|
|
||||||
lfoMatchedCenterVals[i] = 0
|
|
||||||
|
|
||||||
}
|
|
||||||
allNNData = allNNData.concat(lfoMatchedCenterVals);
|
|
||||||
window.max.outlet("NNdata " + allNNData.join(" "));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window.addEventListener('loadDict', handleLoad);
|
window.addEventListener('loadDict', handleLoad);
|
||||||
window.addEventListener('saveDict', handleSave);
|
window.addEventListener('saveDict', handleSave);
|
||||||
window.addEventListener('dumpNN', dumpNN);
|
|
||||||
window.addEventListener('setNN', setNN);
|
|
||||||
window.addEventListener('tick', handleTick);
|
window.addEventListener('tick', handleTick);
|
||||||
window.addEventListener('param', handleParam);
|
window.addEventListener('param', handleParam);
|
||||||
window.addEventListener('enum', handleEnum);
|
window.addEventListener('enum', handleEnum);
|
||||||
|
window.addEventListener('tempo', handleBpm);
|
||||||
window.addEventListener('timesig', handleTimeSig);
|
window.addEventListener('timesig', handleTimeSig);
|
||||||
window.addEventListener('userWave', handleChangeUserWave);
|
|
||||||
window.addEventListener('userFunction', handleChangeUserFunction);
|
|
||||||
window.addEventListener('userDefinedType', handleChangeUserDefinedType);
|
|
||||||
window.addEventListener('maxTicks', handleMaxTicks);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('loadDict', handleLoad);
|
window.removeEventListener('loadDict', handleLoad);
|
||||||
window.removeEventListener('saveDict', handleSave);
|
window.removeEventListener('saveDict', handleSave);
|
||||||
window.removeEventListener('dumpNN', dumpNN);
|
|
||||||
window.removeEventListener('setNN', setNN);
|
|
||||||
window.removeEventListener('tick', handleTick);
|
window.removeEventListener('tick', handleTick);
|
||||||
window.removeEventListener('param', handleParam);
|
window.removeEventListener('param', handleParam);
|
||||||
window.removeEventListener('enum', handleEnum);
|
window.removeEventListener('enum', handleEnum);
|
||||||
|
window.removeEventListener('tempo', handleBpm);
|
||||||
window.removeEventListener('timesig', handleTimeSig);
|
window.removeEventListener('timesig', handleTimeSig);
|
||||||
window.removeEventListener('userWave', handleChangeUserWave);
|
|
||||||
window.removeEventListener('userFunction', handleChangeUserFunction);
|
|
||||||
window.removeEventListener('userDefinedType', handleChangeUserDefinedType);
|
|
||||||
window.removeEventListener('maxTicks', handleMaxTicks);
|
|
||||||
};
|
};
|
||||||
}, [...allModArrays, ...allEnumArrays, ...allEnumMats, userDefinedWaves, userDefinedFunctions, userDefinedTypes, modCenterVals, render, beatsInMeasure, ticks]);
|
}, [...allModArrays, ...allEnumArrays, ...allEnumMats, modCenterVals, render, bpm, beatsInMeasure]);
|
||||||
|
|
||||||
|
|
||||||
function CheckLinked(inst, param, checkInstArr, checkParamArr) {
|
function CheckLinked(inst, param, checkInstArr, checkParamArr){
|
||||||
for (let i = 0; i < checkInstArr.length; i++) {
|
for (let i = 0; i < checkInstArr.length; i++){
|
||||||
if (checkInstArr[i] == inst && checkParamArr[i] == param)
|
if (checkInstArr[i] == inst && checkParamArr[i] == param)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -382,23 +245,16 @@ function MasterLfoHandler() {
|
|||||||
// Generate Modulators
|
// Generate Modulators
|
||||||
///////
|
///////
|
||||||
let modContents = []
|
let modContents = []
|
||||||
for (var i = 0; i < MAXLFOS; i++) {
|
for (var i = 0; i<MAXLFOS; i++){
|
||||||
let id = i;
|
let id = i;
|
||||||
|
|
||||||
modContents.push(
|
modContents.push(
|
||||||
|
|
||||||
e(LfoRow, {
|
e(LfoRow, {
|
||||||
locked: lockMode,
|
instanceNum : modInstanceNumArr[i],
|
||||||
instanceNum: modInstanceNumArr[i],
|
|
||||||
setInstanceNum: CreateParamChanger(modInstanceNumArr, setModInstanceNumArr, i),
|
setInstanceNum: CreateParamChanger(modInstanceNumArr, setModInstanceNumArr, i),
|
||||||
|
|
||||||
type: modTypeArr[i],
|
|
||||||
setType: CreateParamChanger(modTypeArr, setModTypeArr, i),
|
|
||||||
shape: shapeArr[i],
|
shape: shapeArr[i],
|
||||||
setShape: CreateParamChanger(shapeArr, setShapeArr, i),
|
setShape: CreateParamChanger(shapeArr, setShapeArr, i),
|
||||||
|
|
||||||
noise: noiseTypeArr[i],
|
|
||||||
setNoise: CreateParamChanger(noiseTypeArr, setNoiseTypeArr, i),
|
|
||||||
djParam: djParamArr[i],
|
djParam: djParamArr[i],
|
||||||
setDjParam: CreateParamChanger(djParamArr, setDjParamArr, i),
|
setDjParam: CreateParamChanger(djParamArr, setDjParamArr, i),
|
||||||
centerVals: modCenterVals,
|
centerVals: modCenterVals,
|
||||||
@ -410,24 +266,22 @@ function MasterLfoHandler() {
|
|||||||
//setAmp: CreateParamChanger(ampArr, setAmpArr, i),
|
//setAmp: CreateParamChanger(ampArr, setAmpArr, i),
|
||||||
|
|
||||||
min: minArr[i],
|
min: minArr[i],
|
||||||
setMin: CreateParamChanger(minArr, setMinArr, i),
|
setMin : CreateParamChanger(minArr, setMinArr, i),
|
||||||
max: maxArr[i],
|
max: maxArr[i],
|
||||||
setMax: CreateParamChanger(maxArr, setMaxArr, i),
|
setMax: CreateParamChanger(maxArr, setMaxArr, i),
|
||||||
|
|
||||||
phase: initPhaseArr[i],
|
phase: phaseArr[i],
|
||||||
setPhase: CreateParamChanger(initPhaseArr, setInitPhaseArr, i),
|
setPhase: CreateParamChanger(phaseArr, setPhaseArr, i),
|
||||||
visible: modVisibleArr[i],
|
visible: modVisibleArr[i],
|
||||||
|
|
||||||
linked: CheckLinked(modInstanceNumArr[i], djParamArr[i], enumInstanceNumArr, enumDjParamArr),
|
linked: CheckLinked(modInstanceNumArr[i], djParamArr[i], enumInstanceNumArr, enumDjParamArr),
|
||||||
addLfo: () => {
|
addLfo: () => {
|
||||||
|
if (id < MAXLFOS - 1){
|
||||||
if (id < MAXLFOS - 1) {
|
if (modVisibleArr[id + 1]){
|
||||||
|
|
||||||
if (modVisibleArr[id + 1]) {
|
|
||||||
|
|
||||||
let emptyIndex = modVisibleArr.findIndex((item) => !item);
|
let emptyIndex = modVisibleArr.findIndex((item) => !item);
|
||||||
if (emptyIndex != -1) {
|
if (emptyIndex != -1){
|
||||||
for (var j = 0; j < allModArrays.length; j++) {
|
for (var j = 0; j < allModArrays.length; j++){
|
||||||
let array = allModArrays[j];
|
let array = allModArrays[j];
|
||||||
// remove from all arrays
|
// remove from all arrays
|
||||||
array.splice(emptyIndex, 1);
|
array.splice(emptyIndex, 1);
|
||||||
@ -438,29 +292,25 @@ function MasterLfoHandler() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
for (var j = 0; j < allModArrays.length; j++){ // no space below, easy.
|
||||||
for (var j = 0; j < allModArrays.length; j++) { // no space below, easy.
|
|
||||||
let array = allModArrays[j];
|
let array = allModArrays[j];
|
||||||
array[id + 1] = modBlankVals[j];
|
array[id + 1] = modBlankVals[j];
|
||||||
allModSetters[j](array);
|
allModSetters[j](array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SendSaveEvent();
|
|
||||||
rerender(!render);
|
rerender(!render);
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeLfo: () => {
|
removeLfo: () => {
|
||||||
if (modVisibleArr.filter(x => x).length > 1) {
|
if (modVisibleArr.filter(x=>x).length > 1){
|
||||||
let newArr = modVisibleArr.slice();
|
let newArr = modVisibleArr.slice();
|
||||||
newArr[id] = false;
|
newArr[id] = false;
|
||||||
setModVisibleArr(newArr);
|
setModVisibleArr(newArr);
|
||||||
SendSaveEvent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
null));
|
null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -468,36 +318,30 @@ function MasterLfoHandler() {
|
|||||||
// Generate Enumerators
|
// Generate Enumerators
|
||||||
///////
|
///////
|
||||||
let enumContents = []
|
let enumContents = []
|
||||||
for (var i = 0; i < MAXLFOS; i++) {
|
for (var i = 0; i<MAXLFOS; i++){
|
||||||
let id = i;
|
let id = i;
|
||||||
enumContents.push(
|
enumContents.push(
|
||||||
e(EnumeratorRow, {
|
e(EnumeratorRow, {
|
||||||
index: i,
|
index: i,
|
||||||
locked: lockMode,
|
|
||||||
instanceNum: enumInstanceNumArr[i],
|
instanceNum : enumInstanceNumArr[i],
|
||||||
setInstanceNum: CreateParamChanger(enumInstanceNumArr, setEnumInstanceNumArr, i),
|
setInstanceNum: CreateParamChanger(enumInstanceNumArr, setEnumInstanceNumArr, i),
|
||||||
enumItems: enumItemCounts[i],
|
enumItems: enumItemCounts[i],
|
||||||
setEnumItemCounts: CreateParamChanger(enumItemCounts, setEnumItemCounts, i),
|
setEnumItemCounts: CreateParamChanger(enumItemCounts, setEnumItemCounts, i),
|
||||||
enumBreakPoints: enumBreakPoints,
|
enumBreakPoints: enumBreakPoints,
|
||||||
setEnumBreakPoints: (val) => {
|
setEnumBreakPoints: setEnumBreakPoints,
|
||||||
setEnumBreakPoints(val);
|
|
||||||
SendSaveEvent
|
|
||||||
},
|
|
||||||
enumNames: enumNames,
|
enumNames: enumNames,
|
||||||
setEnumNames: (val) => {
|
setEnumNames: setEnumNames,
|
||||||
setEnumNames(val);
|
|
||||||
SendSaveEvent
|
|
||||||
},
|
|
||||||
visible: enumVisibleArr[i],
|
visible: enumVisibleArr[i],
|
||||||
djParam: enumDjParamArr[i],
|
djParam: enumDjParamArr[i],
|
||||||
setDjParam: CreateParamChanger(enumDjParamArr, setEnumDjParamArr, i),
|
setDjParam: CreateParamChanger(enumDjParamArr, setEnumDjParamArr, i),
|
||||||
linked: CheckLinked(enumInstanceNumArr[i], enumDjParamArr[i], modInstanceNumArr, djParamArr),
|
linked: CheckLinked(enumInstanceNumArr[i], enumDjParamArr[i], modInstanceNumArr, djParamArr),
|
||||||
addEnum: () => {
|
addEnum: () => {
|
||||||
if (id < MAXLFOS - 1) {
|
if (id < MAXLFOS - 1){
|
||||||
if (enumVisibleArr[id + 1]) { // if we need to open up space
|
if (enumVisibleArr[id + 1]){ // if we need to open up space
|
||||||
let emptyIndex = enumVisibleArr.findIndex((item) => !item);
|
let emptyIndex = enumVisibleArr.findIndex((item) => !item);
|
||||||
if (emptyIndex != -1) {
|
if (emptyIndex != -1){
|
||||||
for (var j = 0; j < allEnumArrays.length; j++) {
|
for (var j = 0; j < allEnumArrays.length; j++){
|
||||||
let array = allEnumArrays[j];
|
let array = allEnumArrays[j];
|
||||||
// remove from all arrays
|
// remove from all arrays
|
||||||
array.splice(emptyIndex, 1);
|
array.splice(emptyIndex, 1);
|
||||||
@ -508,7 +352,7 @@ function MasterLfoHandler() {
|
|||||||
|
|
||||||
// Now do the same with matrices
|
// Now do the same with matrices
|
||||||
|
|
||||||
for (var j = 0; j < allEnumMats.length; j++) {
|
for (var j = 0; j < allEnumMats.length; j++){
|
||||||
let mat = allEnumMats[j];
|
let mat = allEnumMats[j];
|
||||||
mat.splice(emptyIndex, 1);
|
mat.splice(emptyIndex, 1);
|
||||||
mat.splice(id + 1, 0, 0);
|
mat.splice(id + 1, 0, 0);
|
||||||
@ -518,30 +362,28 @@ function MasterLfoHandler() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (var j = 0; j < allEnumArrays.length; j++) {
|
for (var j = 0; j < allEnumArrays.length; j++){
|
||||||
let array = allEnumArrays[j];
|
let array = allEnumArrays[j];
|
||||||
array[id + 1] = enumBlankVals[j];
|
array[id+1] = enumBlankVals[j];
|
||||||
allEnumArrSetters[j](array);
|
allEnumArrSetters[j](array);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now do the same with matrices
|
// Now do the same with matrices
|
||||||
|
|
||||||
for (var j = 0; j < allEnumMats.length; j++) {
|
for (var j = 0; j < allEnumMats.length; j++){
|
||||||
let mat = allEnumMats[j];
|
let mat = allEnumMats[j];
|
||||||
mat[id + 1] = allGetEnumMatBlankVals[j]();
|
mat[id + 1] = allGetEnumMatBlankVals[j]();
|
||||||
allEnumMatSetters[j](mat);
|
allEnumMatSetters[j](mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rerender(!render);
|
rerender(!render);
|
||||||
SendSaveEvent();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeEnum: () => {
|
removeEnum: () => {
|
||||||
if (enumVisibleArr.filter(x => x).length > 1) {
|
if (enumVisibleArr.filter(x=>x).length > 1){
|
||||||
let newArr = enumVisibleArr.slice();
|
let newArr = enumVisibleArr.slice();
|
||||||
newArr[id] = false;
|
newArr[id] = false;
|
||||||
setEnumVisibleArr(newArr);
|
setEnumVisibleArr(newArr);
|
||||||
SendSaveEvent();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, null)
|
}, null)
|
||||||
@ -550,95 +392,49 @@ function MasterLfoHandler() {
|
|||||||
|
|
||||||
|
|
||||||
var grid;
|
var grid;
|
||||||
var modButtonClass;
|
var title;
|
||||||
var enumButtonClass;
|
|
||||||
var labels;
|
var labels;
|
||||||
if (viewMode === ViewModes.MOD) {
|
if (viewMode === ViewModes.MOD){
|
||||||
grid = modContents;
|
grid = modContents;
|
||||||
modButtonClass = "highlighted-button";
|
title = "MODULATORS";
|
||||||
enumButtonClass = "unhighlighted-button";
|
|
||||||
labels = MODULATORLABELS;
|
labels = MODULATORLABELS;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
grid = enumContents;
|
grid = enumContents;
|
||||||
modButtonClass = "unhighlighted-button";
|
title = "ENUMERATORS";
|
||||||
enumButtonClass = "highlighted-button";
|
|
||||||
labels = ENUMERATORLABELS;
|
labels = ENUMERATORLABELS;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lockClass;
|
|
||||||
if (lockMode == LockModes.LOCK) {
|
|
||||||
lockClass = 'lock';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lockClass = 'lock unlocked';
|
|
||||||
}
|
|
||||||
|
|
||||||
return e('div', null,
|
return e('div', null,
|
||||||
e('div', { className: 'header' },
|
e(Switch, {ontoggle: toggleViewMode}, null),
|
||||||
e('div', {className: 'nav'},
|
e('h5', null, title),
|
||||||
displayIfEnabled(e('button', { onClick: () => setViewMode(ViewModes.MOD), className: modButtonClass}, 'Modulators')),
|
e('ul', null, ...labels.map(x => ListItem(Label(x)))),
|
||||||
displayIfEnabled(e('button', { onClick: () => setViewMode(ViewModes.ENUM), className: enumButtonClass }, 'Enumerators'))
|
e('div', {id: 'grid'}, ...grid)
|
||||||
),
|
|
||||||
e('button', { onClick: toggleEnabled, id: 'hide-button'}, toggleEnabledText),
|
|
||||||
|
|
||||||
//allows lock mode
|
|
||||||
//e('span', { className: lockClass, onClick: toggleLockMode }, null)
|
|
||||||
),
|
|
||||||
|
|
||||||
displayIfEnabled(
|
|
||||||
e('table', { id: 'table' },
|
|
||||||
e('thead', null, e('tr', { id: 'headers' }, ...labels.map(x => e('th', {id: x == '# points' ? 'points' : x}, x)))),
|
|
||||||
e('tbody', null, ...grid)
|
|
||||||
))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DEBUG) {
|
if (!DEBUG){
|
||||||
window.max.bindInlet("load", (dictId) => {
|
window.max.bindInlet("load", (dictId) => {
|
||||||
window.dispatchEvent(new CustomEvent('loadDict', { 'detail': dictId }));
|
window.dispatchEvent(new CustomEvent('loadDict', {'detail' : dictId}));
|
||||||
});
|
});
|
||||||
|
|
||||||
window.max.bindInlet("save", (dictId) => {
|
window.max.bindInlet("save", (dictId) => {
|
||||||
window.dispatchEvent(new CustomEvent('saveDict', { 'detail': dictId }));
|
window.dispatchEvent(new CustomEvent('saveDict', {'detail' : dictId}));
|
||||||
});
|
|
||||||
|
|
||||||
window.max.bindInlet("dumpNN", () => {
|
|
||||||
window.dispatchEvent(new CustomEvent('dumpNN'));
|
|
||||||
});
|
|
||||||
|
|
||||||
window.max.bindInlet("setNN", (...data) => {
|
|
||||||
window.dispatchEvent(new CustomEvent('setNN', { 'detail': data }));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
window.max.bindInlet("param", (inst, paramName, val) => {
|
window.max.bindInlet("param", (inst, paramName, val) => {
|
||||||
window.dispatchEvent(new CustomEvent('param', { 'detail': [inst, paramName, val] }));
|
|
||||||
|
window.dispatchEvent(new CustomEvent('param', {'detail' : [inst, paramName, val]}));
|
||||||
|
});
|
||||||
|
|
||||||
|
window.max.bindInlet("tempo", (val) => {
|
||||||
|
window.dispatchEvent(new CustomEvent('tempo', {'detail' : val}));
|
||||||
});
|
});
|
||||||
|
|
||||||
window.max.bindInlet("timesig", (top, bottom) => {
|
window.max.bindInlet("timesig", (top, bottom) => {
|
||||||
window.dispatchEvent(new CustomEvent('timesig', { 'detail': [top, bottom] }));
|
window.dispatchEvent(new CustomEvent('timesig', {'detail' : [top, bottom]}));
|
||||||
});
|
});
|
||||||
|
|
||||||
window.max.bindInlet("ticks", (val) => {
|
|
||||||
window.dispatchEvent(new CustomEvent('maxTicks', { 'detail': val }));
|
|
||||||
});
|
|
||||||
|
|
||||||
window.max.bindInlet("userWave", (index, ...points) => {
|
|
||||||
let data = { points, index };
|
|
||||||
window.dispatchEvent(new CustomEvent('userWave', { 'detail': data }));
|
|
||||||
});
|
|
||||||
|
|
||||||
window.max.bindInlet("userFunction", (index, ...points) => {
|
|
||||||
//list of 101 points between 0-100
|
|
||||||
let data = { points, index };
|
|
||||||
window.dispatchEvent(new CustomEvent('userFunction', { 'detail': data }));
|
|
||||||
});
|
|
||||||
|
|
||||||
window.max.bindInlet("userDefinedType", (index, type) => {
|
|
||||||
let data = { index, type };
|
|
||||||
window.dispatchEvent(new CustomEvent('userDefinedType', { 'detail': data }));
|
|
||||||
})
|
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
window.dispatchEvent(new CustomEvent('tick'));
|
window.dispatchEvent(new CustomEvent('tick'));
|
||||||
}, 200);
|
}, 200);
|
||||||
|
182
modulators.js
182
modulators.js
@ -2,29 +2,19 @@
|
|||||||
// MODULATORS
|
// MODULATORS
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
|
|
||||||
|
var SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square"];
|
||||||
|
|
||||||
var TYPEOPTIONS = ["LFO", "Noise"];
|
var INSTANCEOPTIONS = ["1", "2", "3", "4"];
|
||||||
var SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square", "Custom_1", "Custom_2", "Custom_3", "Custom_4"];
|
|
||||||
var NOISETYPES = ["Rand", "Line Int.", "Sine Int."]
|
|
||||||
|
|
||||||
var INSTANCEOPTIONS = ["1", "2", "3", "4", "5", "6"];
|
|
||||||
|
|
||||||
const MODPARAMOPTIONS = ["NONE", "stream", "pulse_length", "eventfulness", "event_length", "metriclarity",
|
const MODPARAMOPTIONS = ["NONE", "stream", "pulse_length", "eventfulness", "event_length", "metriclarity",
|
||||||
"harmoniclarity", "melodic_cohesion", "melody_scope", "tonic_pitch", "pitch_center", "pitch_range", "dynamics",
|
"harmoniclarity", "melodic_cohesion", "melody_scope", "tonic_pitch", "pitch_center", "pitch_range", "dynamics",
|
||||||
"attenuation", "chordal_weight", "tonality-profile", "ostinato-buffer", "ostinato", "meter", "scale"];
|
"attenuation", "chordal_weight", "tonality-profile", "ostinato-buffer", "ostinato", "meter", "scale"];
|
||||||
|
|
||||||
const PhaseTypes = Object.freeze({
|
|
||||||
MUSICAL: Symbol("musical"),
|
|
||||||
TIME: Symbol("time")
|
|
||||||
});
|
|
||||||
|
|
||||||
function ControlType(){
|
function ControlType(){
|
||||||
return e('select', {className: 'control-type'}, Option("LFO"));
|
return e('select', {className: 'control-type'}, Option("LFO"));
|
||||||
}
|
}
|
||||||
|
|
||||||
function DataCell(element) {
|
|
||||||
return e('td', null, element);
|
|
||||||
}
|
|
||||||
|
|
||||||
function LfoRow(props){
|
function LfoRow(props){
|
||||||
|
|
||||||
@ -33,45 +23,28 @@ function LfoRow(props){
|
|||||||
if (!center)
|
if (!center)
|
||||||
center = 0;
|
center = 0;
|
||||||
|
|
||||||
let typeOption = null;
|
let content = e('ul', {className: 'lfo-item'},
|
||||||
|
ListItem(DropDown({onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})),
|
||||||
if (props.type == "LFO"){
|
ListItem(ControlType()),
|
||||||
typeOption = DataCell(DropDown({locked:props.locked, onChange: props.setShape, value:props.shape, options: SHAPETYPES}));
|
ListItem(DropDown({onChange: props.setShape, value:props.shape, options: SHAPETYPES})),
|
||||||
}
|
ListItem(DropDown({onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})),
|
||||||
else if (props.type == "Noise"){
|
ListItem(e("input", {onChange:props.setFreq, value:props.freq, className:"timeInput"}, null)),
|
||||||
typeOption = DataCell(DropDown({locked:props.locked, onChange: props.setNoise, value:props.noise, options: NOISETYPES}));
|
ListItem(e(NumberBox, {onChange:props.setMin, value:props.min, step:0.1}, null)),
|
||||||
}
|
ListItem(e(NumberBox, {onChange:props.setMax, value:props.max, step:0.1}, null)),
|
||||||
|
//ListItem(e(NumberBox, {onChange:props.setAmp, value:props.amp, step:0.1}, null)),
|
||||||
let content = e('tr', {className: 'lfo-item'},
|
ListItem(e(NumberBox, {onChange:props.setPhase, value:props.phase, step:0.1}, null)),
|
||||||
DataCell(DropDown({locked:props.locked, onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})),
|
ListItem(e("div", {className:"base-val"}, center.toString())),
|
||||||
DataCell(DropDown({locked:props.locked, options: TYPEOPTIONS, onChange: props.setType, value:props.type})),
|
ListItem(e("input", {type: 'range', min: 0, max: 1, step: 0.01, readonly: true, id: `slider-${props.instanceNum}-${props.djParam}`})),
|
||||||
typeOption,
|
ListItem(e(Button, {text:'+', onClick: props.addLfo}, null)),
|
||||||
DataCell(DropDown({locked:props.locked, onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})),
|
ListItem(e(Button, {text:'-', onClick: props.removeLfo}, null)),
|
||||||
DataCell(e("input", {onChange:props.setFreq, value:props.freq, className:"timeInput"}, null)),
|
ListItem(e("div", {className:"linked"}, linkedText)),
|
||||||
DataCell(e(NumberBox, {onChange:props.setMin, value:props.min, step:0.1}, null)),
|
|
||||||
DataCell(e(NumberBox, {onChange:props.setMax, value:props.max, step:0.1}, null)),
|
|
||||||
//DataCell(e(NumberBox, {onChange:props.setAmp, value:props.amp, step:0.1}, null)),
|
|
||||||
DataCell(e(NumberBox, {onChange:props.setPhase, value:props.phase, step:0.1}, null)),
|
|
||||||
DataCell(e("div", {className:"base-val"}, center.toString())),
|
|
||||||
DataCell(e("input", {type: 'range', min: 0, max: 1, step: 0.01, readonly: true, id: `slider-${props.instanceNum}-${props.djParam}`})),
|
|
||||||
DataCell(e(Button, {text:'+', onClick: props.addLfo, locked: props.locked}, null)),
|
|
||||||
DataCell(e(Button, {text:'-', onClick: props.removeLfo, locked: props.locked}, null)),
|
|
||||||
DataCell(e("div", {className:"linked"}, linkedText)),
|
|
||||||
);
|
);
|
||||||
if (props.visible){
|
if (props.visible){
|
||||||
return content;
|
return content
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function indexUserWave(phase, index, userDefinedWaves){
|
function indexWave(type, phase){
|
||||||
return parseFloat(userDefinedWaves[index][Math.floor(phase * 50)]) / 127;
|
|
||||||
}
|
|
||||||
|
|
||||||
function indexUserFunction(phase, index, userDefinedFunctions){
|
|
||||||
return parseFloat(userDefinedFunctions[index][Math.floor(phase * 101)]) / 127;
|
|
||||||
}
|
|
||||||
|
|
||||||
function indexWave(type, phase, userDefinedWaves, userDefinedFunctions, userDefinedTypes){
|
|
||||||
switch (type){
|
switch (type){
|
||||||
case "Sine":
|
case "Sine":
|
||||||
return (Math.sin(phase * Math.PI * 2) / 2) + 0.5;
|
return (Math.sin(phase * Math.PI * 2) / 2) + 0.5;
|
||||||
@ -83,18 +56,10 @@ function indexWave(type, phase, userDefinedWaves, userDefinedFunctions, userDefi
|
|||||||
return phase > 0.5? (1-phase) * 2 : phase * 2;
|
return phase > 0.5? (1-phase) * 2 : phase * 2;
|
||||||
case "Square":
|
case "Square":
|
||||||
return +(phase > 0.5);
|
return +(phase > 0.5);
|
||||||
case "Custom_1":
|
|
||||||
return userDefinedTypes[0] == 0 ? indexUserWave(phase, 1, userDefinedWaves) : indexUserFunction(phase, 1, userDefinedFunctions);
|
|
||||||
case "Custom_2":
|
|
||||||
return userDefinedTypes[1] == 0 ? indexUserWave(phase, 2, userDefinedWaves) : indexUserFunction(phase, 2, userDefinedFunctions);
|
|
||||||
case "Custom_3":
|
|
||||||
return userDefinedTypes[2] == 0 ? indexUserWave(phase, 3, userDefinedWaves) : indexUserFunction(phase, 3, userDefinedFunctions);
|
|
||||||
case "Custom_4":
|
|
||||||
return userDefinedTypes[3] == 0 ? indexUserWave(phase, 4, userDefinedWaves) : indexUserFunction(phase, 4, userDefinedFunctions);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function operateModulators(visibleArr, typeArr, instanceNumArr, paramNames, centers, freqs, mins, maxs, waveTypes, phaseArr, noiseData, userDefinedWaves, userDefinedFunctions, userDefinedTypes, currTime, beatsInMeasure, ticks){
|
function operateModulators(visibleArr, instanceNumArr, paramNames, centers, freqs, mins, maxs, waveTypes, phaseArr, currTime, bpm, beatsInMeasure){
|
||||||
for (let i=0; i<paramNames.length; i++){
|
for (let i=0; i<paramNames.length; i++){
|
||||||
if (visibleArr[i]){
|
if (visibleArr[i]){
|
||||||
|
|
||||||
@ -104,121 +69,54 @@ function operateModulators(visibleArr, typeArr, instanceNumArr, paramNames, cent
|
|||||||
if (centers[inst].hasOwnProperty(name)){
|
if (centers[inst].hasOwnProperty(name)){
|
||||||
center = centers[inst][name];
|
center = centers[inst][name];
|
||||||
}
|
}
|
||||||
|
let output = operateModulator(center, inst, freqs[i], mins[i], maxs[i], waveTypes[i], phaseArr, i, name, currTime, bpm, beatsInMeasure);
|
||||||
let output = 0;
|
|
||||||
|
|
||||||
if (typeArr[i] == "LFO")
|
|
||||||
output = operateLFO(center, inst, freqs[i], mins[i], maxs[i], waveTypes[i], phaseArr, i, userDefinedWaves, userDefinedFunctions, userDefinedTypes, name, currTime, beatsInMeasure, ticks);
|
|
||||||
else
|
|
||||||
output = operateNoise(center, inst, freqs[i], mins[i], maxs[i], waveTypes[i], phaseArr, i, name, noiseData, currTime, beatsInMeasure, ticks);
|
|
||||||
if (name !== "NONE")
|
if (name !== "NONE")
|
||||||
window.dispatchEvent(new CustomEvent('enum', {'detail' : [inst, name, output]}));
|
window.dispatchEvent(new CustomEvent('enum', {'detail' : [inst, name, output]}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function operateLFO(center, inst, timeBaseStr, min, max, waveType, phaseArr, phaseIndex, userDefinedWaves, userDefinedFunctions, userDefinedTypes, name, currTime, beatsInMeasure, maxTicks){
|
function operateModulator(center, inst, freq, min, max, waveType, phaseArr, phaseI, name, currTime, bpm, beatsInMeasure){
|
||||||
let amp = parseFloat(max) - parseFloat(min);
|
let amp = parseFloat(max) - parseFloat(min);
|
||||||
let phaseType;
|
|
||||||
let timeBase;
|
|
||||||
|
|
||||||
[timeBase, phaseType] = parseLfoTime(timeBaseStr, beatsInMeasure);
|
freq = parseLfoTime(freq, bpm, beatsInMeasure);
|
||||||
let phase;
|
let phase = (currTime * freq + parseFloat(phaseArr[phaseI])) % 1.00;
|
||||||
|
let unscaled = indexWave(waveType, phase);
|
||||||
if (phaseType === PhaseTypes.TIME)
|
|
||||||
phase = (currTime * timeBase + parseFloat(phaseArr[phaseIndex])) % 1.00;
|
|
||||||
else if (phaseType === PhaseTypes.MUSICAL)
|
|
||||||
phase = (maxTicks % timeBase) / timeBase;
|
|
||||||
let unscaled = indexWave(waveType, phase, userDefinedWaves, userDefinedFunctions, userDefinedTypes);
|
|
||||||
syncDisplay(inst, name, unscaled);
|
|
||||||
|
|
||||||
return unscaled * amp + center + parseFloat(min);
|
|
||||||
}
|
|
||||||
|
|
||||||
function syncDisplay(inst, name, val) {
|
|
||||||
let el = document.getElementById(`slider-${inst}-${name}`);
|
let el = document.getElementById(`slider-${inst}-${name}`);
|
||||||
|
|
||||||
if (el)
|
if (el)
|
||||||
el.value = val;
|
el.value = unscaled;
|
||||||
}
|
|
||||||
|
|
||||||
// For now, we're only using sine interpolation
|
|
||||||
function operateNoise(center, inst, timeBaseStr, min, max, waveType, phaseArr, index, name, noiseData, currTime, beatsInMeasure, maxTicks){
|
|
||||||
|
|
||||||
let amp = parseFloat(max) - parseFloat(min);
|
|
||||||
let phaseType;
|
|
||||||
let timeBase;
|
|
||||||
let noiseType = noiseData.noiseTypeArr[index];
|
|
||||||
|
|
||||||
[timeBase, phaseType] = parseLfoTime(timeBaseStr, beatsInMeasure);
|
|
||||||
let phase;
|
|
||||||
|
|
||||||
if (phaseType === PhaseTypes.TIME)
|
|
||||||
phase = (currTime * timeBase + parseFloat(phaseArr[index])) % 1.00;
|
|
||||||
else if (phaseType === PhaseTypes.MUSICAL)
|
|
||||||
phase = (maxTicks % timeBase) / timeBase;
|
|
||||||
|
|
||||||
if (noiseData.cachedNoiseValueArr1[index] == 0 || noiseData.lastPhaseArr[index] > phase){ // occurs if the phase reset to 0 or at the very start
|
|
||||||
|
|
||||||
noiseData.cachedNoiseValueArr2[index] = noiseData.cachedNoiseValueArr1[index];
|
|
||||||
if (noiseData.cachedNoiseValueArr1[index] == 0)
|
|
||||||
noiseData.cachedNoiseValueArr2[index] = center;
|
|
||||||
|
|
||||||
noiseData.cachedNoiseValueArr1[index] = Math.random();
|
|
||||||
noiseData.setCachedNoiseValueArr1(noiseData.cachedNoiseValueArr1);
|
|
||||||
noiseData.setCachedNoiseValueArr2(noiseData.cachedNoiseValueArr2);
|
|
||||||
}
|
|
||||||
noiseData.lastPhaseArr[index] = phase;
|
|
||||||
noiseData.setLastPhaseArr(noiseData.lastPhaseArr);
|
|
||||||
|
|
||||||
//let unscaled = (noiseData.cachedNoiseValueArr[index][1] - noiseData.cachedNoiseValueArr[index][0]) * sinePhase + noiseData.cachedNoiseValueArr[index][0];
|
|
||||||
let unscaled = interpolateNoise(noiseType, noiseData.cachedNoiseValueArr1[index], noiseData.cachedNoiseValueArr2[index], phase);
|
|
||||||
syncDisplay(inst, name, unscaled);
|
|
||||||
|
|
||||||
return unscaled * amp + center + parseFloat(min);
|
return unscaled * amp + center + parseFloat(min);
|
||||||
}
|
}
|
||||||
|
|
||||||
function interpolateNoise(type, cachedVal1, cachedVal2, phase){
|
|
||||||
let interpVal;
|
|
||||||
|
|
||||||
switch (type){
|
function parseLfoTime(lfoTime, bpm, beatsInMeasure){
|
||||||
case "Sine Int.":
|
|
||||||
interpVal = (Math.sin(Math.PI + Math.PI * phase) + 1) / 2;
|
|
||||||
break;
|
|
||||||
case "Rand":
|
|
||||||
interpVal = 0;
|
|
||||||
break;
|
|
||||||
case "Line Int.":
|
|
||||||
interpVal = phase;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return (cachedVal2 - cachedVal1) * interpVal + cachedVal1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// actual returns the period for musical timing, to avoid floating point errors
|
|
||||||
function parseLfoTime(lfoTime, beatsInMeasure){
|
|
||||||
if (lfoTime.slice(-2) == "hz"){
|
if (lfoTime.slice(-2) == "hz"){
|
||||||
return [parseFloat(lfoTime.slice(0, -2)), PhaseTypes.TIME];
|
return parseFloat(lfoTime.slice(0, -2));
|
||||||
}
|
}
|
||||||
else if (lfoTime.slice(-2) == "ms"){
|
else if (lfoTime.slice(-2) == "ms"){
|
||||||
return [1000 / parseFloat(lfoTime.slice(0, -2)), PhaseTypes.TIME];
|
return 1000 / parseFloat(lfoTime.slice(0, -2));
|
||||||
}
|
}
|
||||||
else if (lfoTime.slice(-1) == "s"){
|
else if (lfoTime.slice(-1) == "s"){
|
||||||
return [1 / parseFloat(lfoTime.slice(0, -1)), PhaseTypes.TIME];
|
return 1 / parseFloat(lfoTime.slice(0, -1));
|
||||||
}
|
}
|
||||||
else if ((lfoTime.match(/:/g) || []).length == 2){
|
else if ((lfoTime.match(/:/g) || []).length == 2){
|
||||||
return [1 / moment.duration(lfoTime).asSeconds(), PhaseTypes.TIME];
|
return 1 / moment.duration(lfoTime).asSeconds();
|
||||||
}
|
}
|
||||||
else if ((lfoTime.match(/\./g) || []).length == 2){
|
else if ((lfoTime.match(/\./g) || []).length == 2){
|
||||||
return [musicalTimingToFreq(...lfoTime.split('.'), beatsInMeasure), PhaseTypes.MUSICAL];
|
return musicalTimingToFreq(...lfoTime.split('.'), bpm, beatsInMeasure)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return [0, PhaseTypes.TIME];
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function musicalTimingToFreq(bars, beats, ticks, beatsInMeasure){
|
function musicalTimingToFreq(bars, beats, ticks, bpm, beatsInMeasure){
|
||||||
let totalTicks = (parseFloat(bars) * parseFloat(beatsInMeasure) + parseFloat(beats)) * 480 + parseFloat(ticks);
|
let totalTicks = (parseFloat(bars) * parseFloat(beatsInMeasure) + beats) * 480 + parseFloat(ticks);
|
||||||
return totalTicks;
|
let tpm = bpm * 480;
|
||||||
|
let cyclesPerMinute = tpm / totalTicks;
|
||||||
|
let hz = cyclesPerMinute / 60;
|
||||||
|
return hz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user