58 Commits

Author SHA1 Message Date
7f464366af Merge pull request 'how to integrate tab' (#22) from help-patch-integration into main
Reviewed-on: #22
2025-08-04 16:28:21 +02:00
51420cbd5f how to integrate tab 2025-08-04 16:27:13 +02:00
533de4668a Merge pull request 'initial help patch' (#19) from help-patch into main
Reviewed-on: #19
2025-07-29 14:10:37 +02:00
b850440287 improved text placement 2025-07-29 14:10:14 +02:00
7ac026f35f initial help patch 2025-07-22 15:27:16 +02:00
7cb4180d97 Merge pull request 'setting viewMode directly from Max' (#16) from viewMode-max into main
Reviewed-on: #16
2025-07-21 16:15:52 +02:00
51767ff058 setting viewMode directly from Max 2025-07-21 16:14:12 +02:00
Eveline-97
fe68764e7d fix aligning 2025-07-02 14:29:59 +02:00
Eveline-97
40d0927a0e streamline layout patch 2025-07-02 12:16:30 +02:00
Eveline-97
92b7545e90 match Max layout to jweb 2025-07-02 12:07:53 +02:00
Eveline-97
4912b398dd Merge remote-tracking branch 'refs/remotes/origin/main'
merge
2025-07-01 16:34:50 +02:00
Eveline-97
02d5c6e914 cleanup modulator table 2025-07-01 16:34:27 +02:00
13f3a18c4c Merge pull request 'bpatcher-embed' (#15) from bpatcher-embed into main
Reviewed-on: #15
2025-07-01 16:32:05 +02:00
f21220e7b2 Merge branch 'main' into bpatcher-embed 2025-07-01 16:31:40 +02:00
fe165b77e5 working saving for bpatcher 2025-07-01 16:30:08 +02:00
Eveline-97
a7b0de9e66 navigation bar 2025-07-01 16:15:41 +02:00
43d37f215f Merge branch 'main' into bpatcher-embed 2025-07-01 16:12:51 +02:00
Eveline-97
c1a0a4d919 basic design 2025-07-01 15:04:49 +02:00
e2f33b8ba7 Merge pull request 'properly saving on adding rows, changing enum length, changing enum params' (#14) from hotfix into main
Reviewed-on: #14
2025-07-01 09:54:22 +02:00
a19717a759 properly saving on adding rows, changing enum length, changing enum params 2025-07-01 09:53:39 +02:00
64da80b742 WIP 2025-07-01 09:25:27 +02:00
Eveline-97
34549daf67 also enumerator items as datacells 2025-07-01 09:20:30 +02:00
Eveline-97
dd47c0b030 enumerators as table, jweb bit wider 2025-07-01 09:18:02 +02:00
0b7dbbb775 Merge branch 'main' into bpatcher-embed 2025-06-30 12:00:29 +02:00
290ff73524 Merge pull request 'more instances of DJster' (#13) from more-dj-instances into main
Reviewed-on: #13
2025-06-30 11:59:31 +02:00
9b1a9f2e03 more instances 2025-06-30 11:58:56 +02:00
541ab6d459 created initial bpatcher file and maxhelp 2025-06-30 11:44:03 +02:00
b96f2aa53b Merge pull request 'button for showing and hiding everything' (#12) from showhide-button into main
Reviewed-on: #12
2025-06-30 11:00:09 +02:00
edcddde844 button for showing and hiding everything 2025-06-30 10:58:51 +02:00
e41567c101 Merge pull request 'buttons for switching between modes' (#11) from button-headers into main
Reviewed-on: #11
2025-06-30 10:22:01 +02:00
8002ae8bdb Merge branch 'main' into button-headers 2025-06-30 10:21:44 +02:00
286a43b0b2 buttons for switching between modes 2025-06-30 10:19:42 +02:00
229ddb9c37 Merge pull request 'increased max number of lfos and enums to 200' (#10) from increase-maxlfos into main
Reviewed-on: #10
2025-06-30 09:46:03 +02:00
bbcfd8faab increased max number of lfos and enums to 200 2025-06-30 09:40:14 +02:00
5d092a607c Merge pull request 'removed lock' (#9) from removing-lock into main
Reviewed-on: #9
2025-06-30 09:32:36 +02:00
de28fd87fa removed lock 2025-06-30 09:31:23 +02:00
Eveline-97
07c4826bd9 table layout for modulators 2025-06-29 17:53:12 +02:00
Eveline-97
501fca079e autopattr save and load waves, functions, types 2025-05-15 10:32:39 +02:00
Eveline-97
3507899eb3 debug function waves works now 2025-05-15 10:18:10 +02:00
Eveline-97
dc2daade1b add function functionality for custom shape 2025-05-14 14:42:34 +02:00
149d1a0b8d save on every UI change 2025-05-13 11:24:39 +02:00
4ee8a93791 four user defined waves 2025-02-12 11:02:51 +01:00
c706461443 Merge pull request 'nn-communication' (#8) from nn-communication into main
Reviewed-on: #8
2024-11-29 14:21:11 +01:00
081e33dd07 modulator noise function previous val bug 2024-11-29 14:20:29 +01:00
eb02657b4a center vals included in NN data 2024-10-22 13:27:07 +02:00
d670aefcbd enums start with NONE 2024-10-22 12:32:42 +02:00
68baa3c8de Merge pull request 'nn-communication' (#7) from nn-communication into main
Reviewed-on: #7
2024-10-22 11:00:25 +02:00
a35fecafae NN data receiving 2024-10-22 10:58:46 +02:00
b3ba9b0f2d cachedNoise no longer an array 2024-10-18 15:34:53 +02:00
102a88b242 bugfix - modulators not properly initializing 2024-10-15 14:54:37 +02:00
aebfbe5277 Merge pull request 'main' (#6) from main into nn-communication
Reviewed-on: #6
2024-10-15 12:27:53 +02:00
2d81a832af Merge branch 'nn-communication' into main 2024-10-15 12:27:08 +02:00
cdbcf24dfc Merge pull request 'fixed userwave update' (#5) from lock into main
Reviewed-on: #5
2024-10-15 12:21:08 +02:00
64f1455f69 fixed userwave update 2024-10-14 09:16:05 +02:00
trian-gles
a855d254cd non musical timing to ms value for input from neural net 2024-10-11 15:34:37 +02:00
09a1b5f20f Merge pull request 'lock mode' (#4) from lock into main
Reviewed-on: #4
2024-10-11 13:36:54 +02:00
34e99f09fd lock mode 2024-10-11 12:52:54 +02:00
86a994546e Merge pull request 'noise-functions' (#3) from noise-functions into main
Reviewed-on: #3
2024-10-10 12:25:22 +02:00
12 changed files with 9026 additions and 3337 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.DS_Store

1740
ModEnum.maxhelp Normal file

File diff suppressed because it is too large Load Diff

3345
ModEnum.maxpat Normal file

File diff suppressed because one or more lines are too long

View File

@@ -5,7 +5,8 @@ function isNumeric(str) {
} }
function DropDown(props) { function DropDown(props) {
return e('select', {type: "number", onChange: props.onChange, value: props.value}, let className = props.locked ? 'locked-component' : '';
return e('select', {className, type: "number", onChange: props.onChange, value: props.value},
...props.options.map((item) => Option(item))); ...props.options.map((item) => Option(item)));
} }
@@ -18,11 +19,13 @@ function Label(text){
} }
function NumberBox(props){ function NumberBox(props){
return e('input', {type: "number", onChange: props.onChange, step: props.step, value: props.value, className: props.className}, null); let extraClassName = props.locked ? ' locked-component' : '';
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){
return e('input', {type: "text", value: props.value, onChange: props.onChange, id: props.id}); let className = props.locked ? 'locked-component' : '';
return e('input', {className, type: "text", value: props.value, onChange: props.onChange, id: props.id});
} }
function Option(str, value){ function Option(str, value){
@@ -30,7 +33,8 @@ function Option(str, value){
} }
function Button(props){ function Button(props){
return e('button', {onClick: props.onClick}, props.text); let className = props.locked ? 'locked-component' : '';
return e('button', {onClick: props.onClick, className}, props.text);
} }
function Switch(props){ function Switch(props){
@@ -39,12 +43,20 @@ 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}`);
} }
} }
@@ -56,6 +68,7 @@ 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}`);
} }

View File

@@ -4,14 +4,18 @@
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){ function EnumeratorItems(index, enumBreakPoints, setEnumBreakPoints, enumNames, setEnumNames, djParam, locked){
let items = []; let items = [];
for (let i = 0; i < MAXENUMPOINTS; i++){ for (let i = 0; i < MAXENUMPOINTS; i++){
items.push(ListItem(e(TextBox, {onChange: CreateMatrixParamChanger(enumNames, setEnumNames, index, i), value: enumNames[index][i], id:`text-${djParam}-${enumNames[index][i]}`}, null))); items.push(DataCell(e(TextBox, {locked, 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(ListItem(e(NumberBox, {onChange: CreateMatrixParamChanger(enumBreakPoints, setEnumBreakPoints, index, i + 1), value:enumBreakPoints[index][i + 1]}, null))); items.push(DataCell(e(NumberBox, {locked, onChange: CreateMatrixParamChanger(enumBreakPoints, setEnumBreakPoints, index, i + 1), value:enumBreakPoints[index][i + 1]}, null)));
} }
return items; return items;
} }
@@ -19,15 +23,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('ul', {className: 'lfo-item', id: `${props.djParam}-enum-row`}, let content = e('tr', {className: 'lfo-item', id: `${props.djParam}-enum-row`},
ListItem(DropDown({onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})), DataCell(DropDown({locked:props.locked, onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})),
ListItem(DropDown({onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})), DataCell(DropDown({locked:props.locked, onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})),
ListItem(e(NumberBox, {onChange: props.setEnumItemCounts, step:1, value:props.enumItems, className: 'enum-count'}, null)), DataCell(e(NumberBox, {locked:props.locked, onChange: props.setEnumItemCounts, step:1, value:props.enumItems, className: 'enum-count'}, null)),
ListItem(e(NumberBox, {onChange: CreateMatrixParamChanger(props.enumBreakPoints, props.setEnumBreakPoints, props.index, 0), value:props.enumBreakPoints[props.index][0], step:0.1}, 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)),
...(EnumeratorItems(props.index, props.enumBreakPoints, props.setEnumBreakPoints, props.enumNames, props.setEnumNames, props.djParam).slice(0, props.enumItems * 2)), ...(EnumeratorItems(props.index, props.enumBreakPoints, props.setEnumBreakPoints, props.enumNames, props.setEnumNames, props.djParam, props.locked).slice(0, props.enumItems * 2)),
ListItem(e(Button, {text:'+', onClick: props.addEnum}, null)), DataCell(e(Button, {locked:props.locked, text:'+', onClick: props.addEnum}, null)),
ListItem(e(Button, {text:'-', onClick: props.removeEnum}, null)), DataCell(e(Button, {locked:props.locked, text:'-', onClick: props.removeEnum}, null)),
ListItem(e("div", {className:"linked"}, linkedText)) DataCell(e("div", {className:"linked"}, linkedText))
); );
if (props.visible){ if (props.visible){
return content; return content;

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,43 +1,163 @@
* {
--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: hidden; /* Disable scrollbars */ overflow-x: scroll;
display: block; /* No floating content on sides */ overflow-y: scroll;
display: block;
/* No floating content on sides */
} }
ul { /*navigation*/
list-style-type: none; .header {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
margin: 1em;
border-bottom: 1px solid var(--active);
}
.header button {
border: 1px solid var(--active);
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; margin: 0;
padding: 0; padding: 0;
overflow: hidden; line-height: 1.5em;
background-color: #333333; height: 1.5em;
box-sizing: border-box;
} }
li { input {
float: left; padding-left: 5px;
/*slight padding on left*/
} }
input[type=number] { input[type=number] {
width: 50px; width: 50px;
margin: 0;
padding: 0;
} }
input[type=text] { input[type=text] {
width: 60px; width: 60px;
margin: 0;
padding: 0;
font-weight: bold; font-weight: bold;
} }
.timeInput { .timeInput {
width: 80px; width: 80px;
margin: 0;
padding: 0;
} }
#matrix { #matrix {
@@ -84,51 +204,38 @@ html,
} }
/* The slider */ /* The slider */
.slider { input[type="range"] {
position: absolute; appearance: none;
cursor: pointer; -webkit-appearance: none;
top: 0; height: 8px;
left: 0; border-radius: 6px;
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; background-color: white;
-webkit-transition: .4s; outline: none;
transition: .4s; opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
overflow: hidden;
} }
input:checked + .slider { /*slider knob*/
background-color: #2196F3; input[type="range"]::-webkit-slider-runnable-track {
-webkit-appearance: none;
color: var(--active);
margin-top: -1px;
} }
input:focus + .slider { input[type="range"]::-webkit-slider-thumb {
box-shadow: 0 0 1px #2196F3; -webkit-appearance: none;
} appearance: none;
width: 20px;
input:checked + .slider:before { height: 20px;
-webkit-transform: translateX(13px);
-ms-transform: translateX(13px);
transform: translateX(13px);
}
/* Rounded sliders */
.slider.round {
border-radius: 17px;
}
.slider.round:before {
border-radius: 50%; 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 { h5 {
@@ -136,10 +243,6 @@ html,
padding: 0; padding: 0;
} }
.enum-count {
background-color: aquamarine;
}
.label { .label {
background-color: aliceblue; background-color: aliceblue;
padding: 0 4px 0 4px; padding: 0 4px 0 4px;
@@ -149,12 +252,13 @@ html,
} }
.base-val { .base-val {
background-color: lightgray; border: none;
border-color: #333333; color: white;
border-width: 1px; text-align: center;
font-size: 0.9em;
width: 50px; width: 50px;
margin-left: 2px; margin: 0;
margin-top: 1px; padding: 0;
} }
.linked { .linked {
@@ -164,6 +268,8 @@ html,
font-size: small; font-size: small;
margin-left: 2px; margin-left: 2px;
margin-top: 5px; margin-top: 5px;
display: none;
/*hide*/
} }
@@ -171,6 +277,7 @@ html,
0% { 0% {
color: black; color: black;
} }
100% { 100% {
color: red; color: red;
} }
@@ -179,3 +286,93 @@ html,
#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);
}

View File

@@ -7,6 +7,7 @@
--> -->
<head> <head>
<meta charset="utf-8">
<link rel="stylesheet" href="./lfogui.css"> <link rel="stylesheet" href="./lfogui.css">
</head> </head>
@@ -19,10 +20,7 @@
<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 src="./lfogui.js"></script>
</script>
</body> </body>

273
lfogui.js
View File

@@ -9,9 +9,10 @@ else
const e = React.createElement; const e = React.createElement;
let lfos = []; let lfos = [];
const MAXLFOS = 20; const MAXLFOS = 200;
const MAXENUMS = 20; const MAXENUMS = 200;
const MAXENUMPOINTS = 10; const MAXENUMPOINTS = 10;
const MAXUSERDEFINED = 4;
@@ -20,38 +21,88 @@ const ViewModes = Object.freeze({
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"]; const MODULATORLABELS = ["inst", "type", "shape", "param", "timebase", "min", "max", "phase", "center", "result", "", ""];
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 = () => {
if (viewMode === ViewModes.MOD) const [lockMode, setLockMode] = React.useState(LockModes.UNLOCK);
setViewMode(ViewModes.ENUM); const toggleLockMode = () => {
if (lockMode === LockModes.UNLOCK)
setLockMode(LockModes.LOCK);
else else
setViewMode(ViewModes.MOD); setLockMode(LockModes.UNLOCK);
}; };
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
const [userDefinedWave, setUserDefinedWave] = React.useState(Array(50).fill(0)); 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 [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':{}}); const [modCenterVals, setModCenterVals] = React.useState({ '1': {}, '2': {}, '3': {}, '4': {}, '5': {}, '6': {}});
const [ticks, setTicks] = React.useState(0); const [ticks, setTicks] = React.useState(0);
const [beatsInMeasure, setBeatsInMeasure] = React.useState(4); const [beatsInMeasure, setBeatsInMeasure] = React.useState(4);
@@ -68,25 +119,26 @@ function MasterLfoHandler(){
const [initPhaseArr, setInitPhaseArr] = React.useState(Array(MAXLFOS).fill('0')); const [initPhaseArr, setInitPhaseArr] = React.useState(Array(MAXLFOS).fill('0'));
const [lastPhaseArr, setLastPhaseArr] = React.useState(Array(MAXLFOS).fill(0)); const [lastPhaseArr, setLastPhaseArr] = React.useState(Array(MAXLFOS).fill(0));
const [cachedNoiseValueArr, setCachedNoiseValueArr] = React.useState(Array(MAXLFOS).fill([0, 0])); const [cachedNoiseValueArr1, setCachedNoiseValueArr1] = React.useState(Array(MAXLFOS).fill(0));
const [cachedNoiseValueArr2, setCachedNoiseValueArr2] = React.useState(Array(MAXLFOS).fill(0));
const allModArrays = [modVisibleArr, modTypeArr, modInstanceNumArr, shapeArr, noiseTypeArr, djParamArr, freqArr, minArr, maxArr, initPhaseArr, lastPhaseArr, cachedNoiseValueArr]; const allModArrays = [modVisibleArr, modTypeArr, modInstanceNumArr, shapeArr, noiseTypeArr, djParamArr, freqArr, minArr, maxArr, initPhaseArr, lastPhaseArr, cachedNoiseValueArr1, cachedNoiseValueArr2];
const allModSetters = [setModVisibleArr, setModTypeArr, setModInstanceNumArr, setShapeArr, setNoiseTypeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setInitPhaseArr, lastPhaseArr, cachedNoiseValueArr]; const allModSetters = [setModVisibleArr, setModTypeArr, setModInstanceNumArr, setShapeArr, setNoiseTypeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setInitPhaseArr, setLastPhaseArr, setCachedNoiseValueArr1, setCachedNoiseValueArr2];
const modBlankVals = [true, 'LFO', '1', SHAPETYPES[0], MODPARAMOPTIONS[0], "Sine Int.", '1hz', '0', '1', '0', 0, [0, 0]]; 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('attenuation')); const [enumDjParamArr, setEnumDjParamArr] = React.useState(Array(MAXENUMPOINTS).fill('NONE'));
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; baseEnumBreakpoints[i][j] = j - 0.5;
} }
} }
const [enumBreakPoints, setEnumBreakPoints] = React.useState(baseEnumBreakpoints); const [enumBreakPoints, setEnumBreakPoints] = React.useState(baseEnumBreakpoints);
@@ -94,7 +146,7 @@ function MasterLfoHandler(){
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) arr.push(i - 0.5)
return arr; return arr;
} }
@@ -120,14 +172,12 @@ function MasterLfoHandler(){
function handleLoad(event) { function handleLoad(event) {
window.max.getDict(event.detail, (dict) => { window.max.getDict(event.detail, (dict) => {
for (let i = 0; i<allModArrays.length; i++) { for (let i = 0; i < dict.data.modArrays.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]);
} }
@@ -205,8 +255,8 @@ function MasterLfoHandler(){
function handleTick(event) { function handleTick(event) {
let time = (Date.now() - firstUpdateTime) / 1000; let time = (Date.now() - firstUpdateTime) / 1000;
let noiseData = {lastPhaseArr, setLastPhaseArr, cachedNoiseValueArr, setCachedNoiseValueArr, noiseTypeArr}; let noiseData = { lastPhaseArr, setLastPhaseArr, cachedNoiseValueArr1, setCachedNoiseValueArr1, cachedNoiseValueArr2, setCachedNoiseValueArr2, noiseTypeArr };
operateModulators(modVisibleArr, modTypeArr, modInstanceNumArr, djParamArr, modCenterVals, freqArr, minArr, maxArr, shapeArr, initPhaseArr, noiseData, userDefinedWave, time, beatsInMeasure, ticks); operateModulators(modVisibleArr, modTypeArr, modInstanceNumArr, djParamArr, modCenterVals, freqArr, minArr, maxArr, shapeArr, initPhaseArr, noiseData, userDefinedWaves, userDefinedFunctions, userDefinedTypes, time, beatsInMeasure, ticks);
} }
function handleTimeSig(event) { function handleTimeSig(event) {
@@ -214,34 +264,117 @@ function MasterLfoHandler(){
} }
function handleChangeUserWave(event) { function handleChangeUserWave(event) {
setUserDefinedWave(event.detail); 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) { function handleMaxTicks(event) {
setTicks(event.detail); setTicks(event.detail);
} }
function handleChangeViewMode(event){
setEnabled(true);
setViewMode(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('timesig', handleTimeSig); window.addEventListener('timesig', handleTimeSig);
window.addEventListener('userWave', handleChangeUserWave); window.addEventListener('userWave', handleChangeUserWave);
window.addEventListener('userFunction', handleChangeUserFunction);
window.addEventListener('userDefinedType', handleChangeUserDefinedType);
window.addEventListener('maxTicks', handleMaxTicks); window.addEventListener('maxTicks', handleMaxTicks);
window.addEventListener('viewMode', handleChangeViewMode);
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('timesig', handleTimeSig); window.removeEventListener('timesig', handleTimeSig);
window.removeEventListener('userWave', handleChangeUserWave); window.removeEventListener('userWave', handleChangeUserWave);
window.removeEventListener('userFunction', handleChangeUserFunction);
window.removeEventListener('userDefinedType', handleChangeUserDefinedType);
window.removeEventListener('maxTicks', handleMaxTicks); window.removeEventListener('maxTicks', handleMaxTicks);
window.removeEventListener('viewMode', handleChangeViewMode);
}; };
}, [...allModArrays, ...allEnumArrays, ...allEnumMats, modCenterVals, render, beatsInMeasure, ticks]); }, [...allModArrays, ...allEnumArrays, ...allEnumMats, userDefinedWaves, userDefinedFunctions, userDefinedTypes, modCenterVals, render, beatsInMeasure, ticks]);
function CheckLinked(inst, param, checkInstArr, checkParamArr) { function CheckLinked(inst, param, checkInstArr, checkParamArr) {
@@ -262,6 +395,7 @@ function MasterLfoHandler(){
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),
@@ -311,14 +445,16 @@ function MasterLfoHandler(){
} }
} }
else { else {
log("adding lfo");
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: () => {
@@ -326,6 +462,7 @@ function MasterLfoHandler(){
let newArr = modVisibleArr.slice(); let newArr = modVisibleArr.slice();
newArr[id] = false; newArr[id] = false;
setModVisibleArr(newArr); setModVisibleArr(newArr);
SendSaveEvent();
} }
} }
@@ -343,15 +480,21 @@ function MasterLfoHandler(){
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: setEnumBreakPoints, setEnumBreakPoints: (val) => {
setEnumBreakPoints(val);
SendSaveEvent
},
enumNames: enumNames, enumNames: enumNames,
setEnumNames: setEnumNames, setEnumNames: (val) => {
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),
@@ -397,6 +540,7 @@ function MasterLfoHandler(){
} }
} }
rerender(!render); rerender(!render);
SendSaveEvent();
} }
}, },
removeEnum: () => { removeEnum: () => {
@@ -404,6 +548,7 @@ function MasterLfoHandler(){
let newArr = enumVisibleArr.slice(); let newArr = enumVisibleArr.slice();
newArr[id] = false; newArr[id] = false;
setEnumVisibleArr(newArr); setEnumVisibleArr(newArr);
SendSaveEvent();
} }
} }
}, null) }, null)
@@ -412,24 +557,47 @@ function MasterLfoHandler(){
var grid; var grid;
var title; var modButtonClass;
var enumButtonClass;
var labels; var labels;
if (viewMode === ViewModes.MOD) { if (viewMode === ViewModes.MOD) {
grid = modContents; grid = modContents;
title = "MODULATORS"; modButtonClass = "highlighted-button";
enumButtonClass = "unhighlighted-button";
labels = MODULATORLABELS; labels = MODULATORLABELS;
} }
else { else {
grid = enumContents; grid = enumContents;
title = "ENUMERATORS"; modButtonClass = "unhighlighted-button";
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(Switch, {ontoggle: toggleViewMode}, null), e('div', { className: 'header' },
e('h5', null, title), e('div', {className: 'nav'},
e('ul', null, ...labels.map(x => ListItem(Label(x)))), displayIfEnabled(e('button', { onClick: () => setViewMode(ViewModes.MOD), className: modButtonClass}, 'Modulators')),
e('div', {id: 'grid'}, ...grid) displayIfEnabled(e('button', { onClick: () => setViewMode(ViewModes.ENUM), className: enumButtonClass }, 'Enumerators'))
),
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)
))
); );
} }
@@ -442,8 +610,15 @@ if (!DEBUG){
window.dispatchEvent(new CustomEvent('saveDict', { 'detail': dictId })); window.dispatchEvent(new CustomEvent('saveDict', { 'detail': dictId }));
}); });
window.max.bindInlet("param", (inst, paramName, val) => { 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.dispatchEvent(new CustomEvent('param', { 'detail': [inst, paramName, val] })); window.dispatchEvent(new CustomEvent('param', { 'detail': [inst, paramName, val] }));
}); });
@@ -455,15 +630,25 @@ if (!DEBUG){
window.dispatchEvent(new CustomEvent('maxTicks', { 'detail': val })); window.dispatchEvent(new CustomEvent('maxTicks', { 'detail': val }));
}); });
window.max.bindInlet("userWave", (...points) => { window.max.bindInlet("userWave", (index, ...points) => {
window.dispatchEvent(new CustomEvent('userWave', {'detail' : points})); let data = { points, index };
window.dispatchEvent(new CustomEvent('userWave', { 'detail': data }));
}); });
window.max.bindInlet("viewMode", (mode) => {
window.dispatchEvent(new CustomEvent('viewMode', { 'detail': parseInt(mode) }));
});
/* window.max.binInlet("userWave", (...points) => { window.max.bindInlet("userFunction", (index, ...points) => {
window.dispatchEvent(new CustomEvent('userWave', {'detail' : [points]})); //list of 101 points between 0-100
log("received user points"); 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'));

View File

@@ -4,10 +4,10 @@
var TYPEOPTIONS = ["LFO", "Noise"]; var TYPEOPTIONS = ["LFO", "Noise"];
var SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square", "Custom"]; var SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square", "Custom_1", "Custom_2", "Custom_3", "Custom_4"];
var NOISETYPES = ["Rand", "Line Int.", "Sine Int."] var NOISETYPES = ["Rand", "Line Int.", "Sine Int."]
var INSTANCEOPTIONS = ["1", "2", "3", "4"]; 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",
@@ -22,7 +22,9 @@ 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){
@@ -34,34 +36,42 @@ function LfoRow(props){
let typeOption = null; let typeOption = null;
if (props.type == "LFO"){ if (props.type == "LFO"){
typeOption = ListItem(DropDown({onChange: props.setShape, value:props.shape, options: SHAPETYPES})); typeOption = DataCell(DropDown({locked:props.locked, onChange: props.setShape, value:props.shape, options: SHAPETYPES}));
} }
else if (props.type == "Noise"){ else if (props.type == "Noise"){
typeOption = ListItem(DropDown({onChange: props.setNoise, value:props.noise, options: NOISETYPES})); typeOption = DataCell(DropDown({locked:props.locked, onChange: props.setNoise, value:props.noise, options: NOISETYPES}));
} }
let content = e('ul', {className: 'lfo-item'}, let content = e('tr', {className: 'lfo-item'},
ListItem(DropDown({onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})), DataCell(DropDown({locked:props.locked, onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})),
ListItem(DropDown({options: TYPEOPTIONS, onChange: props.setType, value:props.type})), DataCell(DropDown({locked:props.locked, options: TYPEOPTIONS, onChange: props.setType, value:props.type})),
typeOption, typeOption,
ListItem(DropDown({onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})), DataCell(DropDown({locked:props.locked, onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})),
ListItem(e("input", {onChange:props.setFreq, value:props.freq, className:"timeInput"}, null)), DataCell(e("input", {onChange:props.setFreq, value:props.freq, className:"timeInput"}, null)),
ListItem(e(NumberBox, {onChange:props.setMin, value:props.min, step:0.1}, null)), DataCell(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)), DataCell(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)), //DataCell(e(NumberBox, {onChange:props.setAmp, value:props.amp, step:0.1}, null)),
ListItem(e(NumberBox, {onChange:props.setPhase, value:props.phase, step:0.1}, null)), DataCell(e(NumberBox, {onChange:props.setPhase, value:props.phase, step:0.1}, null)),
ListItem(e("div", {className:"base-val"}, center.toString())), DataCell(e("div", {className:"base-val"}, center.toString())),
ListItem(e("input", {type: 'range', min: 0, max: 1, step: 0.01, readonly: true, id: `slider-${props.instanceNum}-${props.djParam}`})), DataCell(e("input", {type: 'range', min: 0, max: 1, step: 0.01, readonly: true, id: `slider-${props.instanceNum}-${props.djParam}`})),
ListItem(e(Button, {text:'+', onClick: props.addLfo}, null)), DataCell(e(Button, {text:'+', onClick: props.addLfo, locked: props.locked}, null)),
ListItem(e(Button, {text:'-', onClick: props.removeLfo}, null)), DataCell(e(Button, {text:'-', onClick: props.removeLfo, locked: props.locked}, null)),
ListItem(e("div", {className:"linked"}, linkedText)), DataCell(e("div", {className:"linked"}, linkedText)),
); );
if (props.visible){ if (props.visible){
return content return content;
}; };
} }
function indexWave(type, phase, userDefinedWave){ function indexUserWave(phase, index, userDefinedWaves){
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;
@@ -73,12 +83,18 @@ function indexWave(type, phase, userDefinedWave){
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": case "Custom_1":
return parseFloat(userDefinedWave[Math.floor(phase * 50)]) / 127 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, userDefinedWave, currTime, beatsInMeasure, ticks){ function operateModulators(visibleArr, typeArr, instanceNumArr, paramNames, centers, freqs, mins, maxs, waveTypes, phaseArr, noiseData, userDefinedWaves, userDefinedFunctions, userDefinedTypes, currTime, beatsInMeasure, ticks){
for (let i=0; i<paramNames.length; i++){ for (let i=0; i<paramNames.length; i++){
if (visibleArr[i]){ if (visibleArr[i]){
@@ -92,7 +108,7 @@ function operateModulators(visibleArr, typeArr, instanceNumArr, paramNames, cent
let output = 0; let output = 0;
if (typeArr[i] == "LFO") if (typeArr[i] == "LFO")
output = operateLFO(center, inst, freqs[i], mins[i], maxs[i], waveTypes[i], phaseArr, i, userDefinedWave, name, currTime, beatsInMeasure, ticks); output = operateLFO(center, inst, freqs[i], mins[i], maxs[i], waveTypes[i], phaseArr, i, userDefinedWaves, userDefinedFunctions, userDefinedTypes, name, currTime, beatsInMeasure, ticks);
else else
output = operateNoise(center, inst, freqs[i], mins[i], maxs[i], waveTypes[i], phaseArr, i, name, noiseData, currTime, beatsInMeasure, ticks); 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")
@@ -101,7 +117,7 @@ function operateModulators(visibleArr, typeArr, instanceNumArr, paramNames, cent
} }
} }
function operateLFO(center, inst, timeBaseStr, min, max, waveType, phaseArr, phaseIndex, userDefinedWave, name, currTime, beatsInMeasure, maxTicks){ function operateLFO(center, inst, timeBaseStr, min, max, waveType, phaseArr, phaseIndex, userDefinedWaves, userDefinedFunctions, userDefinedTypes, name, currTime, beatsInMeasure, maxTicks){
let amp = parseFloat(max) - parseFloat(min); let amp = parseFloat(max) - parseFloat(min);
let phaseType; let phaseType;
let timeBase; let timeBase;
@@ -113,7 +129,7 @@ function operateLFO(center, inst, timeBaseStr, min, max, waveType, phaseArr, pha
phase = (currTime * timeBase + parseFloat(phaseArr[phaseIndex])) % 1.00; phase = (currTime * timeBase + parseFloat(phaseArr[phaseIndex])) % 1.00;
else if (phaseType === PhaseTypes.MUSICAL) else if (phaseType === PhaseTypes.MUSICAL)
phase = (maxTicks % timeBase) / timeBase; phase = (maxTicks % timeBase) / timeBase;
let unscaled = indexWave(waveType, phase, userDefinedWave); let unscaled = indexWave(waveType, phase, userDefinedWaves, userDefinedFunctions, userDefinedTypes);
syncDisplay(inst, name, unscaled); syncDisplay(inst, name, unscaled);
return unscaled * amp + center + parseFloat(min); return unscaled * amp + center + parseFloat(min);
@@ -142,27 +158,24 @@ function operateNoise(center, inst, timeBaseStr, min, max, waveType, phaseArr, i
else if (phaseType === PhaseTypes.MUSICAL) else if (phaseType === PhaseTypes.MUSICAL)
phase = (maxTicks % timeBase) / timeBase; 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
if (noiseData.cachedNoiseValueArr[index][0] == 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.cachedNoiseValueArr[index][0] = noiseData.cachedNoiseValueArr[index][1]; noiseData.cachedNoiseValueArr1[index] = Math.random();
if (noiseData.cachedNoiseValueArr[index][0] == 0) noiseData.setCachedNoiseValueArr1(noiseData.cachedNoiseValueArr1);
noiseData.cachedNoiseValueArr[index][0] = center; noiseData.setCachedNoiseValueArr2(noiseData.cachedNoiseValueArr2);
noiseData.cachedNoiseValueArr[index][1] = Math.random();
noiseData.setCachedNoiseValueArr(noiseData.cachedNoiseValueArr);
} }
noiseData.lastPhaseArr[index] = phase; noiseData.lastPhaseArr[index] = phase;
noiseData.setLastPhaseArr(noiseData.lastPhaseArr); noiseData.setLastPhaseArr(noiseData.lastPhaseArr);
let sinePhase = (Math.sin(Math.PI + Math.PI * phase) + 1) / 2
//let unscaled = (noiseData.cachedNoiseValueArr[index][1] - noiseData.cachedNoiseValueArr[index][0]) * sinePhase + noiseData.cachedNoiseValueArr[index][0]; //let unscaled = (noiseData.cachedNoiseValueArr[index][1] - noiseData.cachedNoiseValueArr[index][0]) * sinePhase + noiseData.cachedNoiseValueArr[index][0];
let unscaled = interpolateNoise(noiseData.noiseTypeArr[index], noiseData.cachedNoiseValueArr[index][0], noiseData.cachedNoiseValueArr[index][1], phase); let unscaled = interpolateNoise(noiseType, noiseData.cachedNoiseValueArr1[index], noiseData.cachedNoiseValueArr2[index], phase);
syncDisplay(inst, name, unscaled); syncDisplay(inst, name, unscaled);
return unscaled * amp + center + parseFloat(min); return unscaled * amp + center + parseFloat(min);
} }
function interpolateNoise(type, cachedVal1, cachedVal2, phase){ function interpolateNoise(type, cachedVal1, cachedVal2, phase){

93
myStorage.json Normal file

File diff suppressed because one or more lines are too long