diff --git a/packages/stage-ui/src/composables/audio/audio-analyzer.ts b/packages/stage-ui/src/composables/audio/audio-analyzer.ts index aae870343..5e1ff8116 100644 --- a/packages/stage-ui/src/composables/audio/audio-analyzer.ts +++ b/packages/stage-ui/src/composables/audio/audio-analyzer.ts @@ -1,4 +1,4 @@ -import { ref } from 'vue' +import { onUnmounted, ref } from 'vue' export function useAudioAnalyzer() { const analyzer = ref() @@ -8,14 +8,22 @@ export function useAudioAnalyzer() { const onAnalyzerUpdateHooks = ref void | Promise>>([]) const volumeLevel = ref(0) // 0-100 - const error = ref() + const amplification = 3 // Amplification factor for volume visualization + function onAnalyzerUpdate(callback: (volumeLevel: number) => void | Promise) { onAnalyzerUpdateHooks.value.push(callback) + return () => { + // optional cleanup if consumer wants to unsubscribe + onAnalyzerUpdateHooks.value = onAnalyzerUpdateHooks.value.filter(cb => cb !== callback) + } } function start() { + if (animationFrame.value) + return // prevent multiple loops + const analyze = () => { if (!analyzer.value || !dataArray.value) return @@ -29,7 +37,7 @@ export function useAudioAnalyzer() { sum += dataArray.value[i] * dataArray.value[i] } const rms = Math.sqrt(sum / dataArray.value.length) - volumeLevel.value = Math.min(100, (rms / 255) * 100 * 3) // Amplify for better visualization + volumeLevel.value = Math.min(100, (rms / 255) * 100 * amplification) // Amplify for better visualization for (const hook of onAnalyzerUpdateHooks.value) { hook(volumeLevel.value) @@ -47,14 +55,14 @@ export function useAudioAnalyzer() { } try { - // Create analyser for volume detection + // Create analyser for volume detection analyzer.value = audioContext.createAnalyser() analyzer.value.fftSize = 256 analyzer.value.smoothingTimeConstant = 0.3 // Set up data array for analysis const bufferLength = analyzer.value.frequencyBinCount - dataArray.value = new Uint8Array(bufferLength) + dataArray.value = new Uint8Array(bufferLength) as Uint8Array // Start audio analysis loop start() @@ -68,7 +76,7 @@ export function useAudioAnalyzer() { } function stopAnalyzer() { - // Stop animation frame + // Stop animation frame if (animationFrame.value) { cancelAnimationFrame(animationFrame.value) animationFrame.value = undefined @@ -78,9 +86,14 @@ export function useAudioAnalyzer() { dataArray.value = undefined } + // Auto-cleanup when used in a component + onUnmounted(() => { + stopAnalyzer() + }) + return { volumeLevel, - + error, startAnalyzer, stopAnalyzer, onAnalyzerUpdate,