fix: apply max plugin delay compensation#1806
Conversation
|
Codex review completed. Result: PASS No actionable regressions were found in the latency propagation and compensation changes. Local verification passed:
|
There was a problem hiding this comment.
Pull request overview
This PR updates VST3 plugin delay compensation (PDC) to align tracks using the maximum active plugin-chain latency across tracks, while also improving how VST3 latency is tracked and updated live from the companion.
Changes:
- Track and sanitize per-instance VST3 latency (
latencySamples) from instantiation and subsequentlatencyInfoupdates. - Compute cross-track PDC using max chain latency and apply per-track compensation (instead of delaying each track by its own latency).
- Exclude bypassed plugins from chain latency totals; add/extend unit tests around bypass and live latency updates.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/vst3.ts | Adds optional latencySamples to the active instance model. |
| src/store/vst3Store.ts | Persists initial latency on load and adds _updateLatency to apply/store live latency updates. |
| src/store/tests/vst3Store.test.ts | Tests initial latency capture and live latency updates to store + PluginEngine. |
| src/services/vst3bridge/tests/PluginEngineLatency.test.ts | Tests bypass exclusion from latency and live latency update behavior. |
| src/services/vst3bridge/VST3PluginAdapter.ts | Stores latency internally and exposes setLatencySamples for live updates. |
| src/hooks/useVST3Connection.ts | Subscribes to latencyInfo and forwards updates into the store. |
| src/hooks/useEffectsSync.ts | Applies max-latency-based compensation across tracks via TrackNode.setLatencyCompensation. |
| src/hooks/tests/useEffectsSync.vst3.test.ts | Adds coverage for cross-track max-latency compensation calculations. |
| src/engine/PluginEngine.ts | Excludes bypassed nodes from chain latency; adds setPluginLatency API for live updates. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -166,7 +172,10 @@ export const useVST3Store = create<VST3Store>()((set, get) => ({ | |||
| client.off('instanceCreated', onCreated); | |||
| client.off('error', onError); | |||
| const params = (msg.parameters as VST3Parameter[]) ?? []; | |||
| resolve(params); | |||
| resolve({ | |||
| parameters: params, | |||
| latencySamples: sanitizeLatencySamples(msg.latencySamples), | |||
| }); | |||
| } | |||
| }; | |||
|
|
|||
| @@ -182,7 +191,7 @@ export const useVST3Store = create<VST3Store>()((set, get) => ({ | |||
| }); | |||
| /** | ||
| * Derive a stable fingerprint of VST3 instances for effect chain syncing. | ||
| * Only includes fields that affect audio routing (instanceId, trackId, enabled). | ||
| */ | ||
| function selectVst3EffectChainKey(s: { instances: Record<string, VST3ActiveInstance> }): string { | ||
| const parts: string[] = []; | ||
| for (const [id, inst] of Object.entries(s.instances)) { | ||
| parts.push(`${id}:${inst.trackId ?? ''}:${inst.enabled ? '1' : '0'}`); | ||
| parts.push(`${id}:${inst.trackId ?? ''}:${inst.enabled ? '1' : '0'}:${inst.latencySamples ?? 0}`); | ||
| } |
| total += node.plugin.latencySamples ?? 0; | ||
| if (node.bypassed) continue; | ||
| const latencySamples = node.plugin.latencySamples ?? 0; | ||
| total += Number.isFinite(latencySamples) ? Math.max(0, latencySamples) : 0; |
|
Addressed Copilot review feedback:
Re-verified locally:
|
|
Addressed second Codex review finding:
Re-verified locally:
|
|
Addressed third Codex review finding:
Re-verified locally:
|
|
Final Codex review completed after the signal-path PDC fix. Result: PASS No discrete, actionable regressions were identified in the diff. Type checking and targeted changed tests pass. |
Summary
Verification
Closes #1783