diff --git a/src/lib/exporters/ableton/utils.ts b/src/lib/exporters/ableton/utils.ts index 70148fe..6cb16f0 100644 --- a/src/lib/exporters/ableton/utils.ts +++ b/src/lib/exporters/ableton/utils.ts @@ -99,9 +99,20 @@ export function koEnvRangeToSeconds(value: number, maxSeconds: number) { return (value / 255) * maxSeconds; } -export function fixIds(node: any): any { +function isPointeeTarget(key: string, idNum: number) { + return ( + idNum > MIN_ID || + key === 'AutomationTarget' || + key === 'ModulationTarget' || + key === 'Pointee' || + key.endsWith('ModulationTarget') || + key.startsWith('ControllerTargets.') + ); +} + +function assignIds(node: any, key: string, idMap: Map): any { if (Array.isArray(node)) { - return node.map((n) => fixIds(n)); + return node.map((n) => assignIds(n, key, idMap)); } if (!node || typeof node !== 'object') { @@ -111,22 +122,55 @@ export function fixIds(node: any): any { if (node?.['@Id']) { const idNum = parseInt(String(node['@Id']), 10); - if (idNum > MIN_ID && !assignedNodes.has(node)) { + if (isPointeeTarget(key, idNum) && !assignedNodes.has(node)) { + const previousId = String(node['@Id']); node['@Id'] = _id; assignedNodes.add(node); + idMap.set(previousId, _id); _id++; } } + Object.keys(node).forEach((childKey) => { + if (!childKey.startsWith('@')) { + node[childKey] = assignIds(node[childKey], childKey, idMap); + } + }); + + return node; +} + +function rewritePointeeIds(node: any, idMap: Map): any { + if (Array.isArray(node)) { + return node.map((item) => rewritePointeeIds(item, idMap)); + } + + if (!node || typeof node !== 'object') { + return node; + } + + if (node.PointeeId?.['@Value'] !== undefined) { + const replacement = idMap.get(String(node.PointeeId['@Value'])); + if (replacement !== undefined) { + node.PointeeId['@Value'] = replacement; + } + } + Object.keys(node).forEach((key) => { if (!key.startsWith('@')) { - node[key] = fixIds(node[key]); + node[key] = rewritePointeeIds(node[key], idMap); } }); return node; } +export function fixIds(node: any): any { + const idMap = new Map(); + assignIds(node, '', idMap); + return rewritePointeeIds(node, idMap); +} + export function resetIds() { _id = START_ID; assignedNodes = new WeakSet();