Pitch¶
Pitch
¶
Pitch(
pitch: Union[Pitch, int, float, str, None] = 60,
alt: Union[int, float, None] = None,
octave: Union[int, None] = None,
accidental_chars: Optional[str] = None,
)
Represents a symbolic musical pitch.
A pitch is represented by a key_num and an alt. The key_num
is a number that corresponds to the MIDI convention where C4 is 60, C# is
61, etc., but generalized to floats (60.5 would be C4-quarter-tone-sharp).
The alt is an alteration, where +1 represents a sharp and -1
represents a flat. Alterations can also be, for example, 2 (double-sharp)
or -0.5 (quarter-tone flat). The symbolic note name is derived by
subtracting alt from key_num.
E.g., C#4 has key_num=61, alt=1, so 61-1 gives us 60, corresponding
to note name C. A Db has the same key_num=61, but alt=-1, and 61-(-1)
gives us 62, corresponding to note name D. There is no representation
for the “natural sign” (other than alt=0, which could imply no
accidental) or “courtesy accidentals.” Because accidentals normally
“stick” within a measure or are implied by key signatures, accidentals
are often omitted in the score presentation. Nonetheless, these
implied accidentals are encoded in the alt attribute and key_num
is the intended pitch with the accidental applied.
key_num and alt must always satisfy the invariant that
(key_num - alt) % 12 corresponds to one of the pitch classes
corresponding to {C, D, E, F, G, A, B}.
The constructor enforces this invariant via _fix_alteration:
key_num always takes priority, and if the given
alt does not produce a diatonic pitch, alt is replaced with the
smallest-magnitude value that does.
Ties between enharmonic spellings of the same key_num (e.g. C#/Db)
default to the spellings C#, Eb, F#, Ab, and Bb.
Author: Roger B. Dannenberg
Parameters:
-
pitch(Union[int, float, str, None], default:60) –Optional MIDI key_num or string Pitch name. Syntax is A-G followed by accidentals (see
accidental_charsbelow) followed by octave number. (Defaults to 60) -
alt(Union[int, float, None], default:None) –If pitch is a number, alt is an optional alteration (Defaults to 0). If
pitch - altdoes not result in a diatonic pitch number, alt is adjusted, normally choosing spellings C#, Eb, F#, Ab, and Bb. If pitch is a string, alt must be None. If pitch is itself an instance ofPitch, alt is ignored (the source Pitch's own alt is used). -
octave(Optional[int], default:None) –If pitch is a string without an octave specification and
octaveis an int, thenoctaveis used to specify the octave, where 4 denotes thekey_numrange 60 through 71. Theoctavedefaults to -1, which yields pitch classkey_nums 0-11. -
accidental_chars(Optional[str], default:None) –Allows parsing of pitch names with customized accidental characters. The value is a tuple or list consisting of a string of flat characters and a string of sharp characters, e.g. `["fb", "s#"]. (Defaults to None, which admits '♭', 'b' or '-' for flat, and '♯', '#', and '+' for sharp, but does not accept 'f' and 's'.)
Attributes:
-
key_num(float) –MIDI key number, e.g., C4 = 60, generalized to float.
-
alt(float) –Alteration, e.g., flat = -1.
Examples:
>>> p = Pitch(64)
>>> p
Pitch(name='E4', key_num=64)
>>> p.octave
4
>>> p = Pitch("E4")
>>> p.octave
4
>>> p = Pitch("F#################2")
>>> p.alt
17
>>> p.octave
2
>>> p = Pitch("E--------------------4")
>>> p.alt
-20
>>> p.octave
4
>>> p.register
2
>>> Pitch(61.5, alt=1.5)
Pitch(name='C?4', key_num=61.5)
key_num - alt must be a diatonic pitch number.
If not, key_num gets priority and alt is adjusted to the smallest valid value.
Here, alt is adjusted to 0, which preserves the key_num of 60:
>>> Pitch(60, alt=1.4)
Pitch(name='C4', key_num=60)
Source code in amads/core/pitch.py
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
Attributes¶
step
property
¶
step: str
The diatonic name of the pitch: A, B, C, D, E, F, or G.
The diatonic name corresponds to letter name without accidentals.
Returns:
-
str–The name of the pitch, a letter in "A" through "G".
name
property
¶
name: str
The string name including accidentals (# or b).
The octave number is omitted. If alt is not an integer, return the step name concatenated with "?". See also get_name, which accepts a parameter to specify accidental characters.
name_with_octave
property
¶
name_with_octave: str
The string name with octave, e.g., "C4", "B#3", etc.
The octave number is calculated by
(key_num - alteration) // 12 + 1 # (integer division)
and refers to the pitch before alteration, e.g., C4 is enharmonic to B#3 and represents the same (more or less) pitch even though the written octave numbers differ.
See also get_name_with_octave, which accepts a parameter to specify custom characters to represent accidentals.
octave
property
¶
octave: int
The octave number of the note name.
The note name is based on key_num - alt, e.g.,
C4 has octave 4 while B#3 has octave 3.
pitch_class
property
¶
pitch_class: int
The pitch class of the note, e.g., 0, 1, 2, ..., 11.
The pitch class is the key_num modulo 12, which gives the
class of this pitch in the range 0-11. If the key_num is
non-integer, it is rounded.
Returns:
-
int–The pitch class of the note.
fifths_from_c
property
¶
fifths_from_c: float
The position of this pitch's spelling on the line of fifths.
C is 0. Each step sharpward (C->G->D->A->E->B->F#->...) is +1, and
each step flatward (C->F->Bb->Eb->Ab->Db->Gb->...) is -1.
Unlike pitch_class, this distinguishes enharmonic spellings: F# is +6
while Gb is -6, even though both have the same pitch_class.
The result is an integer unless alt is non-integer
(e.g. for a quarter-tone accidental).
Returns:
-
float–The signed number of fifths from C, sharpward positive.
Examples:
>>> Pitch("C4").fifths_from_c
0
Octave invariant.
>>> Pitch("C9").fifths_from_c
0
>>> Pitch("G4").fifths_from_c
1
>>> Pitch("F4").fifths_from_c
-1
>>> Pitch("F#4").fifths_from_c
6
>>> Pitch("Gb4").fifths_from_c
-6
>>> Pitch("B##3").fifths_from_c
19
register
property
¶
register: int
Returns the absolute octave number based on floor(key_num).
Both C4 and B#3 have register 4.
Functions¶
as_tuple
¶
as_tuple()
Return a tuple representation of the Pitch instance.
Returns:
-
tuple–A tuple containing the
key_numandaltvalues.
Source code in amads/core/pitch.py
212 213 214 215 216 217 218 219 220 | |
from_name
classmethod
¶
from_name(
name: str,
octave: Optional[float] = -1,
accidental_chars: Optional[str] = None,
) -> Tuple[float, float]
Converts a string like "Bb" to a (pitch, alt) tuple.
For example, converts "Bb" to (10, -1).
If the string has an octave number or octave is given, the
octave will be applied, e.g., "C4" yields (60, 0). octave takes
effect if it is a number and name does not include an octave.
If both name has no octave and octave is None, the octave is
-1, yielding pitch class numbers 0-11.
The first character must be one of the unmodified base pitch names: C, D, E, F, G, A, B (not case-sensitive).
Subsequent characters must indicate a single accidental type: one of '♭', 'b' or '-' for flat, and '♯', '#', and '+' for sharp, unless accidental_chars specified exactly the acceptable flat and sharp chars, e.g., "fs" indicates 'f' for flat, 's' for sharp.
Note that 's' is not a default accidental type as it is ambiguous: 'Fs' probably indicates F#, but Es is more likely Eb (German).
Also unsupported are: mixtures of sharps and flats (e.g., B#b); symbols for double sharps, quarter sharps, naturals, etc.; any other characters (except space, tab and underscore, which are allowed but ignored).
Following accidentals (if any) is an optional single-digit octave number. Note that MIDI goes below C0; if the octave number is omitted, the octave will be -1, which corresponds to pitch class numbers 0-11 and octave -1 (which you can also specify as octave).
Instructive error messages are given for invalid input.
Parameters:
-
name(str) –The string representation of the pitch name.
-
octave(Optional[float], default:-1) –The octave number if not specified in the name. (Defaults to -1)
-
accidental_chars(Optional[tuple[str, str]], default:None) –The characters to use for flat and sharp accidentals. This is a tuple of two strings, where the first is all possible flat characters, and the second is all possible sharp characters. (Defaults to None, which admits '♭', 'b' or '-' for flat, and '♯', '#', and '+' for sharp.)
Returns:
-
Tuple[float, float]–A tuple containing the
key_numandaltvalues.
Source code in amads/core/pitch.py
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | |
get_name
¶
get_name(accidental_chars: str = 'b#') -> str
Return string name including accidentals (# or b) but no octave.
See the name property for details.
Parameters:
-
accidental_chars(str, default:'b#') –The characters to use for flat and sharp accidentals. (Defaults to "b#")
Returns:
-
str–The string representation of the pitch name, including accidentals.
Source code in amads/core/pitch.py
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | |
get_name_with_octave
¶
get_name_with_octave(accidental_chars: str = 'b#') -> str
Return string name with octave, e.g., C4, B#3, etc.
See the name_with_octave property for details.
Parameters:
-
accidental_chars(str, default:'b#') –The characters to use for flat and sharp accidentals. (Defaults to "b#")
Returns:
-
str–The string representation of the pitch name with octave.
Source code in amads/core/pitch.py
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | |
enharmonic
¶
enharmonic() -> Pitch
Construct an enharmonic equivalent.
If alt is non-zero, return a Pitch where alt is zero
or has the opposite sign and where alt is minimized. E.g.
enharmonic(Cbb) is A# (not Bb). If alt is zero, return a
Pitch with alt of +1 or -1 if possible. Otherwise, return
a Pitch with alt of -2 (Ebb, Abb or Bbb).
Note the difference between this and simplest_enharmonic.
Returns:
-
Pitch–A new Pitch object representing the enharmonic equivalent.
Examples:
>>> Pitch("C4").enharmonic()
Pitch(name='B#3', key_num=60)
>>> Pitch("B3").enharmonic()
Pitch(name='Cb4', key_num=59)
>>> Pitch("B#3").enharmonic()
Pitch(name='C4', key_num=60)
>>> bds = Pitch("B##3")
>>> bds.enharmonic() # change of direction
Pitch(name='Db4', key_num=61)
>>> bds.upper_enharmonic() # note the difference
Pitch(name='C#4', key_num=61)
>>> Pitch("Dbb4").enharmonic()
Pitch(name='C4', key_num=60)
Source code in amads/core/pitch.py
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 | |
simplest_enharmonic
¶
simplest_enharmonic(sharp_or_flat: Optional[str] = 'default') -> Pitch
Create Pitch object with the simplest enharmonic representation.
I.e., if there exists an enharmonic-equivalent pitch with no
alterations, then use that. If the Pitch is already in simplest
form (e.g., C4), it is simply returned. If an alteration is
needed, then use sharps or flats depending on sharp_or_flat.
If sharp_or_flat is omitted, the same enharmonic choice
as the Pitch constructor is used (C#, Eb, F#, Ab, and Bb).
Parameters:
-
sharp_or_flat(Optional[str], default:'default') –This is only relevant if the pitch needs an alteration, otherwise it is unused. The value can be "sharp" (use sharps), "flat" (use flats), and otherwise use the same enharmonic choice as the Pitch constructor.
Examples:
>>> bds = Pitch("B##3")
>>> bds.simplest_enharmonic()
Pitch(name='C#4', key_num=61)
>>> bds.simplest_enharmonic(sharp_or_flat="flat")
Pitch(name='Db4', key_num=61)
>>> Pitch("C4").simplest_enharmonic()
Pitch(name='C4', key_num=60)
Returns:
-
Pitch–A Pitch object representing the enharmonic equivalent.
Source code in amads/core/pitch.py
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | |
upper_enharmonic
¶
upper_enharmonic() -> Pitch
Return the enharmonic based on the note name above.
The result will have the next higher diatonic name
with alt accordingly decreased by 1 or 2, e.g.,
C#->Db, C##->D, Cb->Dbbb.
Returns:
-
Pitch–A Pitch object representing the upper enharmonic equivalent.
Examples:
>>> bds = Pitch("B##3")
>>> bds
Pitch(name='B##3', key_num=61)
>>> cis = bds.upper_enharmonic()
>>> cis
Pitch(name='C#4', key_num=61)
>>> des = cis.upper_enharmonic()
>>> des
Pitch(name='Db4', key_num=61)
>>> des.upper_enharmonic()
Pitch(name='Ebbb4', key_num=61)
>>> Pitch("D4").upper_enharmonic()
Pitch(name='Ebb4', key_num=62)
Source code in amads/core/pitch.py
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 | |
lower_enharmonic
¶
lower_enharmonic() -> Pitch
Return the enharmonic based on the note name below.
The result will have the next lower diatonic name
with alt accordingly increased by 1 or 2, e.g.,
Db->C#, D->C##, D#->C###.
Returns:
-
Pitch–A Pitch object representing the lower enharmonic equivalent.
Examples:
>>> Pitch("Db4").lower_enharmonic()
Pitch(name='C#4', key_num=61)
>>> Pitch("D4").lower_enharmonic()
Pitch(name='C##4', key_num=62)
>>> Pitch("C#4").lower_enharmonic()
Pitch(name='B##3', key_num=61)
Source code in amads/core/pitch.py
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 | |
PitchCollection
dataclass
¶
PitchCollection(pitches: list[Pitch])
Combined representations of more than one pitch. Differs from Chord which has onset, duration, and contains Notes, not Pitches.
Parameters:
-
pitches(list[Pitch]) –A list of Pitch instances.
Attributes:
-
pitches(list[Pitch]) –A list of Pitch instances.
Examples:
>>> test_case = ['G#4', 'G#4', 'B4', 'D4', 'F4', 'Ab4']
>>> pitches = [Pitch(p) for p in test_case]
>>> pitches_gathered = PitchCollection(pitches)
>>> pitches_gathered.pitch_name_multiset
['G#4', 'G#4', 'B4', 'D4', 'F4', 'Ab4']
>>> pitches_gathered.pitch_num_multiset
[68, 68, 71, 62, 65, 68]
>>> pitches_gathered.pitch_class_multiset
[2, 5, 8, 8, 8, 11]
>>> pitches_gathered.pitch_class_set
[2, 5, 8, 11]
>>> pitches_gathered.pitch_class_vector
(0, 0, 1, 0, 0, 1, 0, 0, 3, 0, 0, 1)
>>> pitches_gathered.pitch_class_indicator_vector
(0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1)
Attributes¶
pitch_num_multiset
property
¶
pitch_num_multiset
Return a list of pitch numbers from the pitches in the collection.
pitch_name_multiset
property
¶
pitch_name_multiset
Return a list of pitch names with octaves from the pitches in the collection.
pitch_class_multiset
property
¶
pitch_class_multiset
Return a sorted list of pitch classes from the pitches in the collection, including duplicates.
pitch_class_set
property
¶
pitch_class_set
Return a sorted list of pitch classes from the pitches in the collection without duplicates.
pitch_class_vector
property
¶
pitch_class_vector
Return a pitch class vector (12-dimensional) representing the count of each pitch class in the collection.
pitch_class_indicator_vector
property
¶
pitch_class_indicator_vector
Return a pitch class indicator vector (12-dimensional) representing the presence (1) or absence (0) of each pitch class in the collection.
pitches_from_c
property
¶
pitches_from_c
Return a list of each pitch's fifths_from_c value, in the same
order as pitches (duplicates included, unsorted).
pitches_from_c_centroid
property
¶
pitches_from_c_centroid
Return the arithmetic mean of pitches_from_c,
i.e. the "centre of mass" of this collection's pitches on the line of fifths.
Duplicate pitches are weighted by their multiplicity
(each occurrence counts separately,
matching pitches_from_c/pitch_num_multiset,
as opposed to pitch_class_set-style deduplication).
Raises:
-
ValueError–If the collection has no pitches.
Examples:
>>> test_case = ['G#4', 'G#4', 'B4', 'D4', 'F4', 'Ab4']
>>> pitches = [Pitch(p) for p in test_case]
>>> pitches_gathered = PitchCollection(pitches)
>>> pitches_gathered.pitches_from_c
[8, 8, 5, 2, -1, -4]
>>> pitches_gathered.pitches_from_c_centroid
3.0
Note how this changes with spelling
>>> test_case = ['G#4', 'G#4', 'B4', 'D4', 'F4', 'G#4']
>>> pitches = [Pitch(p) for p in test_case]
>>> pitches_gathered = PitchCollection(pitches)
>>> pitches_gathered.pitches_from_c
[8, 8, 5, 2, -1, 8]
>>> pitches_gathered.pitches_from_c_centroid
5.0