Improve Ableton automation export for filters and add dedicated filter building function
This commit is contained in:
@@ -47,9 +47,9 @@ export function convertFaderValue(
|
||||
case FaderParam.PTC:
|
||||
return (value - 0.5) * 10;
|
||||
case FaderParam.LPF:
|
||||
return filterFreqFromNormalized(value * 0.9);
|
||||
return 20 + value * 0.9 * 115;
|
||||
case FaderParam.HPF:
|
||||
return filterFreqFromNormalized(value * 0.7);
|
||||
return 20 + value * 0.7 * 115;
|
||||
case FaderParam.FX:
|
||||
return value;
|
||||
case FaderParam.ATK:
|
||||
|
||||
@@ -122,6 +122,25 @@ function findSimplers(node: any, result: any[] = []): any[] {
|
||||
return result;
|
||||
}
|
||||
|
||||
function findAutoFilters(node: any, result: any[] = []): any[] {
|
||||
if (Array.isArray(node)) {
|
||||
node.forEach((item) => {
|
||||
findAutoFilters(item, result);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
if (!node || typeof node !== 'object') {
|
||||
return result;
|
||||
}
|
||||
if (node.AutoFilter) {
|
||||
result.push(node.AutoFilter);
|
||||
}
|
||||
Object.values(node).forEach((value) => {
|
||||
findAutoFilters(value, result);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function addTarget(
|
||||
targets: AbletonAutomationTargets,
|
||||
parameter: FaderParam,
|
||||
@@ -157,13 +176,17 @@ function trackAutomationTargets(midiTrack: any, includeArrangementMixer: boolean
|
||||
findSimplers(midiTrack.DeviceChain.DeviceChain.Devices).forEach((simpler) => {
|
||||
addTarget(targets, FaderParam.PTC, targetFor(simpler.Pitch.TransposeKey));
|
||||
addTarget(targets, FaderParam.TUNE, targetFor(simpler.Pitch.TransposeFine));
|
||||
addTarget(targets, FaderParam.LPF, targetFor(simpler.Filter.Slot.Value.SimplerFilter.Freq));
|
||||
addTarget(targets, FaderParam.HPF, targetFor(simpler.Filter.Slot.Value.SimplerFilter.Freq));
|
||||
addTarget(targets, FaderParam.ATK, targetFor(simpler.VolumeAndPan.Envelope.AttackTime));
|
||||
addTarget(targets, FaderParam.REL, targetFor(simpler.VolumeAndPan.Envelope.ReleaseTime));
|
||||
addTarget(targets, FaderParam.MOD, targetFor(simpler.Pitch.PitchLfoAmount));
|
||||
});
|
||||
|
||||
findAutoFilters(midiTrack.DeviceChain.DeviceChain.Devices).forEach((filter) => {
|
||||
const parameter =
|
||||
Number(filter.FilterType.Manual['@Value']) === 1 ? FaderParam.HPF : FaderParam.LPF;
|
||||
addTarget(targets, parameter, targetFor(filter.Cutoff));
|
||||
});
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
@@ -395,24 +418,6 @@ async function buildSimplerDevice(koTrack: AblTrack, abletonVersion: AbletonVers
|
||||
device.Lfo.Slot.Value.SimplerLfo.RateType.Manual['@Value'] = 1; // tempo synced 1/16
|
||||
}
|
||||
|
||||
if (koTrack.faderParams[FaderParam.LPF] !== -1 && koTrack.faderParams[FaderParam.LPF] !== 1) {
|
||||
device.Filter.IsOn.Manual['@Value'] = 'true';
|
||||
device.Filter.Slot.Value.SimplerFilter.Type.Manual['@Value'] = 0; // Low Pass
|
||||
device.Filter.Slot.Value.SimplerFilter.Slope.Manual['@Value'] = 'true'; // 24db/oct
|
||||
device.Filter.Slot.Value.SimplerFilter.Freq.Manual['@Value'] = filterFreqFromNormalized(
|
||||
koTrack.faderParams[FaderParam.LPF] * 0.9, // lowering max freq to match KO behavior
|
||||
);
|
||||
}
|
||||
|
||||
if (koTrack.faderParams[FaderParam.HPF] !== -1 && koTrack.faderParams[FaderParam.HPF] !== 0) {
|
||||
device.Filter.IsOn.Manual['@Value'] = 'true';
|
||||
device.Filter.Slot.Value.SimplerFilter.Type.Manual['@Value'] = 1; // High Pass
|
||||
device.Filter.Slot.Value.SimplerFilter.Slope.Manual['@Value'] = 'false'; // 12db/oct
|
||||
device.Filter.Slot.Value.SimplerFilter.Freq.Manual['@Value'] = filterFreqFromNormalized(
|
||||
koTrack.faderParams[FaderParam.HPF] * 0.7, // lowering max freq to match KO behavior
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: add bandpass filter
|
||||
|
||||
if (koTrack.timeStretch === 'bars') {
|
||||
@@ -471,6 +476,25 @@ async function buildSimplerDevice(koTrack: AblTrack, abletonVersion: AbletonVers
|
||||
};
|
||||
}
|
||||
|
||||
async function buildFaderFilterDevice(
|
||||
parameter: FaderParam.LPF | FaderParam.HPF,
|
||||
value: number,
|
||||
abletonVersion: AbletonVersion,
|
||||
) {
|
||||
const filterTemplate = await loadTemplate<ALSFilter>('effectFilter', abletonVersion);
|
||||
const filter = structuredClone(filterTemplate.AutoFilter);
|
||||
const highPass = parameter === FaderParam.HPF;
|
||||
filter.LastPresetRef.Value = {};
|
||||
filter.UserName['@Value'] = highPass ? 'EP HPF' : 'EP LPF';
|
||||
filter.FilterType.Manual['@Value'] = highPass ? 1 : 0;
|
||||
filter.LegacyFilterType.Manual['@Value'] = highPass ? 1 : 0;
|
||||
filter.Slope.Manual['@Value'] = highPass ? 'false' : 'true';
|
||||
filter.Cutoff.Manual['@Value'] = highPass
|
||||
? 20 + value * 0.7 * 115
|
||||
: 20 + value * 0.9 * 115;
|
||||
return { AutoFilter: filter };
|
||||
}
|
||||
|
||||
async function buildDrumRackDevice(koTrack: AblTrack, abletonVersion: AbletonVersion) {
|
||||
const [drumRackTemplate, drumBranchTemplate] = await Promise.all([
|
||||
loadTemplate<ALSDrumRack>('drumRack', abletonVersion),
|
||||
|
||||
Reference in New Issue
Block a user