/pyharmonytooling

python code to manage music harmony

Primary LanguageHTMLOtherNOASSERTION

PyHarmonyTooling

Circle of 5th

OVERVIEW

Series of tools to handle harmony in music

Install

pip install pyHarmonyTooling 

Features

Usages of this library:

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>]

See related unit tests

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

See related unit tests

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-on
  • p: 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! 😉

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.

See related unit tests

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>]

See related unit tests

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'])

See related unit tests

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]                    [ch]A[/ch]\r\nJ'espere qu'elles y repondent[/tab]\r\n
[tab][ch]A[/ch]                  [ch]D[/ch]           [ch]Dm[/ch]               [ch]A[/ch]\r\nJ'ai jure que je serai content avant la fin de l'annee[/tab]\r\n
[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]                    [ch]A[/ch]\r\nChaque jour et chaque nuit[/tab]\r\n
...

See related unit tests

Song search from a cadence

Searching for songs in the 12 tones from a cadence

    from pyharmonytools.harmony.circle_of_5th import CircleOf5thNaturalMajor
    from pyharmonytools.song.ultimate_guitar_search import UltimateGuitarSearch
    
    ugs = UltimateGuitarSearch()
    cadence = "V-IV-#ii7-VII-vii7-I-V"
    
    cadence_and_tone = Cadence.guess_tone_and_mode_from_cadence(cadence)
    MAX_SONG_PER_SEARCH = 5
    
    cof = CircleOf5th.cof_factory(cadence_and_tone["cof_name"])
    songs = ugs.search_songs_from_cadence(cadence, cof, MAX_SONG_PER_SEARCH, matches_exactly=True,
                                          try_avoiding_blocked_searches=True)
    print(songs)

output:

    {'Bm7 E7 Amaj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/1726600', 
            'https://tabs.ultimate-guitar.com/tab/henri-salvador/jardin-dhiver-chords-2202243', 
            'https://tabs.ultimate-guitar.com/tab/2330957', 
            'https://tabs.ultimate-guitar.com/tab/slimane/a-fleur-de-toi-chords-1873948', 
            'https://tabs.ultimate-guitar.com/tab/1707559'],
    'Cm7 F7 A#maj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/louis-armstrong/a-kiss-to-build-a-dream-on-chords-923726', 
            'https://tabs.ultimate-guitar.com/tab/amy-winehouse/mr-magic-chords-1828391', 
            'https://tabs.ultimate-guitar.com/tab/amy-winehouse/mr-magic-chords-1828391', 
            'https://tabs.ultimate-guitar.com/tab/stevie-wonder/lately-chords-173491', 
            'https://tabs.ultimate-guitar.com/tab/louis-armstrong/a-kiss-to-build-a-dream-on-chords-923726'], 
    'C#m7 F#7 Bmaj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/jvke/this-is-what-falling-in-love-feels-like-chords-3871874', 
            'https://tabs.ultimate-guitar.com/tab/jvke/this-is-what-falling-in-love-feels-like-chords-3871874', 
            'https://tabs.ultimate-guitar.com/tab/jvke/this-is-what-falling-in-love-feels-like-chords-3871874', 
            'https://tabs.ultimate-guitar.com/tab/jvke/this-is-what-falling-in-love-feels-like-chords-3871874', 
            'https://tabs.ultimate-guitar.com/tab/jvke/this-is-what-falling-in-love-feels-like-chords-3871874'], 
    'Dm7 G7 Cmaj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/frank-sinatra/fly-me-to-the-moon-chords-1193296', 
            'https://tabs.ultimate-guitar.com/tab/frank-sinatra/fly-me-to-the-moon-chords-1193296', 
            'https://tabs.ultimate-guitar.com/tab/grover-washington-jr-/just-the-two-of-us-chords-1095786', 
            'https://tabs.ultimate-guitar.com/tab/michel-fugain/une-belle-histoire-chords-391387', 
            'https://tabs.ultimate-guitar.com/tab/michel-fugain/une-belle-histoire-chords-391387'], 
    'D#m7 G#7 C#maj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/941025', 
            'https://tabs.ultimate-guitar.com/tab/941025', 
            'https://tabs.ultimate-guitar.com/tab/941025', 
            'https://tabs.ultimate-guitar.com/tab/941025', 
            'https://tabs.ultimate-guitar.com/tab/941025'], 
    'Em7 A7 Dmaj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/eric-clapton/autumn-leaves-chords-2502690', 
            https://tabs.ultimate-guitar.com/tab/eric-clapton/autumn-leaves-chords-2502690', 
            'https://tabs.ultimate-guitar.com/tab/eric-clapton/autumn-leaves-chords-2502690', 
            https://tabs.ultimate-guitar.com/tab/eric-clapton/autumn-leaves-chords-2502690', 
            'https://tabs.ultimate-guitar.com/tab/frank-sinatra/the-way-you-look-tonight-ukulele-1485850'], 
    'Fm7 A#7 D#maj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/michael-jackson/i-just-cant-stop-loving-you-chords-967366', 
            'https://tabs.ultimate-guitar.com/tab/michael-jackson/i-just-cant-stop-loving-you-chords-967366', 
            'https://tabs.ultimate-guitar.com/tab/michael-jackson/i-just-cant-stop-loving-you-chords-967366', 
            'https://tabs.ultimate-guitar.com/tab/michael-jackson/i-just-cant-stop-loving-you-chords-967366', 
            'https://tabs.ultimate-guitar.com/tab/frank-sinatra/the-way-you-look-tonight-chords-1771608'], 
    F#m7 B7 Emaj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/3709742', 
            'https://tabs.ultimate-guitar.com/tab/misc-soundtrack/la-la-land-audition-the-fools-who-dream-chords-1909336', 
            'https://tabs.ultimate-guitar.com/tab/julie-london/cry-me-a-river-chords-1499105', 
            'https://tabs.ultimate-guitar.com/tab/h-e-r-/wrong-places-chords-3119678', 
            'https://tabs.ultimate-guitar.com/tab/h-e-r-/wrong-places-chords-3119678'], 
    'Gm7 C7 Fmaj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/yves-montand/les-feuilles-mortes-chords-2576898', 
            'https://tabs.ultimate-guitar.com/tab/glen-campbell/by-the-time-i-get-to-phoenix-chords-2129751', 
            'https://tabs.ultimate-guitar.com/tab/yves-montand/les-feuilles-mortes-chords-2576898', 
            'https://tabs.ultimate-guitar.com/tab/glen-campbell/by-the-time-i-get-to-phoenix-chords-2129751', 
            'https://tabs.ultimate-guitar.com/tab/glen-campbell/by-the-time-i-get-to-phoenix-chords-2129751'], 
    'G#m7 C#7 F#maj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/misc-soundtrack/la-la-land-audition-the-fools-who-dream-chords-1909336', 
            'https://tabs.ultimate-guitar.com/tab/tyler-the-creator/boredom-chords-2785219', 
            'https://tabs.ultimate-guitar.com/tab/tyler-the-creator/boredom-chords-2785219', 
            'https://tabs.ultimate-guitar.com/tab/tyler-the-creator/boredom-chords-2785219', 
            'https://tabs.ultimate-guitar.com/tab/yves-montand/les-feuilles-mortes-chords-2576898'], 
    'Am7 D7 Gmaj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/billy-joel/just-the-way-you-are-chords-1404186', 
            'https://tabs.ultimate-guitar.com/tab/laufey/falling-behind-chords-4307414', 
            'https://tabs.ultimate-guitar.com/tab/billy-joel/just-the-way-you-are-chords-1404186', 
            'https://tabs.ultimate-guitar.com/tab/billy-joel/just-the-way-you-are-chords-1404186', 
            'https://tabs.ultimate-guitar.com/tab/john-mayer/new-light-chords-3180788'], 
    'A#m7 D#7 G#maj7 ': 
            ['https://tabs.ultimate-guitar.com/tab/george-benson/give-me-the-night-chords-61898', 
            'https://tabs.ultimate-guitar.com/tab/george-benson/give-me-the-night-chords-61898', 
            'https://tabs.ultimate-guitar.com/tab/george-benson/give-me-the-night-chords-61898', 
            'https://tabs.ultimate-guitar.com/tab/tyler-the-creator/boredom-chords-2785219', 
            'https://tabs.ultimate-guitar.com/tab/tyler-the-creator/boredom-chords-2785219']
            }

See related unit tests

Next Features

(in no specific order)

  • Chords stuff
  • Tabs stuff
    • take guitar tuning into account when handling guitar tabs
    • display degrees in guitar tabs
    • transpose guitar tabs
    • update tabs with guitar tuning
    • guess rhythm from guitar tab
    • use rhythm in guitar tab to guess phrases and improve chord guessing
    • analyze found chords from tabs to make them more consistent (notably with the CoF or b/#)

Test report

see here

Release Notes

  • 06/MAR/23
    • fixing interval distance with octaves
    • comparing notes
    • package v0.10.0
  • 05/MAR/23
    • fixing transposing Notes with octave
    • package v0.9.4
  • 04/MAR/23
    • transposing Notes with octave
    • package v0.9.3
  • 02/MAR/23
    • scales start from C
    • package v0.8.1
  • 28/FEB/23
    • notes frequencies exposed
    • package v0.8.0
  • 27/FEB/23
    • Neck.find_position_from_note handles note synonyms
    • Neck.find_position_from_note handles octaves
    • package v0.7.5
  • 22/FEB/23
    • closest pitch from chciken
    • package v0.7.1
  • 20/FEB/23
    • estimating note from frequency
    • package v0.7.0
  • 18/JAN/23
  • 16/JAN/23
    • cadence with b/# before degree
    • enharmonic notes fixed
    • package v0.6.1
  • 14/JAN/23
    • CoF detailed in triads & 4 notes
    • package v0.6.0
  • 09/JAN/23
    • transpose song chords
    • github building ok
    • package v0.5.1
  • 08/JAN/23
    • spot remarkable cadences in a song
    • hardening UG searches
    • package v0.4.0
  • 06/JAN/23
    • degrees from song chords
    • package v0.3.1
  • 01/DEC/22
    • displaying tabs with chords
    • handling guitar gimmicks in tabs
  • 30/NOV/22
    • a tab on multiple bars can be processed
    • package v0.2.1
  • 28/NOV/22
    • chords can be guessed from a tab
    • package v0.1.4
  • 26/NOV/22
  • 25/NOV/22
    • start reading guitar tabs when chords are vertical or played in arpeggio
  • 24/NOV/22
    • weird notes (eg. Cb)
    • possible chords cached for optimization
    • package v.0.1.2
  • 23/NOV/22 - tag
    • find chords from notes
    • start parsing tabs
  • 20/NOV/22
    • accurate song search (param added)
    • find songs that match a cadence in degrees
  • 19/NOV/22
    • starting API to ultimate-guitar.com
    • querying UG through google.com to retrieve pattern matching over possibilities found in UG
    • circle of 5th extended to Natural/Melodic/Harmonic minors
  • 12/NOV/22:
    • bugs when finding chord fingering on a guitar on vertical fingering such a barres

Additional links