functional modulators
This commit is contained in:
parent
b206270087
commit
72858f0959
@ -12,7 +12,7 @@ function Label(text){
|
||||
}
|
||||
|
||||
function NumberBox(props){
|
||||
return e('input', {type: "number", onChange: props.onChange, value: props.value, className: props.className}, null);
|
||||
return e('input', {type: "number", onChange: props.onChange, step: props.step, value: props.value, className: props.className}, null);
|
||||
}
|
||||
|
||||
function TextBox(props){
|
||||
|
4
enums.js
4
enums.js
@ -18,8 +18,8 @@ function EnumeratorItems(index, enumBreakPoints, setEnumBreakPoints, enumNames,
|
||||
function EnumeratorRow(props){
|
||||
let content = e('ul', {className: 'lfo-item'},
|
||||
ListItem(DropDown({onChange: props.setDjParam, value: props.djParam, options: PARAMOPTIONS})),
|
||||
ListItem(e(NumberBox, {onChange: props.setEnumItemCounts, 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]}, null)),
|
||||
ListItem(e(NumberBox, {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)),
|
||||
...(EnumeratorItems(props.index, props.enumBreakPoints, props.setEnumBreakPoints, props.enumNames, props.setEnumNames).slice(0, props.enumItems * 2)),
|
||||
ListItem(e(Button, {text:'+', onClick: props.addEnum}, null)),
|
||||
ListItem(e(Button, {text:'-', onClick: props.removeEnum}, null))
|
||||
|
@ -3,14 +3,14 @@
|
||||
"fileversion" : 1,
|
||||
"appversion" : {
|
||||
"major" : 8,
|
||||
"minor" : 5,
|
||||
"revision" : 6,
|
||||
"minor" : 6,
|
||||
"revision" : 2,
|
||||
"architecture" : "x64",
|
||||
"modernui" : 1
|
||||
}
|
||||
,
|
||||
"classnamespace" : "box",
|
||||
"rect" : [ 495.0, 87.0, 815.0, 715.0 ],
|
||||
"rect" : [ 292.0, 100.0, 799.0, 715.0 ],
|
||||
"bglocked" : 0,
|
||||
"openinpresentation" : 0,
|
||||
"default_fontsize" : 12.0,
|
||||
@ -39,6 +39,54 @@
|
||||
"subpatcher_template" : "",
|
||||
"assistshowspatchername" : 0,
|
||||
"boxes" : [ {
|
||||
"box" : {
|
||||
"id" : "obj-17",
|
||||
"linecount" : 2,
|
||||
"maxclass" : "comment",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 0,
|
||||
"patching_rect" : [ 520.0, 441.0, 150.0, 34.0 ],
|
||||
"text" : "question for Georg: what should `phase` do?"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"id" : "obj-13",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 130.0, 183.0, 88.0, 22.0 ],
|
||||
"text" : "param pass 30"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"id" : "obj-8",
|
||||
"maxclass" : "message",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 228.0, 294.0, 129.0, 22.0 ],
|
||||
"text" : "param attenuation 200"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"id" : "obj-5",
|
||||
"maxclass" : "button",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "bang" ],
|
||||
"parameter_enable" : 0,
|
||||
"patching_rect" : [ 365.0, 582.0, 24.0, 24.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"id" : "obj-16",
|
||||
"maxclass" : "message",
|
||||
@ -64,11 +112,12 @@
|
||||
"id" : "obj-4",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 4,
|
||||
"outlettype" : [ "dictionary", "", "", "" ],
|
||||
"numoutlets" : 5,
|
||||
"outlettype" : [ "dictionary", "", "", "", "" ],
|
||||
"patching_rect" : [ 693.0, 69.0, 159.0, 22.0 ],
|
||||
"saved_object_attributes" : {
|
||||
"embed" : 1,
|
||||
"legacy" : 1,
|
||||
"parameter_enable" : 0,
|
||||
"parameter_mappable" : 0
|
||||
}
|
||||
@ -95,7 +144,7 @@
|
||||
"maxclass" : "comment",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 0,
|
||||
"patching_rect" : [ 438.52631402015686, 27.5, 150.0, 33.0 ],
|
||||
"patching_rect" : [ 438.52631402015686, 27.5, 150.0, 34.0 ],
|
||||
"text" : "required due to the asynchronous operation"
|
||||
}
|
||||
|
||||
@ -191,6 +240,13 @@
|
||||
"source" : [ "obj-12", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-2", 0 ],
|
||||
"source" : [ "obj-13", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
@ -216,6 +272,15 @@
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-10", 0 ],
|
||||
"order" : 1,
|
||||
"source" : [ "obj-2", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-5", 0 ],
|
||||
"order" : 0,
|
||||
"source" : [ "obj-2", 0 ]
|
||||
}
|
||||
|
||||
@ -242,8 +307,28 @@
|
||||
"source" : [ "obj-3", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-2", 0 ],
|
||||
"source" : [ "obj-8", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
"parameters" : {
|
||||
"parameterbanks" : {
|
||||
"0" : {
|
||||
"index" : 0,
|
||||
"name" : "",
|
||||
"parameters" : [ "-", "-", "-", "-", "-", "-", "-", "-" ]
|
||||
}
|
||||
|
||||
}
|
||||
,
|
||||
"inherited_shortname" : 1
|
||||
}
|
||||
,
|
||||
"dependency_cache" : [ ],
|
||||
"autosave" : 0
|
||||
}
|
||||
|
54
lfogui.js
54
lfogui.js
@ -20,6 +20,10 @@ const ViewModes = Object.freeze({
|
||||
ENUM: 1
|
||||
});
|
||||
|
||||
|
||||
var modPhases = Array(MAXLFOS).fill(0);
|
||||
var lastUpdateTime = Date.now();
|
||||
|
||||
const MODULATORLABELS = ["-type-", "---shape---", "----param----", "freq", "amp", "phase"];
|
||||
const ENUMERATORLABELS = ["--parameter--", "-points-"];
|
||||
|
||||
@ -41,6 +45,8 @@ function MasterLfoHandler(){
|
||||
|
||||
const [modVisibleArr, setModVisibleArr] = React.useState(initVisArr);
|
||||
|
||||
const [modCenterVals, setModCenterVals] = React.useState({});
|
||||
|
||||
const [shapeArr, setShapeArr] = React.useState(Array(MAXLFOS).fill('Sine'));
|
||||
const [djParamArr, setDjParamArr] = React.useState(Array(MAXLFOS).fill('attenuation'));
|
||||
|
||||
@ -114,16 +120,50 @@ function MasterLfoHandler(){
|
||||
window.max.setDict(event.detail, {"data" : data});
|
||||
}
|
||||
|
||||
function handleParam(event) {
|
||||
|
||||
let name = event.detail[0];
|
||||
let val = event.detail[1];
|
||||
|
||||
// if none of the LFOs use this param, then we output it raw
|
||||
let i = 0;
|
||||
while (i < MAXLFOS){
|
||||
if (modVisibleArr[i] && djParamArr[i] == name)
|
||||
break;
|
||||
i++
|
||||
}
|
||||
if (i == MAXLFOS){
|
||||
window.max.outlet(name + ' ' + val);
|
||||
}
|
||||
|
||||
modCenterVals[name] = val;
|
||||
setModCenterVals(modCenterVals);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
function handleTick(event) {
|
||||
|
||||
let newTime = Date.now()
|
||||
let delta = (newTime - lastUpdateTime) / 1000;
|
||||
lastUpdateTime = newTime
|
||||
operateModulators(modVisibleArr, djParamArr, modCenterVals, freqArr, ampArr, shapeArr, modPhases, delta);
|
||||
}
|
||||
|
||||
|
||||
window.addEventListener('loadDict', handleLoad);
|
||||
|
||||
window.addEventListener('saveDict', handleSave);
|
||||
window.addEventListener('tick', handleTick);
|
||||
window.addEventListener('param', handleParam);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('loadDict', handleLoad);
|
||||
window.removeEventListener('saveDict', handleSave);
|
||||
window.removeEventListener('tick', handleTick);
|
||||
window.removeEventListener('param', handleParam);
|
||||
};
|
||||
}, [...allModArrays, ...allEnumArrays, ...allEnumMats]);
|
||||
}, [...allModArrays, ...allEnumArrays, ...allEnumMats, modCenterVals]);
|
||||
|
||||
|
||||
|
||||
@ -288,7 +328,15 @@ if (!DEBUG){
|
||||
|
||||
window.max.bindInlet("save", (dictId) => {
|
||||
window.dispatchEvent(new CustomEvent('saveDict', {'detail' : dictId}));
|
||||
})
|
||||
});
|
||||
|
||||
window.max.bindInlet("param", (paramName, val) => {
|
||||
window.dispatchEvent(new CustomEvent('param', {'detail' : [paramName, val]}));
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
window.dispatchEvent(new CustomEvent('tick'));
|
||||
}, 200);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3,7 +3,9 @@
|
||||
/////////////////////////
|
||||
|
||||
var SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square"];
|
||||
const PARAMOPTIONS = ["attenuation", "melody_scope"];
|
||||
const PARAMOPTIONS = ["pulse_length", "eventfulness", "event_length", "metriclarity",
|
||||
"harmoniclarity", "melodic_cohesion", "melody_scope", "tonic_pitch", "pitch_center", "pitch_range", "dynamics",
|
||||
"attenuation", "chordal_weight"]
|
||||
|
||||
function ControlType(){
|
||||
return e('select', {className: 'control-type'}, Option("LFO"));
|
||||
@ -16,13 +18,52 @@ function LfoRow(props){
|
||||
ListItem(ControlType()),
|
||||
ListItem(DropDown({onChange: props.setShape, value:props.shape, options: SHAPETYPES})),
|
||||
ListItem(DropDown({onChange: props.setDjParam, value: props.djParam, options: PARAMOPTIONS})),
|
||||
ListItem(e(NumberBox, {onChange:props.setFreq, value:props.freq}, null)),
|
||||
ListItem(e(NumberBox, {onChange:props.setAmp, value:props.amp}, null)),
|
||||
ListItem(e(NumberBox, {onChange:props.setPhase, value:props.phase}, null)),
|
||||
ListItem(e(NumberBox, {onChange:props.setFreq, value:props.freq, 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(Button, {text:'+', onClick: props.addLfo}, null)),
|
||||
ListItem(e(Button, {text:'-', onClick: props.removeLfo}, null))
|
||||
);
|
||||
if (props.visible){
|
||||
return content
|
||||
};
|
||||
}
|
||||
|
||||
function indexWave(type, phase){
|
||||
switch (type){
|
||||
case "Sine":
|
||||
return Math.sin(phase * Math.PI * 2);
|
||||
case "SawUp":
|
||||
return phase;
|
||||
case "SawDown":
|
||||
return 1 - phase;
|
||||
case "Tri":
|
||||
return phase > 0.5? (1-phase) * 2 : phase * 2;
|
||||
case "Square":
|
||||
return +(phase > 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
function operateModulators(visibleArr, paramNames, centers, freqs, amps, waveTypes, phaseArr, delta){
|
||||
for (let i=0; i<paramNames.length; i++){
|
||||
if (visibleArr[i]){
|
||||
let name = paramNames[i];
|
||||
let center = 0;
|
||||
if (centers.hasOwnProperty(name)){
|
||||
center = centers[name];
|
||||
}
|
||||
let output = operateModulator(name, center, freqs[i], amps[i], waveTypes[i], phaseArr, i, delta);
|
||||
window.max.outlet(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function operateModulator(paramName, center, freq, amp, waveType, phaseArr, phaseI, delta){
|
||||
|
||||
let oldPhase = phaseArr[phaseI];
|
||||
let newPhase = (oldPhase + freq * delta) % 1.00;
|
||||
|
||||
phaseArr[phaseI] = newPhase;
|
||||
let outputVal = indexWave(waveType, newPhase) * amp + center;
|
||||
return paramName + ' ' + outputVal.toString();
|
||||
}
|
Loading…
Reference in New Issue
Block a user