Enhance group track building and add automation envelope support for tracks in groups

This commit is contained in:
2026-07-13 05:01:04 +02:00
parent a370f00150
commit c4d6cbf317

View File

@@ -702,6 +702,7 @@ async function buildTrack(
async function buildGroupTrack( async function buildGroupTrack(
koTrack: AblTrack, koTrack: AblTrack,
groupLane: AblGroupLane | undefined,
exporterParams: ExporterParams, exporterParams: ExporterParams,
maxScenes: number, maxScenes: number,
) { ) {
@@ -714,6 +715,21 @@ async function buildGroupTrack(
groupTrack.Name.UserName['@Value'] = koTrack.group.toLocaleUpperCase(); groupTrack.Name.UserName['@Value'] = koTrack.group.toLocaleUpperCase();
setColorValue(groupTrack, 5 + _localGroupTrackColor++); setColorValue(groupTrack, 5 + _localGroupTrackColor++);
groupTrack.Slots.GroupTrackSlot = []; groupTrack.Slots.GroupTrackSlot = [];
groupTrack.DeviceChain.Mixer.Sends = {};
if (!exporterParams.clips) {
if (koTrack.faderParams[FaderParam.LVL] !== -1) {
groupTrack.DeviceChain.Mixer.Volume.Manual['@Value'] =
koTrack.faderParams[FaderParam.LVL];
}
if (koTrack.faderParams[FaderParam.PAN] !== -1) {
groupTrack.DeviceChain.Mixer.Pan.Manual['@Value'] =
(koTrack.faderParams[FaderParam.PAN] - 0.5) * 2;
}
} else {
groupTrack.DeviceChain.Mixer.Volume.Manual['@Value'] = 1;
groupTrack.DeviceChain.Mixer.Pan.Manual['@Value'] = 0;
}
// adding empty slots for clips (or Ableton will crash) // adding empty slots for clips (or Ableton will crash)
// must be at least 8 slots to avoid Ableton crashes // must be at least 8 slots to avoid Ableton crashes
@@ -726,18 +742,36 @@ async function buildGroupTrack(
}); });
} }
if (exporterParams.sendEffects && koTrack.faderParams[FaderParam.FX] !== -1) { if (
exporterParams.sendEffects &&
!exporterParams.clips &&
koTrack.faderParams[FaderParam.FX] !== -1
) {
const trackSendHolderTemplate = await loadTemplate<ALSTrackSendHolder>( const trackSendHolderTemplate = await loadTemplate<ALSTrackSendHolder>(
'trackSendHolder', 'trackSendHolder',
abletonVersion, abletonVersion,
); );
const trackSendHolder = structuredClone(trackSendHolderTemplate.TrackSendHolder); const trackSendHolder = structuredClone(trackSendHolderTemplate.TrackSendHolder);
trackSendHolder['@Id'] = 0;
trackSendHolder.Send.Manual['@Value'] = koTrack.faderParams[FaderParam.FX]; trackSendHolder.Send.Manual['@Value'] = koTrack.faderParams[FaderParam.FX];
groupTrack.DeviceChain.Mixer.Sends.TrackSendHolder = trackSendHolder; groupTrack.DeviceChain.Mixer.Sends.TrackSendHolder = trackSendHolder;
} }
fixIds(groupTrack);
if (!exporterParams.clips && groupLane) {
const envelopes = buildArrangementEnvelopes(
groupLane.patterns,
groupAutomationTargets(groupTrack),
koTrack,
true,
);
groupTrack.AutomationEnvelopes.Envelopes = envelopes.length
? ({ AutomationEnvelope: envelopes } as any)
: {};
}
return { GroupTrack: groupTrack }; return { GroupTrack: groupTrack };
} }
@@ -769,7 +803,12 @@ async function buildScenes(
return result; return result;
} }
async function buildTracks(tracks: AblTrack[], maxScenes: number, exporterParams: ExporterParams) { async function buildTracks(
tracks: AblTrack[],
groupLanes: AblGroupLane[],
maxScenes: number,
exporterParams: ExporterParams,
) {
const result = []; const result = [];
let trackGroupId = -1; let trackGroupId = -1;
let currentGroup = ''; let currentGroup = '';
@@ -777,14 +816,21 @@ async function buildTracks(tracks: AblTrack[], maxScenes: number, exporterParams
// if the tracks are grouped, we need to create a group track for each group BEFORE the children midi tracks // if the tracks are grouped, we need to create a group track for each group BEFORE the children midi tracks
// this took me around 3 hours to figure out // this took me around 3 hours to figure out
for (const koTrack of tracks.sort((a, b) => a.group.localeCompare(b.group))) { for (const koTrack of tracks.sort((a, b) => a.group.localeCompare(b.group))) {
const groupLane = groupLanes.find((lane) => lane.group === koTrack.group);
if (exporterParams.groupTracks && koTrack.group !== currentGroup[0]) { if (exporterParams.groupTracks && koTrack.group !== currentGroup[0]) {
currentGroup = koTrack.group; currentGroup = koTrack.group;
const groupTrack = await buildGroupTrack(koTrack, exporterParams, maxScenes); const groupTrack = await buildGroupTrack(koTrack, groupLane, exporterParams, maxScenes);
trackGroupId = groupTrack.GroupTrack['@Id']; trackGroupId = groupTrack.GroupTrack['@Id'];
result.push(groupTrack); result.push(groupTrack);
} }
const midiTrack = await buildTrack(koTrack, maxScenes, trackGroupId, exporterParams); const midiTrack = await buildTrack(
koTrack,
groupLane,
maxScenes,
trackGroupId,
exporterParams,
);
result.push(midiTrack); result.push(midiTrack);
} }