8
$\begingroup$

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

$\endgroup$
9
  • $\begingroup$ Huh, I didn't know that, I'll try a different upload site, what would you recomend? $\endgroup$
    – M.R.
    Jun 9, 2015 at 23:27
  • $\begingroup$ @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. $\endgroup$
    – M.R.
    Jun 9, 2015 at 23:28
  • $\begingroup$ @nasser Is there a way to upload the entire notebook or a zip to stackexhange? $\endgroup$
    – M.R.
    Jun 9, 2015 at 23:32
  • $\begingroup$ @nasser added a new like, wetransfer is a nice site. $\endgroup$
    – M.R.
    Jun 9, 2015 at 23:35
  • 1
    $\begingroup$ @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. $\endgroup$
    – M.R.
    Jun 10, 2015 at 2:35

1 Answer 1

7
$\begingroup$

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,
        GaborWavelet[6], Padding->0.0,
        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.

$\endgroup$
6
  • $\begingroup$ Thanks Timothy, this is exactly what I was looking for! $\endgroup$
    – M.R.
    Jun 10, 2015 at 11:52
  • $\begingroup$ @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? $\endgroup$
    – Steve
    Jul 30, 2015 at 17:26
  • $\begingroup$ @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. $\endgroup$ Jul 30, 2015 at 21:01
  • $\begingroup$ @M.R. Did you get Timothy's code to work for different audio files? See my comment above. $\endgroup$
    – Steve
    Jul 31, 2015 at 15:32
  • $\begingroup$ @TimothyWofford What did you figure out this weekend? $\endgroup$
    – Steve
    Aug 3, 2015 at 15:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.