cwilso / PitchDetect

Pitch detection in Web Audio using autocorrelation
https://cwilso.github.io/PitchDetect/
MIT License
1.31k stars 440 forks source link

I need some explanation #40

Closed olga-sinepalnikova closed 1 year ago

olga-sinepalnikova commented 1 year ago

Hi, i'm using your code for my course work (you can check it here or play here (you'll need a translator)) and i want to understand how your script work The main question is: what are these numbers and how did you get them

function noteFromPitch( frequency ) {
        var noteNum = 12 * (Math.log( frequency / 440 )/Math.log(2) );
        return Math.round( noteNum ) + 69;
}
function frequencyFromNoteNumber( note ) {
        return 440 * Math.pow(2,(note-69)/12);
}
function centsOffFromPitch( frequency, note ) {
        return Math.floor( 1200 * Math.log( frequency / frequencyFromNoteNumber( note ))/Math.log(2) );
}

or can you send a link to materials where i can read about it all?

cwilso commented 1 year ago

Hi Olga!

For both of the first two functions, it's important to know that the note A4 is MIDI note number 69. This corresponds to 440Hz, also known as "A above middle C", or A440. That's where the "440" and the "69" in both of those functions comes from - the functions calculate pitch frequency and note numbers from a known point (note 69 = 440Hz).

It's also important that 12 is the number of semitones in an octave (12 notes, spread evenly on a log scale), and the ratio of frequency from one octave to the next is 2. (A above middle C (440Hz) is exactly twice the frequency as A below middle C (220Hz), for example.). Finally, for the final function, you'll need to know that there are 100 cents in a semitone - that is, each semitone is 100 cents higher or lower than the semitone below or above it.

So, the first function is calculating the closest MIDI note from a known pitch. It does this by calculating a note offset from the known pitch of A440 - by dividing the frequency parameter by 440, you'll get a ratio from A440. You want this as a logarithmic ratio - even temperament pitches are spaced logarithmically - and log(n)/log(2) gives you the base two log because of the mathematics rule that "logarithm of x base b = log(x)/log(b)"

So, "(Math.log( frequency / 440 )/Math.log(2))" gives you the offset, but it's in octaves. The "12 *" part means it gives you the offset in notes. (noteNum is actually the OFFSET from A440. If you ran A220 - one octave below A440 - through this algorithm, noteNum would be -12.)

The Math.round() gives you the CLOSEST note - because the pitch might be 445Hz, for example, which should return A440 (note 69), but you need to round off. The "+69" is to give an absolute MIDI note number answer, rather than an offset.

The second function is the same thing, but in reverse - for a given note, calculate how much higher or lower it is than A440 in terms of note numbers, what ratio it has to A440's pitch, and then multiple that by 440Hz to get that note number's pitch.

The final function just tells you how far off the pitch is from the note number, in cents - that's frequently used for tuning purposes.

A useful reference for all this is https://newt.phys.unsw.edu.au/jw/notes.html.

Does that help?

olga-sinepalnikova commented 1 year ago

Yeah, thanks a lot for a quick answer!