The pitch module
Classes and functions to deal with LilyPond pitches.
A pitch consists of a step (note, the index in the global default scale) and an alteration, which is a rational value (fraction or floating point) in whole tones. The notes 0..6 correspond with the usual “white keys” C, D, E, F, G, A, B; a sharp is represented by a +0.5 alteration value, and a flat by a -0.5 value.
The octave of a pitch is 0 for the octave starting at middle C, just like LilyPond handles the octave.
All functions and classes in this module, and also in the key
module,
allow specifying a different global default scale (set in the
MAJOR_SCALE
module constant), to theoretically support other tone
systems, but that will probably almost never be necessary.
- MAJOR_SCALE = (0, 1, 2, 2.5, 3.5, 4.5, 5.5)
Major scale: C D E F G A B, with the default pitch offset from the starting C in whole tones.
- MAJOR_FLATS = (1.5, 5)
Which pitch values get a flat by default instead of a sharp when converting a MIDI key number to a pitch.
- class Pitch(octave, note, alter)[source]
Bases:
object
A pitch with
octave
,note
, andalter
attributes.The attributes may be manipulated directly, and have the same contents and meaning as the three values in LilyPond’s
(ly:make-pitch octave note alter)
construct.The
octave
is an integer where 0 stands for the octave containing “middle C” (with one apostrophe in LilyPond’s format). Thenote
is an integer in the 0..6 range, where 0 stands for C; thealter
is an integer, float or fraction denoting the alteration in whole tones, where all pitch languages support the values -1, -0.5, 0, 0.5, 1, and some languages also support semi, three-quarter alterations like 0.25 (i.e.Fraction(1, 4)
), or even other alterations.Pitches compare equal when their attributes are the same, and also support the
>
,<
,>=
and<=
operators. These operators compare on octave first, then note, then alter.format(pitch)
returns always the dutch notation (or a question mark if there’s no known name for the note, alter combination), but you can usePitchProcessor
to read/write pitch names in all LilyPond languages.- classmethod from_midi(key, scale=None, flats=None)[source]
Return a
Pitch
from the MIDI key value.All altered notes get a sharp, unless a pitch value is listed in the
flats
parameter. By default, the pitch values 1.5 and 5 get a flat, resulting in an e-flat instead of d-sharp and a b-flat instead of an a-sharp.An example:
>>> from quickly.pitch import Pitch >>> Pitch.from_midi(60) <Pitch note=0, alter=0, octave=1 (c')> >>> Pitch.from_midi(61) <Pitch note=0, alter=0.5, octave=1 (cis')> >>> Pitch.from_midi(70) <Pitch note=6, alter=-0.5, octave=1 (bes')> >>> Pitch.from_midi(70, flats=()) <Pitch note=5, alter=0.5, octave=1 (ais')>
A more powerful way to convert MIDI key numbers to pitches is in the
KeySignature
class.
- class PitchProcessor(language=None)[source]
Bases:
object
Read and write pitch names in all LilyPond languages.
The language to use by default can be given on instantiation or set in the
language
attribute. Some languages have multiple pitch names for the same note; using theprefer_
attributes you can control which style is chosen when writing the pitch name.- prefer_long = False
Prefer long names in english, e.g.
c-sharpsharp
abovecss
- prefer_accented = False
Prefer
ré
abovere
(in francais)
- prefer_x = False
Prefer
dox
abovedoss
,cx
abovecss
, etc in enspanol, english, francais
- prefer_double_s = False
Prefer
ss
aboves
inside note names in norsk
- prefer_classic = True
Prefer
es
aboveees
andas
aboveaes
(in nederlands, norsk)
- prefer_deprecated = False
Prefer names marked as deprecated
- property language
The language to use (default:
"nederlands"
).Deleting this attribute sets it back to
"nederlands"
.Raises a
KeyError
if the language you try to set does not exist. Valid languages are:"arabic"
,"bagpipe"
,"catalan"
,"català"
,"deutsch"
,"english"
,"espanol"
,"español"
,"français"
,"italiano"
,"nederlands"
,"norsk"
,"persian"
,"portugues"
,"português"
,"suomi"
,"svenska"
,"vlaams"
.Do not modify the language between a
read_node()
andwrite_node()
operation on the same node. For translation of pitch names, use two PitchProcessors.
- pitch(name)[source]
Return a
Pitch
for the specified note name.Raises a
KeyError
if the language does not know the pitch name, or when the language name is unknown.For example:
>>> from quickly.pitch import PitchProcessor >>> p = PitchProcessor() >>> p.read('cis') <Pitch octave=-1, note=0, alter=0.5 (cis)>
- name_octave(pitch)[source]
Return a two-tuple (name, octave) for the
Pitch
.The name is the note name, the octave is the number of
,
(if negative) or'
that still need to be added.Raises a
KeyError
if the language does not contain a pitch name.
- to_string(pitch)[source]
Return a string representing the pitch.
Raises a
KeyError
if the language does not contain a pitch name.For example:
>>> from quickly.pitch import PitchProcessor >>> p = PitchProcessor() >>> p.write(Pitch(-1, 0, 0)) 'c' >>> p.write(Pitch(0, 4, 1)) "gisis'" >>> p.language = 'english' >>> p.write(Pitch(0, 4, 1)) "gss'" >>> p.prefer_long = True >>> p.write(Pitch(0, 4, 1)) "g-sharpsharp'"
- read_node(node)[source]
Return a Pitch, initialized from the node.
The
node
is aNote
, positionedPitchedRest
or any otherPitchable
. For example:>>> from quickly.pitch import PitchProcessor >>> from quickly.dom import lily >>> n = lily.Note('re') >>> p = PitchProcessor('français') >>> p.read_node(n) <Pitch octave=-1, note=1, alter=0 (d)>
The octave handling might be a little confusing at first sight: A Note node without octave characters has octave 0, while the pitch has octave -1. This is because, just like in LilyPond, the pitch name itself carries the octave -1, and the octave count of the node is added to it to get the resulting octave of the actual pitch:
>>> n.octave # number of ' or , 0 >>> p.read_node(n).octave # actual octave -1
- write_node(node, pitch)[source]
Write the Pitch’s note, alter and octave to the node.
The
node
is aNote
, positionedPitchedRest
or any otherPitchable
. Example:>>> from quickly.pitch import Pitch, PitchProcessor >>> from quickly.dom import lily >>> n = lily.Note('c') >>> p = PitchProcessor() >>> p.write_node(n, Pitch(2, 1, 0.5)) >>> n.dump() <lily.Note 'dis' (1 child)> ╰╴<lily.Octave 3>
- process(node, write=True)[source]
Return a context manager that yields a
Pitch
when entered.The
node
is aNote
, positionedPitchedRest
or any otherPitchable
. You can manipulate the Pitch, and when done, the node will be updated if the pitch was changed. An example:>>> from quickly.pitch import PitchProcessor >>> from quickly.dom import lily >>> n = lily.Note('c') >>> p = PitchProcessor() >>> with p.process(n) as pitch: ... pitch.note += 2 ... pitch.alter = 0.5 ... pitch.octave += 1 ... >>> n.write() "eis'" >>> n.dump() <lily.Note 'eis' (1 child)> ╰╴<lily.Octave 1>
If you set the
write
parameter to False on invocation, the pitch changes will not be written back to the DOM node, this enables you to e.g. apply changes only within a certain range.
- pitchable(pitch, cls=None)[source]
Return a new Pitchable element for the pitch.
By default, a Note is returned, but you may specify any Pitchable subclass.
>>> from quickly.pitch import * >>> p = PitchProcessor('nederlands') >>> n = p.pitchable(Pitch(2, 3, -.25)) >>> n.dump() <lily.Note 'feh' (1 child)> ╰╴<lily.Octave 3> >>> n.write() "feh'''"
- find_language(node)[source]
Search backwards from node to find the last set language.
If an
\include
command is found that names a language file, or a\language
command with a valid language, that language is set.
- follow_language(nodes)[source]
Iterate over the DOM nodes and follow language changes.
Yield every node, except for
lily.Language
orlily.Include
if a language name is included. Sets the language attribute according to the\language
or\include
command.
- distill_preferences(names)[source]
Iterate over the
names
and try to distill the preferred style.Adjust the preferences based on the encountered pitch names.
This can be used to analyze existing music and use the same pitch name preferences for newly entered music.
The
names
iterable may be a set but also an ordered sequence or generator. If a name is encountered that is a language name, that language is followed to test following pitch names. (Thelanguage
attribute is not changed.)
- octave_to_string(n)[source]
Convert a numeric value to an octave notation.
The octave notation consists of zero or more
'
or,
. The octave0
returns the empty string.
- octave_from_string(octave)[source]
Convert an octave string to a numeric value.
''
is converted to 2,,
to -1. The empty string gives 0.
- determine_language(names)[source]
Yield the language names that have all the specified pitch names.
This can be used to auto-determine the language of music if the language name somehow is not set in a file. Just harvest all the pitch names and call this function. The pitch names
"r"
,"R"
,"s"
and"q"
are ignored. For example:>>> from quickly.pitch import determine_language >>> list(determine_language(['c', 'd', 'es', 'fis', 'bis'])) ['nederlands'] >>> list(determine_language(['c', 'do'])) [] # ambiguous