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) {
|
||||
const effectReverbTemplate = await loadTemplate<ALSReverb>('effectReverb', abletonVersion);
|
||||
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
|
||||
// it's not exact, but close enough
|
||||
effectReverb.PreDelay.Manual['@Value'] = 0.5;
|
||||
effectReverb.RoomSize.Manual['@Value'] = 300;
|
||||
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.ShelfHiGain.Manual['@Value'] = projectData.effects.param2; // param2 is "color" which roughly matches the high shelf gain cut amount
|
||||
effectReverb.ShelfLoFreq.Manual['@Value'] = 1000;
|
||||
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 };
|
||||
}
|
||||
@@ -993,15 +1001,16 @@ async function buildReturnTrack(
|
||||
if (projectData.effects.effectType === EffectType.Delay) {
|
||||
const effectDelayTemplate = await loadTemplate<ALSDelay>('effectDelay', abletonVersion);
|
||||
const effectDelay = structuredClone(effectDelayTemplate.Delay);
|
||||
const values = delayEffectValues(projectData.effects.param1, projectData.effects.param2);
|
||||
|
||||
effectDelay.DelayLine_SyncL.Manual['@Value'] = 'false';
|
||||
effectDelay.DelayLine_SyncR.Manual['@Value'] = 'false';
|
||||
// don't even ask how I came up with this formula
|
||||
effectDelay.DelayLine_TimeL.Manual['@Value'] =
|
||||
0.017397 * (287.725 ** projectData.effects.param1 - 1);
|
||||
effectDelay.DelayLine_TimeR.Manual['@Value'] =
|
||||
0.017397 * (287.725 ** projectData.effects.param1 - 1);
|
||||
effectDelay.Feedback.Manual['@Value'] = projectData.effects.param2;
|
||||
effectDelay.DelayLine_TimeL.Manual['@Value'] = values.time;
|
||||
effectDelay.DelayLine_TimeR.Manual['@Value'] = values.time;
|
||||
effectDelay.Feedback.Manual['@Value'] = values.feedback;
|
||||
effectDelay.Filter_On.Manual['@Value'] = 'false';
|
||||
effectDelay.DryWet.Manual['@Value'] = 1;
|
||||
|
||||
returnTrack.DeviceChain.DeviceChain.Devices = { Delay: effectDelay };
|
||||
}
|
||||
@@ -1012,9 +1021,11 @@ async function buildReturnTrack(
|
||||
abletonVersion,
|
||||
);
|
||||
const effectDistortion = structuredClone(effectDistortionTemplate.Overdrive);
|
||||
const values = distortionEffectValues(projectData.effects.param1, projectData.effects.param2);
|
||||
|
||||
effectDistortion.Drive.Manual['@Value'] = projectData.effects.param1 * 50;
|
||||
effectDistortion.Tone.Manual['@Value'] = projectData.effects.param2 * 100;
|
||||
effectDistortion.Drive.Manual['@Value'] = values.drive;
|
||||
effectDistortion.Tone.Manual['@Value'] = values.tone;
|
||||
effectDistortion.DryWet.Manual['@Value'] = 100;
|
||||
|
||||
returnTrack.DeviceChain.DeviceChain.Devices = { Overdrive: effectDistortion };
|
||||
}
|
||||
@@ -1024,13 +1035,16 @@ async function buildReturnTrack(
|
||||
const effectChorus = structuredClone(
|
||||
abletonVersion === '10' ? (effectChorusTemplate as any).Chorus : effectChorusTemplate.Chorus2,
|
||||
);
|
||||
const values = chorusEffectValues(projectData.effects.param1, projectData.effects.param2);
|
||||
|
||||
if (abletonVersion === '10') {
|
||||
effectChorus.ModAmount.Manual['@Value'] = projectData.effects.param1 * 6.5;
|
||||
effectChorus.ModFreq.Manual['@Value'] = values.rate;
|
||||
effectChorus.LfoMultiplier.Manual['@Value'] = 'false';
|
||||
} 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 = (
|
||||
abletonVersion === '10' ? { Chorus: effectChorus } : { Chorus2: effectChorus }
|
||||
@@ -1041,9 +1055,12 @@ async function buildReturnTrack(
|
||||
if (projectData.effects.effectType === EffectType.Filter) {
|
||||
const effectFilterTemplate = await loadTemplate<ALSFilter>('effectFilter', abletonVersion);
|
||||
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.Resonance.Manual['@Value'] = projectData.effects.param2 * 1.25;
|
||||
effectFilter.FilterType.Manual['@Value'] = values.filterType;
|
||||
effectFilter.LegacyFilterType.Manual['@Value'] = values.filterType;
|
||||
effectFilter.Cutoff.Manual['@Value'] = values.cutoff;
|
||||
effectFilter.Resonance.Manual['@Value'] = values.resonance;
|
||||
|
||||
returnTrack.DeviceChain.DeviceChain.Devices = { AutoFilter: effectFilter };
|
||||
}
|
||||
@@ -1054,8 +1071,19 @@ async function buildReturnTrack(
|
||||
abletonVersion,
|
||||
);
|
||||
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 };
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
type AbletonVersion = '10' | '11';
|
||||
|
||||
function normalized(value: number) {
|
||||
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 {
|
||||
rate: 0.1 * 100 ** normalized(x),
|
||||
feedback: normalized(y) * 0.95,
|
||||
|
||||
Reference in New Issue
Block a user