Improve calculation of arrangement points for Ableton export

This commit is contained in:
2026-07-14 09:38:22 +02:00
parent 496d3ddf21
commit e85124906b

View File

@@ -147,39 +147,49 @@ function getArrangementPoints(
groupMixer: boolean, groupMixer: boolean,
target: AbletonAutomationTarget, target: AbletonAutomationTarget,
) { ) {
const orderedPatterns = patterns.toSorted((a, b) => {
const offsetDifference = a.offset - b.offset;
return offsetDifference || (a.occurrenceIndex ?? 0) - (b.occurrenceIndex ?? 0);
});
const hasAutomation = orderedPatterns.some((pattern) =>
pattern.faderAutomation.some((point) => point.parameter === parameter),
);
if (!hasAutomation) {
return [];
}
const points: AutomationPoint[] = []; const points: AutomationPoint[] = [];
let hasAutomation = false; let previousValue = orderedPatterns[0]
let previousValue = patterns[0] ? getConvertedStaticValue(orderedPatterns[0], parameter, track, groupMixer, target)
? getConvertedStaticValue(patterns[0], parameter, track, groupMixer, target)
: convertFaderValue(parameter, defaultValue(parameter), track, groupMixer, target); : convertFaderValue(parameter, defaultValue(parameter), track, groupMixer, target);
patterns.forEach((pattern) => { orderedPatterns.forEach((pattern) => {
const beats = pattern.timeSignature.numerator * (4 / pattern.timeSignature.denominator); const patternTicks = Math.max(1, pattern.loopDuration * 96);
const patternTicks = pattern.bars * beats * 96; const occurrenceTicks = Math.max(1, pattern.duration * 96);
const sceneTicks = pattern.sceneBars * beats * 96; const startTime = pattern.offset;
const startTime = pattern.offset * beats;
const sourcePoints = pattern.faderAutomation const sourcePoints = pattern.faderAutomation
.filter((point) => point.parameter === parameter) .filter((point) => point.parameter === parameter)
.sort((a, b) => a.position - b.position); .sort((a, b) => a.position - b.position);
const staticValue = getConvertedStaticValue(pattern, parameter, track, groupMixer, target); const staticValue = getConvertedStaticValue(pattern, parameter, track, groupMixer, target);
if (sourcePoints.length === 0) {
if (hasAutomation) {
points.push({ time: Math.max(0, startTime - BOUNDARY_EPSILON), value: previousValue }); points.push({ time: Math.max(0, startTime - BOUNDARY_EPSILON), value: previousValue });
points.push({ time: startTime, value: staticValue }); points.push({ time: startTime, value: staticValue });
}
previousValue = staticValue; previousValue = staticValue;
if (sourcePoints.length === 0) {
return; return;
} }
hasAutomation = true; for (let loopOffset = 0; loopOffset < occurrenceTicks; loopOffset += patternTicks) {
for (let loopOffset = 0; loopOffset < sceneTicks; loopOffset += patternTicks) {
const loopStart = startTime + loopOffset / 96; const loopStart = startTime + loopOffset / 96;
if (loopOffset > 0) {
points.push({ time: Math.max(0, loopStart - BOUNDARY_EPSILON), value: previousValue }); points.push({ time: Math.max(0, loopStart - BOUNDARY_EPSILON), value: previousValue });
points.push({ time: loopStart, value: staticValue }); points.push({ time: loopStart, value: staticValue });
previousValue = staticValue;
}
sourcePoints.forEach((point) => { sourcePoints.forEach((point) => {
if (loopOffset + point.position >= sceneTicks) { if (loopOffset + point.position >= occurrenceTicks) {
return; return;
} }
const value = convertFaderValue(parameter, point.value, track, groupMixer, target); const value = convertFaderValue(parameter, point.value, track, groupMixer, target);
@@ -189,10 +199,6 @@ function getArrangementPoints(
} }
}); });
if (!hasAutomation) {
return [];
}
return [{ time: SENTINEL_TIME, value: points[0]?.value ?? previousValue }, ...points]; return [{ time: SENTINEL_TIME, value: points[0]?.value ?? previousValue }, ...points];
} }
@@ -206,9 +212,6 @@ function getClipPoints(
const sourcePoints = pattern.faderAutomation const sourcePoints = pattern.faderAutomation
.filter((point) => point.parameter === parameter) .filter((point) => point.parameter === parameter)
.sort((a, b) => a.position - b.position); .sort((a, b) => a.position - b.position);
if (sourcePoints.length === 0) {
return [];
}
const staticValue = getConvertedStaticValue(pattern, parameter, track, groupMixer, target); const staticValue = getConvertedStaticValue(pattern, parameter, track, groupMixer, target);
return [ return [