jeanma's picture
Omnilingual ASR transcription demo
ae238b3 verified
import { useRef, useEffect, useState } from 'react';
interface UseAudioAnalyzerReturn {
audioData: Uint8Array;
analyser: AnalyserNode | null;
connectToStream: (stream: MediaStream) => void;
disconnect: () => void;
}
export const useAudioAnalyzer = (fftSize: number = 256): UseAudioAnalyzerReturn => {
const [audioData, setAudioData] = useState<Uint8Array>(new Uint8Array(fftSize / 2));
const [analyser, setAnalyser] = useState<AnalyserNode | null>(null);
const audioContextRef = useRef<AudioContext | null>(null);
const sourceRef = useRef<MediaStreamAudioSourceNode | null>(null);
const animationFrameRef = useRef<number | null>(null);
const connectToStream = (stream: MediaStream) => {
try {
// Clean up existing connections
disconnect();
// Create new audio context and analyser
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
const analyserNode = audioContext.createAnalyser();
analyserNode.fftSize = fftSize;
analyserNode.smoothingTimeConstant = 0.8;
// Connect stream to analyser
const source = audioContext.createMediaStreamSource(stream);
source.connect(analyserNode);
// Store references
audioContextRef.current = audioContext;
sourceRef.current = source;
setAnalyser(analyserNode);
// Start updating audio data
const bufferLength = analyserNode.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const updateAudioData = () => {
if (analyserNode) {
analyserNode.getByteFrequencyData(dataArray);
setAudioData(new Uint8Array(dataArray));
animationFrameRef.current = requestAnimationFrame(updateAudioData);
}
};
updateAudioData();
} catch (error) {
console.error('Error setting up audio analyzer:', error);
}
};
const disconnect = () => {
// Cancel animation frame
if (animationFrameRef.current) {
cancelAnimationFrame(animationFrameRef.current);
animationFrameRef.current = null;
}
// Disconnect audio nodes
if (sourceRef.current) {
sourceRef.current.disconnect();
sourceRef.current = null;
}
// Close audio context
if (audioContextRef.current) {
audioContextRef.current.close();
audioContextRef.current = null;
}
setAnalyser(null);
setAudioData(new Uint8Array(fftSize / 2));
};
// Cleanup on unmount
useEffect(() => {
return () => {
disconnect();
};
}, []);
return {
audioData,
analyser,
connectToStream,
disconnect,
};
};