Web Microphone (Copy 14718)
✨ Jabont
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Pitch Detection</title> </head> <body> <h1>Frequency (Hz)</h1> <h2 id="frequency">0.0</h2> <div> <button onclick="startPitchDetection()"> Start Pitch Detection </button> </div> <script> let audioCtx = new (window.AudioContext || window.webkitAudioContext)(); let microphoneStream = null; let analyserNode = audioCtx.createAnalyser() let audioData = new Float32Array(analyserNode.fftSize);; let corrolatedSignal = new Float32Array(analyserNode.fftSize);; let localMaxima = new Array(10); const frequencyDisplayElement = document.querySelector('#frequency'); function startPitchDetection() { navigator.mediaDevices.getUserMedia ({audio: true}) .then((stream) => { microphoneStream = audioCtx.createMediaStreamSource(stream); microphoneStream.connect(analyserNode); audioData = new Float32Array(analyserNode.fftSize); corrolatedSignal = new Float32Array(analyserNode.fftSize); setInterval(() => { analyserNode.getFloatTimeDomainData(audioData); let pitch = getAutocorrolatedPitch(); frequencyDisplayElement.innerHTML = `${pitch}`; }, 1000); }) .catch((err) => { console.log(err); }); } function getAutocorrolatedPitch() { // First: autocorrolate the signal let maximaCount = 0; for (let l = 0; l < analyserNode.fftSize; l++) { corrolatedSignal[l] = 0; for (let i = 0; i < analyserNode.fftSize - l; i++) { corrolatedSignal[l] += audioData[i] * audioData[i + l]; } if (l > 1) { if ((corrolatedSignal[l - 2] - corrolatedSignal[l - 1]) < 0 && (corrolatedSignal[l - 1] - corrolatedSignal[l]) > 0) { localMaxima[maximaCount] = (l - 1); maximaCount++; if ((maximaCount >= localMaxima.length)) break; } } } // Second: find the average distance in samples between maxima let maximaMean = localMaxima[0]; for (let i = 1; i < maximaCount; i++) maximaMean += localMaxima[i] - localMaxima[i - 1]; maximaMean /= maximaCount; return audioCtx.sampleRate / maximaMean; } </script> </body> </html>