# How to extract notes and chords from audio?

I have a 3-second recording of a guitar chord which you can safely download here. I'm trying to use Mathematica's wavelet features to find out the notes in the chord, at least the docs says that something like this is possible.

So I import it and create a ContinuousWaveletTransform object:

s = Import["chord.aiff"];
cwd = ContinuousWaveletTransform[snd, GaborWavelet[6], {Automatic, 12}]


But I'm stuck here (there are so many wavelet functions I don't know which to use). How can I detect the frequencies for the 4 or 5 notes that make up this chords. I'd like the output to be "c", "d#", etc... and the octave for each note as well.

Reference: frequencies of musical notes

• Huh, I didn't know that, I'll try a different upload site, what would you recomend? – M.R. Jun 9 '15 at 23:27
• @Nasser I googled "upload file link" and speedy share came up first, it's not a virus, I was able to download it, but I'm adding a new upload on a different site. – M.R. Jun 9 '15 at 23:28
• @nasser Is there a way to upload the entire notebook or a zip to stackexhange? – M.R. Jun 9 '15 at 23:32
• @nasser added a new like, wetransfer is a nice site. – M.R. Jun 9 '15 at 23:35
• @Nasser Nice! With or without wavelets is fine by me, but how do you recover the actual notes C4 F5 etc...? I play piano so the actual note values are important to me. – M.R. Jun 10 '15 at 2:35

Here is a rather quick attempt. Define a function which converts frequencies to the nearest pitch.

NoteName[freq_] := Module[{notelist,freqlist,list},
notelist = {"B"}~Join~
Nest[Join[{"C", "C\[Sharp]/D\[Flat]", "D", "D\[Sharp]/E\[Flat]",
"E", "F", "F\[Sharp]/G\[Flat]", "G", "G\[Sharp]/A\[Flat]",
"A", "A\[Sharp]/B\[Flat]", "B"}, #] &, {"C",
"C\[Sharp]/D\[Flat]", "D", "D\[Sharp]/E\[Flat]", "E", "F",
"F\[Sharp]/G\[Flat]", "G", "G\[Sharp]/A\[Flat]", "A",
"A\[Sharp]/B\[Flat]", "B"}, 3]~Join~{"C", "C\[Sharp]/D\[Flat]"};

freqlist = {440.*2^(-2 - 9/12 + #/12 - 1/24),
440.*2^(-2 - 9/12 + #/12 + 1/24)} & /@ Range[-1, 49];

list = Transpose[{notelist,freqlist}];

If[freq < 440.*2^(-2 - 9/12 - 1/12 - 1/24), "Too Low",
If[freq > 440.*2^(-2 - 9/12 + 49/12 + 1/24),"Too High",
Select[list, #[[2, 1]] < freq < #[[2, 2]] &][[1, 1]]
]]
]


Now import the data and perform the wavelet transform.

data = Import["chord.mp3","Data"]//First;
sampleRate = Import["chord.mp3","SampleRate"];
cwt = ContinuousWaveletTransform[data,
SampleRate->sampleRate,
WaveletScale->Automatic];


Convert the results to frequencies and pitches.

notes =
(* convert scales to frequencies *)
(#1[[1]] -> sampleRate/#1[[2]] &) /@ cwt["Scales"] //
(* remove frequencies which are too low or too high *)
# /. {({u_,v_} -> n_?(# < 440.*2^(-2 - 5/12 - 1/24) || # >
440.*2^(-2 + 40/12 + 1/24) &)) :> Sequence[]} & //
(* Label frequencies with pitches *)
# /. ({a_, b_} -> c_) :> ({a, b} -> {NoteName[c], c}) &


The result

{{6, 2} -> {"B", 1006.68}, {6, 3} -> {"G\[Sharp]/A\[Flat]", 846.515},
{6, 4} -> {"F", 711.832}, {7, 1} -> {"D", 598.577},
{7, 2} -> {"B", 503.341}, {7, 3} -> {"G\[Sharp]/A\[Flat]", 423.258},
{7, 4} -> {"F", 355.916}, {8, 1} -> {"D", 299.288},
{8, 2} -> {"B", 251.67},  {8, 3} -> {"G\[Sharp]/A\[Flat]", 211.629},
{8, 4} -> {"F", 177.958}, {9, 1} -> {"D", 149.644},
{9, 2} -> {"B", 125.835}, {9, 3} -> {"G\[Sharp]/A\[Flat]", 105.814},
{9, 4} -> {"F", 88.979}}


Looks like an Fdim chord.

• Thanks Timothy, this is exactly what I was looking for! – M.R. Jun 10 '15 at 11:52
• @TimothyWofford Issue: It appears that no matter which audio file I use to test your code cwt["Scales"] always returns the same essential values thus the frequency calculations always return the same values, resulting in~~> 'Fdim' each time. Could you address this? – Steve Jul 30 '15 at 17:26
• @Steve, I said it was a quick attempt...I just looked at the documentation examples and pieced it together without testing. I assumed someone (like the OP) would verify whether it works or not. I was uncertain about the answer because every time the topic of wavelet scale vs frequency comes up, people suddenly become vague. I will do some research this weekend. Thanks for the quality control. – Timothy Wofford Jul 30 '15 at 21:01
• @M.R. Did you get Timothy's code to work for different audio files? See my comment above. – Steve Jul 31 '15 at 15:32
• @TimothyWofford What did you figure out this weekend? – Steve Aug 3 '15 at 15:37