Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Output chord progressions as Roman numerals for analysis #89

Open
BdR76 opened this issue Mar 26, 2023 · 1 comment
Open

Output chord progressions as Roman numerals for analysis #89

BdR76 opened this issue Mar 26, 2023 · 1 comment

Comments

@BdR76
Copy link

BdR76 commented Mar 26, 2023

First of all this is an excellent library. I'm using it at the moment to analyze pop song and their chord progression.

I have a question, is it possible to add support for Roman Numeral notations? I couldn't find it in documentation or code, but maybe I'm overlooking something.

So I would like to do something like this for example:

cp = pychord.ChordProgression(["Am", "Dm", "G", "C", "F", "Bdim", "E", "Am"])

cp = cp.as_roman_numeral(scale="Amin") # note: .as_roman_numeral() would be new function

>>> ["i", "iv", "VII", "III", "VI", "iidim", "V", "i"]

The way I do it now is using the code below, which I realise is not ideal and a bit hack-y

ROMAN_NUMERAL = {
   -1: "??",
    1: "I",
    2: "II",
    3: "III",
    4: "IV",
    5: "V",
    6: "VI",
    7: "VII",
    8: "VIII"
}

# create chord progression
cp = pychord.ChordProgression(["Am", "Dm", "G", "C", "F", "Bdim", "E", "Am"])
chords_roman = [];
scale = pychord.Chord("Amin")

# which scale
scale_root = scale.root
scale_type = ("min" if str(scale.quality) == 'min' else "maj")
scale_idx = NOTE_VAL_DICT[scale.root]

# iterate all chords
for c in cp:
    # next chord
    str_chord = c
    # determine root note, relative to scale, 
    note_idx = NOTE_VAL_DICT[c.root]
    relative_idx = (12 + note_idx - scale_idx) % 12

    # determine roman numeral
    roman_idx = (-1 if relative_idx not in RELATIVE_KEY_DICT[scale_type] else RELATIVE_KEY_DICT[scale_type].index(relative_idx) + 1)
    roman_num = ROMAN_NUMERAL[roman_idx]
    chord_qual = str(c.quality)
    roman_num = (roman_num.lower() if chord_qual in ['m', 'min'] else roman_num)
    roman_num = roman_num + (chord_qual if chord_qual in ['dim'] else "")

    chords_roman.append(roman_num)

# result
print(cp)
print(f'Roman numerals (scale is {scale_root}{scale_type})')
print(chords_roman)

>>> Am | Dm | G | C | F | Bdim | E | Am
>>> Roman numerals (scale is Amin)
>>> ['i', 'iv', 'VII', 'III', 'VI', 'IIdim', 'V', 'i']
@yuma-m
Copy link
Owner

yuma-m commented Apr 1, 2023

Hello @BdR76, There's a Chord.note_from_index function to generate a Chord from a roman numeral expression, but there's no inversion function implemented. I appreciate it if you could create a pull request. I think Chord class should have as_roman_numeral method and ChordProgression class wraps it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants