From c8c410a38f8ecab7df6753c0c60d92708b02a04d Mon Sep 17 00:00:00 2001 From: trian-gles <69212477+trian-gles@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:31:57 +0200 Subject: [PATCH 1/5] UI changes --- example.maxpat | 6 +++--- lfogui.js | 12 ++++++++++-- modulators.js | 21 ++++++++++++++------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/example.maxpat b/example.maxpat index 1e5b07d..2b56a7d 100644 --- a/example.maxpat +++ b/example.maxpat @@ -130,7 +130,7 @@ "numoutlets" : 1, "outlettype" : [ "" ], "patching_rect" : [ 586.0, 713.0, 89.0, 36.0 ], - "text" : "harmoniclarity 40.156651" + "text" : "harmoniclarity 14.213599" } } @@ -143,7 +143,7 @@ "numoutlets" : 1, "outlettype" : [ "" ], "patching_rect" : [ 491.0, 713.0, 85.0, 36.0 ], - "text" : "event_length 29.843349" + "text" : "event_length 55.786401" } } @@ -156,7 +156,7 @@ "numoutlets" : 1, "outlettype" : [ "" ], "patching_rect" : [ 385.0, 715.0, 84.0, 36.0 ], - "text" : "metriclarity 22.176645" + "text" : "metriclarity 79.192955" } } diff --git a/lfogui.js b/lfogui.js index 29946c1..ec49f43 100644 --- a/lfogui.js +++ b/lfogui.js @@ -48,6 +48,7 @@ function MasterLfoHandler(){ const [userDefinedWave, setUserDefinedWave] = React.useState(Array(50).fill(0)); 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({'1':{}, '2':{}, '3':{}, '4':{}}); @@ -55,6 +56,7 @@ function MasterLfoHandler(){ const [bpm, setBpm] = React.useState(100); 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 [djParamArr, setDjParamArr] = React.useState(Array(MAXLFOS).fill('NONE')); @@ -66,8 +68,8 @@ function MasterLfoHandler(){ const [phaseArr, setPhaseArr] = React.useState(Array(MAXLFOS).fill('0')); - const allModArrays = [modVisibleArr, modInstanceNumArr, shapeArr, djParamArr, freqArr, minArr, maxArr, phaseArr]; - const allModSetters = [setModVisibleArr, setModInstanceNumArr, setShapeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setPhaseArr]; + const allModArrays = [modVisibleArr, modTypeArr, modInstanceNumArr, shapeArr, noiseTypeArr, djParamArr, freqArr, minArr, maxArr, phaseArr]; + const allModSetters = [setModVisibleArr, setModTypeArr, setModInstanceNumArr, setShapeArr, setNoiseTypeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setPhaseArr]; const modBlankVals = [true, '1', SHAPETYPES[0], MODPARAMOPTIONS[0], '1hz', '0', '1', '0']; @@ -258,8 +260,14 @@ function MasterLfoHandler(){ e(LfoRow, { instanceNum : modInstanceNumArr[i], setInstanceNum: CreateParamChanger(modInstanceNumArr, setModInstanceNumArr, i), + + type: modTypeArr[i], + setType: CreateParamChanger(modTypeArr, setModTypeArr, i), shape: shapeArr[i], setShape: CreateParamChanger(shapeArr, setShapeArr, i), + + noise: noiseTypeArr[i], + setNoise: CreateParamChanger(noiseTypeArr, setNoiseTypeArr, i), djParam: djParamArr[i], setDjParam: CreateParamChanger(djParamArr, setDjParamArr, i), centerVals: modCenterVals, diff --git a/modulators.js b/modulators.js index 483c889..4905221 100644 --- a/modulators.js +++ b/modulators.js @@ -2,7 +2,10 @@ // MODULATORS ///////////////////////// + +var TYPEOPTIONS = ["LFO", "Noise"]; var SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square", "Custom"]; +var NOISETYPES = ["Sine Int."] var INSTANCEOPTIONS = ["1", "2", "3", "4"]; @@ -10,11 +13,6 @@ const MODPARAMOPTIONS = ["NONE", "stream", "pulse_length", "eventfulness", "even "harmoniclarity", "melodic_cohesion", "melody_scope", "tonic_pitch", "pitch_center", "pitch_range", "dynamics", "attenuation", "chordal_weight", "tonality-profile", "ostinato-buffer", "ostinato", "meter", "scale"]; -function ControlType(){ - return e('select', {className: 'control-type'}, Option("LFO")); -} - - function LfoRow(props){ @@ -23,10 +21,19 @@ function LfoRow(props){ if (!center) center = 0; + let typeOption = null; + + if (props.type == "LFO"){ + typeOption = ListItem(DropDown({onChange: props.setShape, value:props.shape, options: SHAPETYPES})); + } + else if (props.type == "Noise"){ + typeOption = ListItem(DropDown({onChange: props.setNoise, value:props.noise, options: NOISETYPES})); + } + let content = e('ul', {className: 'lfo-item'}, ListItem(DropDown({onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})), - ListItem(ControlType()), - ListItem(DropDown({onChange: props.setShape, value:props.shape, options: SHAPETYPES})), + ListItem(DropDown({options: TYPEOPTIONS, onChange: props.setType, value:props.type})), + typeOption, ListItem(DropDown({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)), -- 2.45.2 From 45e168ba1133490cadffe82e9babbfdddb3fc2ba Mon Sep 17 00:00:00 2001 From: trian-gles <69212477+trian-gles@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:31:57 +0200 Subject: [PATCH 2/5] UI changes --- example.maxpat | 6 +++--- lfogui.js | 12 ++++++++++-- modulators.js | 16 ++++++++++++++-- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/example.maxpat b/example.maxpat index 2619f50..de201ed 100644 --- a/example.maxpat +++ b/example.maxpat @@ -168,7 +168,7 @@ "numoutlets" : 1, "outlettype" : [ "" ], "patching_rect" : [ 586.0, 713.0, 89.0, 36.0 ], - "text" : "harmoniclarity 40.156651" + "text" : "harmoniclarity 14.213599" } } @@ -181,7 +181,7 @@ "numoutlets" : 1, "outlettype" : [ "" ], "patching_rect" : [ 491.0, 713.0, 85.0, 36.0 ], - "text" : "event_length 29.843349" + "text" : "event_length 55.786401" } } @@ -194,7 +194,7 @@ "numoutlets" : 1, "outlettype" : [ "" ], "patching_rect" : [ 385.0, 715.0, 84.0, 36.0 ], - "text" : "metriclarity 0.5" + "text" : "metriclarity 79.192955" } } diff --git a/lfogui.js b/lfogui.js index 24281fa..7dc65bc 100644 --- a/lfogui.js +++ b/lfogui.js @@ -48,6 +48,7 @@ function MasterLfoHandler(){ const [userDefinedWave, setUserDefinedWave] = React.useState(Array(50).fill(0)); 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({'1':{}, '2':{}, '3':{}, '4':{}}); @@ -55,6 +56,7 @@ function MasterLfoHandler(){ 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 [djParamArr, setDjParamArr] = React.useState(Array(MAXLFOS).fill('NONE')); @@ -66,8 +68,8 @@ function MasterLfoHandler(){ const [phaseArr, setPhaseArr] = React.useState(Array(MAXLFOS).fill('0')); - const allModArrays = [modVisibleArr, modInstanceNumArr, shapeArr, djParamArr, freqArr, minArr, maxArr, phaseArr]; - const allModSetters = [setModVisibleArr, setModInstanceNumArr, setShapeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setPhaseArr]; + const allModArrays = [modVisibleArr, modTypeArr, modInstanceNumArr, shapeArr, noiseTypeArr, djParamArr, freqArr, minArr, maxArr, phaseArr]; + const allModSetters = [setModVisibleArr, setModTypeArr, setModInstanceNumArr, setShapeArr, setNoiseTypeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setPhaseArr]; const modBlankVals = [true, '1', SHAPETYPES[0], MODPARAMOPTIONS[0], '1hz', '0', '1', '0']; @@ -259,8 +261,14 @@ function MasterLfoHandler(){ e(LfoRow, { instanceNum : modInstanceNumArr[i], setInstanceNum: CreateParamChanger(modInstanceNumArr, setModInstanceNumArr, i), + + type: modTypeArr[i], + setType: CreateParamChanger(modTypeArr, setModTypeArr, i), shape: shapeArr[i], setShape: CreateParamChanger(shapeArr, setShapeArr, i), + + noise: noiseTypeArr[i], + setNoise: CreateParamChanger(noiseTypeArr, setNoiseTypeArr, i), djParam: djParamArr[i], setDjParam: CreateParamChanger(djParamArr, setDjParamArr, i), centerVals: modCenterVals, diff --git a/modulators.js b/modulators.js index dc4a778..0f33b22 100644 --- a/modulators.js +++ b/modulators.js @@ -2,7 +2,10 @@ // MODULATORS ///////////////////////// + +var TYPEOPTIONS = ["LFO", "Noise"]; var SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square", "Custom"]; +var NOISETYPES = ["Sine Int."] var INSTANCEOPTIONS = ["1", "2", "3", "4"]; @@ -28,10 +31,19 @@ function LfoRow(props){ if (!center) center = 0; + let typeOption = null; + + if (props.type == "LFO"){ + typeOption = ListItem(DropDown({onChange: props.setShape, value:props.shape, options: SHAPETYPES})); + } + else if (props.type == "Noise"){ + typeOption = ListItem(DropDown({onChange: props.setNoise, value:props.noise, options: NOISETYPES})); + } + let content = e('ul', {className: 'lfo-item'}, ListItem(DropDown({onChange: props.setInstanceNum, value:props.instanceNum, options: INSTANCEOPTIONS})), - ListItem(ControlType()), - ListItem(DropDown({onChange: props.setShape, value:props.shape, options: SHAPETYPES})), + ListItem(DropDown({options: TYPEOPTIONS, onChange: props.setType, value:props.type})), + typeOption, ListItem(DropDown({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)), -- 2.45.2 From a608b083f322fc50a9e2a91227ab91bf78ea7007 Mon Sep 17 00:00:00 2001 From: Kieran McAuliffe Date: Wed, 25 Sep 2024 15:59:27 +0200 Subject: [PATCH 3/5] working sine interpolation --- lfogui.js | 18 ++++++++++------- modulators.js | 56 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/lfogui.js b/lfogui.js index 7dc65bc..9b34d80 100644 --- a/lfogui.js +++ b/lfogui.js @@ -66,10 +66,14 @@ function MasterLfoHandler(){ const [minArr, setMinArr] = React.useState(Array(MAXLFOS).fill('0')); const [maxArr, setMaxArr] = React.useState(Array(MAXLFOS).fill('1')); - const [phaseArr, setPhaseArr] = 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 [cachedNoiseValueArr, setCachedNoiseValueArr] = React.useState(Array(MAXLFOS).fill([0, 0])); - const allModArrays = [modVisibleArr, modTypeArr, modInstanceNumArr, shapeArr, noiseTypeArr, djParamArr, freqArr, minArr, maxArr, phaseArr]; - const allModSetters = [setModVisibleArr, setModTypeArr, setModInstanceNumArr, setShapeArr, setNoiseTypeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setPhaseArr]; + + + const allModArrays = [modVisibleArr, modTypeArr, modInstanceNumArr, shapeArr, noiseTypeArr, djParamArr, freqArr, minArr, maxArr, initPhaseArr]; + const allModSetters = [setModVisibleArr, setModTypeArr, setModInstanceNumArr, setShapeArr, setNoiseTypeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setInitPhaseArr]; const modBlankVals = [true, '1', SHAPETYPES[0], MODPARAMOPTIONS[0], '1hz', '0', '1', '0']; @@ -202,8 +206,8 @@ function MasterLfoHandler(){ function handleTick(event) { let time = (Date.now() - firstUpdateTime) / 1000; - - operateModulators(modVisibleArr, modInstanceNumArr, djParamArr, modCenterVals, freqArr, minArr, maxArr, shapeArr, phaseArr, userDefinedWave, time, beatsInMeasure, ticks); + let noiseData = {lastPhaseArr, setLastPhaseArr, cachedNoiseValueArr, setCachedNoiseValueArr}; + operateModulators(modVisibleArr, modTypeArr, modInstanceNumArr, djParamArr, modCenterVals, freqArr, minArr, maxArr, shapeArr, initPhaseArr, noiseData, userDefinedWave, time, beatsInMeasure, ticks); } function handleTimeSig(event) { @@ -284,8 +288,8 @@ function MasterLfoHandler(){ max: maxArr[i], setMax: CreateParamChanger(maxArr, setMaxArr, i), - phase: phaseArr[i], - setPhase: CreateParamChanger(phaseArr, setPhaseArr, i), + phase: initPhaseArr[i], + setPhase: CreateParamChanger(initPhaseArr, setInitPhaseArr, i), visible: modVisibleArr[i], linked: CheckLinked(modInstanceNumArr[i], djParamArr[i], enumInstanceNumArr, enumDjParamArr), diff --git a/modulators.js b/modulators.js index 0f33b22..1190080 100644 --- a/modulators.js +++ b/modulators.js @@ -78,7 +78,7 @@ function indexWave(type, phase, userDefinedWave){ } } -function operateModulators(visibleArr, instanceNumArr, paramNames, centers, freqs, mins, maxs, waveTypes, phaseArr, userDefinedWave, currTime, beatsInMeasure, ticks){ +function operateModulators(visibleArr, typeArr, instanceNumArr, paramNames, centers, freqs, mins, maxs, waveTypes, phaseArr, noiseData, userDefinedWave, currTime, beatsInMeasure, ticks){ for (let i=0; i phase){ // occurs if the phase reset to 0 or at the very start + + noiseData.cachedNoiseValueArr[index][0] = noiseData.cachedNoiseValueArr[index][1]; + if (noiseData.cachedNoiseValueArr[index][0] == 0) + noiseData.cachedNoiseValueArr[index][0] = center; + + noiseData.cachedNoiseValueArr[index][1] = Math.random(); + noiseData.setCachedNoiseValueArr(noiseData.cachedNoiseValueArr); + } + noiseData.lastPhaseArr[index] = phase; + 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]; + syncDisplay(inst, name, unscaled); return unscaled * amp + center + parseFloat(min); + } // actual returns the period for musical timing, to avoid floating point errors -- 2.45.2 From 43e517cc4ef136765dc1651309ce61b81c91704c Mon Sep 17 00:00:00 2001 From: trian-gles <69212477+trian-gles@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:40:47 +0200 Subject: [PATCH 4/5] added new init values --- lfogui.js | 10 ++++++---- modulators.js | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lfogui.js b/lfogui.js index 9b34d80..d18133e 100644 --- a/lfogui.js +++ b/lfogui.js @@ -72,9 +72,9 @@ function MasterLfoHandler(){ - const allModArrays = [modVisibleArr, modTypeArr, modInstanceNumArr, shapeArr, noiseTypeArr, djParamArr, freqArr, minArr, maxArr, initPhaseArr]; - const allModSetters = [setModVisibleArr, setModTypeArr, setModInstanceNumArr, setShapeArr, setNoiseTypeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setInitPhaseArr]; - const modBlankVals = [true, '1', SHAPETYPES[0], MODPARAMOPTIONS[0], '1hz', '0', '1', '0']; + const allModArrays = [modVisibleArr, modTypeArr, modInstanceNumArr, shapeArr, noiseTypeArr, djParamArr, freqArr, minArr, maxArr, initPhaseArr, lastPhaseArr, cachedNoiseValueArr]; + const allModSetters = [setModVisibleArr, setModTypeArr, setModInstanceNumArr, setShapeArr, setNoiseTypeArr, setDjParamArr, setFreqArr, setMinArr, setMaxArr, setInitPhaseArr, lastPhaseArr, cachedNoiseValueArr]; + const modBlankVals = [true, 'LFO', '1', SHAPETYPES[0], MODPARAMOPTIONS[0], "Sine Int.", '1hz', '0', '1', '0', 0, [0, 0]]; /// ENUMERATOR ARRAYS @@ -118,7 +118,6 @@ function MasterLfoHandler(){ React.useEffect(() => { function handleLoad(event) { - window.max.getDict(event.detail, (dict) => { for (let i = 0; i { + if (id < MAXLFOS - 1){ + if (modVisibleArr[id + 1]){ let emptyIndex = modVisibleArr.findIndex((item) => !item); @@ -310,6 +311,7 @@ function MasterLfoHandler(){ } } else { + log("adding lfo"); for (var j = 0; j < allModArrays.length; j++){ // no space below, easy. let array = allModArrays[j]; array[id + 1] = modBlankVals[j]; diff --git a/modulators.js b/modulators.js index 1190080..80445aa 100644 --- a/modulators.js +++ b/modulators.js @@ -90,6 +90,7 @@ function operateModulators(visibleArr, typeArr, instanceNumArr, paramNames, cent } 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 @@ -101,7 +102,6 @@ function operateModulators(visibleArr, typeArr, instanceNumArr, paramNames, cent } 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; -- 2.45.2 From d22cdc840122ef4bded023dc06aa421e6406728d Mon Sep 17 00:00:00 2001 From: Kieran Date: Thu, 10 Oct 2024 12:23:50 +0200 Subject: [PATCH 5/5] basic random value noise functions --- lfogui.js | 2 +- modulators.js | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lfogui.js b/lfogui.js index d18133e..1a1d9cb 100644 --- a/lfogui.js +++ b/lfogui.js @@ -205,7 +205,7 @@ function MasterLfoHandler(){ function handleTick(event) { let time = (Date.now() - firstUpdateTime) / 1000; - let noiseData = {lastPhaseArr, setLastPhaseArr, cachedNoiseValueArr, setCachedNoiseValueArr}; + let noiseData = {lastPhaseArr, setLastPhaseArr, cachedNoiseValueArr, setCachedNoiseValueArr, noiseTypeArr}; operateModulators(modVisibleArr, modTypeArr, modInstanceNumArr, djParamArr, modCenterVals, freqArr, minArr, maxArr, shapeArr, initPhaseArr, noiseData, userDefinedWave, time, beatsInMeasure, ticks); } diff --git a/modulators.js b/modulators.js index 80445aa..618fd2d 100644 --- a/modulators.js +++ b/modulators.js @@ -5,7 +5,7 @@ var TYPEOPTIONS = ["LFO", "Noise"]; var SHAPETYPES = ["Sine", "SawUp", "SawDown", "Tri", "Square", "Custom"]; -var NOISETYPES = ["Sine Int."] +var NOISETYPES = ["Rand", "Line Int.", "Sine Int."] var INSTANCEOPTIONS = ["1", "2", "3", "4"]; @@ -132,6 +132,7 @@ function operateNoise(center, inst, timeBaseStr, min, max, waveType, phaseArr, i let amp = parseFloat(max) - parseFloat(min); let phaseType; let timeBase; + let noiseType = noiseData.noiseTypeArr[index]; [timeBase, phaseType] = parseLfoTime(timeBaseStr, beatsInMeasure); let phase; @@ -156,13 +157,31 @@ function operateNoise(center, inst, timeBaseStr, min, max, waveType, phaseArr, i 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); 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"){ -- 2.45.2