user2482542
user2482542

Reputation: 361

Convert Frequency to Note in matlab

So I created a MATLAB program to detect the frequencies present in a piano recording. Now I need to convert these detected frequencies to their corresponding piano note.

I know there's a theory about using A4 (440Hz) as the reference note and deriving the rest based on that. But I'm looking for something like a look up table, where I can directly call the respective piano notes by looking at the look up table. I'm not quite sure how to go on about it though and so would like some suggestions on what I could do... Thanx

Upvotes: 2

Views: 1633

Answers (2)

mrflix
mrflix

Reputation: 390

You don't need a lookup table neither do you have to limit yourself to a specific range: (Javascript)

function getNoteFromFrequency(frequency) {
  var noteOrder = 'G# A A# B C C# D D# E F F# G'.split(" ");
  var n = Math.round(49 + 12 * Math.log(frequency / 440) / Math.log(2));
  var note = noteOrder[n % noteOrder.length];
  var index = Math.ceil((n - 3) / noteOrder.length);

  return note + index;
}

Upvotes: 0

Rody Oldenhuis
Rody Oldenhuis

Reputation: 38032

From here (just the first Google hit, nothing special), you can see that all the frequencies of all notes in the equal-tempered scale are related through

f = f0 · 2^(i/12)

with f0 = A4 = 440Hz, and i the number of half-steps away from the base note. This allows you to make a lookup table (LUT) for all the notes.

The only thing you need to put a bit of work in are:

  • find the entry in the LUT closest to your frequencies
  • map those entries to named notes
  • Define what the range of your source piano is (yes, ranges can differ).

Today's your lucky day (I'm bored and procrastinating :), so here's a fairly complete implementation, for notes from C0 to E8♭:

% Your frequencies (can be of any size, must be in Hz)
V = [17 450 4000];


% Generate the lookup table
LUT = 440 * (2^(1/12)).^(-57:42);

% The names of all those notes
noteNames = {...
    'AN' 'AN♯/BN♭' 'BN' 'CN' 'CN♯/DN♭' 'DN' 'DN♯/EN♭' 'EN' 'FN' 'FN♯/GN♭' 'GN' 'GN♯/AN♭'};
allNotes = [];
for ii = 0:8
    allNotes = [allNotes regexprep(noteNames, 'N', num2str(ii))]; end %#ok<AGROW>
allNotes = allNotes(4:end-4);

% Indices into the lookup table
[~,I] = min(abs(bsxfun(@minus, V(:), LUT)), [], 2);

% The named noted corresponding to your frequencies
allNotes(I)

Upvotes: 5

Related Questions