yuma-m / pychord Goto Github PK
View Code? Open in Web Editor NEWPython library to handle musical chords.
Home Page: https://pypi.python.org/pypi/pychord
License: MIT License
Python library to handle musical chords.
Home Page: https://pypi.python.org/pypi/pychord
License: MIT License
>>> cp = ChordProgression([Chord("C"), Chord("G")])
>>> cp.append(Chord("Am"))
>>> cp
["C", "G", "Am"]
>>> cp.transpose(+2)
>>> cp
["D", "A", "Bm"]
find_chords_from_notes(['A', 'C', 'E', 'G']) returns only 2 chords [<Chord: Am7>, <Chord: C6/A>]
What is your vision on this matter?
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']
As discussed in #54, some notes of a chord can be omitted as customary.
>>> note_to_chord(["C", "E", "G", "Bb", "D", "F"])
[<Chord: C11>]
# omit thrid
>>> note_to_chord(["C", "G", "Bb", "D", "F"])
[<Chord: C11>]
However, a quality can have only one combination of notes in the current implementation. It should support multiple combinations or omittable notes.
'11', [(0, 4, 7, 10, 14, 17), (0, 7, 10, 14, 17)]),
'11', Quality((0, 4, 7, 10, 14, 17), omittable=[4])),
some common notation that is missing:
Xsus = X5
Xmaj7 = XM7
Xmaj9 = XM9
Xm6 = (0, 3, 7, 9)
Xmadd9 = (0, 3, 7, 14)
also is there a general way to add quality for aliases?
It'd be nice to be able to iterate what qualities pychord supports.
My specific use case is that I'm scanning existing qualities, and adding some related ones, specifically a no-5th and flat-5th variation on existing qualities.
Right now I have to peek inside QualityManager()._qualities
to do that, which works, but is accessing a protected member, which is a little gross.
Perform like below.
>>> cp = ChordProgression(["C", "G/B", "Am"])
>>> estimate_key(cp)
{ <Key: C major>: 60%, <Key A minor>: 30%, ... }
I'm using pychord-0.5.1
In constant QUALITY_DICT, 13th quality does not have the same number of degrees. 11th degree or 9th degree is sometimes missing. While writing this message I can see similar situation with 11th chords. Here follow some examples:
Quality | degree 1 | degree 3 | degree 5 | degree 7 | degree 9 | degree 11 | degree 13 | Comments |
---|---|---|---|---|---|---|---|---|
7b9b13 | 0 | 4 | 7 | 10 | 13 | 17 | 20 | Correct |
13 | 0 | 4 | 7 | 10 | 14 | 21 | WRONG: 11th degree is missing | |
13-9 & 13b9 | 0 | 4 | 7 | 10 | 13 | 21 | WRONG: 11th degree is missing | |
13+9 & 13#9 | 0 | 4 | 7 | 10 | 15 | 21 | WRONG: 11th degree is missing | |
13+11 & 13#11 | 0 | 4 | 7 | 10 | 18 | 21 | WRONG: 9th degree is missing | |
7-13 & 7b13 | 0 | 4 | 7 | 10 | 20 | WRONG: 9th degree & 11th degree are missing | ||
11 | 0 | 7 | 10 | 14 | 17 | X | WRONG: 3rd degree is missing | |
7+11 & 7#11 | 0 | 4 | 7 | 10 | 18 | X | WRONG: 9th degree is missing |
I think that basically:
Could you please take these observation into account and fix things that may be fixed ?
I can make these changes by myself and make a pull request but I need to know how I can contribute to your project on github.
Cheers,
Serge.
I would like to have classes which can generate a list of random chords. I will probably start the development very soon. This may be useful for music theory training
I ran into this issue. If you try to recognize a say cmaj like so
ch = find_chords_from_notes(["C", "E", "G"])
It works correctly.
However, if i reorder the notes in a way that is not a rotation of the chord
ch = find_chords_from_notes(["C", "G", "E"])
finds nothing.
Would sorting the nodes before recognizing the chord help?
Hello,
I would like to transpose my C chord (C, E, G) in order to get (D, F, A).
I tried:
1/ c = Chord.from_note_index(note=1, quality="", scale="Cmaj")
c.transpose(2)
2/ c = Chord.from_note_index(note=2, quality="", scale="Cmaj")
Both give (D, F#, A). I was expected to get (D, F, A) in the second case
Thanks !
I stumbled upon your repo while looking for a way to easily parse my database of chord progressions into midi files. However, my database has a lot of augmented and diminished triads in the progressions. The program was not able to recognize augmented or diminished chords, which slightly disappointed me. It would be nice to have these triads built-in instead of needing a custom parser to recognize them
Regards,
Connor
When can the chordfree support Chinese?
from pychord import Chord
print(Chord('A/C#').components())
['C#', 'A', 'C#', 'E'] #not sure why C# should appear twice?
Could be included in qualities.py the diminished 5th triad
and chords with omitted notes using either 'no' or 'omitt
2 notes
('no5', (0, 4)), # ('omitt5', (0, 4))
('m(no5)', (0, 3)), # ('m(omitt5)', (0, 3))
3 notes
('(b5)', (0, 4, 6)),
4 notes
('sus4add2', (0, 2, 5, 7),
('sus4add9', (0, 5, 7, 14),
Hi!
this is a followup on some of the comments in issue#34
this followup analysis is based on 117k songs form UltimateGuitarTabs 1960-2023 in the rock, pop, country and folk genres, totaling at 9.9M chords instances and 6000 different chords. this is for my project https://github.com/eyaler/uku3le currently being reworked.
These are the most common issues and qualities that fail parsing, and seem to have sensible solutions
i could go on... but the above helped me reduce the song reject rate in my case from 6.3% to 1.1%
fixes may be required also in from_note_index()
of course instead of dealing with all specific cases it would be useful to have generic normalization rules as
fixing caps where no ambiguity, eg: ADD, Add -> add
fixing strings where no ambiguity, eg: maj -> M
removing brackets where no ambiguity
ends with + or +5 -> aug
etc.
such generic rules (where there is no danger of ambiguity) would greatly help maintaining the qualities table.
disclaimer: i do not know anything about music or music theory.
Thinking about dropping support for Python 2.7, 3.4.
Hello,
Please could you add this missing quality?
m7b9b5 = 0, 3, 6, 10, 13
It's the 9th version of the m7-5 which can be found in 6th degree chord in major scales.
Implement feature to transpose chord.
>>> c = Chord("Am7/G")
>>> c.transpose(3)
>>> c
Cm7/Bb
Hello,
I'm using pychord-0.5.1
In constant QUALITY_DICT, there are 2 "2 chords qualities"
I think that sus quality should be implemented with value (0,5) since I guess it corresponds to the interval between degree-V to degree-VIII (from G to upper C for example)
If I'm right, could you please make the change ?
Sincerely,
Serge.
>>> c = Chord("CM9/D")
>>> c.components(visible=True)
["C", "E", "G", "B", "D"]
However, the expected result is ["D", "C", "E", "G", "B"]
.
Currently chords can be created with .from_note_index
, with chord quality manually specified.
>>> [Chord.from_note_index(note=i, quality="", scale="Cmaj") for i in range(1,8)]
[<Chord: C>, <Chord: D>, <Chord: E>, <Chord: F>, <Chord: G>, <Chord: A>, <Chord: B>]
Basically note
is only there to determine the root. I was thinking of adding a boolean option to adjust certain chord qualities according to the scale.
>>> [Chord.from_note_index(note=i, quality="", diatonic=True, scale="Cmaj") for i in range(1,8)]
[<Chord: C>, <Chord: Dm>, <Chord: Em>, <Chord: F>, <Chord: G>, <Chord: Am>, <Chord: Bdim>]
I think this option would be most useful for the most "generic" chord types, like triads and sevenths.
I'd be willing to implement this; I think it'll be mostly messing around with RELATIVE_KEY_DICT
to get the relevant scale degrees, no?
An example:
In [12]: Chord('Abm').components()
Out[12]: ['Ab', 'B', 'Eb'] # Should be ['Ab', 'Cb', 'Eb']
I might be mistaken (not an expert in music theory), but I believe Cb
is more correct, from a strict perspective.
Chord construction starts with note names: an A triad of any flavor must contain some flavor of A, C, and E. From there, you apply the sharps, flats, double-flats, or double-sharps as needed to achieve the desired chord root and quality. So, in our example, we start with an A triad (A, C, E), flatten everything because we want root of Ab (Ab, Cb, Eb). Since the
A-to-C distance is already minor, we're done.
Another example:
In [13]: Chord('Cbm').components()
Out[13]: ['B', 'D', 'Gb'] # Should be ['Cb', 'Ebb', 'Gb']
Start with C, E, G. Flatten everything to Cb, Eb, Gb. The C-to-E distance is major, so double-flatten it to get Cb, Ebb, Gb.
Thanks for taking a look and working on this project.
Miserlou/chords2midi#34 which blocks ldrolez/free-midi-chords#21
hi, currently trying to fix these issues but im busy with school. is it possible to construct chords of any notes or are we limited to diatonic triads with this library? i'll look into it more if you think it's feasible
Dear all,
the example on the bottom shows the problems with "pychord.analyzer.note_to_chord"
Calling this function the second time using the same parameters returns a different result.
Debugging shows that def: "find_quality" in "pychord/pychord/analyzer.py" has a reference to "QUALITY_DICT" that includes crahed data in "dim6". Try this example and you will see.
#!/usr/bin/env python3
from future import print_function
import sys
from pychord.analyzer import note_to_chord
from pychord.utils import val_to_note
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Constants
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
k_NOTE_OFF = 0
k_NOTE_ON = 1
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Chords
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
def chord_receive(info,n1,n2,n3,n4):
print("\n",info," --------------------")
print("----with notes", n1,n2,n3,n4)
a_chords = note_to_chord([n1,n2,n3,n4])
print("--------",a_chords)
for a_chord in a_chords:
print('------------a_chordStr=%s' % (a_chord))
print("------------components", a_chord.components(True))
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Main
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
try:
chord_receive("first","D","F","G#","B")
chord_receive("second","D","F","G#","B")
6 corresponds to F# when the scale is A, but 6 corresponds Gb when the scale is Db.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.