Update Ableton effect parameter mapping and refactor value calculation logic across multiple effects (Reverb, Delay, Distortion, Chorus, Filter, Compressor).
This commit is contained in:
@@ -978,14 +978,22 @@ async function buildReturnTrack(
|
|||||||
if (projectData.effects.effectType === EffectType.Reverb) {
|
if (projectData.effects.effectType === EffectType.Reverb) {
|
||||||
const effectReverbTemplate = await loadTemplate<ALSReverb>('effectReverb', abletonVersion);
|
const effectReverbTemplate = await loadTemplate<ALSReverb>('effectReverb', abletonVersion);
|
||||||
const effectReverb = structuredClone(effectReverbTemplate.Reverb);
|
const effectReverb = structuredClone(effectReverbTemplate.Reverb);
|
||||||
|
const values = reverbEffectValues(projectData.effects.param1, projectData.effects.param2);
|
||||||
|
|
||||||
// these params are very rough approximation of the KO's reverb
|
// these params are very rough approximation of the KO's reverb
|
||||||
// it's not exact, but close enough
|
// it's not exact, but close enough
|
||||||
effectReverb.PreDelay.Manual['@Value'] = 0.5;
|
effectReverb.PreDelay.Manual['@Value'] = 0.5;
|
||||||
effectReverb.RoomSize.Manual['@Value'] = 300;
|
effectReverb.RoomSize.Manual['@Value'] = 300;
|
||||||
effectReverb.ShelfHiFreq.Manual['@Value'] = 1000;
|
effectReverb.ShelfHiFreq.Manual['@Value'] = 1000;
|
||||||
effectReverb.DecayTime.Manual['@Value'] = projectData.effects.param1 * 8000; // max 8 seconds which is kinda close to how it sounds in KO
|
effectReverb.ShelfLoFreq.Manual['@Value'] = 1000;
|
||||||
effectReverb.ShelfHiGain.Manual['@Value'] = projectData.effects.param2; // param2 is "color" which roughly matches the high shelf gain cut amount
|
effectReverb.DecayTime.Manual['@Value'] = values.decayTime;
|
||||||
|
effectReverb.ShelfHighOn.Manual['@Value'] = values.highShelfOn ? 'true' : 'false';
|
||||||
|
effectReverb.ShelfHiGain.Manual['@Value'] = values.highShelfGain;
|
||||||
|
effectReverb.ShelfLowOn.Manual['@Value'] = values.lowShelfOn ? 'true' : 'false';
|
||||||
|
effectReverb.ShelfLoGain.Manual['@Value'] = values.lowShelfGain;
|
||||||
|
effectReverb.MixReflect.Manual['@Value'] = 1;
|
||||||
|
effectReverb.MixDiffuse.Manual['@Value'] = 1;
|
||||||
|
effectReverb.MixDirect.Manual['@Value'] = 0;
|
||||||
|
|
||||||
returnTrack.DeviceChain.DeviceChain.Devices = { Reverb: effectReverb };
|
returnTrack.DeviceChain.DeviceChain.Devices = { Reverb: effectReverb };
|
||||||
}
|
}
|
||||||
@@ -993,15 +1001,16 @@ async function buildReturnTrack(
|
|||||||
if (projectData.effects.effectType === EffectType.Delay) {
|
if (projectData.effects.effectType === EffectType.Delay) {
|
||||||
const effectDelayTemplate = await loadTemplate<ALSDelay>('effectDelay', abletonVersion);
|
const effectDelayTemplate = await loadTemplate<ALSDelay>('effectDelay', abletonVersion);
|
||||||
const effectDelay = structuredClone(effectDelayTemplate.Delay);
|
const effectDelay = structuredClone(effectDelayTemplate.Delay);
|
||||||
|
const values = delayEffectValues(projectData.effects.param1, projectData.effects.param2);
|
||||||
|
|
||||||
effectDelay.DelayLine_SyncL.Manual['@Value'] = 'false';
|
effectDelay.DelayLine_SyncL.Manual['@Value'] = 'false';
|
||||||
effectDelay.DelayLine_SyncR.Manual['@Value'] = 'false';
|
effectDelay.DelayLine_SyncR.Manual['@Value'] = 'false';
|
||||||
// don't even ask how I came up with this formula
|
// don't even ask how I came up with this formula
|
||||||
effectDelay.DelayLine_TimeL.Manual['@Value'] =
|
effectDelay.DelayLine_TimeL.Manual['@Value'] = values.time;
|
||||||
0.017397 * (287.725 ** projectData.effects.param1 - 1);
|
effectDelay.DelayLine_TimeR.Manual['@Value'] = values.time;
|
||||||
effectDelay.DelayLine_TimeR.Manual['@Value'] =
|
effectDelay.Feedback.Manual['@Value'] = values.feedback;
|
||||||
0.017397 * (287.725 ** projectData.effects.param1 - 1);
|
effectDelay.Filter_On.Manual['@Value'] = 'false';
|
||||||
effectDelay.Feedback.Manual['@Value'] = projectData.effects.param2;
|
effectDelay.DryWet.Manual['@Value'] = 1;
|
||||||
|
|
||||||
returnTrack.DeviceChain.DeviceChain.Devices = { Delay: effectDelay };
|
returnTrack.DeviceChain.DeviceChain.Devices = { Delay: effectDelay };
|
||||||
}
|
}
|
||||||
@@ -1012,9 +1021,11 @@ async function buildReturnTrack(
|
|||||||
abletonVersion,
|
abletonVersion,
|
||||||
);
|
);
|
||||||
const effectDistortion = structuredClone(effectDistortionTemplate.Overdrive);
|
const effectDistortion = structuredClone(effectDistortionTemplate.Overdrive);
|
||||||
|
const values = distortionEffectValues(projectData.effects.param1, projectData.effects.param2);
|
||||||
|
|
||||||
effectDistortion.Drive.Manual['@Value'] = projectData.effects.param1 * 50;
|
effectDistortion.Drive.Manual['@Value'] = values.drive;
|
||||||
effectDistortion.Tone.Manual['@Value'] = projectData.effects.param2 * 100;
|
effectDistortion.Tone.Manual['@Value'] = values.tone;
|
||||||
|
effectDistortion.DryWet.Manual['@Value'] = 100;
|
||||||
|
|
||||||
returnTrack.DeviceChain.DeviceChain.Devices = { Overdrive: effectDistortion };
|
returnTrack.DeviceChain.DeviceChain.Devices = { Overdrive: effectDistortion };
|
||||||
}
|
}
|
||||||
@@ -1024,13 +1035,16 @@ async function buildReturnTrack(
|
|||||||
const effectChorus = structuredClone(
|
const effectChorus = structuredClone(
|
||||||
abletonVersion === '10' ? (effectChorusTemplate as any).Chorus : effectChorusTemplate.Chorus2,
|
abletonVersion === '10' ? (effectChorusTemplate as any).Chorus : effectChorusTemplate.Chorus2,
|
||||||
);
|
);
|
||||||
|
const values = chorusEffectValues(projectData.effects.param1, projectData.effects.param2);
|
||||||
|
|
||||||
if (abletonVersion === '10') {
|
if (abletonVersion === '10') {
|
||||||
effectChorus.ModAmount.Manual['@Value'] = projectData.effects.param1 * 6.5;
|
effectChorus.ModFreq.Manual['@Value'] = values.rate;
|
||||||
|
effectChorus.LfoMultiplier.Manual['@Value'] = 'false';
|
||||||
} else {
|
} else {
|
||||||
effectChorus.Amount.Manual['@Value'] = projectData.effects.param1;
|
effectChorus.Rate.Manual['@Value'] = values.rate;
|
||||||
}
|
}
|
||||||
effectChorus.Feedback.Manual['@Value'] = projectData.effects.param2 * 0.8;
|
effectChorus.Feedback.Manual['@Value'] = values.feedback;
|
||||||
|
effectChorus.DryWet.Manual['@Value'] = 1;
|
||||||
|
|
||||||
returnTrack.DeviceChain.DeviceChain.Devices = (
|
returnTrack.DeviceChain.DeviceChain.Devices = (
|
||||||
abletonVersion === '10' ? { Chorus: effectChorus } : { Chorus2: effectChorus }
|
abletonVersion === '10' ? { Chorus: effectChorus } : { Chorus2: effectChorus }
|
||||||
@@ -1041,9 +1055,12 @@ async function buildReturnTrack(
|
|||||||
if (projectData.effects.effectType === EffectType.Filter) {
|
if (projectData.effects.effectType === EffectType.Filter) {
|
||||||
const effectFilterTemplate = await loadTemplate<ALSFilter>('effectFilter', abletonVersion);
|
const effectFilterTemplate = await loadTemplate<ALSFilter>('effectFilter', abletonVersion);
|
||||||
const effectFilter = structuredClone(effectFilterTemplate.AutoFilter);
|
const effectFilter = structuredClone(effectFilterTemplate.AutoFilter);
|
||||||
|
const values = filterEffectValues(projectData.effects.param1, projectData.effects.param2);
|
||||||
|
|
||||||
effectFilter.Cutoff.Manual['@Value'] = 20 + projectData.effects.param1 * (135 - 20);
|
effectFilter.FilterType.Manual['@Value'] = values.filterType;
|
||||||
effectFilter.Resonance.Manual['@Value'] = projectData.effects.param2 * 1.25;
|
effectFilter.LegacyFilterType.Manual['@Value'] = values.filterType;
|
||||||
|
effectFilter.Cutoff.Manual['@Value'] = values.cutoff;
|
||||||
|
effectFilter.Resonance.Manual['@Value'] = values.resonance;
|
||||||
|
|
||||||
returnTrack.DeviceChain.DeviceChain.Devices = { AutoFilter: effectFilter };
|
returnTrack.DeviceChain.DeviceChain.Devices = { AutoFilter: effectFilter };
|
||||||
}
|
}
|
||||||
@@ -1054,8 +1071,19 @@ async function buildReturnTrack(
|
|||||||
abletonVersion,
|
abletonVersion,
|
||||||
);
|
);
|
||||||
const effectCompressor = structuredClone(effectCompressorTemplate.Compressor2);
|
const effectCompressor = structuredClone(effectCompressorTemplate.Compressor2);
|
||||||
|
const values = compressorEffectValues(projectData.effects.param1, projectData.effects.param2);
|
||||||
|
|
||||||
// params are ignored for now, just putting a basic compressor
|
effectCompressor.Threshold.Manual['@Value'] = values.threshold;
|
||||||
|
effectCompressor.Ratio.Manual['@Value'] = values.ratio;
|
||||||
|
effectCompressor.Attack.Manual['@Value'] = values.attack;
|
||||||
|
effectCompressor.Release.Manual['@Value'] = values.release;
|
||||||
|
effectCompressor.AutoReleaseControlOnOff.Manual['@Value'] = 'false';
|
||||||
|
effectCompressor.Gain.Manual['@Value'] = 0;
|
||||||
|
effectCompressor.GainCompensation.Manual['@Value'] = 'true';
|
||||||
|
effectCompressor.DryWet.Manual['@Value'] = 1;
|
||||||
|
effectCompressor.Model.Manual['@Value'] = 0;
|
||||||
|
effectCompressor.Knee.Manual['@Value'] = 6;
|
||||||
|
effectCompressor.LookAhead.Manual['@Value'] = 0;
|
||||||
|
|
||||||
returnTrack.DeviceChain.DeviceChain.Devices = { Compressor2: effectCompressor };
|
returnTrack.DeviceChain.DeviceChain.Devices = { Compressor2: effectCompressor };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
type AbletonVersion = '10' | '11';
|
|
||||||
|
|
||||||
function normalized(value: number) {
|
function normalized(value: number) {
|
||||||
return Math.max(0, Math.min(1, value));
|
return Math.max(0, Math.min(1, value));
|
||||||
}
|
}
|
||||||
@@ -32,7 +30,7 @@ export function distortionEffectValues(x: number, y: number) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function chorusEffectValues(x: number, y: number, _abletonVersion: AbletonVersion) {
|
export function chorusEffectValues(x: number, y: number) {
|
||||||
return {
|
return {
|
||||||
rate: 0.1 * 100 ** normalized(x),
|
rate: 0.1 * 100 ** normalized(x),
|
||||||
feedback: normalized(y) * 0.95,
|
feedback: normalized(y) * 0.95,
|
||||||
|
|||||||
Reference in New Issue
Block a user