From 4189a4cec6590888ced6b9a23d286a4db6e78739 Mon Sep 17 00:00:00 2001 From: Matthew Huntington Date: Tue, 11 Feb 2025 00:03:17 -0500 Subject: [PATCH] format analyze file --- .analyze.js.swp | Bin 20480 -> 0 bytes .app.js.swp | Bin 12288 -> 0 bytes analyze.js | 202 ++++++++++++++++++++++++------------------------ 3 files changed, 101 insertions(+), 101 deletions(-) delete mode 100644 .analyze.js.swp delete mode 100644 .app.js.swp diff --git a/.analyze.js.swp b/.analyze.js.swp deleted file mode 100644 index de9614fd7edf92afe76f289d54ee7cc2cdd3f07c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 zcmeI2dx#xZ9ml6hebm|*+k#X?PEu)SU-z+TCG2La+udxE)-7Rg8fe!T&Yd~;-f`#7 zxj8elk0fiOe`r;ZLeQ3qe~4(of)W&wR#C7@1VJkW3lm*sd}d!*1*`&A0jq#jz$#!BunJfOtOEbP3M9SV&LgPa zuB?hU0?^NOL%-K&e?OG{zI7;k_t1N9C_MYq{#XU90#*U5fK|XMU=^?mSOu&CRspMk zRlq9nUr>Pij`Opd9A|tFGRNjW-~a#OZI1J8Ai*ejH+Uzw4ZMPHp8*%aqhJL*01kjE zptRnHH2;A^f|tNA!I!~0m;?8MgW!)hI?fltYa}^LgNbcYqtgb-)2nztM4?0JC5c zxZqCk=QlXcW$+kif%gL!ybIh6-VT0(!;x=*O|S&UfCFB@p~xlh1V}*uPJ<7DDR2w; zCk|fz2L1|u1fBxt!Tn$lxSSuvn7+ZX$CFWk4!sxO4TYm947(%HAI$48V6CE$y6bBBE2llKt`;U zMqYyd^doCWj##KlTOVHZB^|-2oTwPG78AaX!hFQZ z($2GDX%BD3ajL#M!p>#EC^gk8h*Fux;YRiqMgC|Ujq*Pqnc7}MWT7VDE&`4(TyAZ62K z(5mq=$~MO8r?w`$KDqVN?LMn-{S2ior$|*qHuta^yW5>{HbT-{`J3Tpu5$9~^KC0md{HyA>#y3zQJ;tX~XUr(a*V$l?`*V{FE(DNtX5 z4}+NXB)Z1-6)TTc8bqbhfMiawu^E=ApxYJxz1pNMqY+1kU!f}WaiI{?V)q-hW*Rk1 zs1ckM5D781G-(7B@D?zfVZmcD&(c}WF5wzi^i3}uLBa1=9D-2cyX4@F! zKk|e_mXIEbIm2|b#Aj5ZQ$hkz^eU}L5iqh=k^U(CTXc?mBBLPPDKOxQ(1C_~EitKA z%Wf}4pI(wOVT*!CtZ^pgFbVF`Vq=7a^E$#?p-C6!MTt9O=p@s22i2pR7mDeY(N!#& zCew>`Co`Sb%v^a{`|Fo2>#}iHtS?IDZ?x)YEg2M9(uw{t#Q`Pu3W#_#CaaRysH zQKzy;G7pHerH}9{MN+dvOE@03r3#V`I+5(pgjotLB~9PbtHx}k=V?_(M{`9?)w2$0 zERA0L9hfu*$Ao-9&*c3MP>y7R(7yfkW2=>D`RX!S$|Sw&a^x_RnDWiVe+?&Za?r}JABe!v?E{@-or#N1f_(N98mESEkT)njL>;j+gEdz9I&x&cl-6qV&#f#jvzH-{ip*U z!GeAc>un{&Dc0g)Y{tGeIgPZ3GR0J+ENontM0g!J$6+Qyvmh%4YT>7_n7<+7t3jJ5 zQdKa+27F$uVg`t5JMkcjr(454hvcf&Yx>eO=@cfQR4`o!wAT_X(Xn*EDiFoY8>nbG zY8_KmvpFzBm;{lbs0gK`a`%@@#IU4@U{qq%T&hI)W<`RxO(oZ8JG5WxN=9|x_T^^h z&$Fup4OHG32{`j#e6xJvX!X*hI!?4M{6-tNp{~yPG{pWx- z|Jau6=R4Tve+fJS8sL6#AGjM-0G$QAgg7r`ai6F7_OS|B1*`&A0jq#jz$#!BunJfO ztO8a6tHA4~fZ4Tg4jf{X_Uwmg>z-}<=_r)WWr}V86x%<}u)EJM z^$7yQGjItxoge2Er^EUdFivJ8x>&-#dqMH8a7(fJMbt+q_%!$wxB%_~zsEts%i!zaGhhSI{r@=F z4St6^{vU(yfhWNS!4W_{0K34;xaa>C*aR`S59|i7;(q@!_#F5wI0Yv57P13q{dJOpk9f5-j)55bcl21fzi{lAL) z{VU+R;1YNWdE*9|d_T{Ezxk!0j3y803rRuECK}u2p7p7Yho47eMxUO*B`6q#QU>IA@gH kVIt$=Kub^Z>DKODaBb?lduVqPT5D8r2oPo7E9OMwKe-j)5dZ)H diff --git a/.app.js.swp b/.app.js.swp deleted file mode 100644 index 8df88374ac63735b318112f86188a92b170f7905..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2&u`pB6vwAk`LX>)1xEy$G@@&_S!a`g6hK?4C9MdwrL?7hq8ujntk=XlcI?^w zXd2ox2aX8Dwcsv$He-S%Kmr1G2n|)H*^MYtOPB-cJp>jCtCBY&e z^>`dcD_t&RIx2gDC!;Kmoews1vB?ak*(hKX*ieCdhqkvK1Kd1on2;=2PPVnm!g!~A;2j79uz-6!oE`l>)61)Un1pC16k0U;C4!jLs27f}^J3wiC16&2> zV-zq77zG|efi?S8Qd=Xnnish}_01_~p~sVzvpnRkj1sFp%pTC?0Zqkd!NQdbyb%Y| z?a)BPJvk#+V&2-HFyZt4vvu29WMPlf7HyJR(6&09CEn?*d#lx=jWK(5vj`tz4p)6S zY$|BCdBTOuk+>U)RMK^JL^C$tY|?}DB$FK{jQsIxV53yAvXJS417#1o zN>a%ZnWZ$vC3FoUVO8AOt;4Ih0N|?=_#KXDTC~fSri+%Ovo9o}9s!U@5n3q!YzQds0Ti*}zX2 zxbuV247fQWC3EMkQolH4D-Yugv+}7RRl}S>K!MlKojd`-v_rL3u&DYCcFCh8V2+3+ zFDG@{3rM5dOEsr6*pgn<%@*nu46`%MS$c?8tZ%uJEpjzMzH2H?Y5=CISm+DbLmPF? zy`Xcpx7uNZb5t?Gq4NjNMoX=_5*yUEN4&2!| z;mkwIV>VU#=2Zo;|X8D;BFw)PYB~s@iQ$Ktmrm)^7J~`#mUQe zmUaZOtEV)Nwd|Tz*rEGfPx>-(JKUY0i{y2x5^`B2gZH{S zS-7ef|*&oH-Sl^wRP~S3J_vm?LIQ=Vf>%$LIY%EMXkm5u? Yrv6R&h(0T_6$+~r%TL53`pz``2jY9fxc~qF diff --git a/analyze.js b/analyze.js index 4ab497f..cc78858 100644 --- a/analyze.js +++ b/analyze.js @@ -1,117 +1,117 @@ function startPitchDetection(callback) { - // Check for browser support - if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { - console.error("getUserMedia is not supported in this browser."); - return; - } + // Check for browser support + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + console.error("getUserMedia is not supported in this browser."); + return; + } - // Request access to the microphone - //navigator.mediaDevices.getUserMedia({ audio: true }) + // Request access to the microphone + //navigator.mediaDevices.getUserMedia({ audio: true }) navigator.mediaDevices.getUserMedia({ - audio: { - echoCancellation: false, - noiseSuppression: false, - autoGainControl: false - } -}) - .then(stream => { - // Create an audio context and an analyser node - const audioContext = new (window.AudioContext || window.webkitAudioContext)(); - const analyser = audioContext.createAnalyser(); - analyser.fftSize = 2048; // Set FFT size; higher values offer more precision but more latency + audio: { + echoCancellation: false, + noiseSuppression: false, + autoGainControl: false + } + }) + .then(stream => { + // Create an audio context and an analyser node + const audioContext = new (window.AudioContext || window.webkitAudioContext)(); + const analyser = audioContext.createAnalyser(); + analyser.fftSize = 2048; // Set FFT size; higher values offer more precision but more latency - // Connect the microphone stream to the analyser node - const source = audioContext.createMediaStreamSource(stream); - source.connect(analyser); + // Connect the microphone stream to the analyser node + const source = audioContext.createMediaStreamSource(stream); + source.connect(analyser); - // Create a buffer to hold the time domain data - const bufferLength = analyser.fftSize; - const buffer = new Float32Array(bufferLength); + // Create a buffer to hold the time domain data + const bufferLength = analyser.fftSize; + const buffer = new Float32Array(bufferLength); - /** - * Autocorrelation algorithm to estimate pitch from the audio buffer. - * Returns the estimated pitch in Hz, or -1 if no pitch is detected. - */ - function autoCorrelate(buf, sampleRate) { - const SIZE = buf.length; - let rms = 0; + /** + * Autocorrelation algorithm to estimate pitch from the audio buffer. + * Returns the estimated pitch in Hz, or -1 if no pitch is detected. + */ + function autoCorrelate(buf, sampleRate) { + const SIZE = buf.length; + let rms = 0; - // Compute Root Mean Square (RMS) to check if there's enough signal - for (let i = 0; i < SIZE; i++) { - const val = buf[i]; - rms += val * val; - } - rms = Math.sqrt(rms / SIZE); - if (rms < 0.01) // Signal too weak – likely silence - return -1; + // Compute Root Mean Square (RMS) to check if there's enough signal + for (let i = 0; i < SIZE; i++) { + const val = buf[i]; + rms += val * val; + } + rms = Math.sqrt(rms / SIZE); + if (rms < 0.01) // Signal too weak – likely silence + return -1; - // Trim the buffer to remove noise at the beginning and end - let r1 = 0, r2 = SIZE - 1; - for (let i = 0; i < SIZE; i++) { - if (Math.abs(buf[i]) < 0.2) { r1 = i; break; } - } - for (let i = 1; i < SIZE; i++) { - if (Math.abs(buf[SIZE - i]) < 0.2) { r2 = SIZE - i; break; } - } - const trimmedBuffer = buf.slice(r1, r2); - const trimmedSize = trimmedBuffer.length; + // Trim the buffer to remove noise at the beginning and end + let r1 = 0, r2 = SIZE - 1; + for (let i = 0; i < SIZE; i++) { + if (Math.abs(buf[i]) < 0.2) { r1 = i; break; } + } + for (let i = 1; i < SIZE; i++) { + if (Math.abs(buf[SIZE - i]) < 0.2) { r2 = SIZE - i; break; } + } + const trimmedBuffer = buf.slice(r1, r2); + const trimmedSize = trimmedBuffer.length; - // Calculate the autocorrelation of the trimmed buffer - const correlations = new Array(trimmedSize).fill(0); - for (let lag = 0; lag < trimmedSize; lag++) { - for (let i = 0; i < trimmedSize - lag; i++) { - correlations[lag] += trimmedBuffer[i] * trimmedBuffer[i + lag]; - } - } + // Calculate the autocorrelation of the trimmed buffer + const correlations = new Array(trimmedSize).fill(0); + for (let lag = 0; lag < trimmedSize; lag++) { + for (let i = 0; i < trimmedSize - lag; i++) { + correlations[lag] += trimmedBuffer[i] * trimmedBuffer[i + lag]; + } + } - // Find the first dip in the autocorrelation – skip lags before this point - let d = 0; - while (d < correlations.length - 1 && correlations[d] > correlations[d + 1]) { - d++; - } + // Find the first dip in the autocorrelation – skip lags before this point + let d = 0; + while (d < correlations.length - 1 && correlations[d] > correlations[d + 1]) { + d++; + } - // Search for the peak correlation after the dip - let maxVal = -1, maxPos = -1; - for (let i = d; i < correlations.length; i++) { - if (correlations[i] > maxVal) { - maxVal = correlations[i]; - maxPos = i; - } - } + // Search for the peak correlation after the dip + let maxVal = -1, maxPos = -1; + for (let i = d; i < correlations.length; i++) { + if (correlations[i] > maxVal) { + maxVal = correlations[i]; + maxPos = i; + } + } - // Parabolic interpolation for a more accurate peak estimate - let T0 = maxPos; - if (T0 > 0 && T0 < correlations.length - 1) { - const x1 = correlations[T0 - 1]; - const x2 = correlations[T0]; - const x3 = correlations[T0 + 1]; - const a = (x1 + x3 - 2 * x2) / 2; - const b = (x3 - x1) / 2; - if (a !== 0) { - T0 = T0 - b / (2 * a); - } - } + // Parabolic interpolation for a more accurate peak estimate + let T0 = maxPos; + if (T0 > 0 && T0 < correlations.length - 1) { + const x1 = correlations[T0 - 1]; + const x2 = correlations[T0]; + const x3 = correlations[T0 + 1]; + const a = (x1 + x3 - 2 * x2) / 2; + const b = (x3 - x1) / 2; + if (a !== 0) { + T0 = T0 - b / (2 * a); + } + } - // Convert lag to frequency - const pitch = sampleRate / T0; - return pitch; - } + // Convert lag to frequency + const pitch = sampleRate / T0; + return pitch; + } - // Continuously update and detect pitch - function updatePitch() { - // Get the latest time-domain data - analyser.getFloatTimeDomainData(buffer); - // Estimate pitch using our autocorrelation function - const pitch = autoCorrelate(buffer, audioContext.sampleRate); - // Pass the detected pitch (in Hz) to the provided callback - callback(pitch); - // Continue the update loop - requestAnimationFrame(updatePitch); - } + // Continuously update and detect pitch + function updatePitch() { + // Get the latest time-domain data + analyser.getFloatTimeDomainData(buffer); + // Estimate pitch using our autocorrelation function + const pitch = autoCorrelate(buffer, audioContext.sampleRate); + // Pass the detected pitch (in Hz) to the provided callback + callback(pitch); + // Continue the update loop + requestAnimationFrame(updatePitch); + } - updatePitch(); - }) - .catch(err => { - console.error("Error accessing the microphone: ", err); - }); + updatePitch(); + }) + .catch(err => { + console.error("Error accessing the microphone: ", err); + }); }