From 2f36da8f4d31f7bd42e9ea0afa3e5e6757a03575 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Mon, 13 Jul 2026 08:42:33 +0200 Subject: [PATCH] Add effect value calculation functions for Ableton export --- src/lib/exporters/ableton/effects.ts | 64 ++++++++++++++++++++++ src/lib/exporters/ableton/types/simpler.ts | 6 +- 2 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 src/lib/exporters/ableton/effects.ts diff --git a/src/lib/exporters/ableton/effects.ts b/src/lib/exporters/ableton/effects.ts new file mode 100644 index 0000000..d5b9924 --- /dev/null +++ b/src/lib/exporters/ableton/effects.ts @@ -0,0 +1,64 @@ +type AbletonVersion = '10' | '11'; + +function normalized(value: number) { + return Math.max(0, Math.min(1, value)); +} + +export function delayEffectValues(x: number, y: number) { + const length = normalized(x); + return { + time: Math.max(0.001, 0.017397 * (287.725 ** length - 1)), + feedback: normalized(y) * 0.95, + }; +} + +export function reverbEffectValues(x: number, y: number) { + const color = normalized(y); + const dark = Math.max(0, (0.5 - color) * 2); + const bright = Math.max(0, (color - 0.5) * 2); + return { + decayTime: 200 + normalized(x) * 7800, + highShelfOn: dark > 0, + highShelfGain: 1 - dark * 0.8, + lowShelfOn: bright > 0, + lowShelfGain: 1 - bright * 0.8, + }; +} + +export function distortionEffectValues(x: number, y: number) { + return { + drive: normalized(x) * 100, + tone: normalized(y) * 100, + }; +} + +export function chorusEffectValues(x: number, y: number, abletonVersion: AbletonVersion) { + const rateMin = abletonVersion === '10' ? 0.03 : 0.1; + const rateMax = abletonVersion === '10' ? 10 : 15; + return { + rate: rateMin * (rateMax / rateMin) ** normalized(x), + amount: abletonVersion === '10' ? 3.25 : 0.5, + feedback: normalized(y) * (abletonVersion === '10' ? 0.95 : 0.99), + }; +} + +export function filterEffectValues(x: number, y: number) { + const cutoff = normalized(x); + const highPass = cutoff > 0.5; + return { + filterType: highPass ? 1 : 0, + cutoff: highPass ? 20 + (cutoff - 0.5) * 230 : 20 + cutoff * 230, + resonance: normalized(y) * 1.25, + }; +} + +export function compressorEffectValues(x: number, y: number) { + const drive = normalized(x); + const speed = normalized(y); + return { + threshold: 10 ** ((-6 - drive * 30) / 20), + ratio: 4, + attack: 30 * (0.1 / 30) ** speed, + release: 300 * (30 / 300) ** speed, + }; +} diff --git a/src/lib/exporters/ableton/types/simpler.ts b/src/lib/exporters/ableton/types/simpler.ts index f4526aa..257cdb4 100644 --- a/src/lib/exporters/ableton/types/simpler.ts +++ b/src/lib/exporters/ableton/types/simpler.ts @@ -187,7 +187,7 @@ interface MultiSampleMap { RoundRobinRandomSeed: ValueElement; } -interface LoopModulator { +interface LoopModulators { IsModulated: ValueElement; SampleStart: ManualElement; SampleLength: ManualElement; @@ -196,10 +196,6 @@ interface LoopModulator { LoopFade: ManualElement; } -interface LoopModulators { - LoopModulator: LoopModulator; -} - interface Player { MultiSampleMap: MultiSampleMap; LoopModulators: LoopModulators;