Improve group track and clip handling for Ableton export
This commit is contained in:
@@ -515,6 +515,7 @@ async function buildDrumRackDevice(koTrack: AblTrack, abletonVersion: AbletonVer
|
||||
|
||||
async function buildTrack(
|
||||
koTrack: AblTrack,
|
||||
groupLane: AblGroupLane | undefined,
|
||||
maxScenes: number,
|
||||
trackGroupId: number,
|
||||
exporterParams: ExporterParams,
|
||||
@@ -532,19 +533,17 @@ async function buildTrack(
|
||||
midiTrack.DeviceChain.MainSequencer.ClipTimeable.ArrangerAutomation.Events.MidiClip = [];
|
||||
midiTrack.TrackGroupId['@Value'] = trackGroupId;
|
||||
midiTrack.DeviceChain.DeviceChain.Devices['#'] = [];
|
||||
midiTrack.DeviceChain.Mixer.Sends = {};
|
||||
midiTrack.DeviceChain.Mixer.Volume.Manual['@Value'] = koTrack.volume;
|
||||
|
||||
if (koTrack.faderParams[FaderParam.PAN] !== -1) {
|
||||
if (!exporterParams.groupTracks && koTrack.faderParams[FaderParam.PAN] !== -1) {
|
||||
midiTrack.DeviceChain.Mixer.Pan.Manual['@Value'] =
|
||||
(koTrack.faderParams[FaderParam.PAN] - 0.5) * 2;
|
||||
}
|
||||
|
||||
if (koTrack.faderParams[FaderParam.LVL] !== -1) {
|
||||
// setting volume to the minimum of track volume and fader param
|
||||
midiTrack.DeviceChain.Mixer.Volume.Manual['@Value'] = Math.min(
|
||||
koTrack.volume,
|
||||
koTrack.faderParams[FaderParam.LVL],
|
||||
);
|
||||
if (!exporterParams.groupTracks && koTrack.faderParams[FaderParam.LVL] !== -1) {
|
||||
midiTrack.DeviceChain.Mixer.Volume.Manual['@Value'] =
|
||||
koTrack.volume * koTrack.faderParams[FaderParam.LVL];
|
||||
}
|
||||
|
||||
if (koTrack.drumRack && exporterParams.includeArchivedSamples) {
|
||||
@@ -566,6 +565,28 @@ async function buildTrack(
|
||||
});
|
||||
});
|
||||
|
||||
if (exporterParams.groupTracks) {
|
||||
midiTrack.DeviceChain.AudioOutputRouting.Target['@Value'] = 'AudioOut/GroupTrack';
|
||||
midiTrack.DeviceChain.AudioOutputRouting.UpperDisplayString['@Value'] = 'Group';
|
||||
}
|
||||
|
||||
if (exporterParams.sendEffects && (!exporterParams.groupTracks || exporterParams.clips)) {
|
||||
const trackSendHolderTemplate = await loadTemplate<ALSTrackSendHolder>(
|
||||
'trackSendHolder',
|
||||
abletonVersion,
|
||||
);
|
||||
const trackSendHolder = structuredClone(trackSendHolderTemplate.TrackSendHolder);
|
||||
trackSendHolder['@Id'] = 0;
|
||||
trackSendHolder.Send.Manual['@Value'] = koTrack.faderParams[FaderParam.FX];
|
||||
midiTrack.DeviceChain.Mixer.Sends.TrackSendHolder = trackSendHolder;
|
||||
}
|
||||
|
||||
fixIds(midiTrack);
|
||||
const automationTargets = trackAutomationTargets(
|
||||
midiTrack,
|
||||
!exporterParams.groupTracks && !exporterParams.clips,
|
||||
);
|
||||
|
||||
// make sure each tracks has the same empty slots for clips
|
||||
// must be equeal to GroupTrackSlot if this track is in a group
|
||||
// must be at least 8 slots to avoid Ableton crashes
|
||||
@@ -608,6 +629,8 @@ async function buildTrack(
|
||||
getColorValue(midiTrack),
|
||||
false,
|
||||
abletonVersion,
|
||||
automationTargets,
|
||||
koTrack,
|
||||
);
|
||||
|
||||
midiTrack.DeviceChain.MainSequencer.ClipTimeable.ArrangerAutomation.Events.MidiClip.push(
|
||||
@@ -615,13 +638,39 @@ async function buildTrack(
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for (const koClip of koTrack.lane.clips.values()) {
|
||||
const sessionClips = [...koTrack.lane.clips];
|
||||
groupLane?.patterns.forEach((pattern) => {
|
||||
const hasClip = sessionClips.some((clip) => clip.sceneIndex === pattern.sceneIndex);
|
||||
const hasSupportedAutomation = pattern.faderAutomation.some(
|
||||
(point) =>
|
||||
point.parameter !== FaderParam.TIM &&
|
||||
point.parameter !== FaderParam.VEL &&
|
||||
automationTargets[point.parameter]?.some((target) => target.session !== undefined),
|
||||
);
|
||||
if (!hasClip && hasSupportedAutomation) {
|
||||
sessionClips.push({
|
||||
notes: [],
|
||||
bars: pattern.bars,
|
||||
offset: pattern.offset,
|
||||
sceneBars: pattern.sceneBars,
|
||||
sceneIndex: pattern.sceneIndex,
|
||||
sceneName: pattern.sceneName,
|
||||
timeSignature: pattern.timeSignature,
|
||||
faderParams: pattern.faderParams,
|
||||
groupPattern: pattern,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
for (const koClip of sessionClips) {
|
||||
const midiClip = await buildMidiClip(
|
||||
koClip,
|
||||
0,
|
||||
getColorValue(midiTrack),
|
||||
true,
|
||||
abletonVersion,
|
||||
automationTargets,
|
||||
koTrack,
|
||||
);
|
||||
|
||||
midiTrack.DeviceChain.MainSequencer.ClipSlotList.ClipSlot[koClip.sceneIndex] = {
|
||||
@@ -636,21 +685,16 @@ async function buildTrack(
|
||||
}
|
||||
}
|
||||
|
||||
if (exporterParams.groupTracks) {
|
||||
midiTrack.DeviceChain.AudioOutputRouting.Target['@Value'] = 'AudioOut/GroupTrack';
|
||||
midiTrack.DeviceChain.AudioOutputRouting.UpperDisplayString['@Value'] = 'Group';
|
||||
}
|
||||
|
||||
if (exporterParams.sendEffects && !exporterParams.groupTracks) {
|
||||
const trackSendHolderTemplate = await loadTemplate<ALSTrackSendHolder>(
|
||||
'trackSendHolder',
|
||||
abletonVersion,
|
||||
if (!exporterParams.clips && groupLane) {
|
||||
const envelopes = buildArrangementEnvelopes(
|
||||
groupLane.patterns,
|
||||
automationTargets,
|
||||
koTrack,
|
||||
false,
|
||||
);
|
||||
const trackSendHolder = structuredClone(trackSendHolderTemplate.TrackSendHolder);
|
||||
|
||||
trackSendHolder.Send.Manual['@Value'] = koTrack.faderParams[FaderParam.FX];
|
||||
|
||||
midiTrack.DeviceChain.Mixer.Sends.TrackSendHolder = trackSendHolder;
|
||||
midiTrack.AutomationEnvelopes.Envelopes = envelopes.length
|
||||
? ({ AutomationEnvelope: envelopes } as any)
|
||||
: {};
|
||||
}
|
||||
|
||||
return { MidiTrack: midiTrack };
|
||||
|
||||
Reference in New Issue
Block a user