diff --git a/analyze.js b/analyze.js index f3f4518..36efa42 100644 --- a/analyze.js +++ b/analyze.js @@ -1,78 +1,78 @@ document.querySelector('#analyze-pitch button').addEventListener('click', startListening); function startListening() { - navigator.mediaDevices.getUserMedia({ audio: true, video: false }) - .then(stream => { - const audioContext = new (window.AudioContext || window.webkitAudioContext)(); - const analyser = audioContext.createAnalyser(); - const microphone = audioContext.createMediaStreamSource(stream); - const scriptProcessor = audioContext.createScriptProcessor(2048, 1, 1); + navigator.mediaDevices.getUserMedia({ audio: true, video: false }) + .then(stream => { + const audioContext = new (window.AudioContext || window.webkitAudioContext)(); + const analyser = audioContext.createAnalyser(); + const microphone = audioContext.createMediaStreamSource(stream); + const scriptProcessor = audioContext.createScriptProcessor(2048, 1, 1); - analyser.smoothingTimeConstant = 0.3; - analyser.fftSize = 2048; + analyser.smoothingTimeConstant = 0.3; + analyser.fftSize = 2048; - microphone.connect(analyser); - analyser.connect(scriptProcessor); - scriptProcessor.connect(audioContext.destination); + microphone.connect(analyser); + analyser.connect(scriptProcessor); + scriptProcessor.connect(audioContext.destination); - scriptProcessor.onaudioprocess = () => { - const buffer = new Float32Array(analyser.fftSize); - analyser.getFloatTimeDomainData(buffer); - const pitch = autoCorrelate(buffer, audioContext.sampleRate); - document.querySelector('#analyze-pitch dd').textContent = pitch.toFixed(2); - }; - }) - .catch(err => { - console.error('Error accessing microphone: ' + err); - }); + scriptProcessor.onaudioprocess = () => { + const buffer = new Float32Array(analyser.fftSize); + analyser.getFloatTimeDomainData(buffer); + const pitch = autoCorrelate(buffer, audioContext.sampleRate); + document.querySelector('#analyze-pitch dd').textContent = pitch.toFixed(2); + }; + }) + .catch(err => { + console.error('Error accessing microphone: ' + err); + }); } function autoCorrelate(buffer, sampleRate) { - const SIZE = buffer.length; - const MAX_SAMPLES = Math.floor(SIZE / 2); - const MIN_SAMPLES = 0; - const GOOD_ENOUGH_CORRELATION = 0.9; + const SIZE = buffer.length; + const MAX_SAMPLES = Math.floor(SIZE / 2); + const MIN_SAMPLES = 0; + const GOOD_ENOUGH_CORRELATION = 0.9; - let bestOffset = -1; - let bestCorrelation = 0; - let rms = 0; - let foundGoodCorrelation = false; - let correlations = new Array(MAX_SAMPLES); + let bestOffset = -1; + let bestCorrelation = 0; + let rms = 0; + let foundGoodCorrelation = false; + let correlations = new Array(MAX_SAMPLES); - for (let i = 0; i < SIZE; i++) { - const val = buffer[i]; - rms += val * val; - } - rms = Math.sqrt(rms / SIZE); + for (let i = 0; i < SIZE; i++) { + const val = buffer[i]; + rms += val * val; + } + rms = Math.sqrt(rms / SIZE); - if (rms < 0.01) // not enough signal - return -1; + if (rms < 0.01) // not enough signal + return -1; - let lastCorrelation = 1; - for (let offset = MIN_SAMPLES; offset < MAX_SAMPLES; offset++) { - let correlation = 0; + let lastCorrelation = 1; + for (let offset = MIN_SAMPLES; offset < MAX_SAMPLES; offset++) { + let correlation = 0; - for (let i = 0; i < MAX_SAMPLES; i++) { - correlation += Math.abs((buffer[i]) - (buffer[i + offset])); - } - correlation = 1 - (correlation / MAX_SAMPLES); - correlations[offset] = correlation; + for (let i = 0; i < MAX_SAMPLES; i++) { + correlation += Math.abs((buffer[i]) - (buffer[i + offset])); + } + correlation = 1 - (correlation / MAX_SAMPLES); + correlations[offset] = correlation; - if ((correlation > GOOD_ENOUGH_CORRELATION) && (correlation > lastCorrelation)) { - foundGoodCorrelation = true; - if (correlation > bestCorrelation) { - bestCorrelation = correlation; - bestOffset = offset; - } - } else if (foundGoodCorrelation) { - const shift = (correlations[bestOffset + 1] - correlations[bestOffset - 1]) / correlations[bestOffset]; - return sampleRate / (bestOffset + (8 * shift)); - } - lastCorrelation = correlation; - } - if (bestCorrelation > 0.01) { - return sampleRate / bestOffset; - } - return -1; + if ((correlation > GOOD_ENOUGH_CORRELATION) && (correlation > lastCorrelation)) { + foundGoodCorrelation = true; + if (correlation > bestCorrelation) { + bestCorrelation = correlation; + bestOffset = offset; + } + } else if (foundGoodCorrelation) { + const shift = (correlations[bestOffset + 1] - correlations[bestOffset - 1]) / correlations[bestOffset]; + return sampleRate / (bestOffset + (8 * shift)); + } + lastCorrelation = correlation; + } + if (bestCorrelation > 0.01) { + return sampleRate / bestOffset; + } + return -1; }