tonaljs/tonal

Chord detection inconsistency

this-fifo opened this issue · 2 comments

Hey @danigb, I am really thankful to you for this incredible project!

I would like your help understanding what is the expected notation for Chord.get, there are many ways to write chords and it seems like some works but others don't.

Additionally, it looks like there are cases where it will behave inconsistently — as in, it works through one API but not through the other.

Here's a simple example to illustrate my point:

import * as Tonal from '@tonaljs/tonal'
console.log(Tonal.Chord.getChord('maj9', 'G', 'F#'))
console.log(Tonal.Chord.get('Gmaj9/F#'))
console.log(Tonal.Chord.getChord('maj9', 'E', 'F#'))
console.log(Tonal.Chord.get('Emaj9/F#'))

That will output the following:

{
  empty: false,
  name: 'G major ninth over F#',
  setNum: 2705,
  chroma: '101010010001',
  normalized: '100011010100',
  intervals: [ '7M', '9M', '8P', '10M', '12P' ],
  quality: 'Major',
  aliases: [ 'maj9', 'Δ9', '^9' ],
  symbol: 'Gmaj9/F#',
  type: 'major ninth',
  root: 'F#',
  rootDegree: 4,
  tonic: 'G',
  notes: [ 'F#', 'A', 'G', 'B', 'D' ]
}, // <— That makes sense 👍
{
  empty: true,
  name: '',
  symbol: '',
  root: '',
  rootDegree: 0,
  type: '',
  tonic: null,
  setNum: NaN,
  quality: 'Unknown',
  chroma: '',
  normalized: '',
  aliases: [],
  notes: [],
  intervals: []
}, // <— This is literally the symbol given from the previous output, 'Gmaj9/F#' that is. Seems like the parser may not work well here? 🤔
{
  empty: true,
  name: '',
  symbol: '',
  root: '',
  rootDegree: 0,
  type: '',
  tonic: null,
  setNum: NaN,
  quality: 'Unknown',
  chroma: '',
  normalized: '',
  aliases: [],
  notes: [],
  intervals: []
}, // <— This is just a different tonic 'E' instead of 'G'. For some reason it doesn't like this? 🤔
{
  empty: true,
  name: '',
  symbol: '',
  root: '',
  rootDegree: 0,
  type: '',
  tonic: null,
  setNum: NaN,
  quality: 'Unknown',
  chroma: '',
  normalized: '',
  aliases: [],
  notes: [],
  intervals: []
} // <— Same as previous but through the `get` API. 🤔

What's also interesting, is that if I try to detect the chord from its notes then it is able to construct it correctly.

Tonal.Chord.detect(['F#', 'B', 'D#', 'G#', 'B', 'E']) // Outputs —> [ 'Emaj9/F#' ]

I noticed the issue goes away if I import from tonal instead of @tonaljs/tonal — I may have imported the package dependencies incorrectly by importing the package directly as opposed to the library as a whole.

This now works

import * as Tonal from 'tonal'

console.log(Tonal.Chord.getChord('maj9', 'G', 'F#'))
console.log(Tonal.Chord.get('Gmaj9/F#'))
console.log(Tonal.Chord.getChord('maj9', 'E', 'F#'))
console.log(Tonal.Chord.get('Emaj9/F#'))

Outputs

{
  empty: false,
  name: 'G major ninth over F#',
  setNum: 2705,
  chroma: '101010010001',
  normalized: '100011010100',
  intervals: [ '7M', '9M', '8P', '10M', '12P' ],
  quality: 'Major',
  aliases: [ 'maj9', 'Δ9', '^9' ],
  symbol: 'Gmaj9/F#',
  tonic: 'G',
  type: 'major ninth',
  root: 'F#',
  bass: 'F#',
  rootDegree: 4,
  notes: [ 'F#', 'A', 'G', 'B', 'D' ]
}
{
  empty: false,
  name: 'G major ninth over F#',
  setNum: 2705,
  chroma: '101010010001',
  normalized: '100011010100',
  intervals: [ '7M', '9M', '8P', '10M', '12P' ],
  quality: 'Major',
  aliases: [ 'maj9', 'Δ9', '^9' ],
  symbol: 'Gmaj9/F#',
  tonic: 'G',
  type: 'major ninth',
  root: 'F#',
  bass: 'F#',
  rootDegree: 4,
  notes: [ 'F#', 'A', 'G', 'B', 'D' ]
}
{
  empty: false,
  name: 'E major ninth over F#',
  setNum: 2705,
  chroma: '101010010001',
  normalized: '100011010100',
  intervals: [ '-7m', '1P', '3M', '5P', '7M', '9M' ],
  quality: 'Major',
  aliases: [ 'maj9', 'Δ9', '^9' ],
  symbol: 'Emaj9/F#',
  tonic: 'E',
  type: 'major ninth',
  root: '',
  bass: 'F#',
  rootDegree: NaN,
  notes: [ 'F#', 'E', 'G#', 'B', 'D#', 'F#' ]
}
{
  empty: false,
  name: 'E major ninth over F#',
  setNum: 2705,
  chroma: '101010010001',
  normalized: '100011010100',
  intervals: [ '-7m', '1P', '3M', '5P', '7M', '9M' ],
  quality: 'Major',
  aliases: [ 'maj9', 'Δ9', '^9' ],
  symbol: 'Emaj9/F#',
  tonic: 'E',
  type: 'major ninth',
  root: '',
  bass: 'F#',
  rootDegree: NaN,
  notes: [ 'F#', 'E', 'G#', 'B', 'D#', 'F#' ]
}