Skip to main content

Toolbox for analyzing, creating and visualizing music

Project description

musy

musy is a comprehensive toolbox for analyzing and visualizing music. It lays the foundation for the Musy web apps.

At its core it has basic building blocks from which all theory can be derived: - Note: The basic atomic unit of music. - Chord and PolyChord: A stack of notes played together. - Scale: Stack of intervals from which harmony, (diatonic) chords, melody, etc. can be derived.

For visualization these objects can be placed on instrument surfaces: - Piano: Basic key layout - Guitar: Guitar fretboard

Installation

pip install musy

Note

Initialization

The Note is the basic building block from which you can create chords, scales, intervals and songs.

from musy import Note

c_sharp = Note("C#")
c_sharp
musy.note.Note(note='C#', oct=4)

Addition and subtraction

Notes can be added and subtracted to form new notes. Each added integer represents a semitone.

c_sharp + 1
musy.note.Note(note='D', oct=4)
c_sharp - 1
musy.note.Note(note='C', oct=4)
c_sharp + 14
musy.note.Note(note='D#', oct=5)

Comparison

Notes can be compared using familiar Python operators.

c = Note("C")
g = Note("G")

c < g
True

Octaves can make a difference in comparisons.

Note("C", oct=4) >= Note("G", oct=3)
True

Relative Major/Minor

Notes can be converted to its relative major or minor. As can be found on the circle of fifths.

Note("C").minor()
musy.note.Note(note='A', oct=4)
Note("C#").major()
musy.note.Note(note='E', oct=4)

Interval

Initialization

Interval objects can be obtained by calling interval on two notes or using the & operator.

f_sharp = Note("F#")

P4 = c_sharp & f_sharp
P4
perfect fourth (4)
P4.semitones, P4.long, P4.short, P4.type()
(5, 'perfect fourth', '4', 'Contextual')

Comparison

Intervals can also be compared.

P5 = c & g
P5
perfect fifth (5)
P5.semitones, P5.long, P5.short, P5.type()
(7, 'perfect fifth', '5', 'Perfect Consonant')
P4 != P5
True
P4 < P5
True

Chord

Initialization

The Chord is a stack of Note objects played together.

from musy import Chord

c_major = Chord(["C", "E", "G"])
c_major
Chord: 'C major triad'. Notes: ['C4', 'E4', 'G4']

Chord objects can be initialized from shorthand notation.

cmaj7 = Chord.from_short("Cmaj7")
cmaj7
Chord: 'C major seventh'. Notes: ['C4', 'E4', 'G4', 'B4']

Inversion

Chords can also be inverted with invert.

# Get 1st inversion chord of C major 7th
cmaj7.invert(1)
Chord: 'C major seventh, first inversion'. Notes: ['E4', 'G4', 'B4', 'C5']

Transposition

Like Note objects, Chord objects can be added and subtracted to transpose them.

cmaj7 + 2
Chord: 'D major seventh'. Notes: ['D4', 'F#4', 'A4', 'C#5']

Notes can be multiplied to create chords.

Note("C") * Note("E") * Note("G")
Chord: 'C major triad'. Notes: ['C4', 'E4', 'G4']

PolyChord

Initialization

For polyphonic use cases you can create PolyChord objects. This objects inherits the same functionality as Chord objects.

from musy import PolyChord

c = Chord.from_short("C")
bbmaj7_3_inv = Chord.from_short("Bbmaj7").invert(3)

poly_chord = PolyChord([c, bbmaj7_3_inv])
poly_chord
PolyChord: 'C major triad|Bb major seventh, third inversion'. Notes: ['C4', 'E4', 'G4', 'A4', 'Bb5', 'D5', 'F5']

Scale

Initialization

Scale objects are collections of intervals from which we can generate notes and chords around a root note.

from musy import Scale

dorian = Scale("dorian")
dorian
Scale: Dorian. Intervals: ['1', '2', 'b3', '4', '5', '6', 'b7']

Note Generation

When given a root note, Scale generates the notes of the scale.

dorian.get_notes("C")
[musy.note.Note(note='C', oct=4),
 musy.note.Note(note='D', oct=4),
 musy.note.Note(note='D#', oct=4),
 musy.note.Note(note='F', oct=4),
 musy.note.Note(note='G', oct=4),
 musy.note.Note(note='A', oct=4),
 musy.note.Note(note='A#', oct=4)]

Intervals

Intervals can be obtained.

dorian.get_interval_names()
['major second',
 'minor third',
 'perfect fourth',
 'perfect fifth',
 'major sixth',
 'minor seventh']

Triad Generation

Triads and seventh chords in the scale can be generated around a root note.

dorian.get_triads("D")
[Chord: 'D minor triad'. Notes: ['D4', 'F4', 'A4'],
 Chord: 'E minor triad'. Notes: ['E4', 'G4', 'B4'],
 Chord: 'F major triad'. Notes: ['F4', 'A4', 'C4'],
 Chord: 'G major triad'. Notes: ['G4', 'B4', 'D5'],
 Chord: 'A minor triad'. Notes: ['A4', 'C4', 'E5'],
 Chord: 'B diminished triad'. Notes: ['B4', 'D5', 'F5'],
 Chord: 'C major triad'. Notes: ['C5', 'E6', 'G6']]

Seventh Chord Generation

dorian.get_sevenths("E")
[Chord: 'E minor seventh'. Notes: ['E4', 'G4', 'B4', 'D4'],
 Chord: 'F# minor seventh'. Notes: ['F#4', 'A4', 'C#4', 'E5'],
 Chord: 'G major seventh'. Notes: ['G4', 'B4', 'D4', 'F#5'],
 Chord: 'A dominant seventh'. Notes: ['A4', 'C#4', 'E5', 'G5'],
 Chord: 'B minor seventh'. Notes: ['B4', 'D4', 'F#5', 'A5'],
 Chord: 'C# half diminished seventh'. Notes: ['C#5', 'E6', 'G6', 'B6'],
 Chord: 'D major seventh'. Notes: ['D5', 'F#6', 'A6', 'C#6']]

All information can be conveniently retrieved and displayed as a Pandas DataFrame with to_frame.

Table

dorian.to_frame(root="E")
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; } .dataframe tbody tr th { vertical-align: top; } .dataframe thead th { text-align: right; } </style>
Intervals Relative Semitones Absolute Semitones Notes Triads Seventh Chords
0 1 0 2 E E minor triad E minor seventh
1 2 2 1 F# F# minor triad F# minor seventh
2 b3 3 2 G G major triad G major seventh
3 4 5 2 A A major triad A dominant seventh
4 5 7 2 B B minor triad B minor seventh
5 6 9 1 C# C# diminished triad C# half diminished seventh
6 b7 10 2 D D major triad D major seventh

Custom Scales

Consult Scale.available_scales for a list of available scales. If a scale is not available, you can create your own scale from intervals.

persian = Scale.from_intervals("persian", ["1", "b2", "3", "4", "b5", "b6", "7"])
persian
Scale: Persian. Intervals: ['1', 'b2', '3', '4', 'b5', 'b6', '7']
persian.get_notes("C")
[musy.note.Note(note='C', oct=4),
 musy.note.Note(note='C#', oct=4),
 musy.note.Note(note='E', oct=4),
 musy.note.Note(note='F', oct=4),
 musy.note.Note(note='F#', oct=4),
 musy.note.Note(note='G#', oct=4),
 musy.note.Note(note='B', oct=4)]

Listening

Note, Chord, PolyChord and Scale objects can all be heard by calling the play method on them. Check out the musy documentation on Note, Chord, PolyChord and Scale for example code and audio playbacks.

Visualization

musy objects can be visualized on a piano or guitar by providing a list of Note objects to the rendering method. Notes can easily be retrieved from Chord and Scale objects.

Piano

from musy import Piano

Piano()(Note("C#"))
<style>
.piano { background: #222; padding: 20px 0; position: relative; width: 480px; }
.white-keys { display: flex; }
.white-key {
    width: 40px; height: 125px; background: #fff;
    border: 1px solid #000;
    color: #111; font-size: 18px; text-align: center; line-height: 200px; font-family: Arial;
    position: relative; z-index: 1;
}
.black-key {
    width: 20px; height: 80px; background: #000; color: #fff;
    border: 1px solid #333; position: absolute; z-index: 2;
    text-align: center; line-height: 100px; font-family: Arial; font-size: 14px;
    left: 0; top: 20px; pointer-events: none;
}
.highlight { background: #ff0 !important; color: #000 !important; }
.highlight-black { background: #ff0 !important; color: #000 !important; }
</style>
<div class="piano" style="width:440px"><div class="white-keys"><div class="white-key">C</div><div class="white-key">D</div><div class="white-key">E</div><div class="white-key">F</div><div class="white-key">G</div><div class="white-key">A</div><div class="white-key">B</div><div class="white-key">C</div><div class="white-key">D</div><div class="white-key">E</div><div class="white-key">F</div><div class="black-key highlight-black" style="left:26px">C#</div><div class="black-key" style="left:66px">D#</div><div class="black-key" style="left:146px">F#</div><div class="black-key" style="left:186px">G#</div><div class="black-key" style="left:226px">A#</div><div class="black-key highlight-black" style="left:306px">C#</div><div class="black-key" style="left:346px">D#</div><div class="black-key" style="left:426px">F#</div></div>
Piano()(list(Chord.from_short("Cmaj7")))
<style>
.piano { background: #222; padding: 20px 0; position: relative; width: 480px; }
.white-keys { display: flex; }
.white-key {
    width: 40px; height: 125px; background: #fff;
    border: 1px solid #000;
    color: #111; font-size: 18px; text-align: center; line-height: 200px; font-family: Arial;
    position: relative; z-index: 1;
}
.black-key {
    width: 20px; height: 80px; background: #000; color: #fff;
    border: 1px solid #333; position: absolute; z-index: 2;
    text-align: center; line-height: 100px; font-family: Arial; font-size: 14px;
    left: 0; top: 20px; pointer-events: none;
}
.highlight { background: #ff0 !important; color: #000 !important; }
.highlight-black { background: #ff0 !important; color: #000 !important; }
</style>
<div class="piano" style="width:440px"><div class="white-keys"><div class="white-key highlight">C</div><div class="white-key">D</div><div class="white-key highlight">E</div><div class="white-key">F</div><div class="white-key highlight">G</div><div class="white-key">A</div><div class="white-key highlight">B</div><div class="white-key highlight">C</div><div class="white-key">D</div><div class="white-key highlight">E</div><div class="white-key">F</div><div class="black-key" style="left:26px">C#</div><div class="black-key" style="left:66px">D#</div><div class="black-key" style="left:146px">F#</div><div class="black-key" style="left:186px">G#</div><div class="black-key" style="left:226px">A#</div><div class="black-key" style="left:306px">C#</div><div class="black-key" style="left:346px">D#</div><div class="black-key" style="left:426px">F#</div></div>
Piano()(Scale("major").get_notes("D"))
<style>
.piano { background: #222; padding: 20px 0; position: relative; width: 480px; }
.white-keys { display: flex; }
.white-key {
    width: 40px; height: 125px; background: #fff;
    border: 1px solid #000;
    color: #111; font-size: 18px; text-align: center; line-height: 200px; font-family: Arial;
    position: relative; z-index: 1;
}
.black-key {
    width: 20px; height: 80px; background: #000; color: #fff;
    border: 1px solid #333; position: absolute; z-index: 2;
    text-align: center; line-height: 100px; font-family: Arial; font-size: 14px;
    left: 0; top: 20px; pointer-events: none;
}
.highlight { background: #ff0 !important; color: #000 !important; }
.highlight-black { background: #ff0 !important; color: #000 !important; }
</style>
<div class="piano" style="width:440px"><div class="white-keys"><div class="white-key">C</div><div class="white-key highlight">D</div><div class="white-key highlight">E</div><div class="white-key">F</div><div class="white-key highlight">G</div><div class="white-key highlight">A</div><div class="white-key highlight">B</div><div class="white-key">C</div><div class="white-key highlight">D</div><div class="white-key highlight">E</div><div class="white-key">F</div><div class="black-key highlight-black" style="left:26px">C#</div><div class="black-key" style="left:66px">D#</div><div class="black-key highlight-black" style="left:146px">F#</div><div class="black-key" style="left:186px">G#</div><div class="black-key" style="left:226px">A#</div><div class="black-key highlight-black" style="left:306px">C#</div><div class="black-key" style="left:346px">D#</div><div class="black-key highlight-black" style="left:426px">F#</div></div>
Piano()(Scale("phrygian dominant").get_notes("D"))
<style>
.piano { background: #222; padding: 20px 0; position: relative; width: 480px; }
.white-keys { display: flex; }
.white-key {
    width: 40px; height: 125px; background: #fff;
    border: 1px solid #000;
    color: #111; font-size: 18px; text-align: center; line-height: 200px; font-family: Arial;
    position: relative; z-index: 1;
}
.black-key {
    width: 20px; height: 80px; background: #000; color: #fff;
    border: 1px solid #333; position: absolute; z-index: 2;
    text-align: center; line-height: 100px; font-family: Arial; font-size: 14px;
    left: 0; top: 20px; pointer-events: none;
}
.highlight { background: #ff0 !important; color: #000 !important; }
.highlight-black { background: #ff0 !important; color: #000 !important; }
</style>
<div class="piano" style="width:440px"><div class="white-keys"><div class="white-key highlight">C</div><div class="white-key highlight">D</div><div class="white-key">E</div><div class="white-key">F</div><div class="white-key highlight">G</div><div class="white-key highlight">A</div><div class="white-key">B</div><div class="white-key highlight">C</div><div class="white-key highlight">D</div><div class="white-key">E</div><div class="white-key">F</div><div class="black-key" style="left:26px">C#</div><div class="black-key highlight-black" style="left:66px">D#</div><div class="black-key highlight-black" style="left:146px">F#</div><div class="black-key" style="left:186px">G#</div><div class="black-key highlight-black" style="left:226px">A#</div><div class="black-key" style="left:306px">C#</div><div class="black-key highlight-black" style="left:346px">D#</div><div class="black-key highlight-black" style="left:426px">F#</div></div>
Piano()(PolyChord([Chord.from_short("E"), Chord.from_short("Am")]))
<style>
.piano { background: #222; padding: 20px 0; position: relative; width: 480px; }
.white-keys { display: flex; }
.white-key {
    width: 40px; height: 125px; background: #fff;
    border: 1px solid #000;
    color: #111; font-size: 18px; text-align: center; line-height: 200px; font-family: Arial;
    position: relative; z-index: 1;
}
.black-key {
    width: 20px; height: 80px; background: #000; color: #fff;
    border: 1px solid #333; position: absolute; z-index: 2;
    text-align: center; line-height: 100px; font-family: Arial; font-size: 14px;
    left: 0; top: 20px; pointer-events: none;
}
.highlight { background: #ff0 !important; color: #000 !important; }
.highlight-black { background: #ff0 !important; color: #000 !important; }
</style>
<div class="piano" style="width:440px"><div class="white-keys"><div class="white-key highlight">C</div><div class="white-key">D</div><div class="white-key highlight">E</div><div class="white-key">F</div><div class="white-key">G</div><div class="white-key highlight">A</div><div class="white-key highlight">B</div><div class="white-key highlight">C</div><div class="white-key">D</div><div class="white-key highlight">E</div><div class="white-key">F</div><div class="black-key" style="left:26px">C#</div><div class="black-key" style="left:66px">D#</div><div class="black-key" style="left:146px">F#</div><div class="black-key highlight-black" style="left:186px">G#</div><div class="black-key" style="left:226px">A#</div><div class="black-key" style="left:306px">C#</div><div class="black-key" style="left:346px">D#</div><div class="black-key" style="left:426px">F#</div></div>

Guitar

from musy import Guitar

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

musy-0.0.5.tar.gz (22.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

musy-0.0.5-py3-none-any.whl (19.2 kB view details)

Uploaded Python 3

File details

Details for the file musy-0.0.5.tar.gz.

File metadata

  • Download URL: musy-0.0.5.tar.gz
  • Upload date:
  • Size: 22.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.0

File hashes

Hashes for musy-0.0.5.tar.gz
Algorithm Hash digest
SHA256 512b0543c40e9010981696ab55fcf7d285bddf937c51e930e941013b11d78463
MD5 d399a1e0fff521f0580cc4a2a20c531f
BLAKE2b-256 ad17cf49ba0d3386212055be2f0d740412a0951a3e5ddee6c92c7a20a65a3296

See more details on using hashes here.

File details

Details for the file musy-0.0.5-py3-none-any.whl.

File metadata

  • Download URL: musy-0.0.5-py3-none-any.whl
  • Upload date:
  • Size: 19.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.0

File hashes

Hashes for musy-0.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 35bdef041c63e07d62efa7f371569be0f27c26f4b22b96ee2cd8e33250266fe9
MD5 3e7086affb46bd24866edf9c1b2fa7d5
BLAKE2b-256 a00960f86256fbb983d4c4f3ca10f70fb21590214143a1b9d777572fb834289e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page