diff --git a/src/tools/mic-tester/mic-tester.service.ts b/src/tools/mic-tester/mic-tester.service.ts new file mode 100644 index 00000000..412b0a94 --- /dev/null +++ b/src/tools/mic-tester/mic-tester.service.ts @@ -0,0 +1,87 @@ +import { ref, onBeforeUnmount } from 'vue'; + +export function useMicrophoneService() { + let audioContext: AudioContext | null = null; + let delayNode: DelayNode | null = null; + let sourceNode: MediaStreamAudioSourceNode | null = null; + let analyserNode: AnalyserNode | null = null; + let stream: MediaStream | null = null; + + const isPlaying = ref(false); + const loudnessLevel = ref(0); // Observable for loudness + + const startMicReplay = async () => { + if (!audioContext) { + audioContext = new (window.AudioContext || window.webkitAudioContext)(); + } + + try { + stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + } catch (err) { + console.error('Microphone access denied:', err); + alert('Microphone access denied (the error is also in the console):', err); + return; + } + + sourceNode = audioContext.createMediaStreamSource(stream); + delayNode = audioContext.createDelay(1.0); + delayNode.delayTime.value = 1.0; + + analyserNode = audioContext.createAnalyser(); + analyserNode.fftSize = 256; + + // Connect nodes: mic -> delay -> speakers + sourceNode.connect(delayNode); + delayNode.connect(audioContext.destination); + sourceNode.connect(analyserNode); + + isPlaying.value = true; + measureLoudness(); + }; + + const stopMicReplay = () => { + if (audioContext && stream) { + const tracks = stream.getTracks(); + tracks.forEach(track => track.stop()); + audioContext.close(); + audioContext = null; + isPlaying.value = false; + loudnessLevel.value = 0; + } + }; + + // Measure loudness and update loudness bar + const measureLoudness = () => { + const dataArray = new Uint8Array(analyserNode!.frequencyBinCount); + + const updateLoudness = () => { + analyserNode!.getByteFrequencyData(dataArray); + + // Calculate average loudness + let sum = 0; + dataArray.forEach(value => sum += value); + const average = sum / dataArray.length; + + // Update the observable loudness level + loudnessLevel.value = average; + + if (isPlaying.value) { + requestAnimationFrame(updateLoudness); + } + }; + + updateLoudness(); + }; + + // Cleanup on service destruction + onBeforeUnmount(() => { + stopMicReplay(); + }); + + return { + startMicReplay, + stopMicReplay, + loudnessLevel, + isPlaying + }; +} diff --git a/src/tools/mic-tester/mic-tester.vue b/src/tools/mic-tester/mic-tester.vue index 6bbda911..fc0addad 100644 --- a/src/tools/mic-tester/mic-tester.vue +++ b/src/tools/mic-tester/mic-tester.vue @@ -1,99 +1,23 @@