Add support for group lanes and pattern-based fader automation in Ableton transformer

This commit is contained in:
2026-07-13 04:57:31 +02:00
parent 3513766ca4
commit 2a86a109a2

View File

@@ -16,6 +16,7 @@ import { findPad, findSoundByPad, findSoundIdByPad } from '../utils';
export type AblData = {
tracks: AblTrack[];
scenes: AblScene[];
groupLanes: AblGroupLane[];
};
export type AblTrack = Omit<Pad, 'file' | 'rawData' | 'midiChannel'> & {
@@ -50,13 +51,30 @@ export type AblClip = {
sceneName: string;
timeSignature: TimeSignature;
faderParams: { [K in FaderParam]: number };
faderAutomation: AblFaderAutomationPoint[];
groupPattern?: AblGroupPatternOccurrence;
};
export type AblFaderAutomationPoint = Pick<FaderAutomationEvent, 'position' | 'value' | 'flags'> & {
parameter: FaderParam;
};
export type AblGroupPatternOccurrence = {
group: string;
bars: number;
sceneBars: number;
sceneIndex: number;
sceneName: string;
offset: number;
timeSignature: TimeSignature;
faderParams: { [K in FaderParam]: number };
faderAutomation: AblFaderAutomationPoint[];
};
export type AblGroupLane = {
group: string;
patterns: AblGroupPatternOccurrence[];
};
export type AblScene = {
name: string;
};
@@ -65,6 +83,7 @@ function abletonTransformer(data: ProjectRawData, exporterParams: ExporterParams
const { pads, scenes } = data;
const customSceneNames = exporterParams.customSceneNames || {};
const lanes: AblLane[] = [];
const groupLanes: AblGroupLane[] = [];
const ablScenes: AblScene[] = [];
let tracks: AblTrack[] = [];
let offset = 0;
@@ -78,6 +97,41 @@ function abletonTransformer(data: ProjectRawData, exporterParams: ExporterParams
const ablScene: AblScene = {
name: customSceneNames[scene.name] || scene.name,
};
const groupPatterns: Record<string, AblGroupPatternOccurrence> = {};
Object.entries(scene.patternEvents).forEach(([group, pattern]) => {
if (!pattern) {
return;
}
const faderParams = data.settings.groupFaderParams[group];
const groupPattern: AblGroupPatternOccurrence = {
group,
bars: pattern.bars,
sceneBars,
sceneIndex,
sceneName: customSceneNames[scene.name] || scene.name,
offset,
timeSignature: data.scenesSettings.timeSignature,
faderParams,
faderAutomation: pattern.events
.filter((event): event is FaderAutomationEvent => event.type === 'fader')
.filter((event) => event.parameter >= FaderParam.LVL && event.parameter <= FaderParam.MOD)
.map((event) => ({
position: event.position,
parameter: event.parameter as FaderParam,
value: event.value,
flags: event.flags,
})),
};
let groupLane = groupLanes.find((lane) => lane.group === group);
if (!groupLane) {
groupLane = { group, patterns: [] };
groupLanes.push(groupLane);
}
groupLane.patterns.push(groupPattern);
groupPatterns[group] = groupPattern;
});
scene.patterns.forEach((pattern) => {
let track = tracks.find((c) => c.padCode === pattern.pad);
@@ -112,15 +166,6 @@ function abletonTransformer(data: ProjectRawData, exporterParams: ExporterParams
}
const faderParams = data.settings.groupFaderParams[pad.group];
const faderAutomation = (scene.patternEvents[pad.group]?.events || [])
.filter((event): event is FaderAutomationEvent => event.type === 'fader')
.filter((event) => event.parameter >= FaderParam.LVL && event.parameter <= FaderParam.MOD)
.map((event) => ({
position: event.position,
parameter: event.parameter as FaderParam,
value: event.value,
flags: event.flags,
}));
if (!track) {
const soundId = findSoundIdByPad(pattern.pad, pads) || 0;
@@ -165,7 +210,7 @@ function abletonTransformer(data: ProjectRawData, exporterParams: ExporterParams
sceneName: customSceneNames[scene.name] || scene.name,
timeSignature: data.scenesSettings.timeSignature,
faderParams,
faderAutomation,
groupPattern: groupPatterns[pad.group],
});
track.lane = lane;
@@ -325,11 +370,13 @@ function abletonTransformer(data: ProjectRawData, exporterParams: ExporterParams
Sentry.setContext(`abletonData`, {
tracks,
scenes: ablScenes,
groupLanes,
});
return {
tracks,
scenes: ablScenes,
groupLanes,
} as AblData;
}