Enhance Ableton exporter to support static automation values and update simpler playback duration calculation
This commit is contained in:
@@ -8,6 +8,7 @@ export type AbletonAutomationTarget = {
|
||||
maxValue?: number;
|
||||
soundLength?: number;
|
||||
invertValue?: boolean;
|
||||
staticValue?: number;
|
||||
};
|
||||
|
||||
export type AbletonAutomationTargets = Partial<Record<FaderParam, AbletonAutomationTarget[]>>;
|
||||
@@ -119,6 +120,19 @@ function getStaticValue(pattern: AblGroupPatternOccurrence, parameter: FaderPara
|
||||
return value === -1 ? defaultValue(parameter) : value;
|
||||
}
|
||||
|
||||
function getConvertedStaticValue(
|
||||
pattern: AblGroupPatternOccurrence,
|
||||
parameter: FaderParam,
|
||||
track: AblTrack,
|
||||
groupMixer: boolean,
|
||||
target: AbletonAutomationTarget,
|
||||
) {
|
||||
if (pattern.faderParams[parameter] === -1 && target.staticValue !== undefined) {
|
||||
return target.staticValue;
|
||||
}
|
||||
return convertFaderValue(parameter, getStaticValue(pattern, parameter), track, groupMixer, target);
|
||||
}
|
||||
|
||||
function getArrangementPoints(
|
||||
patterns: AblGroupPatternOccurrence[],
|
||||
parameter: FaderParam,
|
||||
@@ -128,13 +142,9 @@ function getArrangementPoints(
|
||||
) {
|
||||
const points: AutomationPoint[] = [];
|
||||
let hasAutomation = false;
|
||||
let previousValue = convertFaderValue(
|
||||
parameter,
|
||||
patterns[0] ? getStaticValue(patterns[0], parameter) : defaultValue(parameter),
|
||||
track,
|
||||
groupMixer,
|
||||
target,
|
||||
);
|
||||
let previousValue = patterns[0]
|
||||
? getConvertedStaticValue(patterns[0], parameter, track, groupMixer, target)
|
||||
: convertFaderValue(parameter, defaultValue(parameter), track, groupMixer, target);
|
||||
|
||||
patterns.forEach((pattern) => {
|
||||
const beats = pattern.timeSignature.numerator * (4 / pattern.timeSignature.denominator);
|
||||
@@ -144,13 +154,7 @@ function getArrangementPoints(
|
||||
const sourcePoints = pattern.faderAutomation
|
||||
.filter((point) => point.parameter === parameter)
|
||||
.sort((a, b) => a.position - b.position);
|
||||
const staticValue = convertFaderValue(
|
||||
parameter,
|
||||
getStaticValue(pattern, parameter),
|
||||
track,
|
||||
groupMixer,
|
||||
target,
|
||||
);
|
||||
const staticValue = getConvertedStaticValue(pattern, parameter, track, groupMixer, target);
|
||||
|
||||
if (sourcePoints.length === 0) {
|
||||
if (hasAutomation) {
|
||||
@@ -199,13 +203,7 @@ function getClipPoints(
|
||||
return [];
|
||||
}
|
||||
|
||||
const staticValue = convertFaderValue(
|
||||
parameter,
|
||||
getStaticValue(pattern, parameter),
|
||||
track,
|
||||
groupMixer,
|
||||
target,
|
||||
);
|
||||
const staticValue = getConvertedStaticValue(pattern, parameter, track, groupMixer, target);
|
||||
return [
|
||||
{ time: SENTINEL_TIME, value: staticValue },
|
||||
{ time: 0, value: staticValue },
|
||||
|
||||
@@ -78,6 +78,13 @@ function simplerEnvelopeMilliseconds(
|
||||
return oneshot ? Math.min(2000, milliseconds) : milliseconds;
|
||||
}
|
||||
|
||||
function simplerPlaybackDuration(koTrack: AblTrack) {
|
||||
const trimmedFrames = koTrack.trimRight - koTrack.trimLeft;
|
||||
return trimmedFrames > 0 && koTrack.sampleRate > 0
|
||||
? trimmedFrames / koTrack.sampleRate
|
||||
: koTrack.soundLength;
|
||||
}
|
||||
|
||||
function setColorValue(node: any, value: number) {
|
||||
const color = node.Color || node.ColorIndex;
|
||||
color['@Value'] = value;
|
||||
@@ -121,6 +128,10 @@ function targetFor(parameter: any, maxValue?: number, soundLength?: number, inve
|
||||
maxValue,
|
||||
soundLength,
|
||||
invertValue,
|
||||
staticValue:
|
||||
parameter?.Manual?.['@Value'] === undefined
|
||||
? undefined
|
||||
: Number(parameter.Manual['@Value']),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -196,10 +207,15 @@ function trackAutomationTargets(midiTrack: any, includeArrangementMixer: boolean
|
||||
|
||||
findSimplers(midiTrack.DeviceChain.DeviceChain.Devices).forEach((simpler) => {
|
||||
const oneshot = Number(simpler.Globals.PlaybackMode['@Value']) === 1;
|
||||
const sampleRef = simpler.Player.MultiSampleMap.SampleParts.MultiSamplePart.SampleRef;
|
||||
const samplePart = simpler.Player.MultiSampleMap.SampleParts.MultiSamplePart;
|
||||
const sampleRef = samplePart.SampleRef;
|
||||
const sampleRate = Number(sampleRef.DefaultSampleRate?.['@Value']);
|
||||
const sampleDuration = Number(sampleRef.DefaultDuration?.['@Value']);
|
||||
const soundLength = sampleRate > 0 ? sampleDuration / sampleRate : undefined;
|
||||
const trimmedFrames = Number(samplePart.SampleEnd['@Value']) - Number(samplePart.SampleStart['@Value']);
|
||||
const soundLength =
|
||||
sampleRate > 0
|
||||
? (trimmedFrames > 0 ? trimmedFrames : sampleDuration) / sampleRate
|
||||
: undefined;
|
||||
addTarget(targets, FaderParam.PTC, targetFor(simpler.Pitch.TransposeKey));
|
||||
addTarget(targets, FaderParam.TUNE, targetFor(simpler.Pitch.TransposeFine));
|
||||
addTarget(
|
||||
@@ -376,6 +392,7 @@ async function buildSimplerDevice(koTrack: AblTrack, abletonVersion: AbletonVers
|
||||
const samplePart = device.Player.MultiSampleMap.SampleParts.MultiSamplePart;
|
||||
const loopModulators = device.Player.LoopModulators;
|
||||
const simplerFilter = device.Filter.Slot.Value.SimplerFilter;
|
||||
const playbackDuration = simplerPlaybackDuration(koTrack);
|
||||
|
||||
device.LastPresetRef.Value = {};
|
||||
device.ShouldShowPresetName['@Value'] = 'false';
|
||||
@@ -454,12 +471,12 @@ async function buildSimplerDevice(koTrack: AblTrack, abletonVersion: AbletonVers
|
||||
: device.VolumeAndPan.Envelope.ReleaseTime;
|
||||
attackTarget.Manual['@Value'] = simplerEnvelopeMilliseconds(
|
||||
koTrack.attack,
|
||||
koTrack.soundLength,
|
||||
playbackDuration,
|
||||
oneshot,
|
||||
);
|
||||
releaseTarget.Manual['@Value'] = simplerEnvelopeMilliseconds(
|
||||
koTrack.release,
|
||||
koTrack.soundLength,
|
||||
playbackDuration,
|
||||
oneshot,
|
||||
oneshot,
|
||||
);
|
||||
@@ -469,7 +486,7 @@ async function buildSimplerDevice(koTrack: AblTrack, abletonVersion: AbletonVers
|
||||
if (koTrack.faderParams[FaderParam.ATK] !== -1) {
|
||||
attackTarget.Manual['@Value'] = simplerEnvelopeMilliseconds(
|
||||
koTrack.faderParams[FaderParam.ATK] * 255,
|
||||
koTrack.soundLength,
|
||||
playbackDuration,
|
||||
oneshot,
|
||||
);
|
||||
}
|
||||
@@ -478,7 +495,7 @@ async function buildSimplerDevice(koTrack: AblTrack, abletonVersion: AbletonVers
|
||||
if (koTrack.faderParams[FaderParam.REL] !== -1) {
|
||||
releaseTarget.Manual['@Value'] = simplerEnvelopeMilliseconds(
|
||||
koTrack.faderParams[FaderParam.REL] * 255,
|
||||
koTrack.soundLength,
|
||||
playbackDuration,
|
||||
oneshot,
|
||||
oneshot,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user