Enhance Ableton export logic with scaled note velocity and filter fader canonicalization
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
buildClipEnvelopes,
|
||||
convertFaderValue,
|
||||
getFaderValueAt,
|
||||
getScaledNoteVelocity,
|
||||
} from '../src/lib/exporters/ableton/automation';
|
||||
import { AblGroupPatternOccurrence, AblTrack } from '../src/lib/transformers/ableton';
|
||||
import { FaderParam } from '../src/types/types';
|
||||
@@ -49,6 +50,28 @@ const track = {
|
||||
test('uses original note velocity until a VEL point is reached', () => {
|
||||
assert.equal(getFaderValueAt(occurrence, FaderParam.VEL, 96), undefined);
|
||||
assert.equal(getFaderValueAt(occurrence, FaderParam.VEL, 192), 0.5);
|
||||
assert.equal(getScaledNoteVelocity(101, occurrence, 96), 101);
|
||||
assert.equal(getScaledNoteVelocity(101, occurrence, 192), 51);
|
||||
});
|
||||
|
||||
test('scales P07-like note velocities with static and automated VEL values', () => {
|
||||
const staticVelocity = {
|
||||
...occurrence,
|
||||
faderParams: {
|
||||
...occurrence.faderParams,
|
||||
[FaderParam.VEL]: 0.5325199961662292,
|
||||
},
|
||||
faderAutomation: [
|
||||
{ parameter: FaderParam.VEL, position: 192, value: 0.25, flags: 0 },
|
||||
],
|
||||
};
|
||||
|
||||
assert.deepEqual(
|
||||
[127, 127, 48].map((velocity) => getScaledNoteVelocity(velocity, staticVelocity, 96)),
|
||||
[68, 68, 26],
|
||||
);
|
||||
assert.equal(getScaledNoteVelocity(127, staticVelocity, 192), 32);
|
||||
assert.equal(getScaledNoteVelocity(0, staticVelocity, 192), 1);
|
||||
});
|
||||
|
||||
test('preserves each pad pitch offset while applying group PTC automation', () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
canonicalizeFilterFaderValue,
|
||||
convertGroupFaderValue,
|
||||
FADER_POLICIES,
|
||||
getFaderPolicy,
|
||||
@@ -30,3 +31,10 @@ test('uses one group-fader conversion path for mixer and pad targets', () => {
|
||||
assert.equal(convertGroupFaderValue(FaderParam.PAN, 0.75, { track }), 0.5);
|
||||
assert.equal(convertGroupFaderValue(FaderParam.PTC, 0.75, { track, valueOffset: 7 }), 9.5);
|
||||
});
|
||||
|
||||
test('canonicalizes only effectively-open filter fader values', () => {
|
||||
assert.equal(canonicalizeFilterFaderValue(FaderParam.LPF, 0.9996299743652344), 1);
|
||||
assert.equal(canonicalizeFilterFaderValue(FaderParam.HPF, 0.0003700256347656), 0);
|
||||
assert.equal(canonicalizeFilterFaderValue(FaderParam.LPF, 0.998), 0.998);
|
||||
assert.equal(canonicalizeFilterFaderValue(FaderParam.HPF, 0.002), 0.002);
|
||||
});
|
||||
|
||||
@@ -213,7 +213,10 @@ test('serializes nested Live 10 Simplers without artificial empty Session clips'
|
||||
});
|
||||
data.settings.groupFaderParams.a[FaderParam.ATK] = 0.66;
|
||||
data.settings.groupFaderParams.a[FaderParam.REL] = 0.87;
|
||||
data.settings.groupFaderParams.a[FaderParam.LPF] = 0.9996299743652344;
|
||||
data.settings.groupFaderParams.a[FaderParam.VEL] = 0.5325199961662292;
|
||||
delete data.groupPatterns[0].notes[1];
|
||||
data.groupPatterns[0].notes[0] = [note(72, 0, 127), note(72, 96, 127), note(72, 192, 48)];
|
||||
delete data.groupPatterns[1].notes[0];
|
||||
data.groupPatterns[1].notes[1] = [note(67, 48), note(68, 96)];
|
||||
data.songPositions = [];
|
||||
@@ -272,7 +275,10 @@ test('serializes nested Live 10 Simplers without artificial empty Session clips'
|
||||
assert.doesNotMatch(xml, /<ReturnBranch\s/);
|
||||
assert.doesNotMatch(xml, /<AudioBranchSendInfo\s/);
|
||||
assert.doesNotMatch(xml, /Big Break Kit/);
|
||||
assert.doesNotMatch(xml, /<AutoFilter\b/);
|
||||
assert.doesNotMatch(xml, /<ClipEnvelope\b/);
|
||||
assert.equal([...xml.matchAll(/<MidiNoteEvent\b[^>]*\sVelocity="68"/g)].length, 2);
|
||||
assert.equal([...xml.matchAll(/<MidiNoteEvent\b[^>]*\sVelocity="26"/g)].length, 1);
|
||||
} finally {
|
||||
await server.close();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user