Giter VIP home page Giter VIP logo

thatchord's Introduction

ThatChord: A Python script for chord diagrams

Created by Tom Conti-Leslie: tomcontileslie.com.

I am grateful for the helpful contributions of:

These files are distributed under a Creative Commons Share Alike license.

License: CC BY-SA 4.0

Build Status

What is ThatChord?

That's exactly the question I ask myself a lot when I'm looking at a chord sheet for a song I'm learning, and the key it's in is bad enough that some pretty obscure chord names are in there. This simple set of interdependent Python3 scripts allows you to copy the name of an unknown chord into ThatChord, and have it output one or several diagrams which show you exactly how to play it.

My motivation to make this script came from the restricted capabilities of most currently available online chord tools, as well as a few idle hours I once had on a plane with no internet. With ThatChord, your chosen instrument's number of strings and tuning, as well as your preferred output diagram format and preferences regarding muted strings and so on are fully customisable, with a number of presets available.

ThatChord supports a large list of chord qualities (see dicts.py), as well as chord alterations and bass notes - and, failing that, custom note-by note input. Strings such as C, Fadd9 and Bmin11(b5)/C are all recognised and on guitar, produce delightfully simple plaintext diagrams such as:

   x
   ===========        x           
   | | | | O |      5 | | | O | O      8 O | | | | | 
   | | O | | |        | | | | | |        | | | O | O 
   | O | | | |        | | O | | |        | | | | | | 
   | | | | | |        | O | | O |        | | | | | | 
   | | | | | |        | | | | | |        | | | | | |  

ThatChord can also output equally simplistic, and also rather lightweight, PNG images:

For ukulele For guitar For banjo

These weigh a handful of kilobytes each at most.

ThatChord is smarter than a chord dictionary.

Note that unlike a number of available chord finders, which have a database of common chord fingerings, ThatChord calculates the best way to play the chord you requested on the fly, using the settings you have configured regarding your number of strings, tuning, and your fingering preferences (e.g. how much do you value using few fingers over avoiding stretching your fingers very far?)

When handling a request, ThatChord literally considers every imaginable way of playing your chord, and then keeps only the best options. The "best options" are whatever you want them to be, and you can tweak the coefficients of the ranking algorithm to your liking. Don't like the option ThatChord returned for a given chord? Not to worry. You can ask for the second best, the third best, the 100th best... And you can change your ranking algorithm, or ask for the chord to be played above a certain fret. For one chord on ukulele, ThatChord's usually listed about 70 different fingerings. On guitar, it's closer to 10000. Are most of these options terrible? Yes. But they're there if you need them.

The downside of this is it can take up to two seconds to find, and then render, your request if you're asking for a complicated chord on a many-stringed instrument. The advantage, though, is that this program doesn't need people to keep adding possible fingerings to some massive file. That would make for a fast program, but would never contain every possibility. The only dictionary file that needs improvement in ThatChord is its quality dictionary, which allows it to accurately interpret more input strings (like "dim7", "5", "add9", ...). Everything else, it already knows.

So while you're here, add a couple funky chord quality strings to the list, and then enjoy the endless options ThatChord offers!

Installing and Using ThatChord

If you are a beginner using a Mac, you may wish to check out the more detailed beginner step-by-step setup guide on the wiki.

ThatChord runs by default via the Unix command line (though you can configure it to run via input in the Python console if you prefer). The default assumption is that the ThatChord folder lies in your Documents folder. Install ThatChord there, or anywhere else, by cloning the repo:

cd ~/Documents
git clone https://github.com/tomcontileslie/ThatChord.git ThatChord

To ensure all necessary Python modules are installed, run in your ThatChord directory:

python3 -m pip install -r requirements.txt

To run ThatChord, navigate to your ThatChord directory and run thatchord.py with your chord request as argument:

cd ~/Documents/ThatChord
python3 thatchord.py "Bbadd9(b5)/C@4:2"

In general, chord requests are structured as WX(Y)/Z@V:T where:

  • W is a note, i.e. a letter A-G possibly followed by b or #
  • (optional) X is a chord quality such as min7 or 11. A large list of qualities are supported.
  • (optional) Y is a list of one or more alterations which sharpen or flatten a given note in the chord. To sharpen the fifth, type #5. Concatenate the alterations to have several: Cm7(b5b7).
  • (optional) Z is a bass note. On guitar and banjo, ThatChord favours options where the bass note is played on the lowest non-muted string.
  • (optional) V is the lowest fret that every non-muted string must be played at. Default is 0. This option is helpful if you want to see chords higher up on the neck.
  • (optional) T is a positive number. ThatChord returns the Tth best option found. By default, T is set to 1 (i.e. return the best option). If you are not satisfied with the diagram shown for Cmin7, for example, try running ThatChord again with Cmin7:2 to see the next best option.

Combining all of the optional parts of the request into the above example, Bbadd9(b5)/C@4:2, will ask for:

The second best way of playing a B flat added ninth chord, with a flattened fifth, over a bass note of C, where every finger is placed at least at the 4th fret.

Since chords often contain special characters, you will most likely need to surround the chord request with quotation marks, as in the example above.

Additionally, running:

python3 thatchord.py SETTINGS

will open your settings file so you can change the instrument ThatChord outputs diagrams for (default is ukulele).

For chords that don't have nice names, you can specify the notes making up the chord in a custom format. For example:

python3 thatchord.py "CUSTOM C Eb G"

will return a Cm chord. Make sure you add quotation marks so the notes are not interpreted as separate flags. That being said, most separators work for custom input: python3 thatchord.py CUSTOMC,Eb,G requires no quotes.

For custom input, note that the order of notes is important. Enter the most important ones first, and for an instrument like guitar or banjo you should either set the first note in the list to be the bass note, or choose a less bass-heavy ranking preset than the guitar and banjo presets.

A number of flags can be specified when running ThatChord via the command line. Run:

python3 thatchord.py --help

for more information.

More information is available on the ThatChord wiki.

Contributing to ThatChord

I've made these files with experience mostly with ukulele, despite the fact that the algorithm scales to instruments like guitar. This means that attempting to use it might make you notice issues. Please feel free to suggest any changes in the issues tab, or to fork my repository and submit a pull request if you fix any bugs or have new features to suggest. Namely, the chord quality dictionary (in dicts.py) is crucial to chord interpretation, and will never be complete - so any additions there are much appreciated!

On the programming side, I'm not the most efficient programmer and I remain blissfully unaware, I'm sure, of certain Python and GitHub conventions. (my apologies in advance if you're using a linter on your Python files). You are most welcome to fork this repository to make changes which I would be very happy to pull into the main project. Namely, if you would like to make these files more executable (rather than just a pile of functions), then I would appreciate your help.

Please also have a look at the issues page where some current needed improvements to the code are listed. You have my gratitude if you decide to tackle one of them :)

thatchord's People

Contributors

joshwd36 avatar reiniscirpons avatar tomcontileslie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

thatchord's Issues

Add last resort suspended chord interpretation

In the interpretation phase, if the chord does not match any qualities, there should be a last resort to check if the string ends in sus, sus4, sus2. In these cases we can try re-interpreting the string without this suffix and checking whether that matches, and then tweak the third to suspend it.

Fully configurable command line interface

It would be useful to have command line options that can specify the settings listed in settings.py, to allow the user to avoid having to modify that file. Perhaps something similar to the form:

python thatchord.py <chord> [OPTIONS]
Options:
-i, --instrument: instrument preset
-r, --ranking: ranking preset
-o, --output: print, splash, or none
-s, --save: single, library, or none
-d, --directory: diagrams directory

There could also potentially be options for defining custom instruments, perhaps allowing the user to specify a file which contains instrument definitions.

SETTINGS option wont work on linux

When attempting to run python3 thatchord.py SETTINGS on Ubuntu I get the following error

sh: 1: open: not found

Apparently there is no open command in linux. According to this answer on stack exchange using xdg-open should do the trick.

Allow fret specification

Users should able to ask, "I want this chord played in the general area of fret number 10". This requires changes either to the ranking file rank.py, with a high coefficient for the new ranking function which would cover this - or it requires changes in the filtering process of find.py.

Improve file interdependencies

The current state of things is that necessary files are imported as modules into other files. Notation is fairly consistent across the files, though, so would it not be easier to simply run the necessary scripts at the top of the main file, for example? That way, everything is a global variable.

Add usage examples

Have a part of the README (or the Wiki) just have a list of a load of command line usage examples. Start by saying you should add

alias tc="python3 ~/path/to/ThatChord/thatchord.py"

to your .rc, and then give examples like

tc -h
# get help

tc Cmaj7
# output a Cmaj7 diagram for your default instrument

tc -i guitar -r guitar "D11(b5)"
# punctually change instrument

tc -f text -o print F
# print chord to command line

tc -f text -o print "F:2"
# didn't like the way it suggested playing F, try the second

tc "Cm@4"
# how do I play Cm way up on the frets?

Add framework for dealing with barred chords

Currently, ranking of diagrams is done by looking at which notes are low, and how "stretched" the chord is (via various metrics). How can we get the algorithm to recognise when a given list of frets can be barred conveniently, giving it extra ranking points? The first observation to make is that this would probably depend on handedness.

The second part of this issue is to then implement a method of drawing bars in all types of outputs (plaintext, PNG, and any others).

Change root note handling

Currently the first element of the list of interpreted notes is considered the root, and the following notes are considered the important ones. I suggest we make the interpretation function output a tuple (out, root) where root is the bass note and out contains all the notes, still most to least important. It might be time to retire the rank_important function, in the sense that some important notes (root, fifth) are best places on the low strings while the more musical, but also important, ones (sevenths, ninths, etc) are better on high strings.

Add top of diagram empty string marks as an option

In output.py, the text option indicates muted strings with an x:

   x           
   ===========
   | | | | O | 
   | | O | | | 
   | O | | | | 
   | | | | | | 
   | | | | | | 

but a number of guitar diagrams also put symbols for the empty strings, e.g.

   x     o   o 
   ===========
   | | | | O | 
   | | O | | | 
   | O | | | | 
   | | | | | | 
   | | | | | | 

This should be an available option in the print functions.

Higher priority to chord alterations

Chord alterations get added to the end of the list of target notes (see interpret.py). On instruments with few notes this means the altered note may not appear. Altered notes should be added early in the list.

Make explanatory documentation

So that other users can contribute more effectively, we should create some explanatory documents showing - perhaps in the form of a flowchart - the full process of handling a chord request.

This could include a description of the broad thatchord -> settings -> interpret -> find -> rank -> output workflow, as well as more in-depth discussion of the finder algorithm, which is perhaps the least self-explanatory at first glance.

Add last resort capitalisation change for chord interpretation

Matching a chord quality is case sensitive because we need to be able to distinguish between M and m. However, if a chord request string has a quality which doesn't match any key in the quality dict, perhaps there should be a "last resort" system which checks whether setting some characters to lowercase or uppercase produces something which matches.

Make ThatChord into an actual package and make it object-oriented

There are a number of improvements to the code which would make it more easily maintainable and executable.

  • Swap out ungodly lists of function arguments for **kwargs, since the parameters are very similar for most functions
  • Make a "chord" or "ThatChord" class that has an object instantiated at the beginning of a request, then keeps all important metadata (e.g. choice of settings) internal to the object
  • Make the main subprocesses (INTERPRET -> FIND -> OUTPUT) into submodules e.g. ThatChord.interpret, ThatChord.find, ThatChord.view/ThatChord.save which take a chord object as argument and modify it in place
  • Tuck .py files away in folders, leaving only main scripts like thatchord.py in the home directory
  • Add ThatChord to PyPI
  • Offer to import similar projects as extensions (e.g. fretboard on PyPI)
  • Revamp settings system (edit settings from command line? make settings subclass?)
  • Revamp errors (the current system is garbage)
  • Standardise vocabulary between "request", "chord", "diagram", "fingering" etc

I think what I roughly have in mind is something that could do this:

>>> import thatchord as tc
>>> workspace = tc.new_workspace() # create environment with default settings
>>> # the workspace should contain all the info necessary to run the algorithms:
>>> workspace._INSTRUMENT_SETTINGS # view tuning settings
{'tuning': [0, 1, 2, 3], 'frets': 15, ...}
>>> workspace._RANKING_FUNCTION
<function rank at 0x...>
>>> workspace._OUTPUT_SETTINGS
{'format': 'png', 'height': 5, ...}
>>> ch = workspace.new_request("C/E")
>>> ch
<chord request: C major with notes C,E,G and bass note E>
>>> tc.find.find(ch, 3) # find 3 best chords
>>> # perhaps rather than outputting anything, the result is then stored in ch
>>> ch.solutions
[[0, 0, 0, 3], [5, 4, 3, 3], [0, 4, 0, 3]]
>>> tc.view.generate_drawing(ch, format="txt", index=2) # can overrule settings from workspace._OUTPUT_SETTINGS
'   C\n\n   =======\n   | | | |\n   | | | |\n   | | | O\n   | O | |\n   | | | |'
>>> tc.view.print(ch) # or maybe ch.print()?
   C

   =======
   | | | |
   | | | |
   | | | O
   | O | |
   | | | |
>>> tc.view.splash(ch) # or maybe ch.splash()?
>>> tc.view.save(ch, "/Users/me/outputs/beautiful.txt") # or maybe ch.save()?
>>> ###############
>>> workspace2 = tc.new_workspace(instrument_preset='guitar') # can set up different environments like this
>>> workspace3 = tc.new_worspace(tuning="D A D G B E", frets=22, handedness="left") # custom setups
>>> ch = workspace3.new_request("Em")
>>> # etc

Chords on guitar are slow

Chords with 5 or more notes can take a few seconds to run on instruments like guitar, due to the large number of possibilities for valid frets on each string. How can we improve this? I can see no immediate improvements to the general formula that ThatChord uses:

  • check valid frets on each string
  • look at all combinations of valid frets and remember one combination if it plays the full chord rather than a subset of its notes
  • rank valid combinations

but perhaps some combinations can be disregarded earlier (spread of fingers is higher than some high cutoff e.g. 8) to reduce the number of combinations recalled.

Banjo compatibility

One banjo string can only be played from a higher fret. Compatibility with banjo requires a number of considerations.

  • settings.py: a new setting specifying where each string starts.
  • Need to decide what to do with that string otherwise: mute it? play open?
  • find.py probably needs to filter more.
  • output.py needs to be revamped to allow for some strings starting halfway down the diagram.

Verify and/or Improve Chord Alteration Handling

See interpret.py. Chord alterations are handled blindly, without taking any context from the given chord. This is fine if the alteration is (#5), for example, since 5 is unambiguous. However, with 7, whether we are altering the major or minor seventh depends on context. Currently, the approach is to replace all seventh notes in the chord with a minor seventh if the alteration is (b7), and to replace with a major seventh if the alteration is (#7). However, I'm not sure this scales well to (bb7) and (##7).

Implement unit tests

Great project! I feel in the long run that unit tests would be a great way to spot bugs early that might be introduced by changes to the code. For example, when modifying the chord searching algorithm to make it more efficient, having unit tests would ensure that these changes don't break the algorithm. I'd recommend pytest...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.