fix: reduce main thread pressure to prevent audio buffer underruns

The periodic audio glitches were caused by main thread starvation:
~840 events/sec during playback starved the audio buffer.

Changes:
- Master clock 480→120 Hz (still 6x headroom for 300 BPM sixteenths)
- Connection cache: replace O(n) reduce hash with dirty flag (zero work
  on cache hit, flag set only when connections actually change)
- Tone.js lookAhead: 100ms→50ms for tighter scheduling
- ModuleNode LFO visualization RAF: 60fps→15fps (every 4th frame)
- ScopeDisplay RAF: 60fps→30fps (every 2nd frame)

Net effect: ~840 events/sec → ~200 events/sec during playback.
Audio processing gets 4x more main thread headroom.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jose Luis
2026-03-21 18:19:12 +01:00
parent 7596aea491
commit 7e6c960b0b
5 changed files with 26 additions and 10 deletions

View File

@@ -4,6 +4,7 @@
*/
import { playConnect, playDisconnect, playModuleAdd, playModuleDelete } from './uiSounds.js';
import { getModuleDef } from './moduleRegistry.js';
import { invalidateConnectionCache } from './audioEngine.js';
let _listeners = new Set();
let _nextModuleId = 1;
@@ -93,6 +94,7 @@ export function addConnection(fromModuleId, fromPort, toModuleId, toPort) {
const id = _nextConnectionId++;
state.connections.push({ id, from: { moduleId: fromModuleId, port: fromPort }, to: { moduleId: toModuleId, port: toPort } });
invalidateConnectionCache();
emit();
playConnect();
return id;
@@ -100,6 +102,7 @@ export function addConnection(fromModuleId, fromPort, toModuleId, toPort) {
export function removeConnection(id, _silent = false) {
state.connections = state.connections.filter(c => c.id !== id);
invalidateConnectionCache();
emit();
if (!_silent) playDisconnect();
}