From b9a0c35ccbe68e62f0cad1ae8bb5b022cca5dafe Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Mon, 13 Jul 2026 08:43:43 +0200 Subject: [PATCH] Update Simpler device building logic for better compatibility and feature parity --- src/lib/exporters/ableton/builders.ts | 87 ++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 14 deletions(-) diff --git a/src/lib/exporters/ableton/builders.ts b/src/lib/exporters/ableton/builders.ts index f5c75fe..20a16f9 100644 --- a/src/lib/exporters/ableton/builders.ts +++ b/src/lib/exporters/ableton/builders.ts @@ -20,6 +20,14 @@ import { buildClipEnvelopes, getFaderValueAt, } from './automation'; +import { + chorusEffectValues, + compressorEffectValues, + delayEffectValues, + distortionEffectValues, + filterEffectValues, + reverbEffectValues, +} from './effects'; import { ALSDrumBranch } from './types/drumBranch'; import { ALSDrumRack } from './types/drumRack'; import { ALSChorus } from './types/effectChorus'; @@ -59,6 +67,11 @@ function getAbletonVersion(exporterParams: ExporterParams): AbletonVersion { return exporterParams.abletonVersion === '10' ? '10' : '11'; } +function simplerEnvelopeMilliseconds(value: number, soundLength: number, oneshot: boolean) { + const milliseconds = koEnvRangeToSeconds(value, soundLength) * 1000; + return oneshot ? Math.min(2000, milliseconds) : milliseconds; +} + function setColorValue(node: any, value: number) { const color = node.Color || node.ColorIndex; color['@Value'] = value; @@ -323,8 +336,30 @@ async function buildMidiClip( async function buildSimplerDevice(koTrack: AblTrack, abletonVersion: AbletonVersion) { const simplerTemplate = await loadTemplate('simpler', abletonVersion); const device = structuredClone(simplerTemplate.OriginalSimpler); + const oneshot = koTrack.playMode === 'oneshot'; + const samplePart = device.Player.MultiSampleMap.SampleParts.MultiSamplePart; + const loopModulators = device.Player.LoopModulators; + const simplerFilter = device.Filter.Slot.Value.SimplerFilter; device.LastPresetRef.Value = {}; + device.ShouldShowPresetName['@Value'] = 'false'; + device.UserName['@Value'] = ''; + loopModulators.SampleStart.Manual['@Value'] = 0; + loopModulators.SampleLength.Manual['@Value'] = 1; + loopModulators.LoopOn.Manual['@Value'] = 'false'; + loopModulators.LoopLength.Manual['@Value'] = 1; + loopModulators.LoopFade.Manual['@Value'] = 0; + device.Filter.IsOn.Manual['@Value'] = 'false'; + simplerFilter.Freq.Manual['@Value'] = 22000; + simplerFilter.Res.Manual['@Value'] = 0; + simplerFilter.Envelope.IsOn.Manual['@Value'] = 'false'; + simplerFilter.Envelope.Amount.Manual['@Value'] = 0; + simplerFilter.ModByLfo.Manual['@Value'] = 0; + device.Lfo.IsOn.Manual['@Value'] = 'false'; + device.Pitch.PitchLfoAmount.Manual['@Value'] = 0; + device.VolumeAndPan.OneShotEnvelope.FadeInTime.Manual['@Value'] = 0; + device.VolumeAndPan.OneShotEnvelope.FadeOutTime.Manual['@Value'] = 0; + device.VolumeAndPan.OneShotEnvelope.SustainMode.Manual['@Value'] = 0; switch (koTrack.playMode) { case 'legato': device.Globals.PlaybackMode['@Value'] = 0; @@ -355,36 +390,60 @@ async function buildSimplerDevice(koTrack: AblTrack, abletonVersion: AbletonVers if (sampleRef.DefaultSampleRate) { sampleRef.DefaultSampleRate['@Value'] = koTrack.sampleRate; } - device.Player.MultiSampleMap.SampleParts.MultiSamplePart.Name['@Value'] = koTrack.name; - device.Player.MultiSampleMap.SampleParts.MultiSamplePart.RootKey['@Value'] = koTrack.rootNote; - device.Player.MultiSampleMap.SampleParts.MultiSamplePart.SampleStart['@Value'] = koTrack.trimLeft; - device.Player.MultiSampleMap.SampleParts.MultiSamplePart.SampleEnd['@Value'] = koTrack.trimRight; - device.Player.MultiSampleMap.SampleParts.MultiSamplePart.SampleWarpProperties.TimeSignature.TimeSignatures.RemoteableTimeSignature.Numerator[ + samplePart.Name['@Value'] = koTrack.name; + samplePart.RootKey['@Value'] = koTrack.rootNote; + samplePart.SampleStart['@Value'] = koTrack.trimLeft; + samplePart.SampleEnd['@Value'] = koTrack.trimRight; + samplePart.SustainLoop.Start['@Value'] = koTrack.trimLeft; + samplePart.SustainLoop.End['@Value'] = koTrack.trimRight; + samplePart.SustainLoop.Mode['@Value'] = 0; + samplePart.SustainLoop.Crossfade['@Value'] = 0; + samplePart.ReleaseLoop.Start['@Value'] = 0; + samplePart.ReleaseLoop.End['@Value'] = 0; + samplePart.SampleWarpProperties.TimeSignature.TimeSignatures.RemoteableTimeSignature.Numerator[ '@Value' ] = koTrack.timeSignature.numerator; - device.Player.MultiSampleMap.SampleParts.MultiSamplePart.SampleWarpProperties.TimeSignature.TimeSignatures.RemoteableTimeSignature.Denominator[ + samplePart.SampleWarpProperties.TimeSignature.TimeSignatures.RemoteableTimeSignature.Denominator[ '@Value' ] = koTrack.timeSignature.denominator; // setting velocity scaling to 20% to match KO behavior device.VolumeAndPan.VolumeVelScale.Manual['@Value'] = 0.2; - device.VolumeAndPan.Envelope.ReleaseTime.Manual['@Value'] = - koEnvRangeToSeconds(koTrack.release, koTrack.soundLength) * 1000; - device.VolumeAndPan.Envelope.AttackTime.Manual['@Value'] = - koEnvRangeToSeconds(koTrack.attack, koTrack.soundLength) * 1000; + const attackTarget = oneshot + ? device.VolumeAndPan.OneShotEnvelope.FadeInTime + : device.VolumeAndPan.Envelope.AttackTime; + const releaseTarget = oneshot + ? device.VolumeAndPan.OneShotEnvelope.FadeOutTime + : device.VolumeAndPan.Envelope.ReleaseTime; + attackTarget.Manual['@Value'] = simplerEnvelopeMilliseconds( + koTrack.attack, + koTrack.soundLength, + oneshot, + ); + releaseTarget.Manual['@Value'] = simplerEnvelopeMilliseconds( + koTrack.release, + koTrack.soundLength, + oneshot, + ); device.VolumeAndPan.Panorama.Manual['@Value'] = koTrack.pan; // overriding attack time if ATK fader param is defined if (koTrack.faderParams[FaderParam.ATK] !== -1) { - device.VolumeAndPan.Envelope.AttackTime.Manual['@Value'] = - koEnvRangeToSeconds(koTrack.faderParams[FaderParam.ATK] * 255, koTrack.soundLength) * 1000; + attackTarget.Manual['@Value'] = simplerEnvelopeMilliseconds( + koTrack.faderParams[FaderParam.ATK] * 255, + koTrack.soundLength, + oneshot, + ); } // overriding release time if REL fader param is defined if (koTrack.faderParams[FaderParam.REL] !== -1) { - device.VolumeAndPan.Envelope.ReleaseTime.Manual['@Value'] = - koEnvRangeToSeconds(koTrack.faderParams[FaderParam.REL] * 255, koTrack.soundLength) * 1000; + releaseTarget.Manual['@Value'] = simplerEnvelopeMilliseconds( + koTrack.faderParams[FaderParam.REL] * 255, + koTrack.soundLength, + oneshot, + ); } let pitch = koTrack.pitch || 0;