From b842c4d33f277d46731f822453fc88bbd738e620 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Tue, 14 Jul 2026 08:16:34 +0200 Subject: [PATCH] Feature: Implement device ID assignment utility and apply it to build processes --- src/lib/exporters/ableton/builders.ts | 18 ++++++++++++------ tests/ableton-hybrid.test.ts | 10 ++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/lib/exporters/ableton/builders.ts b/src/lib/exporters/ableton/builders.ts index 01132ce..5ff3292 100644 --- a/src/lib/exporters/ableton/builders.ts +++ b/src/lib/exporters/ableton/builders.ts @@ -121,6 +121,14 @@ function setLive10SampleReference(fileRef: any, sampleName: string) { fileRef.LivePackId = { '@Value': '' }; } +export function assignDeviceListIds(devices: Record[]) { + devices.forEach((device, deviceIdx) => { + Object.values(device).forEach((devContent: any) => { + devContent['@Id'] = deviceIdx; + }); + }); +} + function targetFor( parameter: any, maxValue?: number, @@ -647,10 +655,12 @@ async function buildDrumRackDevice(koTrack: AblTrack, abletonVersion: AbletonVer drumBranch.BranchInfo.SendingNote['@Value'] = subtrack.drumRackSendingNote ?? subtrack.rootNote; // not sure if this matters drumBranch.BranchInfo.ChokeGroup['@Value'] = subtrack.inChokeGroup ? 1 : 0; drumBranch.MixerDevice.Volume.Manual['@Value'] = subtrack.volume; - drumBranch.DeviceChain.MidiToAudioDeviceChain.Devices = await buildSimplerDevice( + const branchDevices = await buildSimplerDevice( subtrack, abletonVersion, ); + assignDeviceListIds([branchDevices]); + drumBranch.DeviceChain.MidiToAudioDeviceChain.Devices = branchDevices; device.Branches.DrumBranch.push(drumBranch); } @@ -727,11 +737,7 @@ async function buildTrack( } // make sure id's are sequential in device chain - midiTrack.DeviceChain.DeviceChain.Devices['#'].forEach((device, deviceIdx) => { - Object.values(device).forEach((devContent: any) => { - devContent['@Id'] = deviceIdx; - }); - }); + assignDeviceListIds(midiTrack.DeviceChain.DeviceChain.Devices['#']); if (exporterParams.groupTracks) { midiTrack.DeviceChain.AudioOutputRouting.Target['@Value'] = 'AudioOut/GroupTrack'; diff --git a/tests/ableton-hybrid.test.ts b/tests/ableton-hybrid.test.ts index 2c4b26e..c9351a0 100644 --- a/tests/ableton-hybrid.test.ts +++ b/tests/ableton-hybrid.test.ts @@ -1,5 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; +import { assignDeviceListIds } from '../src/lib/exporters/ableton/builders'; import abletonTransformer, { AblTrack, getDrumRackMidiNote } from '../src/lib/transformers/ableton'; import { EffectType, @@ -144,6 +145,15 @@ function trackShape(tracks: AblTrack[]) { })); } +test('assigns IDs to every device-list member, including nested rack devices', () => { + const devices = [{ OriginalSimpler: {} }, { AutoFilter: {} }]; + + assignDeviceListIds(devices); + + assert.equal(devices[0].OriginalSimpler['@Id'], 0); + assert.equal(devices[1].AutoFilter['@Id'], 1); +}); + test('automatically builds a per-group rack without flattening chromatic pads', () => { const result = abletonTransformer(project(), { includeArchivedSamples: true,