Implement time signature handling and build arrangement events for Ableton export

This commit is contained in:
2026-07-14 09:41:06 +02:00
parent 18d7095dd2
commit 4bf04cf93c

View File

@@ -280,18 +280,6 @@ function trackAutomationTargets(
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(
koClip: AblClip,
clipIdx: number,
@@ -1107,6 +1095,44 @@ async function buildReturnTrack(
return { ReturnTrack: returnTrack };
}
function getTimeSignatureId(timeSignature: { numerator: number; denominator: number }) {
return (
TIME_SIGNATURES[`${timeSignature.numerator}/${timeSignature.denominator}`] ||
TIME_SIGNATURES['4/4']
);
}
function buildArrangementTimeSignatureEvents(
sections: AblArrangementSection[],
fallbackTimeSignature: { numerator: number; denominator: number },
) {
const initialTimeSignature = sections[0]?.timeSignature || fallbackTimeSignature;
const events = [
{
'@Id': 0,
'@Time': -63072000,
'@Value': getTimeSignatureId(initialTimeSignature),
},
];
let previousTimeSignatureId = getTimeSignatureId(initialTimeSignature);
sections.forEach((section, index) => {
const timeSignatureId = getTimeSignatureId(section.timeSignature);
if (index === 0 || timeSignatureId === previousTimeSignatureId) {
previousTimeSignatureId = timeSignatureId;
return;
}
events.push({
'@Id': events.length,
'@Time': section.offset,
'@Value': timeSignatureId,
});
previousTimeSignatureId = timeSignatureId;
});
return events;
}
export async function buildProject(projectData: ProjectRawData, exporterParams: ExporterParams) {
resetIds();
const abletonVersion = getAbletonVersion(exporterParams);
@@ -1132,18 +1158,21 @@ export async function buildProject(projectData: ProjectRawData, exporterParams:
project.Ableton.LiveSet.MasterTrack.AutomationEnvelopes.Envelopes.AutomationEnvelope[1].Automation.Events.FloatEvent[
'@Value'
] = projectData.settings.bpm;
// setting up time signature
project.Ableton.LiveSet.MasterTrack.AutomationEnvelopes.Envelopes.AutomationEnvelope[0].Automation.Events.EnumEvent[
'@Value'
] =
TIME_SIGNATURES[
`${projectData.scenesSettings.timeSignature.numerator}/${projectData.scenesSettings.timeSignature.denominator}`
] || TIME_SIGNATURES['4/4'];
const initialTimeSignature =
transformedData.arrangementSections[0]?.timeSignature ||
projectData.scenesSettings.timeSignature;
project.Ableton.LiveSet.MasterTrack.DeviceChain.Mixer.TimeSignature.Manual['@Value'] =
getTimeSignatureId(initialTimeSignature);
project.Ableton.LiveSet.MasterTrack.AutomationEnvelopes.Envelopes.AutomationEnvelope[0].Automation.Events.EnumEvent =
buildArrangementTimeSignatureEvents(
transformedData.arrangementSections,
projectData.scenesSettings.timeSignature,
) as any;
const tracks = await buildTracks(
transformedData.tracks,
transformedData.groupLanes,
transformedData.scenes.length,
transformedData.scenes,
exporterParams,
);
project.Ableton.LiveSet.Tracks = { '#': tracks } as any;
@@ -1158,18 +1187,16 @@ export async function buildProject(projectData: ProjectRawData, exporterParams:
project.Ableton.LiveSet.Tracks['#'].push(returnTrack);
}
if (exporterParams.clips) {
const scenes = await buildScenes(
transformedData.scenes,
projectData.settings,
transformedData.scenes.length,
abletonVersion,
);
if (abletonVersion === '10') {
(project.Ableton.LiveSet as any).SceneNames.Scene = scenes;
} else {
project.Ableton.LiveSet.Scenes.Scene = scenes;
}
const scenes = await buildScenes(
transformedData.scenes,
projectData.settings,
transformedData.scenes.length,
abletonVersion,
);
if (abletonVersion === '10') {
(project.Ableton.LiveSet as any).SceneNames.Scene = scenes;
} else {
project.Ableton.LiveSet.Scenes.Scene = scenes;
}
if (exporterParams.sendEffects) {