Core API documentation¶
Frequency¶
Frequencies are the prime substance of pitches. Everything in xenharmlib (and in music, for that matter) ultimately boils down to frequencies and their relations to one another. In this module, we implement a couple of useful representations for frequencies and frequency ratios.
- class xenharmlib.core.frequencies.Frequency(number: int | Fraction | float | FrequencyRatio)¶
Frequency is the class to which all pitch definitions ultimately come down. Frequencies represent the physical layer of sound, stripped from all other abstractions.
Frequency is a wrapper around symbolic mathematical expressions that are provided by the sympy package. Using those expressions instead of floats allows us to do exact precision calculations. This is especially useful in regard to equal division tunings where pitches have irrational frequencies.
Frequency objects can be constructed by providing an integer, float, Fraction or a sympy expression. For example
>>> from xenharmlib import Frequency >>> from fractions import Fraction >>> Frequency(440) Frequency(440) >>> Frequency(1.5) Frequency(3/2) >>> Frequency(Fraction(3, 2)) Frequency(3/2)
>>> import sympy as sp >>> Frequency(sp.Integer(2)**sp.Rational(1, 12)) Frequency(2**(1/12))
As you might have noticed floats get converted to fractions internally. This is done to ensure precision when dealing with frequencies, however despite this safeguard using floats has a lot of pitfalls, as you can see in this example:
>>> Frequency(0.2) Frequency(3602879701896397/18014398509481984)
For very technical reasons floats are pretty bad at saving certain numbers. So even though it is possible to initialize a Frequency from a float it is highly discouraged. Instead, you should use python’s Fraction type
>>> Frequency(Fraction(2, 10)) Frequency(1/5) >>> Frequency(440 + Fraction(2, 10)) Frequency(2201/5)
If you want a more human-readable form you can always convert to float after all calculations have been done:
>>> Frequency(440 + Fraction(2, 10)).to_float() 440.2
Frequency objects are part of a dimensionful arithmetic that is defined on Frequency objects and various scalars. Frequencies can interact with one another and with scalar values in the way how they would in a proper physical equation:
Frequencies can be added to and subtracted from other frequencies:
>>> Frequency(440) + Frequency(100) Frequency(540) >>> Frequency(440) - Frequency(100) Frequency(340)
However, the same way as adding a dimensionless quality to a quantity in Hz is forbidden in a physical equation Frequency objects and scalar values can not be added in xenharmlib:
>>> Frequency(440) + 100 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'Frequency' and 'int'"
For multiplication the same holds in reverse. Frequencies can be multiplied by a scalar, but not with one other:
>>> from xenharmlib import FrequencyRatio >>> 3 * Frequency(100) Frequency(300) >>> Frequency(200) * FrequencyRatio(3, 2) Frequency(300)
A Frequency can be divided by both a scalar and a frequency. While the first case results in a Frequency in Hz, the second will be a scalar FrequencyRatio without a physical unit attached to it:
>>> Frequency(440) / 10 Frequency(44) >>> Frequency(440) / Frequency(100) FrequencyRatio(22/5)
Even though a frequency can be divided by a scalar, the same does not hold in reverse: Dividing a scalar by a frequency will raise an error. Even though an expression like 1 / 80 Hz is technically legal in a physics equation it is outside the scope of this implementation.
>>> 1 / Frequency(100) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for /: 'int' and 'Frequency'"
- get_harmonic(index: int) Frequency¶
Returns the k-th overtone frequency for this frequency.
- Parameters:
index – Index of the harmonic. 0 is the original frequency, 1 the first harmonic, etc
- get_harmonics(limit: Frequency | None = None) List[Frequency]¶
Returns a list of overtone frequencies for this note
- Parameters:
limit – (optional) upper-frequency limit of the list in Hz, defaults to the average audible maximum of the human ear of 20KHz
- to_float() float¶
Converts this object into a floating point number
- class xenharmlib.core.frequencies.FrequencyRatio(numerator: int | Fraction | float | FrequencyRatio, denominator: int | Fraction | float | FrequencyRatio = 1)¶
The FrequencyRatio class can be understood as an augmented version of the Python built-in Fraction type. Different from the built-in Fraction type FrequencyRatio can also hold infinite-precision irrational fractions like \(\frac{\sqrt[12]{2}}{2^{\frac{1}{12}}}\) that are essential for equal temperament intervals.
For infinite-precision calculation, FrequencyRatio wraps the sympy package for symbolic arithmetic. Calculation results do not get converted to approximations until the user explicitly decides to.
FrequencyRatio objects can be created like Fractions:
>>> FrequencyRatio(20, 8) FrequencyRatio(5/2) >>> FrequencyRatio(3) FrequencyRatio(3)
For both numerator and denominator, sympy expressions can be used:
>>> import sympy as sp >>> FrequencyRatio(sp.Integer(3)**sp.Rational(3, 12), sp.sqrt(3)) FrequencyRatio(3**(3/4)/3)
Frequency ratios can also be constructed from prime exponent vectors (monzos):
>>> FrequencyRatio.from_monzo([-11, 7]) FrequencyRatio(2187/2048)
Floats are also supported, however highly discouraged because of the technical limitations of the data type that can lead to surprising and unwanted results:
>>> FrequencyRatio(0.2) # bad FrequencyRatio(3602879701896397/18014398509481984) >>> FrequencyRatio(2, 10) # good FrequencyRatio(1/5)
Frequency ratios define a standard arithmetic and interact seamlessly with other scalar types:
>>> FrequencyRatio(20, 8) * FrequencyRatio(2) FrequencyRatio(5)
>>> FrequencyRatio(20, 8) + 3 FrequencyRatio(11/2) >>> 3 + FrequencyRatio(20, 8) FrequencyRatio(11/2)
>>> from fractions import Fraction >>> FrequencyRatio(20, 8) * Fraction(8, 20) FrequencyRatio(1) >>> Fraction(16, 20) * FrequencyRatio(20, 8) FrequencyRatio(2)
>>> FrequencyRatio(20) / 10 FrequencyRatio(2) >>> 5 / FrequencyRatio(20) FrequencyRatio(1/4)
- property cents¶
The cents equivalent of this frequency ratio
- property denominator: FrequencyRatio¶
The denominator of the ratio
- classmethod from_monzo(monzo: List[int])¶
Creates a frequency ratio from a monzo. A monzo is a list of exponents for the prime numbers, for example, the argument [-1, 1] creates the frequency \(2^{-1} * 3^1\)
- log(base: int | Fraction | float | FrequencyRatio) FrequencyRatio¶
Returns the result of the logarithm of this object
- Parameters:
base – The base that should be assumed for calculation
- property numerator: FrequencyRatio¶
The numerator of the ratio
- to_float() float¶
Converts this object into a floating point number
- to_monzo()¶
Factorizes the frequency ratio into a monzo. A monzo is a list of exponents for the prime numbers, for example, the frequency ratio 3/2 creates the monzo [-1, 1], since \(2^{-1} * 3^1 = \frac{3}{2}\)
Origin Context¶
This module implements the OriginContext class which is the abstract base class for tunings and notations
- class xenharmlib.core.origin_context.OriginContext(freq_repr_cls: type[FreqReprT], interval_cls: type[IntervalT], scale_cls: type[ScaleT], interval_seq_cls: type[IntervalSeqT])¶
OriginContext is the abstract base class for both tunings and notations. It defines a unified interface for collection and interval builder methods as well as an interface for a defined “zero element” which is used as a reference point for other objects.
OriginContext does not define an interface for the builder method of the FreqRepr object (such as pitch or note) as the name and the function signature vary greatly from context to context (e.g. one dimensional tunings demand an integer as construction argument, more-dimensional tunings a vector, notes in periodic tunings mostly demand a string symbol and a base interval index, etc)
- diff_interval(pitch_diff: int) IntervalSeqT¶
Returns an interval the size of a given pitch index difference.
- Parameters:
pitch_diff – The pitch index difference
- diff_interval_seq(pitch_diffs: Iterable[int] | None = None) IntervalSeqT¶
Returns an interval sequence from an iterable of pitch index differences, for example:
>>> from xenharmlib import EDOTuning >>> edo12 = EDOTuning(12) >>> major_chord = edo12.diff_interval_seq([4, 3]) >>> minor_chord = edo12.diff_interval_seq([3, 4])
- Parameters:
pitch_diffs – An iterable containing pitch index differences
- interval(source: FreqReprT, target: FreqReprT) IntervalT¶
Returns an interval having the interval type this origin context was configured with
- Raises:
IncompatibleOriginContexts – If either source or target have a different origin context than this one
- Parameters:
source – The source of the interval
target – The target of the interval
- interval_seq(intervals: Iterable[IntervalT] | None = None) IntervalSeqT¶
Returns an interval sequence having the interval sequence type this origin context was configured with
- Raises:
IncompatibleOriginContexts – If at least one given element has a different origin context than this one
- Parameters:
intervals – A list of intervals originating from this context
- scale(elements: Iterable[FreqReprT] | None = None) ScaleT¶
Returns a scale having the scale type this origin context was configured with
- Raises:
IncompatibleOriginContexts – If at least one given element has a different origin context than this one
- Parameters:
elements – A list of frequency representations originating from this context
- abstract property zero_element: FreqReprT¶
The zero element is a reference point, in one-dimensional tunings it is the element with index 0, in western notation typically C-0, etc
Frequency Representations¶
This module implements base classes for frequency representations (pitches, notes, etc)
- class xenharmlib.core.freq_repr.FreqRepr(origin_context, frequency: Frequency)¶
FreqRepr is the base class for all frequency representations (pitches, notes, etc). The class implements a total order on the set of all frequency representations (based on the total order of frequency values). It also saves the origin context of the frequency representation (a tuning or notation)
In addition it defines an abstract method for short string representation and a proxy method ‘interval’ which redirects to the interval method of the origin context.
- interval(other: Self)¶
Returns an interval between this frequency representation and another representation of the same origin context.
- Parameters:
other – Another frequency representation of the same origin context
- property origin_context¶
The origin context associated with this frequency representation
- reflection(axis: Self | None = None) Self¶
A reflection of this pitch/note across a pitch/note axis. In technical terms the method calculates the interval from this object to the axis and then applies that interval to to the axis.
- Parameters:
axis – The element across which this object is reflected (optional, defaults to the zero element of the origin context)
- scale(interval_seq)¶
Returns a scale that starts with this note and continues with the given interval structure
- Parameters:
interval_seq – An interval sequence of the same origin context
- abstract property short_repr: str¶
(Must be implemented by subclasses) A shortened representation of this note (to be used in collection objects like scales)
- abstractmethod transpose(diff) Self¶
(Must be implemented by subclasses) Transposes the frequency representation
- class xenharmlib.core.freq_repr.SDFreqRepr(origin_context, frequency: Frequency, pitch_index: int)¶
Base class for single dimensional frequency representation objects. Assumes an integer pitch index in addition to the frequency as part of the data structure.
Implements optimizations on the total order based on pitch index data (if objects originate from same context).
Demands that subclasses implement a transpose method
- property pitch_index: int¶
The pitch index of this object
Scales¶
This module implements base classes for scales
- class xenharmlib.core.scale.PeriodicScale(origin_context, elements: Iterable[FreqReprT] | None = None)¶
PeriodicScale is the abstract base class for scales that contain frequency representations of periodic tunings / notations. It overwrites the set operations to allow for the ignore_bi_index flag.
- It implements the following additional methods:
pcs_normalized
pcs_intersection
is_equivalent
rotated_up
rotated_down
rotation
Subclasses must implement at least the transpose function
- Parameters:
origin_context – An origin context (like a tuning or a notation)
elements – A list of frequency representations
- difference(other: Self, ignore_bi_index: bool = False) Self¶
Returns a scale containing only elements from this scale that are NOT present in the other scale
- Parameters:
other – Another scale of the same origin context
ignore_bi_index – (Optional, default False) When set to True elements of the same pitch class will be treated the same. For example, if the difference of two scales including C-0 and C-1 respectively is calculated, C-0 will not be inserted into the new scale
- Raises:
IncompatibleOriginContexts – If the other scale has a different origin context
- intersection(other: Self, ignore_bi_index: bool = False) Self¶
Returns a new scale including all elements that are included in both scales.
- Parameters:
other – Another scale of the same origin context
ignore_bi_index – (Optional, default False) When set to True elements of the same pitch class will be treated the same. For example, if the intersection of two scales including C-0 and C-1 respectively is calculated, both elements will be added to the result
- Raises:
IncompatibleOriginContexts – If the other scale has a different origin context
- is_disjoint(other: Self, ignore_bi_index: bool = False) bool¶
Determines if this scale has any common elements with another scale of the same origin context
- Parameters:
other – Another scale of the same origin context
ignore_bi_index – (Optional, default False) When set to True elements of the same pitch class will be treated the same. For example, if one scale includes C-0 and another C-1 the scales will not be considered disjoint
- Raises:
IncompatibleOriginContexts – If the other scale originates from a different origin context
- is_equivalent(other: PeriodicScale) bool¶
Deprecated since version 0.3.0: Use
is_set_equivalent()instead.Returns True if two scales are set equivalent, i.e. every element in this scale has an equivalent element somewhere(!) in the other scale (and vice versa).
Periodic scales of different origin contexts can be compared if their origin contexts have the same equivalency interval. Set equivalency between scales of different contexts is defined as “equality after pitch class set normalization”
- Raises:
IncompatibleOriginContexts – If the other scale has a different equivalency interval definition
- Parameters:
other – Another periodic scale
- property is_pcs_normalized: bool¶
Returns bool if this scale is pcs normalized. A pcs normalized scale only contains elements with base interval index 0.
- property is_period_normalized: bool¶
Returns bool if this scale is period normalized. A period normalized scale only contains elements smaller than the equivalent of the root note, meaning if the scale starts with F3, all subsequent notes are smaller than F4.
- property is_plusone_normalized: bool¶
Returns a period normalized version of the scale with an additional transposed root at the end, e.g. (F0, G0, A0, B0, C1, D1, E1, F1)
- is_seq_equivalent(other: PeriodicScale) bool¶
Returns True if two scales are sequentially equivalent, i.e. every element in this scale corresponds to another one in the other scale at the same scale index.
Periodic scales of different origin contexts can be compared if their origin contexts have the same equivalency interval. Sequential equivalency between scales of different contexts is defined as “equality after base interval alignment”
- Raises:
IncompatibleOriginContexts – If the other scale has a different equivalency interval definition
- Parameters:
other – Another periodic scale
- is_set_equivalent(other: PeriodicScale) bool¶
Returns True if two scales are set equivalent, i.e. every element in this scale has an equivalent element somewhere(!) in the other scale (and vice versa).
Periodic scales of different origin contexts can be compared if their origin contexts have the same equivalency interval. Set equivalency between scales of different contexts is defined as “equality after pitch class set normalization”
- Raises:
IncompatibleOriginContexts – If the other scale has a different equivalency interval definition
- Parameters:
other – Another periodic scale
- is_subset(other: Self, proper: bool = False, ignore_bi_index: bool = False) bool¶
Determines if all elements in this scale also exist in the other scale.
- Parameters:
other – Another scale of the same origin context
proper – (Optional, default False) When set to True method will return False if the two sets are identical
ignore_bi_index – (Optional, default False) When set to True elements of the same pitch class will be treated the same.
- Raises:
IncompatibleOriginContexts – If the other scale originates from a different origin context
- is_superset(other: Self, proper: bool = False, ignore_bi_index: bool = False) bool¶
Determines if all elements in the other scale also exist in this scale.
- Parameters:
other – Another scale of the same origin context
proper – (Optional, default False) When set to True method will return False if the two sets are identical
ignore_bi_index – (Optional, default False) When set to True elements of the same pitch class will be treated the same.
- Raises:
IncompatibleOriginContexts – If the other scale originates from a different origin context
- property is_zp_normalized: bool¶
Returns bool if the first element is the zero element of the origin context (pitch 0 in tunings, in western-like notations typically C0) and all elements reside in the first base interval.
- pcs_intersection(other: Self) Self¶
Returns a scale including all elements whose pitch class resides in both of the scales, normalized to the first base interval.
- Parameters:
other – The other scale
- pcs_normalized() Self¶
Returns a normalized version of this scale where all the elements of the scale are put into the first base interval of the tuning
Note: If the original scale has equivalent element pairs the normalized scale will be smaller in cardinality.
- period_normalized() Self¶
Returns a version of the scale in which each element that is above the root element will be transposed to the interval between the root element and its equivalent in the next base interval. For example the scale of the Fm7/11 chord with notes (F0, Ab0, C1, Eb1, Bb1) will become the scale (F0, Ab0, Bb0, C1, Eb1)
- plusone_normalized() Self¶
Returns a period normalized version of the scale with an additional transposed root at the end, e.g. (F0, G0, A0, B0, C1, D1, E1, F1)
- rotated_down() Self¶
Create a new scale by transposing the base interval of the highest element downwards until it is below the lowest element
- rotated_up() Self¶
Create a new scale by transposing the base interval of the lowest element upwards until it is above the highest element
- rotation(order: int) Self¶
Returns the n-th rotation of this scale.
- Parameters:
order – The number of times the scale is rotated. If a negative number is given the scale will be rotated downwards. On 0 the scale will return itself
- symmetric_difference(other: Self, ignore_bi_index: bool = False) Self¶
Returns a scale that includes all the elements from both scales that exist in either of them but NOT BOTH. This is the complement operation of the intersection.
- Parameters:
other – Another scale of the same origin context
ignore_bi_index – (Optional, default False) When set to True elements of the same pitch class will be treated the same. For example, if the difference of two scales including C-0 and C-1 respectively is calculated, C-0 will not be inserted into the new scale
- Raises:
IncompatibleOriginContexts – If the other scale has a different origin context
- transpose_bi_index(bi_diff: int) Self¶
Returns a scale with the same pitch class indices and symbols, but with a transposed base interval
- Parameters:
bi_diff – The difference in base interval between this scale and the resulting one
- zp_normalized() Self¶
Returns the scale transposed in a way so the root has pitch index 0 and all elements reside in the first base interval. In notations with enharmonic ambiguity a designated zero note is used (in western-like notations typically C0)
The function is equivalent to successively invoking zero_normalized + period_normalized or (which is the same) zero_normalized + pcs_normalized
- class xenharmlib.core.scale.Scale(origin_context, elements: Iterable[FreqReprT] | None = None)¶
Scale is the abstract base class for all scale types. The class implements iteration, the ‘in’ operator, the == operator, item retrieval with [] and set operations.
Subclasses must implement at least the transpose function
- Parameters:
origin_context – An origin context (like a tuning or a notation)
elements – A list of frequency representations
- difference(other: Self) Self¶
Returns a scale containing only elements from this scale that are NOT present in the other scale
- Parameters:
other – Another scale of the same origin context
- Raises:
IncompatibleOriginContexts – If the other scale has a different origin context
- property frequencies¶
An ordered list of frequencies present in this scale
- intersection(other: Self) Self¶
Returns a new scale including all elements that are included in both scales.
- Parameters:
other – Another scale of the same origin context
- Raises:
IncompatibleOriginContexts – If the other scale has a different origin context
- is_disjoint(other: Self) bool¶
Determines if this scale has any common elements with another scale of the same origin context.
- Parameters:
other – Another scale of the same origin context
- Raises:
IncompatibleOriginContexts – If the other scale has a different origin context
- is_subset(other: Self, proper: bool = False) bool¶
Determines if all elements in this scale also exist in the other scale.
- Parameters:
other – Another scale of the same origin context
proper – (Optional, default False) When set to True method will return False if the two sets are identical
- Raises:
IncompatibleOriginContexts – If the other scale has a different origin context
- is_superset(other: Self, proper: bool = False) bool¶
Determines if all elements in the other scale also exist in this scale.
- Parameters:
other – Another scale of the same origin context
proper – (Optional, default False) When set to True method will return False if the two sets are identical
- Raises:
IncompatibleOriginContexts – If the other scale has a different origin context
- abstract property is_zero_normalized: bool¶
Returns True if this function is zero normalized, meaning that the first element of the scale is identical to the zero element of the origin context (pitch 0 in tunings, typically C0 in western-like notations)
(must be implemented by subclass, since comparison to the the zero note should be done according to notational identity)
- property origin_context¶
The origin context from which this scale was built
- partial(mask_expr: int | Tuple[int | EllipsisType, ...]) Self¶
Returns a new scale consisting of a selection of indices of this scale. The selection is defined by an index mask expression.
An index mask can be defined as a tuple of consecutive indices, e.g. (1, 2, 5) gives a scale including the second, third and sixth element of this one.
An ellipsis between two indices indicates that all indices between them should be selected as well, e.g. (1, …, 5, 9) is equivalent to (1, 2, 3, 4, 5, 9).
If a mask begins with an ellipsis all indices from 0 to the next index are added to the selection, e.g. (…, 3, 5) is equivalent to (0, 1, 2, 3, 5).
A mask without a last index is called right-open and will select all indices from the last index to the end of the scale, for example (2, …) will select all elements of the scale except the first two.
If only one element should be selected a simple integer can be used
- Parameters:
mask_expr – An index mask expression which defines the selection of indices from this scale.
- partial_not(mask_expr: int | Tuple[int | EllipsisType, ...]) Self¶
Returns a new scale consisting of a selection of indices of this scale. The selection will be determined by an index mask and will hold all elements whose index is NOT covered by the mask.
An index mask can be defined as a tuple of consecutive indices, e.g. (1, 2, 5) gives a scale including the second, third and sixth element of this one.
An ellipsis between two indices indicates that all indices between them should be selected as well, e.g. (1, …, 5, 9) is equivalent to (1, 2, 3, 4, 5, 9).
If a mask begins with an ellipsis all indices from 0 to the next index are added to the selection, e.g. (…, 3, 5) is equivalent to (0, 1, 2, 3, 5).
A mask without a last index is called right-open and will select all indices from the last index to the end of the scale, for example (2, …) will select all elements of the scale except the first two.
If only one element should be selected a simple integer can be used
- Parameters:
mask_expr – An index mask expression which defines the selection of indices from this scale.
- partition(mask_expr: int | Tuple[int | EllipsisType, ...]) Tuple[Self, Self]¶
Partitions the scale into two parts using an index mask. The function will return a tuple of two scales with the first scale including all indices that are covered by the index mask and the second one including all indices that are not.
An index mask can be defined as a tuple of consecutive indices, e.g. (1, 2, 5) gives a scale including the second, third and sixth element of this one.
An ellipsis between two indices indicates that all indices between them should be selected as well, e.g. (1, …, 5, 9) is equivalent to (1, 2, 3, 4, 5, 9).
If a mask begins with an ellipsis all indices from 0 to the next index are added to the selection, e.g. (…, 3, 5) is equivalent to (0, 1, 2, 3, 5).
A mask without a last index is called right-open and will select all indices from the last index to the end of the scale, for example (2, …) will select all elements of the scale except the first two.
If only one element should be selected a simple integer can be used
- Parameters:
mask_expr – An index mask expression which defines the selection of indices from this scale.
- reflection(axis: FreqReprT | None = None) Self¶
A reflection of each pitch/note across a pitch/note axis. In technical terms the method calculates the interval from each element to the axis and then applies that interval to to the axis.
- Parameters:
axis – The element across which this object is reflected (optional, defaults to the zero element of the origin context)
If scale is reflected across the zero element, reflection is equivalent to inversion of the pitch class set
- spec_interval(source_index, target_index)¶
Returns the specific interval for a generic interval. For example in the 12-EDO C major scale the generic interval defined by (0, 2) is the specific interval major 3.
- Parameters:
source_index – Source index for the interval
target_index – Target index for the interval
- symmetric_difference(other: Self) Self¶
Returns a scale that includes all the elements from both scales that exist in either of them but NOT BOTH. This is the complement operation of the intersection.
- Parameters:
other – Another scale of the same origin context
- Raises:
IncompatibleOriginContexts – If the other scale has a different origin context
- to_interval_seq()¶
Returns this scale represented as an interval sequence
- abstractmethod transpose(diff) Self¶
Transposes the scale by the given difference (must be overwritten by subclass)
- Parameters:
diff – An interval or interval-like object
- union(other: Self) Self¶
Returns a new scale including all elements from this scale as well as the other
- Parameters:
other – Another scale of the same origin context
- Raises:
IncompatibleOriginContexts – If the other scale has a different origin context
- with_element(element: FreqReprT) Self[FreqRepr]¶
Returns a new scale containing all elements from this scale and the additional one given as a parameter.
- Parameters:
element – The new element to be added to the result
- Raises:
IncompatibleOriginContexts – If element has a different origin context than this scale
- zero_normalized() Self¶
Returns the scale transposed in a way so the root has pitch index 0. In notations with enharmonic ambiguity a designated zero note is used (in western-like notations typically C0)
Intervals¶
This module implements base classes for intervals
- class xenharmlib.core.interval.Interval(origin_context, frequency_ratio: FrequencyRatio)¶
Interval is the abstract bass class for all interval types, consisting only of an origin context and a frequency ratio. Based on frequency ratio it implements the cents property and a total ordering.
It forces subclasses to implement the __abs__ method, the class method from_source_and_target and the property short_repr
- Parameters:
origin_context – An origin context (like a tuning or a notation)
frequency_ratio – A frequency ratio object
- property cents: float¶
The interval size in cents (e.g. 1200 for an octave)
- property frequency_ratio: FrequencyRatio¶
The frequency ratio of this interval (e.g. 2 for an octave)
- abstractmethod classmethod from_source_and_target(source: FreqReprT, target: FreqReprT) Self¶
Constructs an interval from two frequency representations (must be implemented by subclass)
- Parameters:
source – The starting point of the interval
target – The end point of the interval
- property origin_context¶
The context this interval originated from (like a tuning or notation)
- abstract property short_repr: str¶
A short string representation of the interval (must be implemented by subclass)
- class xenharmlib.core.interval.SDInterval(origin_context, frequency_ratio: FrequencyRatio, pitch_diff: int)¶
SDInterval (single dimensional interval) extends the Interval class by a pitch_diff property.
Interval Sequences¶
- class xenharmlib.core.interval_seq.IntervalSeq(origin_context, intervals: Sequence[FreqReprT] | None = None)¶
IntervalSeq is the abstract base class for all interval sequence types. Interval sequences can be understood as “abstract scales” (for example the minor scale as such, instead of C minor). Interval sequences have multiple applications from templating to structure discovery.
In line with its Sequence superclass interval sequences implement iteration, the ‘in’ operator, the == operator, item retrieval with [], concatenation with +, repeated self-concatenation with *, searching with index, and len().
Like scale types interval sequences also allow partitioning with partial, partial_not and partition.
- Parameters:
origin_context – An origin context (like a tuning or a notation)
intervals – A sequence of intervals from the origin context
- property cents: List[float]¶
An ordered list of cent values representing the sequence
- property frequency_ratios¶
An ordered list of frequency ratios present in this sequence
- index(interval, start=0, end=None, /) int¶
Return first index of interval (similar to the index method of python’s list)
- Parameters:
interval – The interval to search for
start – If set method ignores occurences before given index (optional, defaults to 0)
end – If set method ignores occurences after given index (optional, defaults to end of sequence)
- Raises:
ValueError – If interval was not found in sequence
- property origin_context¶
The origin context from which this interval sequence was built
- partial(mask_expr: int | Tuple[int | EllipsisType, ...]) Self¶
Returns a new sequence consisting of a selection of indices of this sequence. The selection is defined by an index mask expression.
An index mask can be defined as a tuple of consecutive indices, e.g. (1, 2, 5) gives a sequence including the second, third and sixth interval of this one.
An ellipsis between two indices indicates that all indices between them should be selected as well, e.g. (1, …, 5, 9) is equivalent to (1, 2, 3, 4, 5, 9).
If a mask begins with an ellipsis all indices from 0 to the next index are added to the selection, e.g. (…, 3, 5) is equivalent to (0, 1, 2, 3, 5).
A mask without a last index is called right-open and will select all indices from the last index to the end of the sequence, for example (2, …) will select all intervals of the sequence except the first two.
If only one interval should be selected a simple integer can be used
- Parameters:
mask_expr – An index mask expression which defines the selection of indices from this sequence.
- partial_not(mask_expr: int | Tuple[int | EllipsisType, ...]) Self¶
Returns a new sequence consisting of a selection of indices of this sequence. The selection will be determined by an index mask and will hold all intervals whose index is NOT covered by the mask.
An index mask can be defined as a tuple of consecutive indices, e.g. (1, 2, 5) gives a sequence including the second, third and sixth interval of this one.
An ellipsis between two indices indicates that all indices between them should be selected as well, e.g. (1, …, 5, 9) is equivalent to (1, 2, 3, 4, 5, 9).
If a mask begins with an ellipsis all indices from 0 to the next index are added to the selection, e.g. (…, 3, 5) is equivalent to (0, 1, 2, 3, 5).
A mask without a last index is called right-open and will select all indices from the last index to the end of the sequence, for example (2, …) will select all intervals of the sequence except the first two.
If only one interval should be selected a simple integer can be used
- Parameters:
mask_expr – An index mask expression which defines the selection of indices from this sequence.
- partition(mask_expr: int | Tuple[int | EllipsisType, ...]) Tuple[Self, Self]¶
Partitions the sequence into two parts using an index mask. The function will return a tuple of two sequences with the first sequence including all indices that are covered by the index mask and the second one including all indices that are not.
An index mask can be defined as a tuple of consecutive indices, e.g. (1, 2, 5) defines a sequence including the second, third and sixth interval of this one.
An ellipsis between two indices indicates that all indices between them should be selected as well, e.g. (1, …, 5, 9) is equivalent to (1, 2, 3, 4, 5, 9).
If a mask begins with an ellipsis all indices from 0 to the next index are added to the selection, e.g. (…, 3, 5) is equivalent to (0, 1, 2, 3, 5).
A mask without a last index is called right-open and will select all indices from the last index to the end of the sequence, for example (2, …) will select all intervals of the sequence except the first two.
If only one interval should be selected a simple integer can be used
- Parameters:
mask_expr – An index mask expression which defines the selection of indices from this sequence.
- property pitch_diffs: List[int]¶
An ordered list of pitch differences representing the sequence
- to_scale(start: FreqRepr) Scale¶
Returns a scale that has the interval structure of this sequence, starting with the given note/pitch
- Parameters:
start – A starting note/pitch of the same origin context
- with_interval(interval: FreqReprT, insert_pos: int | None = None) Self¶
Returns a new interval sequence containing all intervals from this sequence and the additional one given as a parameter. By default new intervals appear at the end of the sequence.
- Parameters:
interval – The new interval to be added to the result
insert_pos – The insertion position of the new interval. 0 will insert the interval at the front, 1 will insert the interval at the second position, etc. (optional, default is None which results in the value len(sequence) + 1)
- Raises:
IncompatibleOriginContexts – If interval has a different origin context than this sequence
Tuning¶
A tuning is the middle piece between the continuous world of frequencies and the discrete world of pitch.
In this module, you will find a collection of tuning classes, each with a certain set of assumptions built into them. Some tuning classes can be used as they are to create tuning objects, some are abstract classes that need a couple of methods implemented by a subclass.
- class xenharmlib.core.tunings.EDOTuning(divisions, pitch_cls: type[~xenharmlib.core.pitch.EDOPitch] = <class 'xenharmlib.core.pitch.EDOPitch'>, pitch_interval_cls: type[~xenharmlib.core.pitch.EDOPitchInterval] = <class 'xenharmlib.core.pitch.EDOPitchInterval'>, pitch_scale_cls: type[~xenharmlib.core.pitch_scale.EDOPitchScale] = <class 'xenharmlib.core.pitch_scale.EDOPitchScale'>, pitch_interval_seq_cls: type[~xenharmlib.core.pitch_interval_seq.EDOPitchIntervalSeq] = <class 'xenharmlib.core.pitch_interval_seq.EDOPitchIntervalSeq'>, ref_frequency: ~xenharmlib.core.frequencies.Frequency = Frequency(<Mock name='mock.Rational()' id='139200634434576'>))¶
EDOTuning (“equal division of the octave tuning”) divides an octave into pitches equally spaced from each other.
- Parameters:
divisions – The number of divisions of the octave
pitch_cls – (Optional) The python class for the pitch that is used to generate a pitch object in the pitch method. (Not to be confused with the ‘pitch class’ of pitches in periodic tunings). Defaults to
EDOPitchpitch_interval_cls – (Optional) The python class for the pitch interval that is used to generate a pitch interval object in the pitch interval method. Defaults to
EDOPitchIntervalpitch_scale_cls – (Optional) The python class for the pitch scale that is used to generate a pitch scale object in the pitch scale method. Defaults to
EDOPitchScaleref_frequency – (Optional) A reference frequency on which this tuning is built. For EDOTunings this is the lowest pitch (pitch index 0). Defaults to the frequency for C0 in EDO tunings for A4 = 440Hz (about 16.35 Hz)
- property best_fifth¶
Returns the pitch that best approximates the pure fifth (frequency ratio 3/2) in this tuning.
- property fifth¶
Returns the pitch that represents the fifth of this tuning. In the default implementation, this is the best fifth, however, subclasses can also overwrite this behavior, so e.g. the second-best fifth is returned.
- get_ring_number(pitch: EDOPitch | None = None) int¶
Returns the greatest common divisor of a pitch and the period length of the tuning.
- Parameters:
pitch – A pitch of this tuning. (Optional, defaults to the pitch that best approximates the perfect fifth)
- property name: str¶
The name of this tuning
- property sharpness: int¶
Sharpness is an indicator of the pitch difference in EDO tunings between a natural and their sharp version (for example the steps needed to reach C# from C)
The sharpness of an EDO is defined by 7 times the pitch difference between the base pitch and the perfect fifth approximation minus 4 times the pitch difference in an octave.
- class xenharmlib.core.tunings.EDTuning(divisions, eq_ratio: ~xenharmlib.core.frequencies.FrequencyRatio, pitch_cls: type[~xenharmlib.core.pitch.EDPitch] = <class 'xenharmlib.core.pitch.EDPitch'>, pitch_interval_cls: type[~xenharmlib.core.pitch.EDPitchInterval] = <class 'xenharmlib.core.pitch.EDPitchInterval'>, pitch_scale_cls: type[~xenharmlib.core.pitch_scale.EDPitchScale] = <class 'xenharmlib.core.pitch_scale.EDPitchScale'>, pitch_interval_seq_cls: type[~xenharmlib.core.pitch_interval_seq.EDPitchIntervalSeq] = <class 'xenharmlib.core.pitch_interval_seq.EDPitchIntervalSeq'>, ref_frequency: ~xenharmlib.core.frequencies.Frequency = Frequency(<Mock name='mock.Rational()' id='139200634434576'>))¶
EDTuning (“equal division tuning”) takes a base interval given as a frequency ratio and divides this base interval into pitches equally spaced from one another.
For example, the Bohlen-Pierce tuning can be created like this:
>>> from xenharmlib import EDTuning >>> from xenharmlib import FrequencyRatio >>> BP = EDTuning( ... divisions=13, ... eq_ratio=FrequencyRatio(3) ... )
- Parameters:
divisions – The number of divisions of the base interval
eq_ratio – The frequency factor defining the base interval (e.g. 2 for an octave, 3/2 for a fifth)
pitch_cls – (Optional) The python class for the pitch that is used to generate a pitch object in the pitch method. (Not to be confused with the ‘pitch class’ of pitches in periodic tunings). Defaults to
EDPitchpitch_interval_cls – (Optional) The python class for the pitch interval that is used to generate a pitch interval object in the pitch interval method. Defaults to
EDPitchIntervalpitch_scale_cls – (Optional) The python class for the pitch scale that is used to generate a pitch scale object in the pitch scale method. Defaults to
EDPitchScaleref_frequency – (Optional) A reference frequency on which this tuning is built. For EDTunings this is the lowest pitch (pitch index 0). Defaults to the frequency for C0 in EDO tunings for A4 = 440Hz (about 16.35 Hz)
- get_frequency(pitch: EDPitch) Frequency¶
Returns the frequency of a given note
- Parameters:
note – A note from this tuning
- Raises:
IncompatibleOriginContexts – If note is from a different tuning
- get_frequency_for_index(pitch_index: int) Frequency¶
Returns the frequency for a given pitch index
- Parameters:
pitch_index – A pitch index
- property name: str¶
The name of this tuning
- class xenharmlib.core.tunings.PeriodicTuning(period_length: int, eq_ratio: FrequencyRatio, pitch_cls: type[PeriodicPitchT], pitch_interval_cls: type[PeriodicIntervalT], pitch_scale_cls: type[PeriodicScaleT], pitch_interval_seq_cls: type[PeriodicIntervalSeqT], ref_frequency: Frequency)¶
This abstract class makes the assumption that the tuning has a period (a fixed distance between two pitches that declares the two pitches as ‘equivalent’). This can be the octave in EDO tunings or a tritave in ED3 tunings.
Periodic tunings implement the len() function that returns the period length:
>>> from xenharmlib import EDOTuning >>> edo12 = EDOTuning(12) >>> len(edo12) 12
The constructor arguments are:
- Parameters:
period_length – The number of pitches that constitute a period (for example 12 in 12EDO)
eq_ratio – A frequency ratio that defines the equivalency interval
pitch_cls – The python class for the pitch that is used to generate a pitch object in the pitch method. (Not to be confused with the ‘pitch class’ of pitches in periodic tunings)
pitch_interval_cls – The python class for the pitch interval that is used to generate a pitch interval object in the pitch interval method.
pitch_scale_cls – The python class for the pitch scale that is used to generate a pitch scale object in the pitch scale method.
ref_frequency – A reference frequency on which this tuning is build.
- property eq_ratio: FrequencyRatio¶
The frequency ratio defining the equivalency interval
- property generator_pitches: List[PeriodicPitchT]¶
Returns a list of pitch objects that can be used to generate the complete set of pitches in this tuning by subsequent interval additions with themselves.
A typical generator pitch in 12-EDO for example is the pitch with index 7 which generates the circle of fifths.
- get_ring_number(pitch: PeriodicPitchT) int¶
Returns the greatest common divisor of a pitch and the period length of the tuning.
- Parameters:
pitch – A pitch of this tuning.
- pc_scale(pc_indices: List[int] | None = None, root_bi_index: int = 0) ScaleT¶
Constructs a pitch scale from a list of pitch class indices. The pitch class indices are assumed to be in the order they appear in the scale meaning that e.g. in 12-EDO the provided argument [7, 3, 4] will result in a scale with pitch indices [7, 15, 16]. The base interval of the first provided pc index will always assumed to be 0.
- Raises:
InvalidPitchClassIndex – If one of the indices in the list is not a valid pitch class index in this tuning
- Parameters:
pc_indices – A list of pitch class indices.
root_bi_index – Base interval index of the root (optional, defaults to 0)
- class xenharmlib.core.tunings.TuningABC(pitch_cls: type[PitchT], pitch_interval_cls: type[IntervalT], pitch_scale_cls: type[ScaleT], pitch_interval_seq_cls: type[IntervalSeqT], ref_frequency: Frequency)¶
The most abstract tuning class and the base class for all other tunings. AbstractTuning makes next to no assumptions about the tuning, only that it has a reference frequency to ‘center’ the tuning and python classes that define the type of pitch, pitch interval, and pitch scale adjacent to this tuning.
A simple tuning can be derived from this simply by overwriting the method
get_frequency()and setting appropriate constructor arguments.The constructor arguments are:
- Parameters:
pitch_cls – The python class for the pitch that is used to generate a pitch object in the
pitch()method. (Not to be confused with the ‘pitch class’ of pitches in periodic tunings)pitch_interval_cls – The python class for the pitch interval that is used to generate a pitch interval object in the
pitch_interval()method.pitch_scale_cls – The python class for the pitch scale that is used to generate a pitch scale object in the
pitch_scale()method.ref_frequency – A reference frequency on which this tuning is built.
- get_approx_pitch(frequency: Frequency) PitchT¶
Returns the closest pitch in the tuning to a given frequency.
- Parameters:
frequency – The frequency in Hz
- abstractmethod get_frequency(pitch: PitchT) Frequency¶
(Must be overwritten by subclasses) Returns the frequency for a given pitch
- abstractmethod get_frequency_for_index(pitch_index: int) Frequency¶
(Must be overwritten by subclasses) Returns the frequency for a given pitch index
- index_scale(pitch_indices: List[int] | None = None) ScaleT¶
Constructs a pitch scale from a list of pitch indices. According to the definition of a scale indices occuring multiple times will only be considered once. The list of indices will also be sorted automatically.
- Parameters:
pitch_indices – A list of pitch indices
- pitch(pitch_index: int) PitchT¶
Returns a pitch having the pitch type this tuning was configured with
- Parameters:
pitch_index – An integer denoting the number of steps from the zero pitch.
- pitch_interval(pitch_a: PitchT, pitch_b: PitchT) IntervalT¶
Deprecated since version 0.2.0: Use
interval()instead.Returns a pitch interval having the pitch intervals type this tuning was configured with
- Parameters:
pitch_a – The starting pitch
pitch_b – The target pitch
- pitch_range(start, stop=None, step=1)¶
Returns a generator for continuous pitches of this tuning similar to pythons range function. The method can be called in the familiar ways:
>>> from xenharmlib import EDOTuning >>> edo12 = EDOTuning(12)
>>> for pitch in edo12.pitch_range(3): ... print(pitch) EDOPitch(0, 12-EDO) EDOPitch(1, 12-EDO) EDOPitch(2, 12-EDO)
>>> for pitch in edo12.pitch_range(5, 10): ... print(pitch) EDOPitch(5, 12-EDO) EDOPitch(6, 12-EDO) EDOPitch(7, 12-EDO) EDOPitch(8, 12-EDO) EDOPitch(9, 12-EDO)
>>> for pitch in edo12.pitch_range(5, 10, 2): ... print(pitch) EDOPitch(5, 12-EDO) EDOPitch(7, 12-EDO) EDOPitch(9, 12-EDO)
- pitch_scale(pitches: List[PitchT] | None = None) ScaleT¶
Deprecated since version 0.2.0: Use
scale()instead.Returns a pitch scale having the pitch scale type this tuning was configured with
- Parameters:
pitches – A list of pitches
- property zero_element: PitchT¶
The zero element is a reference point, in one-dimensional tunings it is the element with index 0, in western notation typically C-0, etc
Pitch and PitchInterval¶
- class xenharmlib.core.pitch.EDOPitch(tuning, frequency, pitch_index: int)¶
The pitch type for ‘equal division of the octave’ tunings
- Parameters:
tuning – The tuning to which this pitch belongs
frequency – The frequency this pitch represents
pitch_index – An integer denoting the pitch (with 0 being the first pitch, 1 being the second, etc)
- class xenharmlib.core.pitch.EDOPitchInterval(tuning, frequency_ratio: FrequencyRatio, pitch_diff: int, ref_pitch: PitchT)¶
Pitch intervals class for ‘equal division of the octave’ pitches
- class xenharmlib.core.pitch.EDPitch(tuning, frequency, pitch_index: int)¶
The pitch type for equal division tunings
- Parameters:
tuning – The tuning to which this pitch belongs
frequency – The frequency this pitch represents
pitch_index – An integer denoting the pitch (with 0 being the first pitch, 1 being the second, etc)
- class xenharmlib.core.pitch.EDPitchInterval(tuning, frequency_ratio: FrequencyRatio, pitch_diff: int, ref_pitch: PitchT)¶
Pitch interval class for equal division tunings
- class xenharmlib.core.pitch.PeriodicPitch(tuning, frequency, pitch_index: int)¶
The pitch type for periodic tunings. Depending on the period length it will classify the pitch into a ‘pitch class index’ (
pc_indexattribute) and a ‘base interval index’ (bi_index)- Parameters:
tuning – The tuning to which this pitch belongs
frequency – The frequency this pitch represents
pitch_index – An integer denoting the pitch (with 0 being the first pitch, 1 being the second, etc)
- property bi_index¶
The base interval index of this pitch
- get_generator_index(generator_pitch: Self)¶
Calculates the number of steps needed to reach this pitch when iteratively adding the given generator to the zero pitch of this tuning
- Parameters:
generator_pitch – A generator pitch. Will be normalized to the equivalent pitch in the first base interval if its pitch index exceeds the period length of the tuning.
- Raises:
IncompatibleOriginContexts – If pitches come from different tuning systems
InvalidGenerator – If the given generator pitch is not in fact a generator in the tuning of this pitch
- is_equivalent(other: PeriodicPitchLike) bool¶
Returns True if this pitch has the same frequency as the other object when normalized to the first base interval
- Parameters:
other – Another periodic pitch or note
- property pc_index¶
The pitch class index of this pitch
- pcs_normalized() Self¶
Returns the equivalent of this pitch in the first base interval
- property pitch_index: int¶
The index of this pitch as an integer
- transpose_bi_index(bi_diff: int) Self¶
Returns a pitch with the same pitch class index but a transposed base interval
- Parameters:
bi_diff – The difference in base interval between this pitch and the resulting one
- class xenharmlib.core.pitch.PeriodicPitchInterval(tuning, frequency_ratio: FrequencyRatio, pitch_diff: int, ref_pitch: PitchT)¶
The pitch interval class for periodic tunings.
- get_generator_distance(generator_pitch: PeriodicPitchT) int¶
Calculates the minimum number of steps needed to reach one pitch from the other when iteratively adding a generator pitch.
A typical application in 12EDO is to calculate the minimum distance of the two pitches on the circle of fifths, hence the generator distance can be a good measure for consonance of an interval given the right generator pitch.
>>> from xenharmlib import EDOTuning >>> edo12 = EDOTuning(12) >>> M3 = edo12.pitch(0).interval(edo12.pitch(4)) >>> M3.get_generator_distance(edo12.pitch(7)) 4
- Parameters:
generator_pitch – A generator pitch. Will be normalized to the equivalent pitch in the first base interval if its pitch index exceeds the period length of the tuning.
- Raises:
InvalidGenerator – If the pitch is not a generator in the tuning attached to the interval
- class xenharmlib.core.pitch.Pitch(tuning, frequency, pitch_index: int)¶
In its most basic form, a Pitch is a tuple of a pitch index (an integer value) and a tuning that interprets this index as a frequency.
Pitch creates a total ordering on all pitches according to their frequency. This means you can sort pitches in lists (e.g. from lowest frequency to highest frequency). You can also compare pitches, even across different tunings:
>>> from xenharmlib import EDOTuning >>> edo12 = EDOTuning(12) >>> edo31 = EDOTuning(31) >>> edo31.pitch(1) < edo12.pitch(1) True >>> edo31.pitch(31) == edo12.pitch(12) True
- Parameters:
tuning – The tuning to which this pitch belongs
frequency – The frequency this pitch represents
pitch_index – An integer denoting the pitch (with 0 being the first pitch, 1 being the second, etc)
- property short_repr: str¶
(Must be implemented by subclasses) A shortened representation of this note (to be used in collection objects like scales)
- transpose(diff: int | PitchInterval) Pitch¶
Transposes the pitch to a different one
- Parameters:
diff – The difference from this pitch. Can be either an integer (positive for upward movement, negative for downward movement) or a pitch interval
- property tuning¶
The origin tuning of this pitch
- class xenharmlib.core.pitch.PitchInterval(tuning, frequency_ratio: FrequencyRatio, pitch_diff: int, ref_pitch: PitchT)¶
The most abstract form of an interval of two pitches. Implements conversion functions to frequency ratios and a total ordering based on the calculated ratios:
>>> from xenharmlib import EDOTuning >>> edo31 = EDOTuning(31) >>> pitch_a = edo31.pitch(4) >>> pitch_b = edo31.pitch(8) >>> pitch_c = edo31.pitch(10) >>> i_ab = pitch_a.interval(pitch_b) >>> i_ac = pitch_a.interval(pitch_c) >>> i_ab < i_ac True
A caveat: Intervals are considered directional in xenharmlib so the order of pitches from which the interval is created is important
- Parameters:
tuning – The tuning associated with this interval
frequency_ratio – The frequency ratio of this interval
pitch_diff – An integer that defines the number of steps this interval encompasses (a positive integer means ‘upward steps’, while a negative one means ‘downward steps’)
ref_pitch – A reference pitch for the pitch difference. This is necessary for tunings that are not equal step. In just intonation tunings frequency ratios may vary depending on the original pitches used to construct the interval, even if their pitch index difference is the same
- classmethod from_pitches(pitch_a: PitchT, pitch_b: PitchT) Self¶
Deprecated since version 0.2.0: Use
from_source_and_target()instead.Constructs an interval out of two pitches of the same tuning. If the second pitch is lower than the first pitch the Interval will have a negative pitch difference
- Raises:
IncompatibleOriginContexts – If pitches come from different tuning systems
- Parameters:
pitch_a – The first (or reference) pitch
pitch_b – The second (or target) pitch
- classmethod from_source_and_target(source: PitchT, target: PitchT) Self¶
Constructs an interval out of two pitches of the same tuning. If the second pitch is lower than the first pitch the Interval will have a negative pitch difference
- Raises:
IncompatibleOriginContexts – If pitches come from different tuning systems
- Parameters:
source – The starting point of the interval
target – The end point of the interval
- property short_repr: str¶
A short string representation of the interval (must be implemented by subclass)
PitchScale¶
A pitch scale is an ordered set of unique pitches in a given tuning. The uniqueness property means that there are no duplicate pitches. However other than in the popular use of the word ‘scale’ the pitch scale object in xenharmlib is not limited to one base interval in periodic tunings. (e.g. C-0 and C-1 are considered distinct) This has a couple of advantages, e.g. that the scale object can be used more generally.
Pitch scales have both a list and a set quality to them. Similar to lists they have an item order, support iteration, positional item retrieval, and slicing. At the same time scales support set operations like intersection, union, symmetric difference, etc.
- class xenharmlib.core.pitch_scale.EDOPitchScale(tuning, pitches: List[PitchT] | None = None)¶
Pitch scale class for ‘equal division of the octave’ tunings
- class xenharmlib.core.pitch_scale.EDPitchScale(tuning, pitches: List[PitchT] | None = None)¶
Pitch scale class for equal division tunings
- class xenharmlib.core.pitch_scale.PeriodicPitchScale(tuning, pitches: List[PitchT] | None = None)¶
Pitch scale class for periodic tunings. Implements operations like rotation and customized set operations (for when you want to treat equivalent pitches the same as equal pitches). It also implements normalization methods.
- property pc_indices: List[int]¶
Returns a list of pitch class indices in the order they appear in this scale. This can include duplicate items if the list has two pitches of the same pitch class
- pcs_complement() Self¶
Normalizes this scale to the first base interval and returns the complement (that is: a scale of all pitches NOT in this scale) as a normalized scale
- class xenharmlib.core.pitch_scale.PitchScale(tuning, pitches: List[PitchT] | None = None)¶
The base class of all pitch scales. Implements list and set operations, transposition, retuning, etc.
PitchScale (or, respectively, its subclasses) are built by the tunings pitch_scale builder method:
>>> from xenharmlib import EDOTuning >>> edo31 = EDOTuning(31) >>> scale = edo31.scale( ... [edo31.pitch(4), edo31.pitch(6), edo31.pitch(9)] ... )
Every pitch will be automatically sorted in its place. The order of the scale is ascending (First lower pitch, then higher pitch)
PitchScale objects support most of the typical list operations:
>>> for pitch in scale: ... print(pitch) EDOPitch(4, 31-EDO) EDOPitch(6, 31-EDO) EDOPitch(9, 31-EDO)
>>> scale[1] EDOPitch(6, 31-EDO)
>>> scale[1:-1] EDOPitchScale([6], 31-EDO)
The ‘in’ operator accepts both pitches and pitch intervals
>>> p = edo31.pitch(4) >>> p in scale True >>> p.interval(edo31.pitch(2)) in scale True
In regards to intervals, it even works across tunings
>>> edo12 = EDOTuning(12) >>> edo24 = EDOTuning(24) >>> edo12_fifth = edo12.pitch(0).interval(edo12.pitch(7)) >>> edo24_scale = edo24.scale(edo24.pitch_range(24)) >>> edo12_fifth in edo24_scale True
In addition similar operations to the native python sets are available (with slightly different naming and additional method arguments):
union
intersection
difference
symmetric_difference
is_disjoint
is_subset
is_superset
- add_pitch(pitch: PitchT)¶
Deprecated since version 0.2.0: objects in xenharmlib are supposed to be immutable
Inserts a new pitch into the scale at the right position
- Raises:
IncompatibleOriginContexts – If the pitch has a different tuning than this scale.
- Parameters:
pitch – The new pitch
- add_pitch_index(pitch_index: int)¶
Deprecated since version 0.2.0: objects in xenharmlib are supposed to be immutable
Inserts a new pitch into the scale denoted by its pitch index
- Parameters:
pitch_index – Index of the pitch
- classmethod from_pitch_indices(pitch_indices: List[int], tuning) Self¶
Creates a scale from a list of pitch indices
- Parameters:
pitch_indices – A list of pitch indices in any order.
tuning – The tuning through which these indices should be interpreted
- property is_zero_normalized: bool¶
Returns True if this function is zero normalized, meaning that the first element of the scale is identical to the pitch with index 0
- property pitch_indices: List[int]¶
A list of the ordered pitch indices present in this scale
- retune(tuning) PitchScale¶
Returns a scale retuned into a different tuning by approximating every pitch in the scale with a pitch from the target tuning.
A caveat: Since pitch scales are a structure of sorted unique pitches this method may produce a scale with a smaller size than the original because two pitches in this tuning can be approximated to the same pitch in the target tuning.
- Parameters:
tuning – The target tuning
- to_pitch_intervals() List[Interval[PitchT]]¶
Deprecated since version 0.2.0: Use
to_intervals()instead.Returns this scale represented as a list of pitch intervals
- transpose(diff: int | PitchInterval[PitchT]) Self¶
Transposes the scale upwards or downwards
- Parameters:
diff – The difference from this pitch. Can be either an integer (positive for upward movement, negative for downward movement) or a pitch interval
Notation¶
The notation core module includes primitives to build notation systems. A notation in xenharmlib is defined as a wrapper around a specific tuning that provides a human-friendly string interface to all the lower-level objects (pitch, pitch interval, pitch scale)
- exception xenharmlib.core.notation.IncompleteNotation¶
Gets raised when a notation is not initialized correctly
- class xenharmlib.core.notation.NatAccNotation(tuning, note_cls: type[~xenharmlib.core.notes.NatAccNote] = <class 'xenharmlib.core.notes.NatAccNote'>, note_interval_cls: type[~xenharmlib.core.notes.NatAccNoteInterval] = <class 'xenharmlib.core.notes.NatAccNoteInterval'>, note_scale_cls: type[~xenharmlib.core.note_scale.NatAccNoteScale] = <class 'xenharmlib.core.note_scale.NatAccNoteScale'>, note_interval_seq_cls: type[~xenharmlib.core.note_interval_seq.NatAccNoteIntervalSeq] = <class 'xenharmlib.core.note_interval_seq.NatAccNoteIntervalSeq'>)¶
NatAccNotation is a notation for periodic tunings that select a subset of pitches called naturals to form a basic symbol set (typically letters) and adds special symbols called accidentals, which signify step deviations from the natural pitch classes.
The standard Western notation for example is a such a notation, defining 7 naturals (C, D, E, G, A, B) and 2 accidentals (#, b) that signify a step deviation of +1 and -1 respectively.
The class supports different ‘categories’ of accidentals that do not interact with one another, for example, a category for sharps/flats and one category for ups/downs. Consequently, accidental values are given in the form of a vector.
It assumes that intervals are uniquely defined by their difference in natural index + the difference of the accidental vectors of their source notes. It further assumes that intervals are notated as a tuple (symbol, number). The class implements the 1-based ordinal notation for numbers by default (e.g. the number 1 for a unison, the number 2 for a second, etc), however this behavior get be changed by subclassing and overwriting the method
nat_diff_to_interval_number()and its counterpartinterval_number_to_nat_diff()- Parameters:
tuning – The tuning this notation refers to
note_cls – Note class used in the
note()builder method (optional, defaults to the class NatAccNote)note_interval_cls – Note interval class used in the
note_interval()builder method (optional, defaults to the class NatAccNoteInterval)note_scale_cls – Note scale class used in the
note_scale()builder method (optional, defaults to the class NatAccNoteScale)
- property acc_symbol_code: SymbolCode¶
The symbol code for the accidentals. Must be set by the subclass constructor
- append_natural(natc_symbol: str, natc_pitch_index: int)¶
Appends a new natural to this notation. The order in which naturals are added determines their natural class index, so the first added natural will get natural class index 0, the second 1, and so forth.
- Raises:
AmbiguousSymbol – If the given natural symbol already denotes a previously appended natural index
- Parameters:
natc_symbol – A string denoting the natural (typically a single letter)
natc_pitch_index – The pitch index of the natural class that is added. For most tunings, this pitch index is equal to the pitch class index because for most tunings there exists no note tuple (natc_symbol, 0) that is not in the first base interval. However, there are outliers like 5-EDO in which (B, 0) = (C, 1) and (B, 0) has a pitch index in the second base interval
- balance_interval_acc(nat_diff: int, unbalanced_nat_pitch_diff: int, unbalanced_acc_vector: Tuple[int])¶
Returns a modified accidental vector that balances the deviation of a pitch diff from the natural pitch diff as defined in this notation. By default, deviations get balanced by adding / subtracting the deviation from the first dimension of the accidental vector.
- Parameters:
nat_diff – a natural index difference that determines the desired pitch difference in accordance with the mapping of natural differences to pitch differences in this notation
unbalanced_nat_pitch_diff – A pitch difference for the natural index that (possibly) deviates from the pitch difference as defined for nat_diff in this notation
unbalanced_acc_vector – An accidental vector that is (possibly) unbalanced because the given pitch difference of the natural difference does not match the pitch difference as defined in this notation
- balance_note_acc_vector(nat_index: int, unbalanced_nat_pitch_index: int, unbalanced_acc_vector: Tuple[int])¶
Returns a modified accidental vector that balances the deviation of a pitch index from the natural pitch index as defined in this notation. By default, deviations get balanced by adding / subtracting the deviation from the first dimension of the accidental vector.
- Parameters:
nat_index – a natural index that determines the desired pitch index in accordance with the mapping of natural indices to pitch indices in this notation
unbalanced_nat_pitch_index – A pitch index for the natural index that (possibly) deviates from the pitch index as defined for nat_index in this notation
unbalanced_acc_vector – An accidental vector that is (possibly) unbalanced because the given pitch index of the natural index does not match the pitch index as defined in this notation
- gen_pc_symbol(natc_index: int, acc_vector: Tuple[int, ...]) Tuple[str, str, str]¶
Creates a pitch class symbol from a natural class index and an accidental vector. This defaults to calculating the first natural symbol found for natc_index and concatenating it with the minimal accidental symbol configuration for the vector.
- The method will return a tuple of 3 with the following semantics:
The first element will be the pitch class symbol
The second element will be the natural class symbol
The third element will be the accidental symbol string
(Subclasses can overwrite this method if they e.g wish to generate pc_symbols that have post-fix or in-fix naturals)
- Parameters:
natc_index – A natural class index of a note
acc_vector – An accidental value vector
- get_acc_symbol(acc_vector: Tuple[int, ...]) str¶
Returns a symbol string for an accidental vector, like (1, 0) -> ‘#’ or (-1, 1) -> ‘^b’
- Raises:
InvalidAccidentalValue – If the accidental symbol code of this notation does not have a symbol or symbol combination that maps to this value
- Parameters:
acc_vector – An integer vector denoting the step deviation from the natural pitch class
- get_interval_symbol(nat_diff: int, acc_vector: Tuple[int]) str¶
Returns the interval symbol for a natural/accidental note interval. Interval symbols depend on the natural index difference class of the two notes (e.g. if the interval is a unison, a third, a fifth, etc) and the deviation from the standard pitch difference of a natural difference (In 12-EDO this standard pitch difference would e.g. be 7 for a fifth, 4 for a third, etc)
- Raises:
IncompleteNotation – If no symbol code was registered for the given parameters
- Parameters:
nat_diff – The difference in natural indices
acc_vector – The accidental vector of the interval
- get_natc_symbol(nat_index: int) str¶
Returns a string symbol for a natural index like 0 -> ‘C’ or 8 -> ‘D’ in 12-EDO
- Raises:
InvalidNaturalIndex – If the natural index is smaller than 0
- Parameters:
nat_index – A natural index of this notation
- interval_number_to_nat_diff(interval_number: int) int¶
Returns a natural index difference for an interval number. By default, it assumes that the interval number is given in 1-based ordinal notation. Subclasses can change this behavior by overwriting this method.
- Parameters:
interval_number – An interval number
- is_natural(pitch_index: int) bool¶
Returns True if the given pitch index refers to a natural in this notation, False otherwise
- Parameters:
pitch_index – The pitch index to consider
- property nat_count: int¶
Returns the number of registered natural symbols for this notation (typically 7 for Western-style notations)
- nat_diff_to_interval_number(nat_diff: int) int¶
Returns an interval number for a natural index difference. By default, it returns a 1-based ordinal number. Subclasses can change this behavior by overwriting this method.
- Parameters:
nat_diff – The natural index difference that characterizes the interval
- nat_index_to_pc_index(nat_index: int) int¶
Returns the pitch class index a natural index refers to
- Parameters:
nat_index – A natural index
- nat_index_to_pitch_index(nat_index: int) int¶
Returns the pitch index a natural index refers to (e.g. in 12-EDO: 0 -> 0, 1 -> 2, 3 -> 4, 4 -> 5)
- Parameters:
nat_index – A natural index
- property natc_pc_indices: List[int]¶
A sorted list of natural class pitch class indices that are present in this notation
- property natc_pitch_indices: List[int]¶
A sorted list of natural class pitch indices that are present in this notation
- natural_scale(bi_index: int = 0) NatAccNoteScale¶
Creates a scale with all the naturals in this notation in a specific base interval (in Western notations this is typically the C major scale)
- Parameters:
bi_index – (optional, defaults to 0). The index of the base interval the notes should reside in
- note(pc_symbol: str, nat_bi_index: int) NatAccNote¶
Creates a note in line with this notation
- Parameters:
pc_symbol – A symbol denoting the pitch class (typically something like ‘C#’, ‘Ab’, ‘F’, etc)
nat_bi_index – The base interval index of the natural (for example a B#-0 in 12-EDO has the natural base interval index of 0, even though the pitch is in base interval 1)
- note_by_numdef(nat_index: int, acc_vector: Tuple[int, ...]) NatAccNote¶
Creates a natural/accidental note by its numerical definition. Autogenerates appropriate symbols
- Parameters:
nat_index – The natural index of the note
acc_vector – The accidental vector of the note
- note_interval(note_a: NatAccNote, note_b: NatAccNote) NatAccNoteInterval¶
Deprecated since version 0.2.0: Use
interval()instead.Creates a note interval between two notes created by this notation
- Raises:
IncompatibleOriginContexts – If one of the notes has a different notation than this one
- Parameters:
note_a – The source note
note_b – The target note
- note_scale(notes: List[NatAccNote] | None = None) NatAccNoteScale¶
Deprecated since version 0.2.0: Use
scale()instead.Creates a note scale from a list of notes
- Raises:
IncompatibleOriginContexts – If one of the notes has a different notation than this one
- Parameters:
notes – A list of notes created by this notation
- parse_pc_symbol(pc_symbol: str) Tuple[str, str, int, Tuple[int, ...]]¶
Parses a pitch class symbol into its natural class symbol part and its accidental symbol part. Returns a 4-tuple (natc_symbol, acc_symbol, natc_index, acc_vector) with the parsing result.
- pc_scale(pc_symbols: List[str] | None = None, root_nat_bi_index: int = 0) NatAccNoteScale¶
Constructs a note scale from a list of pitch class symbols. The pitch class symbols are assumed to be in the order they appear in the scale meaning that e.g. in 12-EDO the provided argument [‘G’, ‘D’, ‘E’] will result in a scale with notes G0, D1, E1. The base interval of the natural of the first provided pc symbol will always assumed to be 0.
- Raises:
UnknownNoteSymbol – If one of the pc symbols is not valid in the definition of this notation
- Parameters:
pc_symbols – A list of pitch class symbols.
root_nat_bi_index – (optional, defaults to 0) The base interval index of the natural of the root (for example a B#-2 in 12-EDO has the natural base interval index of 2, even though the pitch is in base interval 3).
- set_interval_symbol_code(nat_diffc: int, symbol_code: SymbolCode)¶
Sets an interval class symbol for a natural index difference class. The natural index difference class is a number between 0 and the number of naturals in the notation (exclusive), so e.g. [0, …, 6] in a traditional Western system that has 7 naturals. It is calculated by taking the absolute distance of two natural indices modulo the number of naturals in the notation, so e.g. 2 for intervals (C0, E#0), (C0, E1) and (E#2, C0).
The natural index difference class is closely related to the Roman numeral index of intervals, for example, a difference of 2 is the same as III, a difference of 0 is the same as I, etc.
Associating a natural index difference class with a specific symbol code allows setting different interval naming schemes for different interval numbers, e.g. making a difference between perfect and imperfect interval naming schemes. In the Western system differences 0 (unison), 3 (fourth) and 4 (fifth) use the P/A/d interval symbols while for differences 1 (second), 2 (third), 5 (sixth), 6 (sevenths) the system M/m/A/d is used.
- Raises:
InvalidNaturalDiffClassIndex – If the natural diff class index is out of bounds
- Parameters:
nat_diffc – The difference of the natural indices forming the interval modulo the naturals count
symbol_code – A symbol code defining how the center and the deviations from it should be represented as strings.
- shorthand_interval(symbol: str, number: int) NatAccNoteInterval¶
Creates an interval without specifying two notes.
A caveat for tunings that are not equal-step: Intervals can have irregular sizes, even if they are notated the same. This method will automatically add some reference note to the interval to be able to calculate ANY size of the interval, so the result of this method might differ in size from a result that you obtained by forming an interval through the note_interval method.
- Parameters:
symbol – An interval symbol of this notation (for example P, A, M, m)
number – An interval number indicating the interval step width according to the convention laid out by this notation
- std_pitch_diff(nat_diff: int) int¶
Returns the standardized pitch difference for a natural index difference (e.g. in 12-EDO: 0 -> 0, 1 -> 2, 4 -> 7, (-1) -> (-2), (-4) -> (-7), etc)
- Parameters:
nat_diff – A natural index difference
- property zero_element: NatAccNote¶
The ‘standard note’ with pitch_index 0
- class xenharmlib.core.notation.NotationABC(tuning, note_cls: type[NoteT], note_interval_cls: type[IntervalT], note_scale_cls: type[ScaleT], note_interval_seq_cls: type[IntervalSeqT])¶
Abstract base class for all notations. A notation can be understood as a wrapper around the tuning, providing a string interface to the underlying integer system.
Notations in the core package are defined as generics with three type variables: One for the note class, one for the interval class, and one for the scale class.
- Parameters:
tuning – The tuning for which the notation should be constructed
note_cls – The python class that is used to generate the note object in the note method.
note_interval_cls – The python class that is used to generate a note interval object in the note_interval method.
note_scale_cls – The python class that is used to generate a note scale object in the note_scale method.
- property enharm_strategy¶
The enharmonic strategy of this notation. Enharmonic strategies define different ways to map pitch layer objects to notation layer objects.
- guess_note(pitch) NoteT¶
Guesses a note from a pitch using the preferred enharmonic strategy of this notation
- Pitch:
A pitch object originating from the underlying tuning
- guess_note_interval(pitch_interval) NoteT¶
Guesses a note interval from a pitch interval using the preferred enharmonic strategy of this notation
- Pitch_interval:
A pitch interval object originating from the underlying tuning
- guess_note_scale(pitch_scale) NoteT¶
Guesses a note scale from a pitch scale using the preferred enharmonic strategy of this notation
- Pitch_scale:
A pitch scale object originating from the underlying tuning
- abstractmethod note(*args, **kwargs) NoteT¶
(Must be overwritten by subclasses) Returns a note object of the note type this notation was initialized with
- abstractmethod note_interval(note_a: NoteT, note_b: NoteT) IntervalT¶
Returns a note interval of the note interval type this notation was initialized with
- Parameters:
note_a – The source note
note_b – The target note
- abstractmethod note_scale(notes: List[NoteT] | None = None) ScaleT¶
Returns a note scale of the note scale type this notation was initialized with
- Parameters:
notes – A list of notes
- property tuning¶
Returns the tuning this notation was built for
Note and NoteInterval¶
The note core module implements primitives to handle different types of notes and note intervals. Notes and note intervals wrap the integer-based pitch and pitch interval classes.
- class xenharmlib.core.notes.NatAccNote(notation, frequency, pitch_index, nat_index: int, acc_vector: Tuple[int, ...], pc_symbol: str, natc_symbol: str, acc_symbol: str)¶
A base class for notes that are constructed from a natural and accidentals (the appropriate base class for notes of notations subclassing from
NatAccNotation)- Parameters:
notation – The notation object this note belongs to
frequency – The frequency this note represents
pitch_index – The pitch index of this note
nat_index – The natural index of this note, which is an index counting the naturals starting with 0 (e.g. in Western notation C0 ^= 0, D0 ^= 1, C1 ^=7, etc)
acc_vector – A vector detailing the different deviations in steps that were introduced through accidentals
pc_symbol – The chosen symbol for the pitch class (in most notations this is equal to natc_symbol + acc_symbol, however, there are notations - like UpDownNotation - that put some of the accidentals before the natural)
natc_symbol – The chosen symbol for the natural class (e.g. ‘C’ for C#)
acc_symbol – The chosen symbol for the accidental (e.g. ‘#’ for C#)
- acc_altered(acc_diff: Tuple[int, ...])¶
Returns a note with altered accidentals from an accidental difference vector, so for example in UpDownNotation for a tuning with sharpness 2 altering ^C# by (2, -1) results in the note Cx
- Parameters:
acc_diff – The accidental difference vector
- property acc_direction: int¶
The accidental direction of this note (0 if the note is a natural, 1 if the note is a sharp note, -1 if it is a flat note)
- property acc_symbol: str¶
The symbol for the accidental of this note
- property acc_value: int¶
The accidental value of this note (e.g. in 31edo 2 for #, -2 for b, 0 for natural)
- property acc_vector: Tuple[int, ...]¶
The accidental vector of this note
- property is_enharmonic_natural: bool¶
Returns True if note refers to a pitch class that is a natural
- is_notated_equivalent(other) bool¶
Returns True, if this note is notated the same way as the other, False otherwise
- Parameters:
other – Another note to compare
- property is_notated_natural: bool¶
Returns True if this note is notated(!) as a natural, False otherwise (e.g. the note E# refers to a natural, however, it is notated with an accidental, thus the property will be False here)
- is_notated_same(other) bool¶
Returns True, if this note is notated the same way as the other, False otherwise
- Parameters:
other – Another note to compare
- property nat_bi_index: int¶
The base interval index of the natural of this note
- property nat_index: int¶
Returns the natural index of this note. The natural index is the number of steps needed to reach the natural part of this note, so for example in a notation with naturals C, D, E, F, G, A, B the natural index of C#-0 is 0, D-1 is 8, Eb-3 is 16
- property nat_pc_index: int¶
The pitch class index of the natural of this note
- property nat_pitch_index: int¶
The pitch index of the natural of this note
- property natc_index: int¶
Returns the natural class index of this note. The natural class index is the equivalency class of the natural index, so for example in a notation with naturals C, D, E, F, G, A, B the notes C#-3 and Cb-0 both have natural class index 0 while F#-2 and Fbb-5 have natural class index 3
- property natc_pitch_index: int¶
The pitch index of the natural class of this note
- property natc_symbol: str¶
The symbol for the natural of this note
- property pc_short_repr¶
The pitch class symbol of this note
- property pc_symbol: str¶
The pitch class symbol of this note
- property pitch: PeriodicPitch¶
Returns the underlying pitch object
- property short_repr¶
A shortened representation of this note
- transpose(diff: int | NatAccNoteInterval) NatAccNote¶
Transposes the note to another one by a natural/accidental note interval.
- Parameters:
diff – A natural/accidental note interval object or an integer denoting the pitch difference
- transpose_bi_index(bi_diff: int) Self¶
Returns a note with the same pitch class index and symbol, but with a transposed base interval
- Parameters:
bi_diff – The difference in base interval between this note and the resulting one
- class xenharmlib.core.notes.NatAccNoteInterval(notation, frequency_ratio, pitch_diff, ref_note: NatAccNote, nat_diff: int, acc_vector: Tuple[int, ...], symbol: str, number: int)¶
Note interval class for intervals with natural/accidental notes. The class assumes that the interval is value-representable by the difference in natural indices and an accidental vector signifying step alterations of different categories. It is meant as a solid basis for interval notations that are similar to the traditional Western interval notation having a interval symbol (like ‘M’) and an interval number (like 2)
The concrete way an interval symbol and number are chosen is dependent on the underlying notation from which a symbol and a number are received in the
from_source_and_target()builder method.- Parameters:
notation – The notation this interval refers to
frequency_ratio – A frequency ratio object
pitch_diff – The difference in pitch that this interval represents
ref_note – A reference note (needed for non-equal step tunings)
nat_diff – The difference of the natural indices of the two notes defining the interval
acc_vector – A vector defining the alteration of the standard pitch index difference of a natural index difference
symbol – An interval symbol (like ‘M’, ‘d’, ‘P’)
number – An interval number
- property acc_vector: Tuple[int, ...]¶
The accidental vector of this interval (signifying the different pitch deviations from the standard natural pitch difference)
- classmethod from_notes(note_a: NatAccNote, note_b: NatAccNote) Self¶
Deprecated since version 0.2.0: Use
from_source_and_target()instead.Creates a note interval from two notes
- Raises:
IncompatibleOriginContexts – If notes belong to different notations
- Parameters:
note_a – The source note
note_b – The target note
- classmethod from_source_and_target(source: NatAccNote, target: NatAccNote) Self¶
Creates a note interval from two notes
- Raises:
IncompatibleOriginContexts – If notes belong to different notations
- Parameters:
source – The source note
target – The target note
- property nat_diff: int¶
The difference of the natural indices of the two notes forming the interval
- property number: int¶
A number signifying the size of the interval (closely related to the
nat_diffproperty but traditionally implemented as 1-based index)
- property short_repr: str¶
A short representation string of the interval (to be shown in collections)
- property shorthand_name: Tuple[str, int]¶
A tuple consisting of the interval symbol and the interval number
- property symbol: str¶
A symbol classifying this interval in regard to size and quality
- class xenharmlib.core.notes.NoteABC(notation, frequency, pitch_index)¶
Abstract base class for notes. Implements the properties
tuning,frequencyandpitch_indexas well as the equality and lesser-than relation based on thefrequencyproperty.Subclasses must implement the
pitchproperty, theis_notated_samemethod and thetranspose()method.- Parameters:
notation – The notation object this note belongs to
pitch_index – The pitch index of this note
frequency – The frequency this note represents
- property enharm_strategy¶
Proxy property for the enharmonic strategy of the notation
- abstractmethod is_notated_same(other) bool¶
(Must be implemented by subclasses) Returns True, if this note is notated the same way as the other, False otherwise
- Parameters:
other – Another note of the same notation or class
- property notation¶
The notation associated with this note
- abstract property pitch¶
(Must be implemented by subclasses) Returns the underlying pitch object
- property tuning¶
The tuning associated with this note
- class xenharmlib.core.notes.NoteIntervalABC(notation, frequency_ratio, pitch_diff: int, ref_note: NoteT)¶
Abstract base class for note intervals. Implements the property
pitch_intervalthat constructs the equivalent pitch intervalNote intervals are implemented as generic types with the inner type being a note class.
Subclasses must at least implement the
from_source_and_target()class method.- Parameters:
notation – The notation this interval refers to
frequency_ratio – A frequency ratio object
pitch_diff – The difference in pitch that this interval represents
ref_note – A reference note (needed for non-equal step tunings)
- property notation¶
The notation associated with this note interval
- property pitch_interval¶
Returns the pitch interval equivalent to this note interval
- property ref_note: NoteT¶
A reference note for the interval. (This is important for tunings that are not equal step where the same pitch difference does not imply the same frequency ratio)
- property tuning¶
The tuning associated with this note interval
- class xenharmlib.core.notes.PeriodicNoteABC(notation, frequency, pitch_index)¶
Abstract base class for periodic notes. Implements proxy properties
pc_indexandbi_indexthat refer to the underlying periodic pitch object.Subclasses need to implement the
transpose_bi_index()method (in addition to the abstract properties and methods of NoteABC)- property bi_index: int¶
The base interval index of this note
- get_generator_index(generator_note: Self)¶
Calculates the number of steps needed to reach this note when iteratively adding the pitch of the given generator note to the zero pitch of this tuning
- Parameters:
generator_note – A generator note. Will be normalized to the equivalent note in the first base interval if its pitch index exceeds the period length of the tuning.
- Raises:
IncompatibleOriginContexts – If notes come from a different notation system
InvalidGenerator – If the pitch of given generator note is not in fact a generator in the underlying tuning
- is_equivalent(other: PeriodicPitchLike) bool¶
Returns True if this note has the same frequency as the other object when normalized to the first base interval
- Parameters:
other – Another periodic pitch or note
- abstractmethod is_notated_equivalent(other) bool¶
(Must be implemented by subclasses) Returns True, if this note is notated the same way as the other in regards to its pitch class symbol
- Parameters:
other – Another note
- property pc_index: int¶
The pitch class index of this note
- pcs_normalized() Self¶
Returns the equivalent of this note in the first base interval
- abstractmethod transpose_bi_index(bi_diff: int) Self¶
Returns a note with the same pitch class index and symbol, but with a transposed base interval
- Parameters:
bi_diff – The difference in base interval between this note and the resulting one
- class xenharmlib.core.notes.PeriodicNoteInterval(notation, frequency_ratio, pitch_diff: int, ref_note: NoteT)¶
Abstract base class for intervals referring to notations of periodic tunings.
Implements the method
get_generator_distance()- get_generator_distance(generator_note: NoteT) int¶
Calculates the minimum number of steps needed to reach one note from the other when iteratively adding a generator note.
A typical application in 12EDO is to calculate the minimum distance of the two notes on the circle of fifths, hence the generator distance can be a good measure for consonance of an interval given the right generator note.
- Parameters:
generator_note – A generator note. Will be normalized to the equivalent pitch in the first base interval if its pitch index exceeds the period length of the tuning.
- Raises:
InvalidGenerator – If the note is not a generator in the tuning attached to this interval’s notation
NoteScale¶
The note scale core module implements basic classes for different types of scale notation systems.
- class xenharmlib.core.note_scale.NatAccNoteScale(notation, notes=None)¶
Basic note scale class for natural/accidental notations. Implements the scale equivalents of properties special to natural/accidental notes.
- property acc_directions: List[int]¶
The list of accidental directions of notes in the scale (0 if the note is a natural, 1 if the note is a sharp note, -1 if it is a flat note, so for example in 31-EDO [0, 1, -1] for [C0, ^B#2, Cb0])
- property acc_symbols: List[str]¶
The symbol list for the accidental part of each note in the scale (e.g. in 12-EDO [‘#’, ‘b’, ‘’] for [C#0, Gb1, B4])
- property acc_values: List[int]¶
A list of accidental values for each note in the scale
- property acc_vectors: List[int]¶
A list of accidental vectors for each note in the scale
- property nat_bi_indices: List[int]¶
A list of natural base interval indices represented in this scale. The natural base interval is the base interval index of the natural part of the note, so e.g. 0 for B#-0
- property nat_indices: List[int]¶
A list of the natural indices of notes in this scale
The natural index is the number of natural steps needed to reach the natural part of this note, so for example in a notation with naturals C, D, E, F, G, A, B the natural index of C#-0 is 0, D-1 is 8, Eb-3 is 16
- property nat_pc_indices: List[int]¶
A list of pitch class indices of the natural part of each note in the scale (e.g. in 12-EDO [0, 2, 4] for [C#0, D1, Eb2])
- property nat_pitch_indices: List[int]¶
A list of pitch indices of the natural part of each note in the scale (e.g. in 12-EDO [0, 14, 18] for [C#0, D1, Eb2])
- property natc_indices: List[int]¶
A list of natural class indices of notes in this scale.
The natural class index is the equivalency class of the natural index, so for example in a notation with naturals C, D, E, F, G, A, B the notes C#-3 and Cb-0 both have natural class index 0 while F#-2 and Fbb-5 have natural class index 3
- property natc_symbols: List[str]¶
The symbol list for the natural part of each note in the scale (e.g. in 12-EDO [‘C’, ‘G’, ‘B’] for [C#0, Gb1, B4])
- property pc_symbols: List[str]¶
The symbol list for the pitch classes represented in the scale (e.g. in 12-EDO [‘C#’, ‘Gb’, ‘B’] for [C#0, Gb1, B4])
- class xenharmlib.core.note_scale.NoteScale(notation, notes=None)¶
Base class for all note scales. Implements list and set operations, transposition, etc
Note scales are implemented as generic types with the inner type being a note class.
- Parameters:
notation – The notation this scale refers to
notes – (optional) A list of notes from the notation. If the parameter is omitted an empty scale will be initialized
- add_note(note: NoteT)¶
Deprecated since version 0.2.0: objects in xenharmlib are supposed to be immutable
Inserts a new note into to the scale at the right position. If the note already exists in the scale the method will do nothing.
- Raises:
IncompatibleOriginContexts – If the note has a different notation than this scale.
- Parameters:
note – The new note
- property enharm_strategy¶
A proxy property to the enharmonic strategy of the notation
- is_notated_disjoint(other: Self) bool¶
Determines if this scale has any common notes with another scale of the same notation. In contrast to is_disjoint enharmonically equivalent but differently notated notes will be treated as distinct
- Raises:
IncompatibleOriginContexts – If the other scale has a different notation
- is_notated_same(other: Self) bool¶
Returns True if this scale has the exact same notes as the other scale while ignoring possible enharmonic equivalence.
- is_note_subset(other: Self, proper: bool = False) bool¶
Determines if all notes in this scale also exist in the other scale. In contrast to is_subset enharmonically equivalent but differently notated notes will be treated as distinct
- Parameters:
other – Another scale of the same notation
proper – (Optional, default False) When set to True method will return False if the two sets are identical
- Raises:
IncompatibleOriginContexts – If the other scale has a different notation
- is_note_superset(other: Self, proper: bool = False) bool¶
Determines if all notes in the other scale also exist in this scale. In contrast to is_superset enharmonically equivalent but differently notated notes will be treated as distinct
- Parameters:
other – Another scale of the same notation
proper – (Optional, default False) When set to True method will return False if the two sets are identical
- Raises:
IncompatibleOriginContexts – If the other scale has a different notation
- property is_zero_normalized: bool¶
Returns True if this function is zero normalized, meaning that the first element of the scale is notated the same as the zero element of the origin context (typically C0 in western-like notations)
- note_difference(other: Self) Self¶
Returns a new scale containing only notes from this scale that are NOT present in the other scale. In contrast to the difference method notes will only be considered shared notes of the sets if they are notated the same. If a note is in the second set that is enharmonically equivalent to a note in this set but notated in a different way, the latter will stay in the result set.
- Raises:
IncompatibleOriginContexts – If the other scale has a different notation
- note_intersection(other: Self) Self¶
Returns a new scale including all notes that are included in both scales. In contrast to the intersection method notes will only be considered shared notes of the sets if they are notated the same and excluded otherwise, even if they are enharmonically equivalent
- Raises:
IncompatibleOriginContexts – If the other scale has a different notation
- property pitch_indices: List[int]¶
An ordered list of pitch indices present in this scale
- property pitch_scale¶
Returns the equivalent pitch scale for this object
- to_note_intervals() List[NoteIntervalABC]¶
Deprecated since version 0.2.0: Use
to_intervals()instead.Returns this scale represented as a list of note intervals
- transpose(diff: int | NoteIntervalABC) Self¶
Transposes the scale by the given interval
- Parameters:
diff – A note interval or pitch difference given as an integer
- property tuning¶
The tuning the origin notation of this scale relies upon
- class xenharmlib.core.note_scale.PeriodicNoteScale(notation, notes=None)¶
Note scale class for periodic notations. Implements customized set operations (for when you want to treat equivalent notes the same as equal notes).
- is_notated_disjoint(other: Self, ignore_bi_index: bool = False) bool¶
Determines if this scale has any common notes with another scale of the same notation. In contrast to is_disjoint enharmonically equivalent but differently notated notes will be treated as distinct
- Parameters:
other – Another scale of the same notation
ignore_bi_index – (Optional, default False) When set to True notes of the same pitch class will be treated the same. For example, if one scale includes C-0 and another C-1 the scales will not be considered disjoint
- Raises:
IncompatibleOriginContexts – If the other scale originates from a different notation
- is_notated_equivalent(other: Self) bool¶
Returns True if this scale has, apart from the base interval, the exact same notes as the other while ignoring possible enharmonic equivalence.
- is_note_subset(other: Self, proper: bool = False, ignore_bi_index: bool = False) bool¶
Determines if all notes in this scale also exist in the other scale. In contrast to is_subset enharmonically equivalent but differently notated notes will be treated as distinct
- Parameters:
other – Another scale of the same notation
proper – (Optional, default False) When set to True method will return False if the two sets are identical
ignore_bi_index – (Optional, default False) When set to True notes of the same pitch class will be treated the same.
- Raises:
IncompatibleOriginContexts – If the other scale originates from a different notation
- is_note_superset(other: Self, proper: bool = False, ignore_bi_index: bool = False) bool¶
Determines if all notes in the other scale also exist in this scale. In contrast to is_superset enharmonically equivalent but differently notated notes will be treated as distinct
- Parameters:
other – Another scale of the same notation
proper – (Optional, default False) When set to True method will return False if the two sets are identical
ignore_bi_index – (Optional, default False) When set to True notes of the same pitch class will be treated the same.
- Raises:
IncompatibleOriginContexts – If the other scale originates from a different notation
- note_difference(other: Self, ignore_bi_index: bool = False) Self¶
Returns a new scale containing only notes from this scale that are NOT present in the other scale. In contrast to the difference method notes will only be considered shared notes of the sets if they are notated the same. If a note is in the second set that is enharmonically equivalent to a note in this set, but notated in a different way, the latter will stay in the result set.
- Parameters:
other – Another scale of the same notation
ignore_bi_index – (Optional, default False) When set to True notes of the same pitch class will be treated the same. For example, if the difference of two scales including C-0 and C-1 respectively is calculated, C-0 will not be inserted into the new scale
- Raises:
IncompatibleOriginContexts – If the other scale has a different notation
- note_intersection(other: Self, ignore_bi_index: bool = False) Self¶
Returns a new scale including all notes that are included in both scales. In contrast to the intersection method notes will only be considered shared notes of the sets if they are notated the same and excluded otherwise, even if they are enharmonically equivalent
- Parameters:
ignore_bi_index – (Optional, default False) When set to True notes of the same pitch class will be treated the same. For example, if the intersection of two scales including C-0 and C-1 respectively is calculated, both notes will be added to the result
- Raises:
IncompatibleOriginContexts – If the other scale has a different notation
- property pc_indices: List[int]¶
Returns a list of pitch class indices in the order they appear in this scale. This can include duplicate items if the scale has two notes of the same pitch class
- pcs_complement() Self¶
Returns a complement version of this scale that includes all the notes in the first base interval that are not part of this scale
Enharmonic Strategies¶
This module includes functionality to deal with enharmonic ambiguity
- class xenharmlib.core.enharm_strategies.EnharmonicStrategy¶
An enharmonic strategy is a drop-in function set to solve the problem of enharmonic ambiguity when translating pitches into notes.
An example: On the pitch/tuning layer the transpose method is well-defined if given an integer:
>>> from xenharmlib import EDOTuning >>> edo12 = EDOTuning(12) >>> edo12.pitch(0).transpose(1) EDOPitch(1, 12-EDO)
However on the notation layer it is unclear, if “C + 1” should result in C# or Db, if “C + 2” should result in “D” or “C##”, etc. The same problem is encountered on operations like pcs_complement: Should the PCS complement of [C, D, E, F, G, A, B] be notated with upwards accidentals [C#, D#, F#, G#, A#], downward accidentals [Db, Eb, Gb, Ab, Bb] or a mixture of both?
An enharmonic strategy makes an opinionated(!) choice which pitches translate to which notes. Because not every strategy is fit for every context and purpose xenharmlib allows choosing a custom strategy when initializing a notation.
This base class implements stubs of all hook functions which get called by the notation layer classes. By default these stubs are not abstract, but simply raise NotImplementedError, so it is possible for EnharmonicStrategy subclasses to not support all operations that need an enharmonic strategy. This way custom enharmonic strategies implemented by the user also keep working if the feature set expands on an update.
- guess_note(notation, pitch)¶
Notation.guess_note relays to here
- Parameters:
notation – The notation object that relayed here
pitch – The pitch object
- guess_note_interval(notation, pitch_interval)¶
Notation.guess_note_interval relays to here
- Parameters:
notation – The notation object that relayed here
pitch_interval – The pitch interval object
- guess_note_scale(notation, pitch_scale)¶
Notation.guess_note_scale relays to here
- Parameters:
notation – The notation object that relayed here
pitch_scale – The pitch scale object
- note_scale_pcs_complement(note_scale)¶
NoteScale.pcs_complement relays to here
- Parameters:
note_scale – The note scale on which the pcs_complement method was called
- note_scale_transpose(note_scale, pitch_diff: int)¶
NoteScale.transpose relays to here if the interval argument was not given as a suitable NoteInterval object but as an integer.
- Parameters:
note_scale – The note scale on which the transpose method was called
pitch_diff – The pitch difference as an integer
- note_transpose(note, pitch_diff: int)¶
Note.transpose relays to here if the interval argument was not given as a suitable NoteInterval object but as an integer.
- Parameters:
note – The note on which the transpose method was called
pitch_diff – The pitch difference as an integer
- class xenharmlib.core.enharm_strategies.PCBlueprintStrategy(pc_blueprint: Sequence[PeriodicNoteABC])¶
PCBlueprintStrategy is an enharmonic strategy that defines fixed note symbols for each pitch class and translates every pitch to a note by matching the pitch class and transposing the base interval.
- Parameters:
pc_blueprint – An iterable of notes that together form a pitch class blueprint for the whole pitch range
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib.core.enharm_strategies import PCBlueprintStrategy >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> >>> S = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] >>> strategy = PCBlueprintStrategy( ... [n_edo12.note(symbol, 0) for symbol in S] ... ) >>> n_edo12.enharmonic_strategy = strategy >>> >>> n_edo12.guess_note(edo12.pitch(13)) UpDownNote(C#, 1, 12-EDO) >>> n_edo12.note('D#', 2).transpose(1) UpDownNote(E, 2, 12-EDO)
- guess_note(notation, pitch)¶
Notation.guess_note relays to here
- Parameters:
notation – The notation object that relayed here
pitch – The pitch object
- guess_note_interval(notation, pitch_interval)¶
Notation.guess_note_interval relays to here
- Parameters:
notation – The notation object that relayed here
pitch – The pitch interval object
- guess_note_scale(notation, pitch_scale)¶
Notation.guess_note_scale relays to here
- Parameters:
notation – The notation object that relayed here
pitch_scale – The pitch scale object
- note_scale_pcs_complement(note_scale)¶
NoteScale.pcs_complement relays to here
- Parameters:
note_scale – The note scale on which the pcs_complement method was called
- note_scale_transpose(note_scale, pitch_diff: int)¶
NoteScale.transpose relays to here if the interval argument was not given as a suitable NoteInterval object but as an integer.
- Parameters:
note_scale – The note scale on which the transpose method was called
pitch_diff – The pitch difference as an integer
- note_transpose(note, pitch_diff: int)¶
Note.transpose relays to here if the interval argument was not given as a suitable NoteInterval object but as an integer.
- Parameters:
note – The note on which the transpose method was called
pitch_diff – The pitch difference as an integer
Symbol Codes¶
The symbol module implements primitives to parse languages in which each literal and each word represents an integer vector. These languages are called ‘symbol codes’ and are used as utils in notations.
- exception xenharmlib.core.symbols.AmbiguousSymbol¶
Gets raised whenever a symbol is added to a symbol code that already exists or if the associated value is already represented by another symbol
- class xenharmlib.core.symbols.SymbolArithmetic(dimensions: int = 1, offset: Tuple[int, ...] | None = None, allow_empty: bool = False)¶
A symbol arithmetic is a mapping between string symbol sequences and integer vector sums.
A simple use case is to parse and generate accidentals, for example parsing the standard western accidental string ‘x#b’ into a list of one-dimensional integer vectors that signify the pitch index alterations of each accidental (like (2,), (1,), (-1,)), resulting in the sum (2,) denoting the total pitch index alteration of an accidental string.
Higher dimensional arithmetics can be useful if there are multiple classes of accidentals (like sharp/flat on the one hand and up/down on the other). Given a value dimensionality of 2, it can e.g. parse an expression like ‘^b##x’ into a list of integer vectors (here: (0, 1), (-1, 0), (1, 0), (1, 0), (2, 0)) from which it creates a sum vector (3, 1)
Vice-versa for a given integer or integer vector it can create an equivalent minimal sequence of symbols (e.g. (-1, 1) -> ‘b^’).
SymbolArithmetic parses in a greedy way, so if ‘bb’, ‘b’ and ‘#’ are registered as symbols, it will parse ‘bb#’ into the list ‘bb’, ‘#’ (NOT ‘b’, ‘b’, ‘#’)
The class can also be used to design accidental systems for dense tunings (like prime limit tunings), that don’t have an enumerable pitch index sequence. For example, given a 3-limit tuning one can define accidentals as their monzo, defining ‘#’ as the value vector (-11, 7), ‘b’ as the vector (11, -7), and so forth. The addition of the monzo vectors is then equal to the product in |R+: (e.g. ‘b#’ = (11, -7) + (-11, 7) = (0, 0), which is the same as (2^11)/(3^7) * (3^7)/(2^11) = (2^0) * (3^0) = 1.
On initialization of an arithmetic, an offset can be set, which adds a fixed integer vector to all symbol value vectors. This is especially powerful when defining partial arithmetics in a SymbolArithmeticSet, e.g. if one wants to parse ‘^A’ into (4, 1), ‘AA’ into (5, 0), ‘^AAA’ into (6, 1), etc. In a case like this one can define the value of ‘A’ to be (1, 0), the value of ‘^’ to be (0, 1) and the offset to be (3, 0).
- Parameters:
dimensions – Dimensions of the value vector (optional, defaults to 1)
offset – (optional, defaults to the 0-vector). A fixed value vector that will be added to the sum
allow_empty – (optional, default False). If True, empty strings are part of this arithmetic (with the value of the offset, or the 0 vector if offset is not given). If False exceptions will be raised on empty strings
- add_symbol(symbol: str, vector: Tuple[int, ...], position: int | None = None, min_occurence: int | None = None, max_occurence: int | None = None)¶
Adds a string symbol with its corresponding integer vector to this arithmetic
- Raises:
AmbiguousSymbol – If symbol already exists in the arithmetic or if vector is already represented by another symbol
- Parameters:
symbol – A string (can be multi-character)
vector – An integer tuple defining the value vector of the symbol (dimensions must match the dimensions with which the arithmetic was initialized)
position – The desired positional value of the symbol in the sorting process of get_symbol_str (optional, if no parameter is given the position of the symbol will be analogous to the order in which symbols were added to the arithmetic)
min_occurence – (optional) The minimum number of times this symbol must occur in the arithmetic symbol string in order for the string to be considered valid
max_occurence – (optional) The maximum number of times this symbol can occur in the arithmetic symbol string in order for the string to be considered valid
- get_symbol_str(vector: Tuple[int, ...]) str¶
Partitions the given vector into vector summands that are represented by symbols and returns those symbols sorted according to the positional value of each symbol and joined as a single string.
- Parameters:
vector – The sum vector that should be resolved into a symbol term
- get_symbols(vector: Tuple[int, ...]) Tuple[str, ...]¶
Returns a sorted, minimal tuple of symbols whose combined value together with the offset result in the given sum.
- Raises:
SymbolValueNotMapped – If the value can not be represented by any combination of symbols in the arithmetic
- Parameters:
vector – The sum vector that should be resolved into a symbol term
- get_vector(symbol_str: str) Tuple[int, ...]¶
Returns the vector integer sum (adjusted for offset, if set) for a given symbol string.
- Raises:
UnknownSymbolString – If arithmetic did not match the string
- Parameters:
symbol_str – A string consisting of symbols defined in this arithmetic
- get_vector_from_symbols(symbols: Tuple[str, ...]) Tuple[int, ...]¶
Returns the vector integer sum (adjusted for offset, if set) for a given tuple of parsed symbol literals
- Parameters:
symbols – A tuple with each element being a symbol literal in this arithmetic
- parse(symbol_str: str) Tuple[str, ...]¶
Parses a symbol string into a list of symbols
>>> from xenharmlib.core.symbols import SymbolArithmetic >>> arithmetic = SymbolArithmetic(dimensions=2) >>> arithmetic.add_symbol('x', (2, 0)) >>> arithmetic.add_symbol('#', (1, 0)) >>> arithmetic.add_symbol('b', (-1, 0)) >>> arithmetic.add_symbol('^', (0, 1)) >>> symbols = arithmetic.parse('xbb#') >>> symbols ('x', 'b', 'b', '#')
- Raises:
UnknownSymbolString – If arithmetic did not match the string
- Parameters:
symbol_str – A symbol string consisting of symbols defined in this arithmetic
- class xenharmlib.core.symbols.SymbolArithmeticSet(dimensions: int = 1, pref_func: Callable[[List[Tuple[SymbolArithmetic, Tuple[str, ...]]]], Tuple[SymbolArithmetic, Tuple[str, ...]]] | None = None)¶
SymbolArithmeticSets combine different SymbolArithmetics allowing to use multiple symbols for the same integer vector and to segment the space of integer vectors into multiple arithmetics with different offsets.
You can for example combine four arithmetics to represent traditional interval naming of imperfect intervals:
‘M’ represents vector (0, 0)
‘^M’ represents vector (0, 1)
‘A’ represents vector (2, 0)
‘m’ represents vector (-1, 0)
‘d’ represents vector (-2, 0)
‘vd’ represents vector (-2, -1)
- Parameters:
dimensions – The dimensions of the arithmetics in the set (optional, defaults to 1)
pref_func – (optional) A preference function that returns a definite parsing result from a list of possible ones. The function should accept a list of tuples (arithmetic, parsed_str) with parsed_str being a tuple of single symbols. It should return one element of the list that should be preferred. If no preference function is given, then the class will choose the result with the shortest length.
- add_arithmetic(arithmetic: SymbolArithmetic)¶
Adds another symbol arithmetic to this set
- Parameters:
arithmetic – The arithmetic to add
- property dimensions: int¶
The vector dimensions of arithmetics in this set
- get_symbol_str(vector: Tuple[int, ...]) str¶
Returns a minimal symbol string for a given value
- Raises:
SymbolValueNotMapped – If the value can not be represented by any combination of symbols in any arithmetic
- Parameters:
value – A positive or negative integer
- get_vector(symbol_str: str) Tuple[int, ...]¶
Returns the vector sum value for a given string
- Raises:
UnknownSymbolString – If no arithmetic in the set matched the string
- Parameters:
symbol_str – A symbol string consisting of symbols defined by at least one arithmetic in the set.
- parse(symbol_str: str) Tuple[SymbolArithmetic, Tuple[str, ...]]¶
Tries to parse a symbol string by each arithmetic in the set. If an arithmetic returns a result it is added to the list of possible results from which then subsequently one result is selected using the preference function given during set initialization.
The function returns a tuple (arithmetic, symbols) with the first element being the chosen arithmetic and the second being the parsing result from that arithmetic.
- Raises:
UnknownSymbolString – If no arithmetic in the set matched the string
- class xenharmlib.core.symbols.SymbolCode¶
SymbolCode defines a general interface for different strategies to turn symbol strings into integer vectors and vice versa.
- The interface consists of two abstract methods
SymbolCode.get_value()
- abstractmethod get_symbol_str(vector: Tuple[int, ...]) str¶
Abstract method placeholder for a specific implementation to convert an integer vector into a symbol or sequence of symbols
- Parameters:
vector – An integer vector
- Raises:
SymbolValueNotMapped – If mapping has no ruleset to convert the vector into a string
- abstractmethod get_vector(symbol_str: str) Tuple[int, ...]¶
Abstract method placeholder for a specific implementation to convert a string of one or more symbols into an integer vector
- Parameters:
string – A string consisting of one or more symbols
- Raises:
UnknownSymbolString – If mapping has no ruleset to convert the string into an integer vector
- exception xenharmlib.core.symbols.SymbolValueNotMapped¶
Gets raised whenever an integer value is not mapped by a word in a symbol code
- exception xenharmlib.core.symbols.UnfittingDimensions¶
Gets raised whenever a vector does not fit to the dimension configuration of the symbol code
- exception xenharmlib.core.symbols.UnknownSymbolString¶
Gets raised whenever a SymbolCode receives a string that is not part of its grammar
Exceptions¶
This module includes all exceptions that must be handled by the user of the library
- exception xenharmlib.exc.IncompatibleOriginContexts¶
Gets raised whenever two or more objects are not compatible because they are based on different orgin contexts
- exception xenharmlib.exc.InvalidAccidentalValue¶
Gets raised when an accidental value is not allowed in a notation
- exception xenharmlib.exc.InvalidBaseIntervalIndex¶
Gets raised when a base interval index does not adhere to a certain restriction, for example if it is out of bounds of a predefined limit
- exception xenharmlib.exc.InvalidFrequency¶
Gets raised when a frequency argument does not adhere to a certain restriction, for example if it is out of bounds of a predefined limit
- exception xenharmlib.exc.InvalidGenerator¶
Gets raised when a given pitch or pitch-like argument is not a generator in respect to the tuning
- exception xenharmlib.exc.InvalidIndexMask¶
Gets raised when an index mask expression is invalid
- exception xenharmlib.exc.InvalidIntervalNumber¶
Gets raised when an interval number is not valid
- exception xenharmlib.exc.InvalidNaturalDiffClassIndex¶
Gets raised when a natural diff class index does not adhere to a certain restriction, for example if it is out of bounds of a predefined limit
- exception xenharmlib.exc.InvalidNaturalIndex¶
Gets raised when a natural index does not adhere to a certain restriction, for example if it is out of bounds of a predefined limit
- exception xenharmlib.exc.InvalidPitchClassIndex¶
Gets raised when a pitch class index does not adhere to a certain restriction, for example if it is out of bounds of a predefined limit
- exception xenharmlib.exc.InvalidPitchIndex¶
Gets raised when a pitch index does not adhere to a certain restriction, for example if it is out of bounds of a predefined limit
- exception xenharmlib.exc.UnfittingNotation¶
Gets raised on construction of notations when a property of the tuning prohibits the use of the specific notation
- exception xenharmlib.exc.UnknownNoteSymbol¶
Gets raised on construction of notes if a provided symbol was not recognized by the notation