Add comprehensive automation target extraction for Ableton export

This commit is contained in:
2026-07-13 04:59:40 +02:00
parent b75d4d23d4
commit 5dab4233e2

View File

@@ -7,7 +7,12 @@ import {
ProjectSettings, ProjectSettings,
} from '../../../types/types'; } from '../../../types/types';
import { EFFECTS } from '../../constants'; import { EFFECTS } from '../../constants';
import abletonTransformer, { AblClip, AblScene, AblTrack } from '../../transformers/ableton'; import abletonTransformer, {
AblClip,
AblGroupLane,
AblScene,
AblTrack,
} from '../../transformers/ableton';
import { getQuarterNotesPerBar } from '../utils'; import { getQuarterNotesPerBar } from '../utils';
import { ALSDrumBranch } from './types/drumBranch'; import { ALSDrumBranch } from './types/drumBranch';
import { ALSDrumRack } from './types/drumRack'; import { ALSDrumRack } from './types/drumRack';
@@ -25,6 +30,12 @@ import { ALSReturnTrack } from './types/returnTrack';
import { ALSScene, ALSSceneContent } from './types/scene'; import { ALSScene, ALSSceneContent } from './types/scene';
import { ALSSimpler } from './types/simpler'; import { ALSSimpler } from './types/simpler';
import { ALSTrackSendHolder } from './types/trackSendHolder'; import { ALSTrackSendHolder } from './types/trackSendHolder';
import {
AbletonAutomationTargets,
buildArrangementEnvelopes,
buildClipEnvelopes,
getFaderValueAt,
} from './automation';
import { import {
filterFreqFromNormalized, filterFreqFromNormalized,
fixIds, fixIds,
@@ -82,6 +93,94 @@ function setLive10SampleReference(fileRef: any, sampleName: string) {
fileRef.LivePackId = { '@Value': '' }; fileRef.LivePackId = { '@Value': '' };
} }
function targetFor(parameter: any): { arrangement?: number; session?: number } {
return {
arrangement:
parameter?.AutomationTarget?.['@Id'] === undefined
? undefined
: Number(parameter.AutomationTarget['@Id']),
session:
parameter?.ModulationTarget?.['@Id'] === undefined
? undefined
: Number(parameter.ModulationTarget['@Id']),
};
}
function findSimplers(node: any, result: any[] = []): any[] {
if (Array.isArray(node)) {
node.forEach((item) => findSimplers(item, result));
return result;
}
if (!node || typeof node !== 'object') {
return result;
}
if (node.OriginalSimpler) {
result.push(node.OriginalSimpler);
}
Object.values(node).forEach((value) => findSimplers(value, result));
return result;
}
function addTarget(
targets: AbletonAutomationTargets,
parameter: FaderParam,
target: { arrangement?: number; session?: number },
) {
if (target.arrangement === undefined && target.session === undefined) {
return;
}
targets[parameter] = [...(targets[parameter] || []), target];
}
function trackAutomationTargets(midiTrack: any, includeArrangementMixer: boolean) {
const targets: AbletonAutomationTargets = {};
const mixer = midiTrack.DeviceChain.Mixer;
const sequencer = midiTrack.DeviceChain.MainSequencer;
addTarget(targets, FaderParam.LVL, {
arrangement: includeArrangementMixer
? Number(mixer.Volume.AutomationTarget['@Id'])
: undefined,
session: Number(sequencer.VolumeModulationTarget['@Id']),
});
addTarget(targets, FaderParam.PAN, {
arrangement: includeArrangementMixer ? Number(mixer.Pan.AutomationTarget['@Id']) : undefined,
session: Number(mixer.Pan.ModulationTarget['@Id']),
});
const send = mixer.Sends?.TrackSendHolder?.Send;
if (send) {
const target = targetFor(send);
if (!includeArrangementMixer) {
target.arrangement = undefined;
}
addTarget(targets, FaderParam.FX, target);
}
findSimplers(midiTrack.DeviceChain.DeviceChain.Devices).forEach((simpler) => {
addTarget(targets, FaderParam.PTC, targetFor(simpler.Pitch.TransposeKey));
addTarget(targets, FaderParam.TUNE, targetFor(simpler.Pitch.TransposeFine));
addTarget(targets, FaderParam.LPF, targetFor(simpler.Filter.Slot.Value.SimplerFilter.Freq));
addTarget(targets, FaderParam.HPF, targetFor(simpler.Filter.Slot.Value.SimplerFilter.Freq));
addTarget(targets, FaderParam.ATK, targetFor(simpler.VolumeAndPan.Envelope.AttackTime));
addTarget(targets, FaderParam.REL, targetFor(simpler.VolumeAndPan.Envelope.ReleaseTime));
addTarget(targets, FaderParam.MOD, targetFor(simpler.Pitch.PitchLfoAmount));
});
return targets;
}
function groupAutomationTargets(groupTrack: any) {
const targets: AbletonAutomationTargets = {};
const mixer = groupTrack.DeviceChain.Mixer;
addTarget(targets, FaderParam.LVL, targetFor(mixer.Volume));
addTarget(targets, FaderParam.PAN, targetFor(mixer.Pan));
const send = mixer.Sends?.TrackSendHolder?.Send;
if (send) {
addTarget(targets, FaderParam.FX, targetFor(send));
}
return targets;
}
async function buildMidiClip( async function buildMidiClip(
koClip: AblClip, koClip: AblClip,
clipIdx: number, clipIdx: number,