T
I've spoken a few times here, it may seem silly to want to catch frequencies, but it turns out it's not, everything will depend on N factors, how precise you want the capture to be, the frequencies captured will be monophonic or not sounds? what would be the maximum frequency your tuner needs to capture, are many variables, there is no only way to do this, capture the Pitch/F0/Frequency/Period/Hz can be something physical, i.e. count how many times a pattern repeats or something psychoacoustic perception in which...There are different ways to do this, have how to do this in the domain of time (in JS there is the getFloatTimeDomainData to return the initial data in the time domain) applying techniques https://pt.wikipedia.org/wiki/Autocorrela%C3%A7%C3%A3o#:%7E:text=A%20autocorrela%C3%A7%C3%A3o%20%C3%A9%20a%20correla%C3%A7%C3%A3o,impl%C3%ADcita%20pelas%20suas%20frequ%C3%AAncias%20harm%C3%B3nicas. in the signal, there are techniques derived from self-correlation such as AMDF, ASDF, YIN, etc., in the domain of Frequency also exists the equivalent of self-correlation to find periodicity in the signal, there are more elaborate techniques that involve finding CEPSTRUM, other techniques involve adding subharmonics of spectral components returned by FFT(Fourier), by their code above I realized that it is going through the domain of frequency and trying to apply https://pt.wikipedia.org/wiki/Transformada_de_Fourier , there is a very simplistic way of finding frequencies using a FFT, it is not recommended to do this in tuners but it is an initial output for your tests and studies, when returning the FFT components you may find the signal periodicity if you find what is the most amplitude component, remembering that this method is quite rudimentary and may cause several false positives .... in short to do this you will need the following data:Frequencia = Fs * i / N
Onde:
Fs = taxa de amostragem (Hz)
i = index da maior amplitude/magnitude
N = número de pontos da sua FFT
The standard sampling rate https://developer.mozilla.org/pt-BR/docs/Web/API/Web_Audio_API It is 44100Hz then if you use 4096 points in your FFT vc will have a frequency of resolution order 10,7666015625hz i.e. each component may be erring approximately 10Hz so it's not that precise, you can then smooth/improve accuracy using http://fourier.eng.hmc.edu/e176/lectures/NM/node25.html with the help of the adjacent components ...I wrote a conceptual basic code to demonstrate how to use the web audio API to take the spectral components, capture the maximum amplitude of the signal and convert the index to hertz:Hertz. html<!DOCTYPE html>
<html>
<head>
<style>
div {
--volume: 0%;
position: relative;
width: 200px;
height: 20px;
margin: 50px;
background-color: #DDD;
}
div::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: var(--volume);
background-color: green;
transition: width 100ms linear;
}
button {
margin-left: 50px;
}
h3 {
margin: 20px;
font-family: sans-serif;
}
</style>
</head>
<body>
<h3>ederwander hertz teste</h3>
<div id="volumeBar"></div>
<button id="start">Start</button>
<button id="stop">Stop</button>
<p id="Hertz"></p>
<script type="text/javascript">
(async () => {
let volumeCallback = null;
let volumeInterval = null;
const volumeShow = document.getElementById('volumeBar');
const startButton = document.getElementById('start');
const stopButton = document.getElementById('stop');
var index = 0;
try {
const audioStream = await navigator.mediaDevices.getUserMedia({
audio: {
echoCancellation: true
}
});
const audioContext = new AudioContext();
const audioSource = audioContext.createMediaStreamSource(audioStream);
const analyser = audioContext.createAnalyser();
const sampleRate = audioContext.sampleRate;
analyser.fftSize = 4096;
analyser.minDecibels = -127;
analyser.maxDecibels = 0;
analyser.smoothingTimeConstant = 0.4;
audioSource.connect(analyser);
var FFT = new Uint8Array(analyser.frequencyBinCount);
volumeCallback = () => {
analyser.getByteFrequencyData(FFT);
let dBsoma = 0;
for(const dB of FFT)
dBsoma += dB;
var mediadB = dBsoma / FFT.length;
volumeShow.style.setProperty('--volume', (mediadB * 100 / 127) + '%');
index = FFT.indexOf(Math.max(...FFT));
document.getElementById("Hertz").innerHTML = index*sampleRate/analyser.fftSize;
};
} catch(e) {
console.error('Falha para inicializar', e);
}
startButton.addEventListener('click', () => {
// update a cada 100ms
if(volumeCallback !== null && volumeInterval === null)
volumeInterval = setInterval(volumeCallback, 100);
});
stopButton.addEventListener('click', () => {
if(volumeInterval !== null) {
clearInterval(volumeInterval);
volumeInterval = null;
}
});
})();
</script>
</body>
</html>
Basic test with pure senoids:440hz test with connected mic capturing a senoid 440Hz (link youtube of the senoid): It was very close, captured 441HzAnother test with senoid, trying to capture with Mic a senoid in 528Hz It also went very close...Well this is the basics of how to capture freq in frequency domain(FFT), the code is very simplistic, if you want something more accurate tries to introduce parabolic interpolation or use the combination of other methods described above ....PS: For capture of monophonic audios that approach a pure senoid this method can work, perhaps it is a good start to capture waves of loose string frequencies (string cut), this method could in short capture frequencies that lie above the limit of human hearing (22050hz) a little more than the limit of a super human ear ... follows table of frequencies by string of a guitar... I use a more elaborate code and more accurate than this example to tune my own instruments at home, loose string frequency table of a guitar:StringNoteFrequencyFormal note1 (more acute)Mi330 Hz.E42Si247 HzB.3Sun19 Hz.G.4Ré146 Hz.D35There110 Hz.A26Mi82 HzE.Then for each loose rope played you will have a parameter to know if it is near or far from the correct tuning!