Update Ableton exporter to use scenes array instead of maxScenes count
This commit is contained in:
@@ -671,7 +671,7 @@ async function buildDrumRackDevice(koTrack: AblTrack, abletonVersion: AbletonVer
|
||||
async function buildTrack(
|
||||
koTrack: AblTrack,
|
||||
groupLane: AblGroupLane | undefined,
|
||||
maxScenes: number,
|
||||
scenes: AblScene[],
|
||||
trackGroupId: number,
|
||||
exporterParams: ExporterParams,
|
||||
): Promise<ALSMidiTrack> {
|
||||
@@ -691,14 +691,12 @@ async function buildTrack(
|
||||
midiTrack.DeviceChain.Mixer.Sends = {} as any;
|
||||
midiTrack.DeviceChain.Mixer.Volume.Manual['@Value'] = koTrack.volume;
|
||||
|
||||
const useChildGroupMixer = !exporterParams.groupTracks || exporterParams.clips;
|
||||
|
||||
if (useChildGroupMixer && koTrack.faderParams[FaderParam.PAN] !== -1) {
|
||||
if (koTrack.faderParams[FaderParam.PAN] !== -1) {
|
||||
midiTrack.DeviceChain.Mixer.Pan.Manual['@Value'] =
|
||||
(koTrack.faderParams[FaderParam.PAN] - 0.5) * 2;
|
||||
}
|
||||
|
||||
if (useChildGroupMixer && koTrack.faderParams[FaderParam.LVL] !== -1) {
|
||||
if (koTrack.faderParams[FaderParam.LVL] !== -1) {
|
||||
midiTrack.DeviceChain.Mixer.Volume.Manual['@Value'] =
|
||||
koTrack.volume * koTrack.faderParams[FaderParam.LVL];
|
||||
}
|
||||
@@ -719,7 +717,10 @@ async function buildTrack(
|
||||
for (const parameter of [FaderParam.LPF, FaderParam.HPF] as const) {
|
||||
const staticValue = koTrack.faderParams[parameter];
|
||||
const defaultValue = parameter === FaderParam.LPF ? 1 : 0;
|
||||
const hasAutomation = groupLane?.patterns.some((pattern) =>
|
||||
const hasAutomation = [
|
||||
...(groupLane?.sessionPatterns || []),
|
||||
...(groupLane?.arrangementPatterns || []),
|
||||
].some((pattern) =>
|
||||
pattern.faderAutomation.some((point) => point.parameter === parameter),
|
||||
);
|
||||
if (hasAutomation || (staticValue !== -1 && staticValue !== defaultValue)) {
|
||||
@@ -742,7 +743,7 @@ async function buildTrack(
|
||||
midiTrack.DeviceChain.AudioOutputRouting.UpperDisplayString['@Value'] = 'Group';
|
||||
}
|
||||
|
||||
if (exporterParams.sendEffects && (!exporterParams.groupTracks || exporterParams.clips)) {
|
||||
if (exporterParams.sendEffects) {
|
||||
const trackSendHolderTemplate = await loadTemplate<ALSTrackSendHolder>(
|
||||
'trackSendHolder',
|
||||
abletonVersion,
|
||||
@@ -754,11 +755,7 @@ async function buildTrack(
|
||||
}
|
||||
|
||||
fixIds(midiTrack);
|
||||
const automationTargets = trackAutomationTargets(
|
||||
midiTrack,
|
||||
!exporterParams.groupTracks && !exporterParams.clips,
|
||||
koTrack,
|
||||
);
|
||||
const automationTargets = trackAutomationTargets(midiTrack, true, koTrack);
|
||||
|
||||
// make sure each tracks has the same empty slots for clips
|
||||
// must be equeal to GroupTrackSlot if this track is in a group
|
||||
@@ -766,7 +763,9 @@ async function buildTrack(
|
||||
midiTrack.DeviceChain.MainSequencer.ClipSlotList.ClipSlot = [];
|
||||
midiTrack.DeviceChain.FreezeSequencer.ClipSlotList.ClipSlot = [];
|
||||
|
||||
for (let sc = 0; sc < Math.max(MIN_CLIP_LAUNCHER_SCENES, maxScenes); sc++) {
|
||||
for (let sc = 0; sc < Math.max(MIN_CLIP_LAUNCHER_SCENES, scenes.length); sc++) {
|
||||
const scene = scenes[sc];
|
||||
const hasStop = !scene || scene.affectedGroups.includes(koTrack.group);
|
||||
midiTrack.DeviceChain.MainSequencer.ClipSlotList.ClipSlot[sc] = {
|
||||
'@Id': sc,
|
||||
LomId: {
|
||||
@@ -775,6 +774,9 @@ async function buildTrack(
|
||||
ClipSlot: {
|
||||
Value: {},
|
||||
},
|
||||
HasStop: {
|
||||
'@Value': hasStop ? 'true' : 'false',
|
||||
},
|
||||
};
|
||||
midiTrack.DeviceChain.FreezeSequencer.ClipSlotList.ClipSlot[sc] = {
|
||||
'@Id': sc,
|
||||
@@ -793,9 +795,7 @@ async function buildTrack(
|
||||
};
|
||||
}
|
||||
|
||||
if (koTrack.lane) {
|
||||
if (!exporterParams.clips) {
|
||||
for (const [clipIdx, koClip] of koTrack.lane.clips.entries()) {
|
||||
for (const [clipIdx, koClip] of (koTrack.lane?.arrangementClips || []).entries()) {
|
||||
const midiClip = await buildMidiClip(
|
||||
koClip,
|
||||
clipIdx,
|
||||
@@ -806,28 +806,22 @@ async function buildTrack(
|
||||
midiTrack.DeviceChain.MainSequencer.MidiControllers,
|
||||
koTrack,
|
||||
);
|
||||
|
||||
midiTrack.DeviceChain.MainSequencer.ClipTimeable.ArrangerAutomation.Events.MidiClip.push(
|
||||
midiClip,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const sessionClips = [...koTrack.lane.clips];
|
||||
groupLane?.patterns.forEach((pattern) => {
|
||||
|
||||
const sessionClips = [...(koTrack.lane?.sessionClips || [])];
|
||||
groupLane?.sessionPatterns.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) {
|
||||
if (!hasClip && pattern.sceneIndex !== undefined) {
|
||||
sessionClips.push({
|
||||
notes: [],
|
||||
midiEvents: [],
|
||||
bars: pattern.bars,
|
||||
offset: pattern.offset,
|
||||
sceneBars: pattern.sceneBars,
|
||||
offset: 0,
|
||||
duration: pattern.duration,
|
||||
loopDuration: pattern.loopDuration,
|
||||
sceneIndex: pattern.sceneIndex,
|
||||
sceneName: pattern.sceneName,
|
||||
timeSignature: pattern.timeSignature,
|
||||
@@ -838,6 +832,9 @@ async function buildTrack(
|
||||
});
|
||||
|
||||
for (const koClip of sessionClips) {
|
||||
if (koClip.sceneIndex === undefined) {
|
||||
continue;
|
||||
}
|
||||
const midiClip = await buildMidiClip(
|
||||
koClip,
|
||||
0,
|
||||
@@ -848,7 +845,6 @@ async function buildTrack(
|
||||
midiTrack.DeviceChain.MainSequencer.MidiControllers,
|
||||
koTrack,
|
||||
);
|
||||
|
||||
midiTrack.DeviceChain.MainSequencer.ClipSlotList.ClipSlot[koClip.sceneIndex] = {
|
||||
...midiTrack.DeviceChain.MainSequencer.ClipSlotList.ClipSlot[koClip.sceneIndex],
|
||||
ClipSlot: {
|
||||
@@ -858,12 +854,10 @@ async function buildTrack(
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!exporterParams.clips && groupLane) {
|
||||
if (groupLane) {
|
||||
const envelopes = buildArrangementEnvelopes(
|
||||
groupLane.patterns,
|
||||
groupLane.arrangementPatterns,
|
||||
automationTargets,
|
||||
koTrack,
|
||||
false,
|
||||
@@ -878,7 +872,6 @@ async function buildTrack(
|
||||
|
||||
async function buildGroupTrack(
|
||||
koTrack: AblTrack,
|
||||
groupLane: AblGroupLane | undefined,
|
||||
exporterParams: ExporterParams,
|
||||
maxScenes: number,
|
||||
) {
|
||||
@@ -892,19 +885,8 @@ async function buildGroupTrack(
|
||||
setColorValue(groupTrack, 5 + _localGroupTrackColor++);
|
||||
groupTrack.Slots.GroupTrackSlot = [];
|
||||
groupTrack.DeviceChain.Mixer.Sends = {} as any;
|
||||
|
||||
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)
|
||||
// must be at least 8 slots to avoid Ableton crashes
|
||||
@@ -917,36 +899,7 @@ async function buildGroupTrack(
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
exporterParams.sendEffects &&
|
||||
!exporterParams.clips &&
|
||||
koTrack.faderParams[FaderParam.FX] !== -1
|
||||
) {
|
||||
const trackSendHolderTemplate = await loadTemplate<ALSTrackSendHolder>(
|
||||
'trackSendHolder',
|
||||
abletonVersion,
|
||||
);
|
||||
const trackSendHolder = structuredClone(trackSendHolderTemplate.TrackSendHolder);
|
||||
|
||||
trackSendHolder['@Id'] = 0;
|
||||
trackSendHolder.Send.Manual['@Value'] = koTrack.faderParams[FaderParam.FX];
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
@@ -966,10 +919,22 @@ async function buildScenes(
|
||||
|
||||
sceneContent['@Id'] = _localId++;
|
||||
if (abletonVersion === '10') {
|
||||
(sceneContent as any)['@Value'] = scene?.name || ` ${index + 1}`;
|
||||
const meter = scene?.timeSignature;
|
||||
(sceneContent as any)['@Value'] = scene
|
||||
? `${scene.name}${meter ? ` ${meter.numerator}/${meter.denominator}` : ''}`
|
||||
: ` ${index + 1}`;
|
||||
} else {
|
||||
sceneContent.Name['@Value'] = scene?.name || '';
|
||||
sceneContent.Tempo['@Value'] = settings.bpm;
|
||||
if (scene?.timeSignature) {
|
||||
sceneContent.TimeSignatureId['@Value'] =
|
||||
TIME_SIGNATURES[
|
||||
`${scene.timeSignature.numerator}/${scene.timeSignature.denominator}`
|
||||
] || TIME_SIGNATURES['4/4'];
|
||||
sceneContent.IsTimeSignatureEnabled['@Value'] = 'true';
|
||||
} else {
|
||||
sceneContent.IsTimeSignatureEnabled['@Value'] = 'false';
|
||||
}
|
||||
}
|
||||
|
||||
result.push(sceneContent);
|
||||
@@ -981,7 +946,7 @@ async function buildScenes(
|
||||
async function buildTracks(
|
||||
tracks: AblTrack[],
|
||||
groupLanes: AblGroupLane[],
|
||||
maxScenes: number,
|
||||
scenes: AblScene[],
|
||||
exporterParams: ExporterParams,
|
||||
) {
|
||||
const result = [];
|
||||
@@ -994,12 +959,12 @@ async function buildTracks(
|
||||
const groupLane = groupLanes.find((lane) => lane.group === koTrack.group);
|
||||
if (exporterParams.groupTracks && koTrack.group !== currentGroup[0]) {
|
||||
currentGroup = koTrack.group;
|
||||
const groupTrack = await buildGroupTrack(koTrack, groupLane, exporterParams, maxScenes);
|
||||
const groupTrack = await buildGroupTrack(koTrack, exporterParams, scenes.length);
|
||||
trackGroupId = groupTrack.GroupTrack['@Id'];
|
||||
result.push(groupTrack);
|
||||
}
|
||||
|
||||
const midiTrack = await buildTrack(koTrack, groupLane, maxScenes, trackGroupId, exporterParams);
|
||||
const midiTrack = await buildTrack(koTrack, groupLane, scenes, trackGroupId, exporterParams);
|
||||
|
||||
result.push(midiTrack);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user