Pyharmonytooling
python code to manage music harmony
Install / Use
/learn @Moustov/PyharmonytoolingREADME
PyHarmonyTooling
<div align="center"> <img src="circle_of_5th.png" width="300" alt="Circle of 5th"> </div>OVERVIEW
Series of tools to handle harmony in music
Install
pip install pyHarmonyTooling
Features
Usages of this library:
- https://github.com/Moustov/pyHarmonyUI
Warning
All possible chord names are defined by the PyChord library See here
Features on Harmony
Find substitutes from a chord
It is possible to find a chord other names
from pyharmonytools.harmony.cof_chord import CofChord
chord = "G6"
substitutes = CofChord.find_substitutes(Chord(chord))
print("substitutes from :", chord, substitutes)
ouput (detailed log skipped):
substitutes from : G6 [<Chord: Em7>, <Chord: Em7/9>, <Chord: Em7/11>, <Chord: Em7/13>, <Chord: Em/D>, <Chord: Em7/B>, <Chord: Em7/D>, <Chord: Em7/G>, <Chord: Em7/9/B>, <Chord: Em7/9/D>, <Chord: Em7/9/G>, <Chord: Em7/11/B>, <Chord: Em7/11/D>, <Chord: Em7/11/G>, <Chord: Em7/13/B>, <Chord: Em7/13/D>, <Chord: Em7/13/G>, <Chord: G6>, <Chord: G6/9>, <Chord: G/E>, <Chord: G6/B>, <Chord: G6/D>, <Chord: G6/E>, <Chord: G6/9/B>, <Chord: G6/9/D>, <Chord: G6/9/E>]
Guess chord from notes
To guess a chord from notes, there is a feature that enables:
- to have a list of possible chords that include all the provided notes
- to limit this list to chord with exactly the same notes (
is_strictly_compliant=True) - to provide the simplest possible chord (
simplest_chord_only=True)
Code sample:
from pychord import Chord
from pyharmonytools.harmony.cof_chord import CofChord
from pyharmonytools.harmony.note import Note
expected = [Chord("Cmaj7")]
notes = [Note("C"), Note("E"), Note("G"), Note("B")]
res = CofChord.guess_chord_name(notes, is_strictly_compliant=True, simplest_chord_only=True)
print(res == expected)
output:
True
Guitar tools
Find chord fingering on a guitar
from pyharmonytools.guitar_neck.fingering import Fingering
fng = Fingering()
f = fng.get_fingering_from_chord(Chord("C"))
print(f)
output:
[[0, 3, 2, 0, 1, 0], [0, 3, 2, 0, 1, 3], [3, 3, 2, 0, 1, 0], ... ]
Find chords from tabs
This tool is done to guess involved chords from a guitar tab. It is supposed to handle tab guitar techniques such as
h: Hammer-onp: Pull-off^: Bend/: Slide up\: Slide down~: Vibrato
The involved method is based on building chords as long as the fret range is acceptable (Fingering.FINGERING_WIDTH) and you have enough fingers or a tab therefore, sometimes the chord guessing is not accurate since musical phrases are not taken into account.
This wizard is then merely a guide you should check with both hears and fingers! :wink:
from pyharmonytools.displays.console_for_guitar_tab import ConsoleForGuitarTab
from pyharmonytools.guitar_tab.guitar_tab import GuitarTab
tab = """
e|--11-----11-----10-----11---|
B|--11-----12-----11-----11---|
G|--11-----13-----10-----11---|
D|----------------------------|
A|----------------------------|
E|----------------------------|
"""
gt = GuitarTab(tab_full)
ConsoleForGuitarTab.display(gt)
Output
----------------
Bar #0:
D#m G#m A# D#m
e|--11-----11-----10-----11----|
B|--11-----12-----11-----11----|
G|--11-----13-----10-----11----|
D|-----------------------------|
A|-----------------------------|
E|-----------------------------|
If the tab if well formatted (only tabbed strings with names and | as bars separators), a whole song can be processes. Among the unit tests, a chord guessing of Johann Sebastian Bach's Prelude for Cello, Suite No. 1 (BWV1007) can be found.
Song Processing
Song processing tools on simple text song
It is possible to extracts chords from a song
from pychord import Chord
from pyharmonytools.song.text_song import TextSongWithLineForChords
song = """
A E
Happy Birthday to you
E A
Happy Birthday to you
A7 D
Happy Birthday dear (name)
A E A
Happy Birthday to you
"""
the_song = TextSongWithLineForChords()
the_song.digest(song)
print(the_song.chords_sequence)
output:
[<Chord: A>, <Chord: E>, <Chord: E>, <Chord: A>, <Chord: A7>, <Chord: D>, <Chord: A>, <Chord: E>, <Chord: A>]
Guess the tonality & mode of a song"
It is possible to guess a song tonality and the mode that goes along
from pyharmonytools.displays.console import _HarmonyLogger
from pyharmonytools.harmony.circle_of_5th import CircleOf5th
_HarmonyLogger.outcome_level_of_detail = _HarmonyLogger.LOD_NONE
ouput:
[1.0, 'A', 'Natural Major', ['A', 'B', 'Db', 'D', 'E', 'Gb', 'Ab', 'Ab']]
Guess borrowed chords in a song
It is possible to guess borrowed chords from a song from a tonality point of view
song = """
C Dm Em F G Am Bdim Cm
"""
cof = CircleOf5thNaturalMajor()
cp = cof.digest_song(song)
tone = cof.generate_circle_of_fifths()["C"]
borrowed_chords = cof.get_borrowed_chords(tone, cp)
print(" Borrowed chords:", borrowed_chords.keys())
ouput:
Borrowed chords: dict_keys(['Cm'])
Get degrees on a song from a guessed tonality
It is possible to guess a chord song from a degree point of view
from pychord import Chord
from pyharmonytools.displays.unit_test_report import UnitTestReport
from pyharmonytools.song.text_song import TextSongWithLineForChords
song = """
A E
Happy Birthday to you
E A
Happy Birthday to you
A7 D
Happy Birthday dear (name)
A E A
Happy Birthday to you
"""
the_song = TextSongWithLineForChords()
the_song.digest(song)
the_song.generate_degrees_from_chord_progression()
assert (the_song.degrees == ['I', 'V', 'V', 'I', 'I7', 'IV', 'I', 'V', 'I'])
Guess chord progressions ("cadences" in a song)
It is possible to guess remarkable cadences in a song
from deepdiff import DeepDiff
from pyharmonytools.displays.unit_test_report import UnitTestReport
from pyharmonytools.song.text_song import TextSongWithLineForChords
song = """
A E
Happy Birthday to you
E A
Happy Birthday to you
A7 D
Happy Birthday dear (name)
A E A
Happy Birthday to you
"""
the_song = TextSongWithLineForChords()
the_song.digest(song)
the_song.generate_degrees_from_chord_progression()
res = the_song.get_remarquable_cadences()
expected = {'REMARQUABLE_CADENCES_NATURAL_MAJOR:AUTHENTIC CADENCE': [4]}
diff = DeepDiff(res, expected, ignore_order=True)
self.ut_report.assertTrue(diff == {})
The returned dictionary provides for each cadence the chord position the progression starts
Transpose song chords
It is possible to transpose a song with a number_half_tone:
from pychord import Chord
from pyharmonytools.displays.unit_test_report import UnitTestReport
from pyharmonytools.song.text_song import TextSongWithLineForChords
song_happy_birthday = """
A E
Happy Birthday to you
E A
Happy Birthday to you
A7 D
Happy Birthday dear (name)
A E A
Happy Birthday to you
"""
the_song = TextSongWithLineForChords()
the_song.digest(song_happy_birthday)
the_song.generate_degrees_from_chord_progression()
res = the_song.transpose(number_half_tone=-5)
expected = ['E', 'B', 'B', 'E', 'E7', 'A', 'E', 'B', 'E']
self.ut_report.assertTrue(res == expected)
Song Querying
Song search & processing tools on Ultimate Guitar through Google.com
You may search and handle song lyrics & tabs
from pyharmonytools.song.song import UltimateGuitarSong
from pyharmonytools.song.ultimate_guitar_search import UltimateGuitarSearch
ug_engine = UltimateGuitarSearch()
query = "D Dm A"
urls = ug_engine.search(query, 20)
song = UltimateGuitarSong()
for link in urls:
print("===================================")
song.extract_song_from_url(link)
print(song.get_string())
This piece of code will display 20 songs matching the query (songs holding the "D/Dm/A" cadence)
Output:
===================================
Title: AUTREFOIS
Artist: Pink Martini
[tab][ch]A[/ch] [ch]D[/ch]\r\nJ'ai ecris des mots doux а toutes les filles de France[/tab]\r\n
[tab][ch]Dm[/ch]
Related Skills
node-connect
334.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
82.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
334.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
82.3kCommit, push, and open a PR
