@@ -589,7 +589,8 @@ function updateInputGain() {
589589
590590// Debounce timer for cache render
591591let cacheRenderTimeout = null ;
592- const CACHE_RENDER_DEBOUNCE_MS = 300 ;
592+ let cacheRenderQueued = false ;
593+ const CACHE_RENDER_DEBOUNCE_MS = 500 ;
593594
594595// getCurrentSettings imported from ./ui/controls.js
595596
@@ -614,13 +615,15 @@ function scheduleRenderToCache() {
614615
615616 // Debounce the actual render
616617 cacheRenderTimeout = setTimeout ( async ( ) => {
618+ cacheRenderTimeout = null ;
617619 if ( ! fileState . originalBuffer ) return ;
618620 if ( fileState . isRenderingCache ) {
619- // Already rendering, schedule another after current completes
620- scheduleRenderToCache ( ) ;
621+ // Already rendering; remember to run one more pass when it completes.
622+ cacheRenderQueued = true ;
621623 return ;
622624 }
623625
626+ cacheRenderQueued = false ;
624627 fileState . isRenderingCache = true ;
625628 console . log ( '[Cache] Starting render, version:' , thisVersion ) ;
626629
@@ -644,13 +647,11 @@ function scheduleRenderToCache() {
644647 // Build a master-preview buffer that matches export (includes final limiter).
645648 'export' ,
646649 ( progress , status ) => {
647- // Show progress in modal and LUFS display
650+ // Show progress in LUFS display
648651 const percent = Math . round ( progress * 100 ) ;
649652 if ( outputLufsDisplay && progress < 1 ) {
650653 outputLufsDisplay . textContent = `${ percent } %` ;
651654 }
652- // Update modal progress (85-100% range for cache phase)
653- showLoadingModal ( 'Building cache...' , 85 + percent * 0.15 ) ;
654655 }
655656 ) ;
656657 buffer = result . audioBuffer ;
@@ -688,7 +689,6 @@ function scheduleRenderToCache() {
688689 // Enable playback now that cache is ready
689690 playBtn . disabled = false ;
690691 stopBtn . disabled = false ;
691- hideLoadingModal ( ) ;
692692
693693 console . log ( '[Cache] Render complete, version:' , thisVersion , 'LUFS:' , lufs . toFixed ( 1 ) ) ;
694694
@@ -711,9 +711,12 @@ function scheduleRenderToCache() {
711711 // Still enable playback on error so user isn't stuck
712712 playBtn . disabled = false ;
713713 stopBtn . disabled = false ;
714- hideLoadingModal ( ) ;
715714 } finally {
716715 fileState . isRenderingCache = false ;
716+ if ( cacheRenderQueued && fileState . originalBuffer ) {
717+ cacheRenderQueued = false ;
718+ scheduleRenderToCache ( ) ;
719+ }
717720 }
718721 } , CACHE_RENDER_DEBOUNCE_MS ) ;
719722}
@@ -905,8 +908,8 @@ async function loadAudioFile(file) {
905908 // Show live indicators
906909 document . body . classList . add ( 'audio-loaded' ) ;
907910
908- // Show "Building cache" modal - stays visible until cache render completes
909- showLoadingModal ( 'Building cache...' , 85 ) ;
911+ // Cache render now runs in the background; loading flow is complete here.
912+ hideLoadingModal ( ) ;
910913
911914 return true ;
912915 } catch ( error ) {
@@ -1524,7 +1527,7 @@ normalizeLoudness.addEventListener('change', () => {
15241527 updateChecklist ( ) ;
15251528} ) ;
15261529
1527- [ truePeakLimit , cleanLowEnd , glueCompression , centerBass , cutMud , addAir , tapeWarmth , autoLevel , addPunch ] . forEach ( el => {
1530+ [ truePeakLimit , cleanLowEnd , glueCompression , centerBass , cutMud , autoLevel ] . forEach ( el => {
15281531 el . addEventListener ( 'change' , ( ) => {
15291532 updateAudioChain ( ) ;
15301533 updateChecklist ( ) ;
@@ -1536,6 +1539,7 @@ normalizeLoudness.addEventListener('change', () => {
15361539[ deharsh , addAir , tapeWarmth , addPunch ] . forEach ( el => {
15371540 el . addEventListener ( 'change' , ( ) => {
15381541 processEffects ( ) ;
1542+ updateChecklist ( ) ;
15391543 } ) ;
15401544} ) ;
15411545
@@ -1554,7 +1558,11 @@ levelMatchBtn.addEventListener('change', () => {
15541558stereoWidthSlider . addEventListener ( 'input' , ( ) => {
15551559 stereoWidthValue . textContent = `${ stereoWidthSlider . value } %` ;
15561560 updateStereoWidth ( ) ;
1557- // Stereo width affects the master preview render, so rebuild cache.
1561+ // Live node update while dragging; defer cache rebuild to interaction commit.
1562+ updateAudioChain ( { scheduleCache : false } ) ;
1563+ } ) ;
1564+
1565+ stereoWidthSlider . addEventListener ( 'change' , ( ) => {
15581566 updateAudioChain ( ) ;
15591567} ) ;
15601568
@@ -1642,7 +1650,7 @@ targetLufsSlider.addEventListener('input', () => {
16421650
16431651 lufsDebounceTimeout = setTimeout ( ( ) => {
16441652 renormalizeAudio ( newValue ) ;
1645- } , 300 ) ; // 300ms debounce
1653+ } , 500 ) ; // 500ms debounce
16461654} ) ;
16471655
16481656[ sampleRate , bitDepth ] . forEach ( el => {
@@ -1764,13 +1772,25 @@ window.addEventListener('beforeunload', () => {
17641772initFaders ( {
17651773 onInputGainChange : ( val ) => {
17661774 updateInputGain ( ) ;
1767- // Input gain affects the master preview render (pre-limiter), so rebuild cache.
1775+ // Keep live chain responsive while dragging; defer cache rebuild to commit.
1776+ updateAudioChain ( { scheduleCache : false } ) ;
1777+ } ,
1778+ onInputGainChangeEnd : ( ) => {
1779+ updateAudioChain ( ) ;
1780+ } ,
1781+ onCeilingChange : ( ) => {
1782+ // Live preview updates immediately; defer cache rebuild to commit.
1783+ updateAudioChain ( { scheduleCache : false } ) ;
1784+ } ,
1785+ onCeilingChangeEnd : ( ) => {
17681786 updateAudioChain ( ) ;
17691787 } ,
1770- onCeilingChange : ( val ) => updateAudioChain ( ) ,
17711788 onEQChange : ( eqVals ) => {
17721789 updateEQ ( ) ;
1773- // EQ affects the master preview render, so rebuild cache.
1790+ // Keep live chain responsive while dragging; defer cache rebuild to commit.
1791+ updateAudioChain ( { scheduleCache : false } ) ;
1792+ } ,
1793+ onEQChangeEnd : ( ) => {
17741794 updateAudioChain ( ) ;
17751795 }
17761796} ) ;
0 commit comments