Enhance Ableton exporter by incorporating automated fader parameter handling and default value logic

This commit is contained in:
2026-07-14 11:26:26 +02:00
parent e8f75c6b39
commit e2a142b547

View File

@@ -30,7 +30,7 @@ import {
filterEffectValues,
reverbEffectValues,
} from './effects';
import { convertGroupFaderValue } from './faderPolicies';
import { convertGroupFaderValue, getFaderDefaultValue } from './faderPolicies';
import { AbletonMidiControllerTargets, buildMidiClipEnvelopes } from './midi';
import { getPadEnvelopeState, getPadSoundState } from './padSound';
import { getSimplerPlaybackState } from './playback';
@@ -545,7 +545,11 @@ async function buildFaderFilterDevice(
return { AutoFilter: filter };
}
async function buildDrumRackDevice(koTrack: AblTrack, abletonVersion: AbletonVersion) {
async function buildDrumRackDevice(
koTrack: AblTrack,
abletonVersion: AbletonVersion,
automatedParameters: ReadonlySet<FaderParam>,
) {
const [drumRackTemplate, drumBranchTemplate] = await Promise.all([
loadTemplate<ALSDrumRack>('drumRack', abletonVersion),
loadTemplate<ALSDrumBranch>('drumBranch', abletonVersion),
@@ -579,7 +583,11 @@ async function buildDrumRackDevice(koTrack: AblTrack, abletonVersion: AbletonVer
drumBranch.BranchInfo.ChokeGroup['@Value'] = subtrack.inChokeGroup ? 1 : 0;
drumBranch.MixerDevice.Volume.Manual['@Value'] = subtrack.volume;
drumBranch.MixerDevice.SendInfos = {};
const branchDevices = await buildSimplerDevice(subtrack, abletonVersion);
const branchDevices = await buildSimplerDevice(
subtrack,
abletonVersion,
automatedParameters,
);
assignDeviceListIds([branchDevices]);
drumBranch.DeviceChain.MidiToAudioDeviceChain.Devices = branchDevices;
@@ -601,6 +609,11 @@ async function buildTrack(
const abletonVersion = getAbletonVersion(exporterParams);
const midiTrackTemplate = await loadTemplate<ALSMidiTrack>('midiTrack', abletonVersion);
const midiTrack = structuredClone(midiTrackTemplate.MidiTrack);
const automatedParameters = new Set(
[...(groupLane?.sessionPatterns || []), ...(groupLane?.arrangementPatterns || [])].flatMap(
(pattern) => pattern.faderAutomation.map((point) => point.parameter),
),
);
midiTrack['@Id'] = _localId++;
midiTrack.Name.EffectiveName['@Value'] = koTrack.soundId
@@ -615,40 +628,44 @@ async function buildTrack(
midiTrack.DeviceChain.Mixer.Volume.Manual['@Value'] = koTrack.volume;
if (koTrack.faderParams[FaderParam.PAN] !== -1) {
midiTrack.DeviceChain.Mixer.Pan.Manual['@Value'] =
(koTrack.faderParams[FaderParam.PAN] - 0.5) * 2;
midiTrack.DeviceChain.Mixer.Pan.Manual['@Value'] = convertGroupFaderValue(
FaderParam.PAN,
koTrack.faderParams[FaderParam.PAN],
{ track: koTrack },
);
}
if (koTrack.faderParams[FaderParam.LVL] !== -1) {
midiTrack.DeviceChain.Mixer.Volume.Manual['@Value'] =
koTrack.volume * koTrack.faderParams[FaderParam.LVL];
midiTrack.DeviceChain.Mixer.Volume.Manual['@Value'] = convertGroupFaderValue(
FaderParam.LVL,
koTrack.faderParams[FaderParam.LVL],
{ track: koTrack },
);
}
if (koTrack.drumRack && exporterParams.includeArchivedSamples) {
midiTrack.DeviceChain.DeviceChain.Devices['#'].push(
await buildDrumRackDevice(koTrack, abletonVersion),
await buildDrumRackDevice(koTrack, abletonVersion, automatedParameters),
);
}
if (!koTrack.drumRack && koTrack.sampleName && exporterParams.includeArchivedSamples) {
midiTrack.DeviceChain.DeviceChain.Devices['#'].push(
await buildSimplerDevice(koTrack, abletonVersion),
await buildSimplerDevice(koTrack, abletonVersion, automatedParameters),
);
}
if (exporterParams.includeArchivedSamples) {
for (const parameter of [FaderParam.LPF, FaderParam.HPF] as const) {
const staticValue = koTrack.faderParams[parameter];
const defaultValue = parameter === FaderParam.LPF ? 1 : 0;
const hasAutomation = [
...(groupLane?.sessionPatterns || []),
...(groupLane?.arrangementPatterns || []),
].some((pattern) => pattern.faderAutomation.some((point) => point.parameter === parameter));
const defaultValue = getFaderDefaultValue(parameter);
const hasAutomation = automatedParameters.has(parameter);
if (hasAutomation || (staticValue !== -1 && staticValue !== defaultValue)) {
midiTrack.DeviceChain.DeviceChain.Devices['#'].push(
await buildFaderFilterDevice(
parameter,
staticValue === -1 ? defaultValue : staticValue,
koTrack,
abletonVersion,
),
);
@@ -671,7 +688,11 @@ async function buildTrack(
);
const trackSendHolder = structuredClone(trackSendHolderTemplate.TrackSendHolder);
trackSendHolder['@Id'] = 0;
trackSendHolder.Send.Manual['@Value'] = Math.max(0, koTrack.faderParams[FaderParam.FX]);
trackSendHolder.Send.Manual['@Value'] = convertGroupFaderValue(
FaderParam.FX,
Math.max(getFaderDefaultValue(FaderParam.FX), koTrack.faderParams[FaderParam.FX]),
{ track: koTrack },
);
midiTrack.DeviceChain.Mixer.Sends.TrackSendHolder = trackSendHolder;
}