musical-timing-phase #2
@ -10,7 +10,7 @@
|
||||
}
|
||||
,
|
||||
"classnamespace" : "box",
|
||||
"rect" : [ 34.0, 76.0, 981.0, 763.0 ],
|
||||
"rect" : [ 34.0, 76.0, 1155.0, 763.0 ],
|
||||
"bglocked" : 0,
|
||||
"openinpresentation" : 0,
|
||||
"default_fontsize" : 12.0,
|
||||
@ -39,6 +39,44 @@
|
||||
"subpatcher_template" : "",
|
||||
"assistshowspatchername" : 0,
|
||||
"boxes" : [ {
|
||||
"box" : {
|
||||
"fontname" : "Arial",
|
||||
"fontsize" : 13.0,
|
||||
"id" : "obj-29",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 2,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "bang" ],
|
||||
"patching_rect" : [ 465.0, 141.0, 210.0, 23.0 ],
|
||||
"text" : "metro @interval 40 ticks @active 1"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"id" : "obj-28",
|
||||
"maxclass" : "button",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "bang" ],
|
||||
"parameter_enable" : 0,
|
||||
"patching_rect" : [ 826.0, 79.0, 24.0, 24.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"id" : "obj-3",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 817.0, 147.0, 80.0, 22.0 ],
|
||||
"text" : "prepend ticks"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"id" : "obj-54",
|
||||
"maxclass" : "newobj",
|
||||
@ -156,7 +194,7 @@
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 385.0, 715.0, 84.0, 36.0 ],
|
||||
"text" : "metriclarity 22.176645"
|
||||
"text" : "metriclarity 0.5"
|
||||
}
|
||||
|
||||
}
|
||||
@ -244,18 +282,6 @@
|
||||
"text" : "prepend timesig"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
"id" : "obj-52",
|
||||
"maxclass" : "newobj",
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 1,
|
||||
"outlettype" : [ "" ],
|
||||
"patching_rect" : [ 545.0, 135.0, 89.0, 22.0 ],
|
||||
"text" : "prepend tempo"
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"box" : {
|
||||
@ -299,8 +325,7 @@
|
||||
"numinlets" : 1,
|
||||
"numoutlets" : 5,
|
||||
"outlettype" : [ "preset", "int", "preset", "int", "" ],
|
||||
"patching_rect" : [ 934.0, 27.0, 100.0, 40.0 ],
|
||||
"pattrstorage" : "storage"
|
||||
"patching_rect" : [ 934.0, 27.0, 100.0, 40.0 ]
|
||||
}
|
||||
|
||||
}
|
||||
@ -784,6 +809,27 @@
|
||||
"source" : [ "obj-27", 1 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-47", 0 ],
|
||||
"source" : [ "obj-28", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-47", 0 ],
|
||||
"source" : [ "obj-29", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-2", 0 ],
|
||||
"source" : [ "obj-3", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
@ -886,8 +932,8 @@
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-52", 0 ],
|
||||
"source" : [ "obj-47", 4 ]
|
||||
"destination" : [ "obj-3", 0 ],
|
||||
"source" : [ "obj-47", 7 ]
|
||||
}
|
||||
|
||||
}
|
||||
@ -904,13 +950,6 @@
|
||||
"source" : [ "obj-5", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
"destination" : [ "obj-2", 0 ],
|
||||
"source" : [ "obj-52", 0 ]
|
||||
}
|
||||
|
||||
}
|
||||
, {
|
||||
"patchline" : {
|
||||
|
27
lfogui.js
27
lfogui.js
@ -52,7 +52,7 @@ function MasterLfoHandler(){
|
||||
|
||||
const [modCenterVals, setModCenterVals] = React.useState({'1':{}, '2':{}, '3':{}, '4':{}});
|
||||
|
||||
const [bpm, setBpm] = React.useState(100);
|
||||
const [ticks, setTicks] = React.useState(0);
|
||||
const [beatsInMeasure, setBeatsInMeasure] = React.useState(4);
|
||||
|
||||
const [shapeArr, setShapeArr] = React.useState(Array(MAXLFOS).fill('Sine'));
|
||||
@ -200,11 +200,8 @@ function MasterLfoHandler(){
|
||||
|
||||
function handleTick(event) {
|
||||
let time = (Date.now() - firstUpdateTime) / 1000;
|
||||
operateModulators(modVisibleArr, modInstanceNumArr, djParamArr, modCenterVals, freqArr, minArr, maxArr, shapeArr, phaseArr, userDefinedWave, time, bpm, beatsInMeasure);
|
||||
}
|
||||
|
||||
function handleBpm(event) {
|
||||
setBpm(event.detail);
|
||||
|
||||
operateModulators(modVisibleArr, modInstanceNumArr, djParamArr, modCenterVals, freqArr, minArr, maxArr, shapeArr, phaseArr, userDefinedWave, time, beatsInMeasure, ticks);
|
||||
}
|
||||
|
||||
function handleTimeSig(event) {
|
||||
@ -215,15 +212,19 @@ function MasterLfoHandler(){
|
||||
setUserDefinedWave(event.detail);
|
||||
}
|
||||
|
||||
function handleMaxTicks(event){
|
||||
setTicks(event.detail);
|
||||
}
|
||||
|
||||
|
||||
window.addEventListener('loadDict', handleLoad);
|
||||
window.addEventListener('saveDict', handleSave);
|
||||
window.addEventListener('tick', handleTick);
|
||||
window.addEventListener('param', handleParam);
|
||||
window.addEventListener('enum', handleEnum);
|
||||
window.addEventListener('tempo', handleBpm);
|
||||
window.addEventListener('timesig', handleTimeSig);
|
||||
window.addEventListener('userWave', handleChangeUserWave);
|
||||
window.addEventListener('maxTicks', handleMaxTicks);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('loadDict', handleLoad);
|
||||
@ -231,11 +232,11 @@ function MasterLfoHandler(){
|
||||
window.removeEventListener('tick', handleTick);
|
||||
window.removeEventListener('param', handleParam);
|
||||
window.removeEventListener('enum', handleEnum);
|
||||
window.removeEventListener('tempo', handleBpm);
|
||||
window.removeEventListener('timesig', handleTimeSig);
|
||||
window.removeEventListener('userWave', handleChangeUserWave);
|
||||
window.removeEventListener('maxTicks', handleMaxTicks);
|
||||
};
|
||||
}, [...allModArrays, ...allEnumArrays, ...allEnumMats, modCenterVals, render, bpm, beatsInMeasure]);
|
||||
}, [...allModArrays, ...allEnumArrays, ...allEnumMats, modCenterVals, render, beatsInMeasure, ticks]);
|
||||
|
||||
|
||||
function CheckLinked(inst, param, checkInstArr, checkParamArr){
|
||||
@ -432,14 +433,14 @@ if (!DEBUG){
|
||||
window.dispatchEvent(new CustomEvent('param', {'detail' : [inst, paramName, val]}));
|
||||
});
|
||||
|
||||
window.max.bindInlet("tempo", (val) => {
|
||||
window.dispatchEvent(new CustomEvent('tempo', {'detail' : val}));
|
||||
});
|
||||
|
||||
window.max.bindInlet("timesig", (top, bottom) => {
|
||||
window.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}));
|
||||
});
|
||||
|
@ -10,6 +10,11 @@ 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"];
|
||||
|
||||
const PhaseTypes = Object.freeze({
|
||||
MUSICAL: Symbol("musical"),
|
||||
TIME: Symbol("time")
|
||||
});
|
||||
|
||||
function ControlType(){
|
||||
return e('select', {className: 'control-type'}, Option("LFO"));
|
||||
}
|
||||
@ -61,7 +66,7 @@ function indexWave(type, phase, userDefinedWave){
|
||||
}
|
||||
}
|
||||
|
||||
function operateModulators(visibleArr, instanceNumArr, paramNames, centers, freqs, mins, maxs, waveTypes, phaseArr, userDefinedWave, currTime, bpm, beatsInMeasure){
|
||||
function operateModulators(visibleArr, instanceNumArr, paramNames, centers, freqs, mins, maxs, waveTypes, phaseArr, userDefinedWave, currTime, beatsInMeasure, ticks){
|
||||
for (let i=0; i<paramNames.length; i++){
|
||||
if (visibleArr[i]){
|
||||
|
||||
@ -71,18 +76,26 @@ function operateModulators(visibleArr, instanceNumArr, paramNames, centers, freq
|
||||
if (centers[inst].hasOwnProperty(name)){
|
||||
center = centers[inst][name];
|
||||
}
|
||||
let output = operateModulator(center, inst, freqs[i], mins[i], maxs[i], waveTypes[i], phaseArr, i, userDefinedWave, name, currTime, bpm, beatsInMeasure);
|
||||
let output = operateModulator(center, inst, freqs[i], mins[i], maxs[i], waveTypes[i], phaseArr, i, userDefinedWave, name, currTime, beatsInMeasure, ticks);
|
||||
if (name !== "NONE")
|
||||
window.dispatchEvent(new CustomEvent('enum', {'detail' : [inst, name, output]}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function operateModulator(center, inst, freq, min, max, waveType, phaseArr, phaseI, userDefinedWave, name, currTime, bpm, beatsInMeasure){
|
||||
let amp = parseFloat(max) - parseFloat(min);
|
||||
function operateModulator(center, inst, timeBaseStr, min, max, waveType, phaseArr, phaseI, userDefinedWave, name, currTime, beatsInMeasure, maxTicks){
|
||||
|
||||
freq = parseLfoTime(freq, bpm, beatsInMeasure);
|
||||
let phase = (currTime * freq + parseFloat(phaseArr[phaseI])) % 1.00;
|
||||
let amp = parseFloat(max) - parseFloat(min);
|
||||
let phaseType;
|
||||
let timeBase;
|
||||
|
||||
[timeBase, phaseType] = parseLfoTime(timeBaseStr, beatsInMeasure);
|
||||
let phase;
|
||||
|
||||
if (phaseType === PhaseTypes.TIME)
|
||||
phase = (currTime * timeBase + parseFloat(phaseArr[phaseI])) % 1.00;
|
||||
else if (phaseType === PhaseTypes.MUSICAL)
|
||||
phase = (maxTicks % timeBase) / timeBase;
|
||||
let unscaled = indexWave(waveType, phase, userDefinedWave);
|
||||
let el = document.getElementById(`slider-${inst}-${name}`);
|
||||
|
||||
@ -92,33 +105,30 @@ function operateModulator(center, inst, freq, min, max, waveType, phaseArr, phas
|
||||
return unscaled * amp + center + parseFloat(min);
|
||||
}
|
||||
|
||||
|
||||
function parseLfoTime(lfoTime, bpm, beatsInMeasure){
|
||||
// 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));
|
||||
return [parseFloat(lfoTime.slice(0, -2)), PhaseTypes.TIME];
|
||||
}
|
||||
else if (lfoTime.slice(-2) == "ms"){
|
||||
return 1000 / parseFloat(lfoTime.slice(0, -2));
|
||||
return [1000 / parseFloat(lfoTime.slice(0, -2)), PhaseTypes.TIME];
|
||||
}
|
||||
else if (lfoTime.slice(-1) == "s"){
|
||||
return 1 / parseFloat(lfoTime.slice(0, -1));
|
||||
return [1 / parseFloat(lfoTime.slice(0, -1)), PhaseTypes.TIME];
|
||||
}
|
||||
else if ((lfoTime.match(/:/g) || []).length == 2){
|
||||
return 1 / moment.duration(lfoTime).asSeconds();
|
||||
return [1 / moment.duration(lfoTime).asSeconds(), PhaseTypes.TIME];
|
||||
}
|
||||
else if ((lfoTime.match(/\./g) || []).length == 2){
|
||||
return musicalTimingToFreq(...lfoTime.split('.'), bpm, beatsInMeasure)
|
||||
return [musicalTimingToFreq(...lfoTime.split('.'), beatsInMeasure), PhaseTypes.MUSICAL];
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
return [0, PhaseTypes.TIME];
|
||||
}
|
||||
}
|
||||
|
||||
function musicalTimingToFreq(bars, beats, ticks, bpm, beatsInMeasure){
|
||||
let totalTicks = (parseFloat(bars) * parseFloat(beatsInMeasure) + beats) * 480 + parseFloat(ticks);
|
||||
let tpm = bpm * 480;
|
||||
let cyclesPerMinute = tpm / totalTicks;
|
||||
let hz = cyclesPerMinute / 60;
|
||||
return hz;
|
||||
function musicalTimingToFreq(bars, beats, ticks, beatsInMeasure){
|
||||
let totalTicks = (parseFloat(bars) * parseFloat(beatsInMeasure) + parseFloat(beats)) * 480 + parseFloat(ticks);
|
||||
return totalTicks;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user