Skip to content

Commit 2470e5d

Browse files
authored
Merge pull request #163 from espadonne/main
fix multitrack EQ preset logging and Firefox worker decode
2 parents e5a8e43 + 3455fd2 commit 2470e5d

File tree

4 files changed

+66
-28
lines changed

4 files changed

+66
-28
lines changed

components/audio/DAW/Multitrack/AudioProcessor.js

Lines changed: 58 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,28 @@ class AudioProcessor {
117117
processing.reject(new Error(data.error));
118118
this.processingQueue.delete(clipId);
119119
break;
120+
121+
case 'decode-failed':
122+
// Worker fetched audio but couldn't decode (Firefox/Safari lack
123+
// OfflineAudioContext in workers). Decode on main thread using
124+
// the already-fetched data to avoid a second network request.
125+
debugLog('AudioProcessor', `🔄 Main-thread decode for ${clipId} (worker transferred data)`);
126+
processing.onProgress?.('decoding', 70);
127+
{
128+
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
129+
audioCtx.decodeAudioData(data.arrayBuffer)
130+
.then(audioBuffer => {
131+
const peaks = this.generateSimplePeaks(audioBuffer);
132+
processing.resolve({ duration: audioBuffer.duration, peaks, method: 'worker-fetch-main-decode' });
133+
})
134+
.catch(err => {
135+
processing.reject(new Error('Main-thread decode failed: ' + err.message));
136+
})
137+
.finally(() => {
138+
this.processingQueue.delete(clipId);
139+
});
140+
}
141+
break;
120142
}
121143
}
122144

@@ -451,32 +473,42 @@ class AudioProcessor {
451473
self.postMessage({ type: 'progress', clipId, stage: 'decoding', progress: 60 });
452474
console.log('🔧 Worker: Starting audio decode for', clipId);
453475
454-
// Use OfflineAudioContext in worker
455-
const decodeStart = performance.now();
456-
const sampleRate = WORKER_CONSTANTS.DEFAULT_SAMPLE_RATE;
457-
const offlineCtx = new OfflineAudioContext(2, sampleRate, sampleRate);
458-
const audioBuffer = await offlineCtx.decodeAudioData(arrayBuffer);
459-
const decodeTime = Math.round(performance.now() - decodeStart);
460-
console.log('🔧 Worker: Decode completed in', decodeTime + 'ms for', clipId, '(duration:', audioBuffer.duration.toFixed(2) + 's)');
461-
462-
self.postMessage({ type: 'progress', clipId, stage: 'generating-peaks', progress: 85 });
463-
console.log('🌊 Worker: Generating peaks for', clipId);
464-
465-
// Generate peaks
466-
const peaksStart = performance.now();
467-
const peaks = generatePeaks(audioBuffer, WORKER_CONSTANTS.DEFAULT_SAMPLES_PER_PIXEL);
468-
const peaksTime = Math.round(performance.now() - peaksStart);
469-
console.log('🌊 Worker: Peaks generated in', peaksTime + 'ms for', clipId, '(' + peaks.length + ' samples)');
470-
471-
const totalTime = Math.round(performance.now() - startTime);
472-
console.log('✅ Worker: Completed', clipId, 'in', totalTime + 'ms total');
473-
474-
self.postMessage({
475-
type: 'success',
476-
clipId,
477-
duration: audioBuffer.duration,
478-
peaks
479-
});
476+
// OfflineAudioContext is not available in Web Workers on Firefox/Safari.
477+
// If decode fails, transfer the fetched data back so the main thread
478+
// can decode without re-fetching.
479+
try {
480+
const decodeStart = performance.now();
481+
const sampleRate = WORKER_CONSTANTS.DEFAULT_SAMPLE_RATE;
482+
const offlineCtx = new OfflineAudioContext(2, sampleRate, sampleRate);
483+
const audioBuffer = await offlineCtx.decodeAudioData(arrayBuffer);
484+
const decodeTime = Math.round(performance.now() - decodeStart);
485+
console.log('🔧 Worker: Decode completed in', decodeTime + 'ms for', clipId, '(duration:', audioBuffer.duration.toFixed(2) + 's)');
486+
487+
self.postMessage({ type: 'progress', clipId, stage: 'generating-peaks', progress: 85 });
488+
console.log('🌊 Worker: Generating peaks for', clipId);
489+
490+
const peaksStart = performance.now();
491+
const peaks = generatePeaks(audioBuffer, WORKER_CONSTANTS.DEFAULT_SAMPLES_PER_PIXEL);
492+
const peaksTime = Math.round(performance.now() - peaksStart);
493+
console.log('🌊 Worker: Peaks generated in', peaksTime + 'ms for', clipId, '(' + peaks.length + ' samples)');
494+
495+
const totalTime = Math.round(performance.now() - startTime);
496+
console.log('✅ Worker: Completed', clipId, 'in', totalTime + 'ms total');
497+
498+
self.postMessage({
499+
type: 'success',
500+
clipId,
501+
duration: audioBuffer.duration,
502+
peaks
503+
});
504+
} catch (decodeError) {
505+
console.warn('⚠️ Worker: Decode failed for', clipId, '- transferring data to main thread:', decodeError.message);
506+
self.postMessage({
507+
type: 'decode-failed',
508+
clipId,
509+
arrayBuffer: arrayBuffer
510+
}, [arrayBuffer]);
511+
}
480512
481513
} catch (error) {
482514
const totalTime = Math.round(performance.now() - startTime);

components/audio/DAW/Multitrack/ClipEffectParametersModal.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ export default function ClipEffectParametersModal({
6868
clipId,
6969
effectId,
7070
effectType,
71-
currentParameters
71+
currentParameters,
72+
logOperation = null
7273
}) {
7374
const { tracks, updateTrack } = useMultitrack();
7475

@@ -121,6 +122,7 @@ export default function ClipEffectParametersModal({
121122
<EffectComponent
122123
parameters={currentParameters}
123124
onParametersChange={handleParameterChange}
125+
logOperation={logOperation}
124126
/>
125127
</Modal.Body>
126128

components/audio/DAW/Multitrack/ClipEffectsRack.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,7 @@ export default function ClipEffectsRack({ show, onHide, selectedClipId, logOpera
675675
effectId={selectedEffect.id}
676676
effectType={selectedEffect.type}
677677
currentParameters={selectedEffect.parameters}
678+
logOperation={logOperation}
678679
/>
679680
)}
680681
</Modal>

components/audio/DAW/Multitrack/effects/ClipEQ.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ function calculateFrequencyResponse(bands, sampleRate, numPoints = 512) {
244244
/**
245245
* Clip EQ Component
246246
*/
247-
export default function ClipEQ({ parameters, onParametersChange }) {
247+
export default function ClipEQ({ parameters, onParametersChange, logOperation = null }) {
248248
const canvasRef = useRef(null);
249249
const [eqBands, setEqBands] = useState(parameters.bands || EQPresets.flat.bands);
250250
const [outputGain, setOutputGain] = useState(parameters.outputGain || 0);
@@ -396,6 +396,9 @@ export default function ClipEQ({ parameters, onParametersChange }) {
396396
setEqBands(preset.bands.map(band => ({ ...band })));
397397
setOutputGain(preset.outputGain);
398398
onParametersChange({ bands: preset.bands, outputGain: preset.outputGain });
399+
if (logOperation && presetKey !== 'flat') {
400+
logOperation('eq_preset_applied', { presetName: preset.name });
401+
}
399402
}
400403
}}
401404
className="bg-secondary text-white border-0"

0 commit comments

Comments
 (0)