Compare commits
38 Commits
af98d457cd
...
nn-communi
| Author | SHA1 | Date | |
|---|---|---|---|
| 081e33dd07 | |||
| eb02657b4a | |||
| d670aefcbd | |||
| a35fecafae | |||
| b3ba9b0f2d | |||
| 102a88b242 | |||
| aebfbe5277 | |||
| 2d81a832af | |||
| cdbcf24dfc | |||
| 64f1455f69 | |||
|
|
a855d254cd | ||
| 09a1b5f20f | |||
| 34e99f09fd | |||
| 86a994546e | |||
| d22cdc8401 | |||
|
|
43e517cc4e | ||
| a608b083f3 | |||
| 83cf801ec3 | |||
|
|
45e168ba11 | ||
| 37a65058bc | |||
|
|
45847fbae4 | ||
|
|
c794b5bc2f | ||
|
|
c8c410a38f | ||
| 985b6c832f | |||
|
|
ff0e8443fc | ||
| 446713d5d3 | |||
| 2369ed5ddf | |||
| 071a78dc20 | |||
| 1d8610fa5f | |||
| ebd09dfd26 | |||
| 13cddd8f03 | |||
| 1f3972fc6f | |||
| b860254884 | |||
| a4842b4865 | |||
| 315a8df1a0 | |||
| f9a8c05955 | |||
| 8381daf468 | |||
| e50e4c1e0c |
24
common.js
24
common.js
@@ -1,5 +1,12 @@
|
|||||||
|
function isNumeric(str) {
|
||||||
|
if (typeof str != "string") return false // we only process strings!
|
||||||
|
return !isNaN(str) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
|
||||||
|
!isNaN(parseFloat(str)) // ...and ensure strings of whitespace fail
|
||||||
|
}
|
||||||
|
|
||||||
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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12,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){
|
||||||
@@ -24,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){
|
||||||
@@ -33,12 +43,12 @@ function Switch(props){
|
|||||||
e('span', {className: 'slider round'}, null))
|
e('span', {className: 'slider round'}, null))
|
||||||
}
|
}
|
||||||
|
|
||||||
function CreateParamChanger(arr, setArr, index, cb=() => {}){
|
function CreateParamChanger(arr, setArr, index, postCB=() => {}, preCB=(val) => val){
|
||||||
return (event) => {
|
return (event) => {
|
||||||
let newArr = arr.slice();
|
let newArr = arr.slice();
|
||||||
newArr[index] = event.target.value;
|
newArr[index] = preCB(event.target.value);
|
||||||
setArr(newArr);
|
setArr(newArr);
|
||||||
cb();
|
postCB();
|
||||||
log(`${index} ${event.target.value}`);
|
log(`${index} ${event.target.value}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
enums.js
37
enums.js
@@ -5,33 +5,48 @@
|
|||||||
|
|
||||||
|
|
||||||
// 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(ListItem(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(ListItem(e(NumberBox, {locked, onChange: CreateMatrixParamChanger(enumBreakPoints, setEnumBreakPoints, index, i + 1), value:enumBreakPoints[index][i + 1]}, null)));
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
function EnumeratorRow(props){
|
function EnumeratorRow(props){
|
||||||
|
let linkedText = props.linked ? "<- mods" : "";
|
||||||
|
|
||||||
let content = e('ul', {className: 'lfo-item', id: `${props.djParam}-enum-row`},
|
let content = e('ul', {className: 'lfo-item', id: `${props.djParam}-enum-row`},
|
||||||
ListItem(DropDown({onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})),
|
ListItem(DropDown({locked:props.locked, onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})),
|
||||||
ListItem(e(NumberBox, {onChange: props.setEnumItemCounts, step:1, value:props.enumItems, className: 'enum-count'}, null)),
|
ListItem(DropDown({locked:props.locked, onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})),
|
||||||
ListItem(e(NumberBox, {onChange: CreateMatrixParamChanger(props.enumBreakPoints, props.setEnumBreakPoints, props.index, 0), value:props.enumBreakPoints[props.index][0], step:0.1}, null)),
|
ListItem(e(NumberBox, {locked:props.locked, onChange: props.setEnumItemCounts, step:1, value:props.enumItems, className: 'enum-count'}, null)),
|
||||||
...(EnumeratorItems(props.index, props.enumBreakPoints, props.setEnumBreakPoints, props.enumNames, props.setEnumNames, props.djParam).slice(0, props.enumItems * 2)),
|
ListItem(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(Button, {text:'+', onClick: props.addEnum}, null)),
|
...(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.removeEnum}, null))
|
ListItem(e(Button, {locked:props.locked, text:'+', onClick: props.addEnum}, null)),
|
||||||
|
ListItem(e(Button, {locked:props.locked, text:'-', onClick: props.removeEnum}, null)),
|
||||||
|
ListItem(e("div", {className:"linked"}, linkedText))
|
||||||
);
|
);
|
||||||
if (props.visible){
|
if (props.visible){
|
||||||
return content;
|
return content;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function denumerate(inval, count, keys, vals){
|
||||||
|
let output = inval;
|
||||||
|
for (let i=0; i < count; i++){
|
||||||
|
log(vals[i]);
|
||||||
|
if (inval == vals[i]){
|
||||||
|
output = (parseFloat(keys[i]) + parseFloat(keys[i+1])) / 2; // linear interpolate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
function enumerate(name, inval, count, keys, vals){
|
|
||||||
|
function enumerate(name, inst, inval, count, keys, vals){
|
||||||
let output = "OUT OF RANGE";
|
let output = "OUT OF RANGE";
|
||||||
for (let i=0; i < count + 1; i++){
|
for (let i=0; i < count + 1; i++){
|
||||||
if (inval <= keys[i]){
|
if (inval <= keys[i]){
|
||||||
@@ -52,6 +67,6 @@ function enumerate(name, inval, count, keys, vals){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name !== "NONE")
|
if (name !== "NONE")
|
||||||
window.max.outlet(name + " " + output);
|
window.max.outlet(inst + " " + name + " " + output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2680
example-with-dj.maxpat
Normal file
2680
example-with-dj.maxpat
Normal file
File diff suppressed because it is too large
Load Diff
1007
example.maxpat
1007
example.maxpat
File diff suppressed because it is too large
Load Diff
272
lfogui.css
Normal file
272
lfogui.css
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
* {
|
||||||
|
--locked-color: #5fadbf;
|
||||||
|
--unlocked-color: #ff5153;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0px;
|
||||||
|
border: 0;
|
||||||
|
overflow: hidden; /* Disable scrollbars */
|
||||||
|
display: block; /* No floating content on sides */
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
input[type=number] {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pulse {
|
||||||
|
animation: pulse-animation 0.2s normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* :::::::::::::: LOCK CSS */
|
||||||
|
|
||||||
|
.locked-component {
|
||||||
|
pointer-events: none;
|
||||||
|
background-color: #333333;
|
||||||
|
color : white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
163
lfogui.html
163
lfogui.html
@@ -7,167 +7,7 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<style>
|
<link rel="stylesheet" href="./lfogui.css">
|
||||||
html,
|
|
||||||
body {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
margin: 0px;
|
|
||||||
border: 0;
|
|
||||||
overflow: hidden; /* Disable scrollbars */
|
|
||||||
display: block; /* No floating content on sides */
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
background-color: #333333;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
input[type=number] {
|
|
||||||
width: 50px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type=text] {
|
|
||||||
width: 60px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse-animation {
|
|
||||||
0% {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pulse {
|
|
||||||
animation: pulse-animation 0.2s normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@@ -175,6 +15,7 @@
|
|||||||
|
|
||||||
<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="./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>
|
||||||
|
|||||||
304
lfogui.js
304
lfogui.js
@@ -4,7 +4,7 @@ var log;
|
|||||||
if (DEBUG)
|
if (DEBUG)
|
||||||
log = console.log;
|
log = console.log;
|
||||||
else
|
else
|
||||||
log = window.max.outlet;
|
log = (msg) => {window.max.outlet("debug " + msg)};
|
||||||
|
|
||||||
const e = React.createElement;
|
const e = React.createElement;
|
||||||
|
|
||||||
@@ -20,12 +20,43 @@ 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 = ["-type-", "---shape---", "-------param-------", "--freq--", "--amp--", "--phase--"];
|
const MODULATORLABELS = ["inst", "-type-", "---shape---", "-------param-------", "--timebase--", "-min-", "-max", "-phase-", "center"];
|
||||||
const ENUMERATORLABELS = ["---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(){
|
||||||
@@ -41,33 +72,59 @@ function MasterLfoHandler(){
|
|||||||
setViewMode(ViewModes.MOD);
|
setViewMode(ViewModes.MOD);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [lockMode, setLockMode] = React.useState(LockModes.LOCK);
|
||||||
|
const toggleLockMode = () => {
|
||||||
|
if (lockMode === LockModes.UNLOCK)
|
||||||
|
setLockMode(LockModes.LOCK);
|
||||||
|
else
|
||||||
|
setLockMode(LockModes.UNLOCK);
|
||||||
|
};
|
||||||
|
|
||||||
/// MODULATOR ARRAYS
|
/// MODULATOR ARRAYS
|
||||||
|
|
||||||
|
const [userDefinedWave, setUserDefinedWave] = React.useState(Array(50).fill(0));
|
||||||
|
|
||||||
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 [modCenterVals, setModCenterVals] = React.useState({});
|
const [modCenterVals, setModCenterVals] = React.useState({'1':{}, '2':{}, '3':{}, '4':{}});
|
||||||
|
|
||||||
|
const [ticks, setTicks] = React.useState(0);
|
||||||
|
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'));
|
||||||
|
|
||||||
const [freqArr, setFreqArr] = React.useState(Array(MAXLFOS).fill('1'));
|
const [freqArr, setFreqArr] = React.useState(Array(MAXLFOS).fill('1hz'));
|
||||||
const [ampArr, setAmpArr] = React.useState(Array(MAXLFOS).fill('1'));
|
|
||||||
const [phaseArr, setPhaseArr] = React.useState(Array(MAXLFOS).fill('0'));
|
|
||||||
|
|
||||||
const allModArrays = [modVisibleArr, shapeArr, djParamArr, freqArr, ampArr, phaseArr];
|
// const [ampArr, setAmpArr] = React.useState(Array(MAXLFOS).fill('1'));
|
||||||
const allModSetters = [setModVisibleArr, setShapeArr, setDjParamArr, setFreqArr, setAmpArr, setPhaseArr];
|
const [minArr, setMinArr] = React.useState(Array(MAXLFOS).fill('0'));
|
||||||
const modBlankVals = [true, SHAPETYPES[0], MODPARAMOPTIONS[0], '1', '1', '0'];
|
const [maxArr, setMaxArr] = React.useState(Array(MAXLFOS).fill('1'));
|
||||||
|
|
||||||
|
const [initPhaseArr, setInitPhaseArr] = 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, modTypeArr, modInstanceNumArr, shapeArr, noiseTypeArr, djParamArr, freqArr, minArr, maxArr, initPhaseArr, lastPhaseArr, cachedNoiseValueArr1, cachedNoiseValueArr2];
|
||||||
|
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 [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);
|
||||||
@@ -75,7 +132,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,14 +141,14 @@ function MasterLfoHandler(){
|
|||||||
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);
|
||||||
|
|
||||||
const allEnumArrays = [enumVisibleArr, enumItemCounts, enumDjParamArr];
|
const allEnumArrays = [enumVisibleArr, enumInstanceNumArr, enumItemCounts, enumDjParamArr];
|
||||||
const allEnumArrSetters = [setEnumVisibleArr, setEnumItemCounts, setEnumDjParamArr];
|
const allEnumArrSetters = [setEnumVisibleArr, setEnumInstanceNumArr, setEnumItemCounts, setEnumDjParamArr];
|
||||||
|
|
||||||
const allEnumMats = [enumBreakPoints, enumNames];
|
const allEnumMats = [enumBreakPoints, enumNames];
|
||||||
const allEnumMatSetters = [setEnumBreakPoints, setEnumNames];
|
const allEnumMatSetters = [setEnumBreakPoints, setEnumNames];
|
||||||
const allGetEnumMatBlankVals = [getBlankEnumBreakPointRow, getBlankEnumNameRow]
|
const allGetEnumMatBlankVals = [getBlankEnumBreakPointRow, getBlankEnumNameRow]
|
||||||
|
|
||||||
const enumBlankVals = [true, 2, MODPARAMOPTIONS[0]];
|
const enumBlankVals = [true, '1', 2, MODPARAMOPTIONS[0]];
|
||||||
|
|
||||||
const [render, rerender] = React.useState(false); // BAD. I SHOULDN'T BE DOING THIS
|
const [render, rerender] = React.useState(false); // BAD. I SHOULDN'T BE DOING THIS
|
||||||
|
|
||||||
@@ -99,25 +156,18 @@ 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<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]);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSave(event) {
|
function handleSave(event) {
|
||||||
@@ -127,26 +177,28 @@ function MasterLfoHandler(){
|
|||||||
'enumMats' : allEnumMats
|
'enumMats' : allEnumMats
|
||||||
}
|
}
|
||||||
window.max.setDict(event.detail, {"data" : data});
|
window.max.setDict(event.detail, {"data" : data});
|
||||||
|
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 name = event.detail[0];
|
let inst = event.detail[0];
|
||||||
let val = event.detail[1];
|
let name = event.detail[1];
|
||||||
|
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)
|
if (enumVisibleArr[i] && enumDjParamArr[i] == name && enumInstanceNumArr[i] == inst)
|
||||||
break;
|
break;
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
if (i == MAXENUMS){
|
if (i == MAXENUMS){
|
||||||
window.max.outlet(name + ' ' + val);
|
window.max.outlet(inst + ' ' + name + ' ' + val);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
enumerate(name, val, enumItemCounts[i], enumBreakPoints[i], enumNames[i]);
|
enumerate(name, inst, val, enumItemCounts[i], enumBreakPoints[i], enumNames[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -154,76 +206,194 @@ function MasterLfoHandler(){
|
|||||||
|
|
||||||
|
|
||||||
function handleParam(event) {
|
function handleParam(event) {
|
||||||
|
let inst = event.detail[0]; // djster instance
|
||||||
let name = event.detail[0];
|
let name = event.detail[1];
|
||||||
let val = event.detail[1];
|
let val = event.detail[2];
|
||||||
|
// CHECK FOR INDEX OF THIS NAME IN ENUM MATRIX, AND IF IT IS THERE DENUMERATE
|
||||||
|
let index = -1;
|
||||||
|
for (let i = 0; i < MAXENUMS; i++){
|
||||||
|
if (enumDjParamArr[i] == name && enumInstanceNumArr[i] == inst)
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
if (index != -1){
|
||||||
|
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)
|
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' : [name, val]}));
|
window.dispatchEvent(new CustomEvent('enum', {'detail' : [inst, name, val]}));
|
||||||
}
|
}
|
||||||
|
|
||||||
modCenterVals[name] = val;
|
modCenterVals[inst][name] = val;
|
||||||
setModCenterVals(modCenterVals);
|
setModCenterVals(modCenterVals);
|
||||||
|
rerender(!render); // BAD! SHOULD NOT BE DOING THIS!
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTick(event) {
|
function handleTick(event) {
|
||||||
let time = (Date.now() - firstUpdateTime) / 1000;
|
let time = (Date.now() - firstUpdateTime) / 1000;
|
||||||
operateModulators(modVisibleArr, djParamArr, modCenterVals, freqArr, ampArr, shapeArr, phaseArr, time);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleTimeSig(event) {
|
||||||
|
setBeatsInMeasure(parseFloat(event.detail[0]) * parseFloat(event.detail[1])/ 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleChangeUserWave(event){
|
||||||
|
setUserDefinedWave(event.detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
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('timesig', handleTimeSig);
|
||||||
|
window.addEventListener('userWave', handleChangeUserWave);
|
||||||
|
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('timesig', handleTimeSig);
|
||||||
|
window.removeEventListener('userWave', handleChangeUserWave);
|
||||||
|
window.removeEventListener('maxTicks', handleMaxTicks);
|
||||||
};
|
};
|
||||||
}, [...allModArrays, ...allEnumArrays, ...allEnumMats, modCenterVals]);
|
}, [...allModArrays, ...allEnumArrays, ...allEnumMats, userDefinedWave, modCenterVals, render, beatsInMeasure, ticks]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function CheckLinked(inst, param, checkInstArr, checkParamArr){
|
||||||
|
for (let i = 0; i < checkInstArr.length; i++){
|
||||||
|
if (checkInstArr[i] == inst && checkParamArr[i] == param)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
///////
|
///////
|
||||||
// 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],
|
||||||
|
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,
|
||||||
|
|
||||||
freq: freqArr[i],
|
freq: freqArr[i],
|
||||||
setFreq: CreateParamChanger(freqArr, setFreqArr, i),
|
setFreq: CreateParamChanger(freqArr, setFreqArr, i),
|
||||||
amp: ampArr[i],
|
|
||||||
setAmp: CreateParamChanger(ampArr, setAmpArr, i),
|
//amp: ampArr[i],
|
||||||
phase: phaseArr[i],
|
//setAmp: CreateParamChanger(ampArr, setAmpArr, i),
|
||||||
setPhase: CreateParamChanger(phaseArr, setPhaseArr, i),
|
|
||||||
|
min: minArr[i],
|
||||||
|
setMin : CreateParamChanger(minArr, setMinArr, i),
|
||||||
|
max: maxArr[i],
|
||||||
|
setMax: CreateParamChanger(maxArr, setMaxArr, i),
|
||||||
|
|
||||||
|
phase: initPhaseArr[i],
|
||||||
|
setPhase: CreateParamChanger(initPhaseArr, setInitPhaseArr, i),
|
||||||
visible: modVisibleArr[i],
|
visible: modVisibleArr[i],
|
||||||
|
|
||||||
|
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);
|
||||||
@@ -239,6 +409,7 @@ 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];
|
||||||
@@ -246,6 +417,7 @@ function MasterLfoHandler(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
rerender(!render);
|
rerender(!render);
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeLfo: () => {
|
removeLfo: () => {
|
||||||
@@ -270,6 +442,9 @@ function MasterLfoHandler(){
|
|||||||
enumContents.push(
|
enumContents.push(
|
||||||
e(EnumeratorRow, {
|
e(EnumeratorRow, {
|
||||||
index: i,
|
index: i,
|
||||||
|
locked : lockMode,
|
||||||
|
instanceNum : enumInstanceNumArr[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,
|
||||||
@@ -279,6 +454,7 @@ function MasterLfoHandler(){
|
|||||||
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),
|
||||||
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
|
||||||
@@ -348,8 +524,19 @@ function MasterLfoHandler(){
|
|||||||
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: 'container'},
|
||||||
|
e(Switch, {ontoggle: toggleViewMode}, null),
|
||||||
|
e('span', {className: lockClass, onClick: toggleLockMode}, null)),
|
||||||
|
|
||||||
e('h5', null, title),
|
e('h5', null, title),
|
||||||
e('ul', null, ...labels.map(x => ListItem(Label(x)))),
|
e('ul', null, ...labels.map(x => ListItem(Label(x)))),
|
||||||
e('div', {id: 'grid'}, ...grid)
|
e('div', {id: 'grid'}, ...grid)
|
||||||
@@ -365,8 +552,29 @@ if (!DEBUG){
|
|||||||
window.dispatchEvent(new CustomEvent('saveDict', {'detail' : dictId}));
|
window.dispatchEvent(new CustomEvent('saveDict', {'detail' : dictId}));
|
||||||
});
|
});
|
||||||
|
|
||||||
window.max.bindInlet("param", (paramName, val) => {
|
window.max.bindInlet("dumpNN", () => {
|
||||||
window.dispatchEvent(new CustomEvent('param', {'detail' : [paramName, val]}));
|
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.max.bindInlet("timesig", (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", (...points) => {
|
||||||
|
window.dispatchEvent(new CustomEvent('userWave', {'detail' : points}));
|
||||||
});
|
});
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
|||||||
186
modulators.js
186
modulators.js
@@ -2,11 +2,22 @@
|
|||||||
// MODULATORS
|
// MODULATORS
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
|
|
||||||
var SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square"];
|
|
||||||
|
var TYPEOPTIONS = ["LFO", "Noise"];
|
||||||
|
var SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square", "Custom"];
|
||||||
|
var NOISETYPES = ["Rand", "Line Int.", "Sine Int."]
|
||||||
|
|
||||||
|
var INSTANCEOPTIONS = ["1", "2", "3", "4"];
|
||||||
|
|
||||||
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"));
|
||||||
}
|
}
|
||||||
@@ -14,23 +25,43 @@ function ControlType(){
|
|||||||
|
|
||||||
|
|
||||||
function LfoRow(props){
|
function LfoRow(props){
|
||||||
let content = e('ul', {className: 'lfo-item'},
|
|
||||||
ListItem(ControlType()),
|
let linkedText = props.linked ? "-> enums" : "";
|
||||||
ListItem(DropDown({onChange: props.setShape, value:props.shape, options: SHAPETYPES})),
|
let center = props.centerVals[props.instanceNum][props.djParam];
|
||||||
ListItem(DropDown({onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})),
|
if (!center)
|
||||||
ListItem(e(NumberBox, {onChange:props.setFreq, value:props.freq, step: 0.1}, null)),
|
center = 0;
|
||||||
ListItem(e(NumberBox, {onChange:props.setAmp, value:props.amp, step:0.1}, null)),
|
|
||||||
|
let typeOption = null;
|
||||||
|
|
||||||
|
if (props.type == "LFO"){
|
||||||
|
typeOption = ListItem(DropDown({locked:props.locked, onChange: props.setShape, value:props.shape, options: SHAPETYPES}));
|
||||||
|
}
|
||||||
|
else if (props.type == "Noise"){
|
||||||
|
typeOption = ListItem(DropDown({locked:props.locked, onChange: props.setNoise, value:props.noise, options: NOISETYPES}));
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = e('ul', {className: 'lfo-item'},
|
||||||
|
ListItem(DropDown({locked:props.locked, onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})),
|
||||||
|
ListItem(DropDown({locked:props.locked, options: TYPEOPTIONS, onChange: props.setType, value:props.type})),
|
||||||
|
typeOption,
|
||||||
|
ListItem(DropDown({locked:props.locked, onChange: props.setDjParam, value: props.djParam, options: MODPARAMOPTIONS})),
|
||||||
|
ListItem(e("input", {onChange:props.setFreq, value:props.freq, className:"timeInput"}, null)),
|
||||||
|
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)),
|
||||||
ListItem(e(NumberBox, {onChange:props.setPhase, value:props.phase, step:0.1}, null)),
|
ListItem(e(NumberBox, {onChange:props.setPhase, value:props.phase, step:0.1}, null)),
|
||||||
ListItem(e("input", {type: 'range', min: 0, max: 1, step: 0.01, readonly: true, id: `slider-${props.djParam}`})),
|
ListItem(e("div", {className:"base-val"}, center.toString())),
|
||||||
ListItem(e(Button, {text:'+', onClick: props.addLfo}, null)),
|
ListItem(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.removeLfo}, null))
|
ListItem(e(Button, {text:'+', onClick: props.addLfo, locked: props.locked}, null)),
|
||||||
|
ListItem(e(Button, {text:'-', onClick: props.removeLfo, locked: props.locked}, null)),
|
||||||
|
ListItem(e("div", {className:"linked"}, linkedText)),
|
||||||
);
|
);
|
||||||
if (props.visible){
|
if (props.visible){
|
||||||
return content
|
return content
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function indexWave(type, phase){
|
function indexWave(type, phase, userDefinedWave){
|
||||||
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;
|
||||||
@@ -42,32 +73,141 @@ function indexWave(type, phase){
|
|||||||
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":
|
||||||
|
return parseFloat(userDefinedWave[Math.floor(phase * 50)]) / 127
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function operateModulators(visibleArr, paramNames, centers, freqs, amps, waveTypes, phaseArr, time){
|
function operateModulators(visibleArr, typeArr, instanceNumArr, paramNames, centers, freqs, mins, maxs, waveTypes, phaseArr, noiseData, userDefinedWave, 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]){
|
||||||
|
|
||||||
let name = paramNames[i];
|
let name = paramNames[i];
|
||||||
|
let inst = instanceNumArr[i];
|
||||||
let center = 0;
|
let center = 0;
|
||||||
if (centers.hasOwnProperty(name)){
|
if (centers[inst].hasOwnProperty(name)){
|
||||||
center = centers[name];
|
center = centers[inst][name];
|
||||||
}
|
}
|
||||||
let output = operateModulator(center, freqs[i], amps[i], waveTypes[i], phaseArr, i, name, time);
|
|
||||||
|
let output = 0;
|
||||||
|
|
||||||
|
if (typeArr[i] == "LFO")
|
||||||
|
output = operateLFO(center, inst, freqs[i], mins[i], maxs[i], waveTypes[i], phaseArr, i, userDefinedWave, 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' : [name, output]}));
|
window.dispatchEvent(new CustomEvent('enum', {'detail' : [inst, name, output]}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function operateModulator(center, freq, amp, waveType, phaseArr, phaseI, name, time){
|
function operateLFO(center, inst, timeBaseStr, min, max, waveType, phaseArr, phaseIndex, userDefinedWave, name, currTime, beatsInMeasure, maxTicks){
|
||||||
|
let amp = parseFloat(max) - parseFloat(min);
|
||||||
|
let phaseType;
|
||||||
|
let timeBase;
|
||||||
|
|
||||||
let phase = (time * freq + parseFloat(phaseArr[phaseI])) % 1.00;
|
[timeBase, phaseType] = parseLfoTime(timeBaseStr, beatsInMeasure);
|
||||||
let unscaled = indexWave(waveType, phase);
|
let phase;
|
||||||
let el = document.getElementById(`slider-${name}`);
|
|
||||||
|
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, userDefinedWave);
|
||||||
|
syncDisplay(inst, name, unscaled);
|
||||||
|
|
||||||
|
return unscaled * amp + center + parseFloat(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncDisplay(inst, name, val) {
|
||||||
|
let el = document.getElementById(`slider-${inst}-${name}`);
|
||||||
|
|
||||||
if (el)
|
if (el)
|
||||||
el.value = unscaled;
|
el.value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, we're only using sine interpolation
|
||||||
|
function operateNoise(center, inst, timeBaseStr, min, max, waveType, phaseArr, index, name, noiseData, currTime, beatsInMeasure, maxTicks){
|
||||||
|
|
||||||
return unscaled * amp + center;
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function interpolateNoise(type, cachedVal1, cachedVal2, phase){
|
||||||
|
let interpVal;
|
||||||
|
|
||||||
|
switch (type){
|
||||||
|
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"){
|
||||||
|
return [parseFloat(lfoTime.slice(0, -2)), PhaseTypes.TIME];
|
||||||
|
}
|
||||||
|
else if (lfoTime.slice(-2) == "ms"){
|
||||||
|
return [1000 / parseFloat(lfoTime.slice(0, -2)), PhaseTypes.TIME];
|
||||||
|
}
|
||||||
|
else if (lfoTime.slice(-1) == "s"){
|
||||||
|
return [1 / parseFloat(lfoTime.slice(0, -1)), PhaseTypes.TIME];
|
||||||
|
}
|
||||||
|
else if ((lfoTime.match(/:/g) || []).length == 2){
|
||||||
|
return [1 / moment.duration(lfoTime).asSeconds(), PhaseTypes.TIME];
|
||||||
|
}
|
||||||
|
else if ((lfoTime.match(/\./g) || []).length == 2){
|
||||||
|
return [musicalTimingToFreq(...lfoTime.split('.'), beatsInMeasure), PhaseTypes.MUSICAL];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return [0, PhaseTypes.TIME];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function musicalTimingToFreq(bars, beats, ticks, beatsInMeasure){
|
||||||
|
let totalTicks = (parseFloat(bars) * parseFloat(beatsInMeasure) + parseFloat(beats)) * 480 + parseFloat(ticks);
|
||||||
|
return totalTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user