tonaljs / tonal

A music theory library for Javascript
https://tonaljs.github.io/tonal/docs
3.81k stars 219 forks source link

Chord detection only working for C as root (Why is this a feature?!) #130

Closed mathaou closed 4 years ago

mathaou commented 4 years ago

The docs here say that the 'poor man's chord detection' works on the list of intervals starting from C. In testing this, I was trying to get my program to detect chord inversions, so I gave it a Dm7 (C4, D4, F4, A4) and cycled through trying to find an inversion that the library liked.

permutations(arr).map(e => {
    let index = 3;
    let sanitizedArray = e.map(note => {
      let trim = note.replace(/[\d]/gm, '');
      if(trim === 'C') index++; // need to be more sophisticated in future, just for testing
      return `${trim}${index}`;
    });

    let chroma = chordType(pcset(sanitizedArray).chroma);

    if(chroma.name.length > 0) console.log(sanitizedArray);
  });

In testing, I found that it only likes specific C chords (C+/ Cdim didn't work, didn't test any complex extensions past maj7). Why does it matter that the list of intervals has to start from C? A collection of intervals [1P, 3M, 5P] will be a major chord no matter where you go, so why is the root note the deciding factor on chord quality? My fix for the moment is to transpose every one of my notes down whatever interval gets me to C as the root, but goodness gracious...

danigb commented 4 years ago

Something is broken with that. I'll look into it. Thanks for reporting!

thebne commented 4 years ago

@danigb just out of curiosity, why don't you support some more "fancy" chord detection?

Either a limited one like this and this - or a more sophisticated version like music21's (I don't like their implementation because it has no runtime boundaries, but that's the most robust implementation I've seen).

Adding to that, in the (allegedly broken) version above there's no way to get the root. So if I use ["C", "E", "G"] it returns the same as ["G", "E", "C"] etc.

danigb commented 4 years ago

Just because is not easy, and I didn't find time nor energy to write one πŸ€·β€β™€

But help with this issue is more than welcomed (ideas on how to implement, PRs, comments...)

mathaou commented 4 years ago

@danigb Not to knock the work you've already done, but the library I found to work best out of the large handful of different ones I've tried was mingus. If you have a midi controller you can test out the full capability of its chord detection here, but I think they have a really solid way of determining chords. I had to peek/modify the source some in working on that chord detection website, but It's pretty powerful and super cool. Only thing is they have to really ground themselves in super traditional music theory (the 2nd of an D# major scale is E# for example), so I had to throw various mixes of chords at it until I got something that worked (replaced all C's with B# and F with E#), then just sanitized it down to the more friendly enharmonic note and removed all duplicate responses before presenting to the user.

danigb commented 4 years ago

@mathaou Thanks for mingus link! πŸ™ I liked a lot, looks like a great library.

And encouraged by that, I've implemented a chord detection mechanism that hopefully works πŸ˜… (it's not based in mungus approach, since tonal uses dictionaries... but it was nice to see other approaches)

So heres the new package: https://github.com/tonaljs/tonal/tree/master/packages/chord-detect

thebne commented 4 years ago

@danigb , just wanted to thank you for this logic again. I finally released some stable-ish version of my MIDI project, and I'm basing my chord detection (along with some other manipulation) solely on this functionality :)

The only thing I'd consider changing is removing the capital M from the detection (or making it optional), since it's not the standard notation I'm familiar with.