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
- to_int() int¶
Converts this object into an integer
- 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: Tuple[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_int() int¶
Converts this object into an integer
- 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}\)
Lattices¶
The lattice module implements a generalization of pitch indices.
In sparse, equally-spaced tunings the pitch index group \((\mathbb{Z}, +)\) can be mapped to the frequency ratio group \((\mathbb{R}, \cdot)\) by group homomorphism \(H_b\) as follows:
\(H_b(x) := b^x\)
\(H_b(x + y) := b^x \cdot b^y = b^{(x + y)}\)
Lattices generalize this homomorphism by mapping a vector group \((\mathbb{Z}^n, +)\) to the frequency ratio group \((R, \cdot)\) refering to a base vector B:
\(H_B(X) := b_1^{x_1} \cdot b_2^{x_2} \cdot ... \cdot b_n^{x_n}\)
\(H_B(X + Y) := b_1^{(x_1 + y_1)} \cdot b_2^{(x_2 + y_2)} \cdot ... \cdot b_n^{(x_n + y_n)}\)
By defining an order on \(\mathbb{Z}^n\) with the following definition
\(X < Y\) iff \(H_B(X) < H_B(Y)\)
and by introducing scalar multiplication \(kX\) on \(\mathbb{Z}^n\) as a short form for repeated addition of an element \(X\) in \(\mathbb{Z}^n\) with itself, equivalency classes on \(\mathbb{Z}^n\) can be obtained by defining division with remainder:
\(\lfloor \frac{X}{Y} \rfloor = C\)
\(X \bmod Y = k\)
so that \(X = kY + C\) with \(C < Y\)
For \(n = 1\) this reduces to simple integer modulo arithmetic.
Using this definition for a n-dimensional pitch index both pitch class indices and base interval indices can be obtained with C being the n-dimensional pitch class index and k being the integer base interval index.
While for \(n = 1\) pitch class indices are finite, for \(n > 1\) pitch class indices are infinite.
- class xenharmlib.core.lattice.Lattice(base: Tuple[FrequencyRatio, ...])¶
A Lattice is a point cloud representing a frequency ratio space. For a given base \(b_1, ...., b_n\) and integer lattice coordinates \(x_1, ..., x_n\) the point represents \(r(X) = b_1^{x_1} \cdot ... \cdot b_n^{x_n}\).
The 0 is understood as an n-dimensional 0-vector and can be obtained through the
zeroproperty.- Parameters:
base – A tuple of frequency ratios
- contains_point(point: LatticePoint) bool¶
Returns True if a given lattice point is part of this lattice, False otherwise.
- Parameters:
point – A lattice point
- point(vector: Tuple[int, ...]) LatticePoint¶
Create a point inside this lattice
- Parameters:
vector – The lattice integer coordinates
- property zero: LatticePoint¶
Returns the lattice point with the zero vector coordinates
- class xenharmlib.core.lattice.LatticePoint(vector: Tuple[int, ...], base: Tuple[FrequencyRatio, ...])¶
A point in a n-dimensional lattice representing a frequency ratio. For a given base \(b_1, ..., b_n\) and integer lattice coordinates \(x_1, ..., x_n\) the point represents \(r(X) = b_1^{x_1} \cdot ... \cdot b_n^{x_n}\).
The 0 is understood as an n-dimensional 0-vector and can be obtained through the
zero()class method.For two lattice points X and Y with the same base the class implements the following operations:
addition (X + Y): defined as vector addition, equivalent to frequency ratio multiplication r(X + Y) = r(X) * r(Y)
subtraction (X - Y): defined as vector subtraction, equivalent to frequency ratio division r(X - Y) = r(X) / r(Y)
scalar multiplication (k * X): defined as scalar vector multiplication
modulo (X % Y): being defined as X - kY so that (X - kY) < Y and (X - kY) >= 0
floordiv (X // Y): being defined for two lattice points X and Y as k with X - kY so that (X - kY) < Y and (X - kY) >= 0
equality (X == Y): defined as vector equality X == Y
ordering operations (X < Y): defined as X < Y iff r(X) < r(Y)
As unitary operators the class implements:
negation (-X): being defined as component-wise negation or, geometrically, point reflection through 0
abs (abs(X)): being defined as -X for X < 0, X otherwise
LatticePoints are also hashable, so they can be used in sets
- Parameters:
vector – An integer tuple
base – A base vector of frequency ratios with the same dimensions as the vector
- property frequency_ratio: FrequencyRatio¶
Returns the frequency ratio represented by this lattice point
- classmethod zero(base: Tuple[FrequencyRatio, ...])¶
Returns the 0 vector for a given base
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], interval_fan_cls: type[IntervalFanT], freq_repr_seq_cls: type[FreqReprSeqT])¶
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)
- abstractmethod closest_freq_repr(frequency: Frequency) FreqReprT¶
Returns the frequency representation closest to a given frequency. This function is only implemented for origin contexts which mathematically allow to determine a closest frequency representation.
If the origin context e.g. is a prime limit tuning every frequency can be approximated infinitesimally close. In this case the method should raise a TypeError
(Must be implemented by subclasses)
- abstractmethod closest_interval(frequency_ratio: FrequencyRatio) IntervalT¶
Returns the interval closest to a given frequency ratio. This function is only implemented for origin contexts which mathematically allow to determine a closest frequency ratio approximation.
If the origin context e.g. is a prime limit tuning every frequency ratio can be approximated infinitesimally close. In this case the method should raise a TypeError
(Must be implemented by subclasses)
- abstractmethod closest_interval_fan(frequency_ratios: Iterable[FrequencyRatio]) IntervalFanT¶
Returns the interval fan closest to a given iterable of frequency ratios. This function is only implemented for origin contexts which mathematically allow to determine a closest frequency ratio approximation.
If the origin context e.g. is a prime limit tuning every frequency ratio can be approximated infinitesimally close. In this case the method should raise a TypeError
(Must be implemented by subclasses)
- abstractmethod closest_interval_seq(frequency_ratios: Iterable[FrequencyRatio]) IntervalSeqT¶
Returns the interval sequence closest to a given iterable of frequency ratios. This function is only implemented for origin contexts which mathematically allow to determine a closest frequency ratio approximation.
If the origin context e.g. is a prime limit tuning every frequency ratio can be approximated infinitesimally close. In this case the method should raise a TypeError
(Must be implemented by subclasses)
- abstractmethod closest_scale(frequencies: Iterable[Frequency]) ScaleT¶
Returns the scale closest to a given iterable of frequencies This function is only implemented for origin contexts which mathematically allow to determine a closest frequency representation.
If the origin context e.g. is a prime limit tuning every frequency can be approximated infinitesimally close. In this case the method should raise a TypeError
(Must be implemented by subclasses)
- abstractmethod closest_seq(frequencies: Iterable[Frequency]) FreqReprSeqT¶
Returns the sequence closest to a given iterable of frequencies This function is only implemented for origin contexts which mathematically allow to determine a closest frequency representation.
If the origin context e.g. is a prime limit tuning every frequency can be approximated infinitesimally close. In this case the method should raise a TypeError
(Must be implemented by subclasses)
- diff_interval(pitch_diff: IndexT) IntervalT¶
Returns an interval the size of a given pitch index difference.
- Parameters:
pitch_diff – The pitch index difference
- diff_interval_fan(pitch_diffs: Iterable[IndexT] | None = None) IntervalFanT¶
Returns an interval fan from an iterable of pitch index differences, for example:
>>> from xenharmlib import EDOTuning >>> edo12 = EDOTuning(12) >>> major_chord = edo12.diff_interval_fan([4, 7]) >>> minor_chord = edo12.diff_interval_fan([3, 7])
- Parameters:
pitch_diffs – An iterable containing pitch index differences
- diff_interval_seq(pitch_diffs: Iterable[IndexT] | 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_fan(intervals: Iterable[IntervalT] | None = None) IntervalFanT¶
Returns an interval fan having the interval fan 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
- 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
- seq(elements: Iterable[FreqReprT] | None = None) FreqReprSeqT¶
Returns a pitch/note sequence
- Raises:
IncompatibleOriginContexts – If at least one given element has a different origin context than this one
- Parameters:
elements – A list of elements originating from this context
- property unison_diff: IndexT¶
The unison diff is the pitch difference of the unison interval. In tunings with integer indexing this is 0, in tunings with lattice indexing this is typically the zero-vector.
- property unison_interval: IntervalT¶
The unison interval is a reference point, in one-dimensional tunings it is the element with pitch diff 0, in western notation typically P1, etc.
- 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
- abstract property zero_index: IndexT¶
The zero index is a reference point, in tunings with integer indexing this is 0, in tunings with lattice indexing this is typically the zero-vector.
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)
- retune_closest(origin_context) Self¶
Gets the frequency representation in a target origin context that is closest to the frequency of this object.
- Parameters:
origin_context – The target origin context
- Raises:
TypeError – If the target context does not have a proper definition of a closest representation to a given frequency
- scale(istruct)¶
Depending on given parameter this method constructs a new scale with this pitch/note as a starting point (if an interval sequence is given), or as a reference point (if an interval fan is given)
- Parameters:
istruct – An interval sequence or interval fan of the same origin context
- seq(istruct)¶
Depending on given parameter this method constructs a new sequence with this pitch/note as a starting point (if an interval sequence is given), or as a reference point (if an interval fan is given)
- Parameters:
istruct – An interval sequence or interval fan 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.IndexedFreqRepr(origin_context, frequency: Frequency, pitch_index: IndexT)¶
Base class for indexed frequency representation objects. Assumes a 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: IndexT¶
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
- retune_closest(origin_context) Self¶
Gets the scale in a target origin context that is closest to the frequency series of this scale.
A caveat: Since scales are a structure of sorted unique frequency representation this method may produce a scale with a smaller size than the original because two representations in this context can be approximated to the same representation in the target context.
- Parameters:
origin_context – The target origin context
- Raises:
TypeError – If the target context does not have a proper definition of a closest representation to a given frequency
- 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_fan(ref: Self | None = None)¶
Returns this scale represented as an interval fan
- to_interval_seq()¶
Returns this scale represented as an interval sequence
- to_intervals() List[Interval[FreqReprT]]¶
Deprecated since version 0.3.0: Use
to_interval_seq()instead.Returns this scale represented as a list of intervals
- to_seq()¶
Returns this scale represented as sequence of frequency representations
- 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¶
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.IndexedInterval(origin_context, frequency_ratio: FrequencyRatio, pitch_diff: IndexT)¶
IndexedInterval extends the Interval class by a pitch_diff property.
- 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)
- retune_closest(origin_context) Self¶
Gets the interval in a target origin context that is closest to the frequency ratio of this object.
- Parameters:
origin_context – The target origin context
- Raises:
TypeError – If the target context does not have a proper definition of a closest representation to a given frequency ratio
- abstract property short_repr: str¶
A short string representation of the interval (must be implemented by subclass)
- property sign: int¶
Returns 1 if this interval is an upward interval, -1 if it is a downward interval and 0 if it is the unison interval
Interval Sequences¶
- class xenharmlib.core.interval_seq.IntervalSeq(origin_context, intervals: Iterable[IntervalT] | 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
- inversion() Self¶
Returns an interval sequence with all ascending intervals flipped into descending intervals and vice versa.
Warning
Inversion has a different meaning on intervals and interval sequences. This function does not call the inversion function on every interval in the sequence but the negation (-) function
- 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[IndexT]¶
An ordered list of pitch differences representing the sequence
- retune_closest(origin_context) Self¶
Gets the interval sequence in a target origin context that is closest to the frequency ratio series of this sequence.
- Parameters:
origin_context – The target origin context
- Raises:
TypeError – If the target context does not have a proper definition of a closest representation to a given frequency ratio
- 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
- to_seq(start: FreqRepr) Scale¶
Returns a pitch/note sequence that has the interval structure of this object, starting with the given note/pitch
- Parameters:
start – A starting note/pitch of the same origin context
- with_interval(interval: IntervalT, 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
Interval Fans¶
- class xenharmlib.core.interval_fan.IntervalFan(origin_context, intervals: Iterable[IntervalT] | None = None)¶
IntervalSeq is the abstract base class for all interval fan types. An interval fan is a list of intervals that all refer to a single reference pitch (e.g. in prime limit tunings (1/1, 5/4, 3/2) is the interval fan for a pure major triad, all referencing to a common point of origin)
In line with its Sequence superclass interval fans 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 fans 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 fan
- property frequency_ratios¶
An ordered list of frequency ratios present in this fan
- 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 fan)
- Raises:
ValueError – If interval was not found in fan
- inversion() Self¶
Returns an interval fan with all ascending intervals flipped into descending intervals and vice versa.
Warning
Inversion has a different meaning on intervals and interval fans. This function does not call the inversion function on every interval in the fan but the negation (-) function
- property origin_context¶
The origin context from which this interval fan was built
- partial(mask_expr: int | Tuple[int | EllipsisType, ...]) Self¶
Returns a new fan consisting of a selection of indices of this fan. 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 fan 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 fan, for example (2, …) will select all intervals of the fan 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 fan.
- partial_not(mask_expr: int | Tuple[int | EllipsisType, ...]) Self¶
Returns a new fan consisting of a selection of indices of this fan. 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 fan 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 fan, for example (2, …) will select all intervals of the fan 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 fan.
- partition(mask_expr: int | Tuple[int | EllipsisType, ...]) Tuple[Self, Self]¶
Partitions the fan into two parts using an index mask. The function will return a tuple of two fans with the first fan 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 fan 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 fan, for example (2, …) will select all intervals of the fan 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 fan.
- property pitch_diffs: List[IndexT]¶
An ordered list of pitch differences representing the fan
- retune_closest(origin_context) Self¶
Gets the interval fan in a target origin context that is closest to the frequency ratio series of this sequence.
- Parameters:
origin_context – The target origin context
- Raises:
TypeError – If the target context does not have a proper definition of a closest representation to a given frequency ratio
- to_scale(reference: FreqRepr) Scale¶
Returns a scale that has the interval structure of this fan, with the given note/pitch being the pitch mapped to the unison
- Parameters:
reference – A reference note/pitch of the same origin context
- to_seq(reference: FreqRepr) Scale¶
Returns a pitch/note fan that has the interval structure of this fan, with the given note/pitch being the pitch mapped to the unison
- Parameters:
reference – A reference note/pitch of the same origin context
- with_interval(interval: IntervalT, insert_pos: int | None = None) Self¶
Returns a new interval fan containing all intervals from this fan and the additional one given as a parameter. By default new intervals appear at the end of the fan.
- 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(fan) + 1)
- Raises:
IncompatibleOriginContexts – If interval has a different origin context than this fan
Pitch / Note Sequences¶
- class xenharmlib.core.freq_repr_seq.FreqReprSeq(origin_context, elements: Iterable[FreqReprT] | None = None)¶
FreqReprSeq is the abstract base class for all pitch/note sequence types.
In line with its Sequence superclass frequency representation 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 sequences also allow partitioning with partial, partial_not and partition.
- Parameters:
origin_context – An origin context (like a tuning or a notation)
elements – A sequence of elements from the origin context
- property frequencies¶
An ordered list of frequencies present in this sequence
- index(element, start=0, end=None, /) int¶
Return first index of element (similar to the index method of python’s list)
- Parameters:
element – The element 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 element was not found in sequence
- inversion() Self¶
Returns the inversion of this sequence, which is defined as transforming all ascending intervals in the sequence into their descending counterpart and vice versa.
- is_subseq(seq: Self, proper=False)¶
Returns True if this sequence is a subsequence of another one, False otherwise.
- Parameters:
seq – The (possible) supersequence
proper – (optional, default is False). If set to True function will return False if sequences are identical
- is_superseq(seq: Self, proper=False)¶
Returns True if this sequence is a supersequence of another one, False otherwise.
- Parameters:
seq – The (possible) subsequence
proper – (optional, default is False). If set to True function will return False if sequences are identical
- 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 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 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 sequence, for example (2, …) will select all elements of the sequence 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 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 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 sequence 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 sequence, for example (2, …) will select all elements of the sequence 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 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 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 sequence, for example (2, …) will select all elements of the sequence 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 sequence.
- retrograde() Self¶
Returns the retrograde of this sequence, which is defined as “mirroring” the sequence so the last note becomes the first note and vice versa
- retune_closest(origin_context) Self¶
Gets the sequence in a target origin context that is closest to the frequency series of this sequence.
- Parameters:
origin_context – The target origin context
- Raises:
TypeError – If the target context does not have a proper definition of a closest representation to a given frequency
- subseq_index(subseq: Self) int¶
Given a (possible) subsequence this method returns the starting index of the subsequence in this sequence or raises ValueError (if given parameter turned out not to be a subsequence)
This method works across origin contexts
- Parameters:
subseq – The subsequence to search for
- Raises:
ValueError – If subsequence was not found or an empty sequence was given as parameter
- to_interval_fan(ref: Self | None = None)¶
Returns this sequence represented as an interval fan
- to_interval_seq()¶
Returns this sequence represented as an interval sequence
- transpose(diff) Self¶
Transposes the sequence by the given difference
- with_element(element: FreqReprT, insert_pos: int | None = None) Self¶
Returns a new sequence containing all elements from this sequence and the additional one given as a parameter. By default new elements appear at the end of the sequence.
- Parameters:
element – The new element to be added to the result
insert_pos – The insertion position of the new element. 0 will insert the element at the front, 1 will insert the element at the second position, etc. (optional, default is None which results in the value len(sequence) + 1)
- Raises:
IncompatibleOriginContexts – If element has a different origin context than this sequence
- zero_normalized() Self¶
Returns the sequence transposed in a way so the first element has pitch index 0. In notations with enharmonic ambiguity a designated zero note is used (in western-like notations typically C0)
- class xenharmlib.core.freq_repr_seq.PeriodicFreqReprSeq(origin_context, elements: Iterable[FreqReprT] | None = None)¶
PeriodicFreqReprSeq is the abstract base class for frequency representation sequences that contain frequency representations of periodic tunings / notations.
- It implements the following additional methods:
transpose_bi_index
is_equivalent
- Parameters:
origin_context – An origin context (like a tuning or a notation)
elements – A list of frequency representations
- is_equivalent(other: PeriodicFreqReprSeq) bool¶
Returns True if two sequences are equivalent, i.e. every element in this sequence corresponds to another one in the other sequence at the same index.
Periodic sequences of different origin contexts can be compared if their origin contexts have the same equivalency interval. Equivalency between sequences of different contexts is defined as “equality after base interval alignment”
- Raises:
IncompatibleOriginContexts – If the other sequence has a different equivalency interval definition
- Parameters:
other – Another periodic scale
- transpose_bi_index(bi_diff: int) Self¶
Returns a sequence with the same pitch class indices and symbols, but with a transposed base interval
- Parameters:
bi_diff – The difference in base interval between this sequence and the resulting one
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[EDOPitch] = <class 'xenharmlib.core.pitch.EDOPitch'>, pitch_interval_cls: type[EDOPitchInterval] = <class 'xenharmlib.core.pitch.EDOPitchInterval'>, pitch_scale_cls: type[EDOPitchScale] = <class 'xenharmlib.core.pitch_scale.EDOPitchScale'>, pitch_interval_seq_cls: type[EDOPitchIntervalSeq] = <class 'xenharmlib.core.pitch_interval_seq.EDOPitchIntervalSeq'>, pitch_interval_fan_cls: type[EDOPitchIntervalFan] = <class 'xenharmlib.core.pitch_interval_fan.EDOPitchIntervalFan'>, pitch_seq_cls: type[EDOPitchSeq] = <class 'xenharmlib.core.pitch_seq.EDOPitchSeq'>, ref_frequency: Frequency = Frequency(<Mock name='mock.Rational()' id='130468837690256'>))¶
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 base interval
Optional keyword-only arguments
- Parameters:
ref_frequency – 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)
The following optional keyword-only arguments are only relevant if you are building your own tuning class:
- Parameters:
pitch_cls – The python class that is used for the pitch object returned from the pitch method.
pitch_interval_cls – The python class that is used for the pitch interval object returned from the interval builder methods.
pitch_scale_cls – The python class that is used for the pitch scale object returned from the scale builder methods.
pitch_interval_seq_cls – The python class that is used for the pitch interval sequence object returned from the interval sequence builder methods.
pitch_interval_fan_cls – The python class that is used for the pitch interval fan object returned from the interval fan builder methods.
pitch_seq_cls – The python class that is used for the pitch sequence object returned from the sequence builder methods.
- 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: FrequencyRatio, *, pitch_cls: type[EDPitch] = <class 'xenharmlib.core.pitch.EDPitch'>, pitch_interval_cls: type[EDPitchInterval] = <class 'xenharmlib.core.pitch.EDPitchInterval'>, pitch_scale_cls: type[EDPitchScale] = <class 'xenharmlib.core.pitch_scale.EDPitchScale'>, pitch_interval_seq_cls: type[EDPitchIntervalSeq] = <class 'xenharmlib.core.pitch_interval_seq.EDPitchIntervalSeq'>, pitch_interval_fan_cls: type[EDPitchIntervalFan] = <class 'xenharmlib.core.pitch_interval_fan.EDPitchIntervalFan'>, pitch_seq_cls: type[EDPitchSeq] = <class 'xenharmlib.core.pitch_seq.EDPitchSeq'>, ref_frequency: Frequency = Frequency(<Mock name='mock.Rational()' id='130468837690256'>))¶
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)
Optional keyword-only arguments
- Parameters:
ref_frequency – 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)
The following optional keyword-only arguments are only relevant if you are building your own tuning class:
- Parameters:
pitch_cls – The python class that is used for the pitch object returned from the pitch method.
pitch_interval_cls – The python class that is used for the pitch interval object returned from the interval builder methods.
pitch_scale_cls – The python class that is used for the pitch scale object returned from the scale builder methods.
pitch_interval_seq_cls – The python class that is used for the pitch interval sequence object returned from the interval sequence builder methods.
pitch_interval_fan_cls – The python class that is used for the pitch interval fan object returned from the interval fan builder methods.
pitch_seq_cls – The python class that is used for the pitch sequence object returned from the sequence builder methods.
- get_frequency(pitch: EDPitch) Frequency¶
Deprecated since version 0.3.0: Use the frequency property of the pitch object instead
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
- property zero_index: int¶
The zero index is a reference point, in tunings with integer indexing this is 0, in tunings with lattice indexing this is typically the zero-vector.
- class xenharmlib.core.tunings.PeriodicTuning(period_length: PeriodicIndexT, eq_ratio: FrequencyRatio, *, pitch_cls: type[PeriodicPitchT], pitch_interval_cls: type[PeriodicIntervalT], pitch_scale_cls: type[PeriodicScaleT], pitch_interval_seq_cls: type[PeriodicIntervalSeqT], pitch_interval_fan_cls: type[PeriodicIntervalFanT], pitch_seq_cls: type[PeriodicSeqT], 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 eq_diff attribute that returns the pitch difference of the equality interval:
>>> from xenharmlib import EDOTuning >>> edo12 = EDOTuning(12) >>> edo12.eq_diff 12
The constructor arguments are:
- Parameters:
period_length – The number of pitches that constitute a period (for example 12 in 12EDO)
eq_ratio – The frequency factor defining the base interval (e.g. 2 for an octave, 3/2 for a fifth)
Mandatory keyword-only argument
- Parameters:
ref_frequency – A reference frequency on which this tuning is built (i.e. the frequency of the zero element)
The following optional keyword-only arguments are only relevant if you are building your own tuning class:
- Parameters:
pitch_cls – The python class that is used for the pitch object returned from the pitch method.
pitch_interval_cls – The python class that is used for the pitch interval object returned from the interval builder methods.
pitch_scale_cls – The python class that is used for the pitch scale object returned from the scale builder methods.
pitch_interval_seq_cls – The python class that is used for the pitch interval sequence object returned from the interval sequence builder methods.
pitch_interval_fan_cls – The python class that is used for the pitch interval fan object returned from the interval fan builder methods.
pitch_seq_cls – The python class that is used for the pitch sequence object returned from the sequence builder methods.
- property eq_interval: PeriodicIntervalT¶
The equivalency interval of this tuning
- property eq_ratio: FrequencyRatio¶
The frequency ratio defining the equivalency interval
- pc_scale(pc_indices: List[PeriodicIndexT] | None = None, root_bi_index: int = 0) PeriodicScaleT¶
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.SDPeriodicTuningMixin¶
Mixin class for single-dimensional periodic tunings. Implements various methods that are only defined in the one-dimensional case.
- 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.
- class xenharmlib.core.tunings.SDTuningMixin¶
Mixin class for single-dimensional tunings. Implements various methods that are only defined in the one-dimensional case.
- closest_freq_repr(frequency: Frequency) PitchLike¶
Returns the pitch in the tuning that is closest to a given frequency
- Parameters:
frequency – The frequency in Hz
- closest_interval(frequency_ratio: FrequencyRatio) PitchIntervalLike¶
Returns the interval in the tuning that is closest to a given frequency ratio.
- Parameters:
frequency_ratio – The frequency ratio
- closest_interval_fan(frequency_ratios: Iterable[FrequencyRatio])¶
Returns the interval fan in the tuning that is closest to a given iterable of frequency ratios
- Parameters:
frequency_ratios – An iterable of frequency ratios
- closest_interval_seq(frequency_ratios: Iterable[FrequencyRatio])¶
Returns the interval sequence in the tuning that is closest to a given iterable of frequency ratios
- Parameters:
frequency_ratios – An iterable of frequency ratios
- closest_scale(frequencies: Iterable[Frequency])¶
Returns the scale in the tuning that is closest to a given iterable of frequencies
- Parameters:
frequencies – An iterable of frequencies in Hz
- closest_seq(frequencies: Iterable[Frequency])¶
Returns the pitch sequence in the tuning that is closest to a given iterable of frequencies
- Parameters:
frequencies – An iterable of frequencies in Hz
- get_approx_pitch(frequency: Frequency) PitchLike¶
Deprecated since version 0.4.0: Use
closest_freq_repr()instead.Returns the closest pitch in the tuning to a given frequency.
- Parameters:
frequency – The frequency in Hz
- 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)
- 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], pitch_interval_fan_cls: type[IntervalFanT], pitch_seq_cls: type[SeqT], 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_for_index()and and setting appropriate constructor arguments.Mandatory keyword-only argument:
- Parameters:
ref_frequency – Frequency of the zero pitch (pitch with pitch index 0, or in case of lattice points the 0 vector)
Optional keyword-only arguments: (only relevant if you want to develop your own custom tuning class inheriting from this class)
- Parameters:
pitch_cls – The python class that is used for the pitch object returned from the pitch method.
pitch_interval_cls – The python class that is used for the pitch interval object returned from the interval builder methods.
pitch_scale_cls – The python class that is used for the pitch scale object returned from the scale builder methods.
pitch_interval_seq_cls – The python class that is used for the pitch interval sequence object returned from the interval sequence builder methods.
pitch_interval_fan_cls – The python class that is used for the pitch interval fan object returned from the interval fan builder methods.
pitch_seq_cls – The python class that is used for the pitch sequence object returned from the sequence builder methods.
- abstractmethod get_frequency_for_index(pitch_index: IndexT) Frequency¶
(Must be overwritten by subclasses) Returns the frequency for a given pitch index
- index_scale(pitch_indices: Iterable[IndexT] | None = None) ScaleT¶
Constructs a pitch scale from an iterable 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 – An iterable of pitch indices
- index_seq(pitch_indices: Iterable[IndexT] | None = None) SeqT¶
Constructs a pitch sequence from an iterable of pitch indices.
- Parameters:
pitch_indices – An iterable of pitch indices
- pitch(pitch_index: IndexT) 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_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: PeriodicIndexT)¶
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: IndexT, ref_pitch: PitchT)¶
Pitch intervals class for ‘equal division of the octave’ pitches
- class xenharmlib.core.pitch.EDPitch(tuning, frequency, pitch_index: PeriodicIndexT)¶
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: IndexT, ref_pitch: PitchT)¶
Pitch interval class for equal division tunings
- class xenharmlib.core.pitch.PeriodicPitch(tuning, frequency, pitch_index: PeriodicIndexT)¶
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: int¶
The base interval index 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: PeriodicIndexT¶
The pitch class index of this pitch
- pcs_normalized() Self¶
Returns the equivalent of this pitch in the first base interval
- 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: IndexT, ref_pitch: PitchT)¶
The pitch interval class for periodic tunings.
- property ic_index: PeriodicIndexT¶
Returns the interval class index of this interval (often simply called “interval class” or “ic”) as known from pitch class set theory.
The interval class is the shortest distance in pitch class space between two unordered pitch classes.
It is calculated by comparing the absolute value of the simple portion of the interval and its inversion, returning whatever pitch difference is smaller, so e.g. in 12-EDO the ic class for P5 is min(7, 5) = 5
- ic_normalized() Self¶
Returns an interval class normalized version of this interval. The interval normalized version is calculated by converting (if necessary) this interval into a simple interval, normalizing it to a upwards interval and then building the minimum from that result and its inversion.
- inversion() Self¶
Returns the inversion of this interval. The inversion is calculated by subtracting this interval from the equivalency interval.
- property is_compound: bool¶
Returns True if this interval is a compound interval, False otherwise. A compound interval is defined as an interval whose absolute value is strictly greater than the equivalency interval (meaning the equivalency interval itself and its negation are not considered compound)
- property is_simple: bool¶
Returns True if this interval is a simple interval, False otherwise. A simple interval is defined as an interval whose absolute value is lesser or equal than the equivalency interval (meaning the equivalency interval itself and its negation are considered a simple interval)
- to_simple() Self¶
Returns the corresponding simple interval if this is a compound interval (or the interval itself if it is already simple)
The method preserves direction, so if this interval is a downward interval, the resulting interval will also be a downward interval.
- class xenharmlib.core.pitch.Pitch(tuning, frequency, pitch_index: IndexT)¶
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)
- retune(tuning: SDTuningLike) Self¶
Deprecated since version 0.4.0: Use
retune_closest()instead.Gets the frequency representation in a given origin context that is closest to the frequency of this object.
- Parameters:
origin_context – The target origin context
- Raises:
TypeError – If the target tuning does not have a proper definition of a closest representation to a given frequency
- 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: IndexT | 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: IndexT, 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.
- 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: Iterable[PitchT] | None = None)¶
Pitch scale class for ‘equal division of the octave’ tunings
- class xenharmlib.core.pitch_scale.EDPitchScale(tuning, pitches: Iterable[PitchT] | None = None)¶
Pitch scale class for equal division tunings
- class xenharmlib.core.pitch_scale.PeriodicPitchScale(tuning, pitches: Iterable[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[PeriodicIndexT]¶
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
- class xenharmlib.core.pitch_scale.PitchScale(tuning, pitches: Iterable[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: IndexT)¶
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[IndexT], tuning) Self¶
Deprecated since version 0.3.0: Use
index_scale()instead.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[IndexT]¶
A list of the ordered pitch indices present in this scale
- retune(tuning) PitchScale¶
Deprecated since version 0.4.0: Use
retune_closest()instead.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_interval_seq()instead.Returns this scale represented as a list of pitch intervals
- transpose(diff: IndexT | PitchInterval[IndexT, PitchT]) Self¶
Transposes the scale upwards or downwards
- Parameters:
diff – The difference from this pitch. Can be either a pitch index difference (positive for upward movement, negative for downward movement) or a pitch interval
Multi-Generator Tunings¶
This module implements tunings and musical objects relating to multi-generator tunings.
A multi-generator tuning describes the frequency space as a lattice in which each integer vector \((x_1, ..., x_n)\) represents the exponents in the expression g_1^{x_1} cdot … cdot g_n^{x_n} built from a generator vector \((g_1, ..., g_n)\)
Multi-generator tunings are an abstraction of JI prime limit tuning classes, that can hold arbitrary generators. Because of this they have multiple applications in temperament theory.
- class xenharmlib.core.multigen.MultiGenPitch(tuning, frequency, pitch_index: PeriodicIndexT)¶
- property short_repr: str¶
(Must be implemented by subclasses) A shortened representation of this note (to be used in collection objects like scales)
- class xenharmlib.core.multigen.MultiGenPitchInterval(tuning, frequency_ratio: FrequencyRatio, pitch_diff: IndexT, ref_pitch: PitchT)¶
- property short_repr: str¶
A short string representation of the interval (must be implemented by subclass)
- class xenharmlib.core.multigen.MultiGenPitchIntervalFan(tuning, intervals: Iterable[PitchIntervalT] | None = None)¶
- class xenharmlib.core.multigen.MultiGenPitchIntervalSeq(tuning, intervals: Iterable[PitchIntervalT] | None = None)¶
- class xenharmlib.core.multigen.MultiGenPitchScale(tuning, pitches: Iterable[PitchT] | None = None)¶
- class xenharmlib.core.multigen.MultiGenPitchSeq(tuning, elements: Iterable[PitchT] | None = None)¶
- class xenharmlib.core.multigen.MultiGenTuning(generators: ~typing.Tuple[~xenharmlib.core.frequencies.FrequencyRatio, ...], eq_diff_vec: ~typing.Tuple[int, ...], ref_frequency: ~xenharmlib.core.frequencies.Frequency = Frequency(<Mock name='mock.Rational()' id='130468837690256'>), pitch_cls: type[~xenharmlib.core.multigen.MultiGenPitchT] = <class 'xenharmlib.core.multigen.MultiGenPitch'>, pitch_interval_cls: type[~xenharmlib.core.multigen.MultiGenIntervalT] = <class 'xenharmlib.core.multigen.MultiGenPitchInterval'>, pitch_scale_cls: type[~xenharmlib.core.multigen.MultiGenScaleT] = <class 'xenharmlib.core.multigen.MultiGenPitchScale'>, pitch_interval_seq_cls: type[~xenharmlib.core.multigen.MultiGenIntervalSeqT] = <class 'xenharmlib.core.multigen.MultiGenPitchIntervalSeq'>, pitch_interval_fan_cls: type[~xenharmlib.core.multigen.MultiGenIntervalFanT] = <class 'xenharmlib.core.multigen.MultiGenPitchIntervalFan'>, pitch_seq_cls: type[~xenharmlib.core.multigen.MultiGenSeqT] = <class 'xenharmlib.core.multigen.MultiGenPitchSeq'>)¶
Base class for multi-generator tunings. A multi-generator tuning describes the frequency space as a lattice in which each integer vector \((x_1, ..., x_n)\) represents the exponents in the expression g_1^{x_1} cdot … cdot g_n^{x_n} built from a generator vector \((g_1, ..., g_n)\)
- Parameters:
generators – A tuple of frequency ratios that constitutes the generator vector of this tuning
eq_diff_vec – A vector of integers that defines the pitch difference of the interval that should be considered the equivalence interval, so for example in a pythagorean tuning with generators 2 and 3, this should be (1, 0) for the octave.
ref_frequence – A reference frequency for the zero index (optional, defaults to the frequency for C0 in EDO tunings for A4 = 440 Hz (about 16.35 Hz))
- closest_freq_repr(frequency: Frequency)¶
Returns the frequency representation closest to a given frequency. Raises TypeError in here, because a closest frequency representation does not exist in the general case for multi-generator tunings.
- closest_interval(frequency_ratio: FrequencyRatio)¶
Returns the interval closest to a given frequency ratio Raises TypeError in here, because a closest interval does not exist in the general case for multi-generator tunings.
- closest_interval_fan(frequency_ratios: Iterable[FrequencyRatio])¶
Returns the interval fan closest to a given iterable of frequency ratios. Raises TypeError in here, because a closest interval sequence does not exist in the general case for multi-generator tunings.
- closest_interval_seq(frequency_ratios: Iterable[FrequencyRatio])¶
Returns the interval sequence closest to a given iterable of frequency ratios. Raises TypeError in here, because a closest interval sequence does not exist in the general case for multi-generator tunings.
- closest_scale(frequencies: Iterable[Frequency])¶
Returns the scale closest to a given iterable of frequencies Raises TypeError in here, because a closest scale does not exist in the general case for multi-generator tunings.
- closest_seq(frequencies: Iterable[Frequency])¶
Returns the sequence closest to a given iterable of frequencies Raises TypeError in here, because a closest scale does not exist in the general case for multi-generator tunings.
- diff_interval(pitch_diff: LatticePoint) MultiGenIntervalT¶
Returns an interval the size of a given pitch index difference.
- Parameters:
pitch_diff – The pitch index difference
- get_frequency_for_index(pitch_index: LatticePoint) Frequency¶
Returns the frequency for a given pitch index
- vec_interval(vector: Tuple[int, ...]) MultiGenIntervalT¶
Convenience function to create an interval from an integer vector defining the exponents of the generators of this tuning, so for example in a pythagorean tuning with generators 2 and 3 input parameter (-1, 1) produces the perfect fifth interval
- Parameters:
vector – An integer tuple
- vec_interval_fan(vectors: Iterable[Tuple[int, ...]] | None = None) MultiGenIntervalFanT¶
Convenience function to create an interval fan from an iterable of integer vectors defining all the exponents of the generators of each respective interval in the sequence, so for example in a pythagorean tuning with generators 2 and 3 the value [(0, 0), (-7, 4), (-1, 1)] produces the interval fan of the major triad.
- Parameters:
vectors – An iterable of integer tuples
- vec_interval_seq(vectors: Iterable[Tuple[int, ...]] | None = None) MultiGenIntervalSeqT¶
Convenience function to create an interval sequence from an iterable of integer vectors defining all the exponents of the generators of each respective interval in the sequence, so for example in a pythagorean tuning with generators 2 and 3 the value [(-7, 4), (6, -3)] produces the interval sequence of the major triad.
- Parameters:
vectors – An iterable of integer tuples
- vec_pitch(vector: Tuple[int, ...]) MultiGenPitchT¶
Convenience function to create a pitch from an integer vector defining the exponents of the generators of this tuning, so for example in a pythagorean tuning with generators 2 and 3 input parameter (-1, 1) produces the pitch equivalent to the note G0
- Parameters:
vector – An integer tuple
- vec_scale(vectors: Iterable[Tuple[int, ...]] | None = None) MultiGenScaleT¶
Convenience function to create a scale from an iterable of integer vectors defining all the exponents of the generators of each respective pitch in the scale, so for example in a pythagorean tuning with generators 2 and 3 the value [(0, 0), (-7, 4), (-1, 1)] produces the C0 major triad.
- Parameters:
vectors – An iterable of integer tuples
- vec_seq(vectors: Iterable[Tuple[int, ...]] | None = None) MultiGenSeqT¶
Convenience function to create a sequence from an iterable of integer vectors defining all the exponents of the generators of each respective pitch in the sequence, so for example in a pythagorean tuning with generators 2 and 3 the value [(0, 0), (-7, 4), (-1, 1)] produces the C0 major triad sequence
- Parameters:
vectors – An iterable of integer tuples
- property zero_index: LatticePoint¶
The lattice point representing the zero index
Prime-Limit Tunings¶
This module implements tunings in which pitches and intervals are formed by using consecutive prime numbers as generators up until to a specified prime (the “prime limit”).
- class xenharmlib.core.primelimit.PrimeLimitPitch(tuning, frequency, pitch_index: PeriodicIndexT)¶
The pitch type for prime limit tunings
- Parameters:
tuning – The tuning to which this pitch belongs to
frequency – The frequency this pitch represents
pitch_index – An lattice point denoting the pitch
- property monzo: Tuple[int, ...]¶
Returns the monzo of this pitch. A monzo is a tuple of exponents for the prime number generator vector, e.g. in 5-Limit for 5/4 = 2**(-2) * 3**(0) * 5**(1) the monzo is (-2, 0, 1)
- property pc_short_repr: str¶
A shortened representation string of the pitch class ratio of this pitch
- property short_repr: str¶
A shortened representation string of this pitch without any type prefix
- class xenharmlib.core.primelimit.PrimeLimitPitchInterval(tuning, frequency_ratio: FrequencyRatio, pitch_diff: IndexT, ref_pitch: PitchT)¶
The pitch interval type for prime limit tunings
- 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.
- property monzo: Tuple[int, ...]¶
Returns the monzo of this pitch. A monzo is a tuple of exponents for the prime number generator vector, e.g. in 5-Limit for 5/4 = 2**(-2) * 3**(0) * 5**(1) the monzo is (-2, 0, 1)
- property short_repr: str¶
A shortened representation string of the frequency ratio of this interval
- class xenharmlib.core.primelimit.PrimeLimitPitchIntervalFan(tuning, intervals: Iterable[PitchIntervalT] | None = None)¶
The pitch interval fan type for prime limit tunings
- property monzos: List[Tuple[int, ...]]¶
Returns the monzos of the intervals in this interval fan. A monzo is a tuple of exponents for the prime number generator vector, e.g. in a 5-Limit tuning fan for 5/4 = 2**(-2) * 3**(0) * 5**(1) the monzo is (-2, 0, 1)
- to_ec_expr() str¶
Transforms this interval fan into an enumerated chord expression e.g. [1/1, 5/4, 3/2] into ‘4:5:6’
An enumerated chord expression is a short form to notate frequency ratios of an interval fan as a sequence of integers where each integer is divided by the first integer.
- Raises:
ValueError – If fan includes less than two intervals
ValueError – If fan does not start with unison interval
- class xenharmlib.core.primelimit.PrimeLimitPitchIntervalSeq(tuning, intervals: Iterable[PitchIntervalT] | None = None)¶
The pitch interval sequence type for prime limit tunings
- property monzos: List[Tuple[int, ...]]¶
Returns the monzos of the intervals in this interval sequence. A monzo is a tuple of exponents for the prime number generator vector, e.g. in a 5-Limit tuning sequence for 5/4 = 2**(-2) * 3**(0) * 5**(1) the monzo is (-2, 0, 1)
- class xenharmlib.core.primelimit.PrimeLimitPitchScale(tuning, pitches: Iterable[PitchT] | None = None)¶
The pitch scale type for prime limit tunings
- property monzos: List[Tuple[int, ...]]¶
Returns the monzos of the pitches in this scale. A monzo is a tuple of exponents for the prime number generator vector, e.g. in a 5-Limit tuning scale for 5/4 = 2**(-2) * 3**(0) * 5**(1) the monzo is (-2, 0, 1)
- class xenharmlib.core.primelimit.PrimeLimitPitchSeq(tuning, elements: Iterable[PitchT] | None = None)¶
The pitch sequence type for prime limit tunings
- property monzos: List[Tuple[int, ...]]¶
Returns the monzos of the pitches in this sequence. A monzo is a tuple of exponents for the prime number generator vector, e.g. in a 5-Limit tuning sequence for 5/4 = 2**(-2) * 3**(0) * 5**(1) the monzo is (-2, 0, 1)
- class xenharmlib.core.primelimit.PrimeLimitTuning(prime_limit: int, eq_diff_vec: Tuple[int, ...] | None=None, *, ref_frequency: Frequency = Frequency(<Mock name='mock.Rational()' id='130468837690256'>), pitch_cls: type[PrimeLimitPitchT] = <class 'xenharmlib.core.primelimit.PrimeLimitPitch'>, pitch_interval_cls: type[PrimeLimitIntervalT] = <class 'xenharmlib.core.primelimit.PrimeLimitPitchInterval'>, pitch_scale_cls: type[PrimeLimitScaleT] = <class 'xenharmlib.core.primelimit.PrimeLimitPitchScale'>, pitch_interval_seq_cls: type[PrimeLimitIntervalSeqT] = <class 'xenharmlib.core.primelimit.PrimeLimitPitchIntervalSeq'>, pitch_interval_fan_cls: type[PrimeLimitIntervalFanT] = <class 'xenharmlib.core.primelimit.PrimeLimitPitchIntervalFan'>, pitch_seq_cls: type[PrimeLimitSeqT] = <class 'xenharmlib.core.primelimit.PrimeLimitPitchSeq'>)¶
A prime limit tuning is a multi-generator tuning in which the generator vector consists of consecutive primes up to a certain point (the prime limit), so for example a 7-Limit tuning spans a frequency space with generators (2, 3, 5, 7)
- Parameters:
prime_limit – The last prime number in the sequence of consecutive prime numbers which form the generator vector
ref_frequency – A reference frequency defining the frequency of the zero index (optional, defaults to the frequency of C0 for A4=440 in 12-EDO)
eq_diff_vec – (optional) A vector of integers that defines the pitch difference of the interval that should be considered the equivalence interval, so for example in a 5 limit tuning with generators (2, 3, 5), this should be (1, 0, 0) for the octave, (0, 1, 0) for the tritave, etc. If parameter is omitted the octave is assumed to be the equivalence interval
- ec_interval_fan(expr: str) PrimeLimitIntervalFanT¶
Creates an interval fan from an enumerated chord expression, e.g. ‘4:5:6’ ^= [4/4, 5/4, 6/4] ^= [1/1, 5/4, 3/2]
An enumerated chord expression is a short form to notate frequency ratios of an interval fan as a sequence of integers where each integer is divided by the first integer.
- Parameters:
expr – An expression of the form ‘4:5:6’
- Raises:
ValueError – If expression string is invalid
ValueError – If expression contains a number that violates the prime limit of this tuning
- property prime_limit: int¶
The highest prime number in the sequence of consecutive prime number frequency ratios that forms the generator vector
- ratio_interval(frequency_ratio: FrequencyRatio) PrimeLimitIntervalT¶
Convenience function to create an interval from a frequency ratio. The frequency ratio must be an element of the rational numbers and its biggest prime factor must not exceed the prime limit of this tuning.
- Parameters:
frequency_ratio – A frequency ratio object
- Raises:
ValueError – If biggest prime factor exceeds the limit
- ratio_interval_fan(frequency_ratios: Iterable[FrequencyRatio] | None = None) PrimeLimitIntervalFanT¶
Convenience function to create an interval fan from an iterable of frequency ratios. The frequency ratios must all be elements of the rational numbers and their biggest prime factors must not exceed the prime limit of this tuning.
- Parameters:
frequency_ratios – An iterable of frequency ratio objects
- Raises:
ValueError – If a prime factor of one of the frequency ratios exceeds the prime limit of this tuning
- ratio_interval_seq(frequency_ratios: Iterable[FrequencyRatio] | None = None) PrimeLimitIntervalSeqT¶
Convenience function to create an interval sequence from an iterable of frequency ratios. The frequency ratios must all be elements of the rational numbers and their biggest prime factors must not exceed the prime limit of this tuning.
- Parameters:
frequency_ratios – An iterable of frequency ratio objects
- Raises:
ValueError – If a prime factor of one of the frequency ratios exceeds the prime limit of this tuning
- ratio_pc_scale(pc_frequency_ratios: Iterable[FrequencyRatio] | None = None, root_bi_index: int = 0) PrimeLimitScaleT¶
Constructs a scale from a list of frequency ratios representing successive pitch classes (meaning all ratios have to be between the unison ratio (1/1) and the equivalency ratio). The pitch class ratios are assumed to be in the order they appear in the scale, meaning that the following expression will result in the G-B-D triad:
>>> from xenharmlib import PrimeLimitTuning >>> >>> tuning = PrimeLimitTuning(5) >>> scale = tuning.ratio_pc_scale( ... [ ... FrequencyRatio(3, 2), ... FrequencyRatio(15, 8), ... FrequencyRatio(10, 9) ... ], ... )
- Parameters:
ratio_strs – A list of ratio string expressions
root_bi_index – The base interval index of the root pitch (optional, defaults to 0)
- Raises:
ValueError – If one of the frequency ratios is not between the unison ratio and the equivalency ratio
ValueError – If a prime factor of one of the frequency ratios exceeds the prime limit of this tuning
- ratio_pitch(frequency_ratio: FrequencyRatio) PrimeLimitPitchT¶
Convenience function to create a pitch from a frequency ratio defining the resulting pitch by the interval from the zero element.
The frequency ratio must be an element of the rational numbers and its biggest prime factor must not exceed the prime limit of this tuning.
- Parameters:
frequency_ratio – A frequency ratio object
- Raises:
ValueError – If biggest prime factor exceeds the limit
- ratio_scale(frequency_ratios: Iterable[FrequencyRatio] | None = None) PrimeLimitScaleT¶
Convenience function to create a scale from an iterable of frequency ratios, all refering to the interval distance of the scale pitches to the zero element, e.g. in 5 limit tuning, creating a major chord on C1 can be done like this:
>>> from xenharmlib import PrimeLimitTuning >>> >>> tuning = PrimeLimitTuning(5) >>> scale = tuning.ratio_scale( ... [FrequencyRatio(2, 1), FrequencyRatio(5, 2), FrequencyRatio(3)], ... ) >>> scale PrimeLimitPitchScale([2, 5/2, 3], 5-Limit)
- Parameters:
frequency_ratios – An iterable of frequency ratio objects
- Raises:
ValueError – If a prime factor of one of the frequency ratios exceeds the prime limit of this tuning
- ratio_seq(frequency_ratios: Iterable[FrequencyRatio] | None = None) PrimeLimitSeqT¶
Convenience function to create a sequence from an iterable of frequency ratios, all refering to the interval distance of the sequence pitches to the zero element, e.g. in 5 limit tuning, creating a major chord sequence on C1 can be done like this:
>>> from xenharmlib import PrimeLimitTuning >>> >>> tuning = PrimeLimitTuning(5) >>> scale = tuning.ratio_seq( ... [FrequencyRatio(2, 1), FrequencyRatio(5, 2), FrequencyRatio(3)], ... ) >>> scale PrimeLimitPitchSeq([2, 5/2, 3], 5-Limit)
- Parameters:
frequency_ratios – An iterable of frequency ratio objects
- Raises:
ValueError – If a prime factor of one of the frequency ratios exceeds the prime limit of this tuning
- rs_interval(ratio_str: str) PrimeLimitIntervalT¶
Convenience function to create an interval from a frequency ratio string expression. String expressions can be two natural numbers separated by a slash (e.g. ‘5/4’) or a single number (e.g. ‘3’, refering to the 3/1 ratio)
- Parameters:
ratio_str – The ratio string expression
- Raises:
ValueError – If a prime factor of the frequency ratio exceeds the prime limit of this tuning
ValueError – If expression was ill-formatted
- rs_interval_fan(ratio_strs: Iterable[str] | None = None) PrimeLimitIntervalFanT¶
Convenience function to create an interval fan from an iterable of frequency ratio string expressions. String expressions can be two natural numbers separated by a slash (e.g. ‘5/4’) or a single number (e.g. ‘3’, refering to the 3/1 ratio)
- Parameters:
ratio_strs – A list of ratio string expressions
- Raises:
ValueError – If a prime factor of one of the frequency ratios exceeds the prime limit of this tuning
ValueError – If expression was ill-formatted
- rs_interval_seq(ratio_strs: Iterable[str] | None = None) PrimeLimitIntervalSeqT¶
Convenience function to create an interval sequence from an iterable of frequency ratio string expressions. String expressions can be two natural numbers separated by a slash (e.g. ‘5/4’) or a single number (e.g. ‘3’, refering to the 3/1 ratio)
- Parameters:
ratio_strs – A list of ratio string expressions
- Raises:
ValueError – If a prime factor of one of the frequency ratios exceeds the prime limit of this tuning
ValueError – If expression was ill-formatted
- rs_pc_scale(ratio_strs: Iterable[str] | None = None, root_bi_index: int = 0) PrimeLimitScaleT¶
Constructs a scale from a list of frequency ratios given as strings representing successive pitch classes (meaning all ratios have to be between the unison ratio (1/1) and the equivalency ratio). The pitch class ratios are assumed to be in the order they appear in the scale, meaning that the following expression will result in the G-B-D triad:
>>> from xenharmlib import PrimeLimitTuning >>> >>> tuning = PrimeLimitTuning(5) >>> tuning.rs_pc_scale(['3/2', '15/8', '10/9']) PrimeLimitPitchScale([3/2, 15/8, 20/9], 5-Limit)
- Parameters:
ratio_strs – A list of ratio string expressions
root_bi_index – The base interval index of the root pitch (optional, defaults to 0)
- Raises:
ValueError – If one of the frequency ratios is not between the unison ratio and the equivalency ratio
ValueError – If a prime factor of one of the frequency ratios exceeds the prime limit of this tuning
ValueError – If expression was ill-formatted
- rs_pitch(ratio_str: str) PrimeLimitPitchT¶
Convenience function to create a pitch from a frequency ratio string expression, defining the resulting pitch by the interval from the zero element. String expressions can be two natural numbers separated by a slash (e.g. ‘5/4’) or a single number (e.g. ‘3’, refering to the 3/1 ratio)
- Parameters:
ratio_str – The ratio string expression
- Raises:
ValueError – If a prime factor of the frequency ratio exceeds the prime limit of this tuning
ValueError – If expression was ill-formatted
- rs_scale(ratio_strs: Iterable[str] | None = None) PrimeLimitScaleT¶
Convenience function to create a scale from an iterable of frequency ratio expressions, all refering to the interval distance of the scale pitches to the zero element, e.g. in 5 limit tuning, creating a major chord on C1 can be done like this:
>>> from xenharmlib import PrimeLimitTuning >>> >>> tuning = PrimeLimitTuning(5) >>> tuning.rs_scale(['2', '5/2', '3']) PrimeLimitPitchScale([2, 5/2, 3], 5-Limit)
- Parameters:
ratio_strs – A list of ratio string expressions
- Raises:
ValueError – If a prime factor of one of the frequency ratios exceeds the prime limit of this tuning
ValueError – If expression was ill-formatted
- rs_seq(ratio_strs: Iterable[str] | None = None) PrimeLimitSeqT¶
Convenience function to create a sequence from an iterable of frequency ratio expressions, all refering to the interval distance of the sequence pitches to the zero element, e.g. in 5 limit tuning, creating a major chord sequence on C1 can be done like this:
>>> from xenharmlib import PrimeLimitTuning >>> >>> tuning = PrimeLimitTuning(5) >>> tuning.rs_seq(['2', '5/2', '3']) PrimeLimitPitchSeq([2, 5/2, 3], 5-Limit)
- Parameters:
ratio_strs – A list of ratio string expressions
- Raises:
ValueError – If a prime factor of one of the frequency ratios exceeds the prime limit of this tuning
ValueError – If expression was ill-formatted
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, acc_weights: ~typing.Tuple[~xenharmlib.core.notation.PeriodicIndexT, ...], *, 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'>, note_interval_fan_cls: type[~xenharmlib.core.note_interval_fan.NatAccNoteIntervalFan] = <class 'xenharmlib.core.note_interval_fan.NatAccNoteIntervalFan'>, note_seq_cls: type[~xenharmlib.core.note_seq.NatAccNoteSeq] = <class 'xenharmlib.core.note_seq.NatAccNoteSeq'>)¶
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
acc_weight – A vector defining a mapping between the (unweighted) accidental sum vector and the (weighted) accidental diff vector
Additional, optional keyword-only arguments: (only relevant if you want to develop your own notation)
- Parameters:
note_cls – The python class that is used for the note object returned from the note method.
note_interval_cls – The python class that is used for the note interval object returned from the interval builder methods.
note_scale_cls – The python class that is used for the note scale object returned from the scale builder methods.
note_interval_seq_cls – The python class that is used for the note interval sequence object returned from the interval sequence builder methods.
note_interval_fan_cls – The python class that is used for the note interval fan object returned from the interval fan builder methods.
note_seq_cls – The python class that is used for the note sequence object returned from the sequence builder methods.
- acc_diff_vector_to_acc_sum_vector(acc_diff_vector: Tuple[PeriodicIndexT, ...]) Tuple[int, ...]¶
Transforms a (weighted) accidental diff vector into a (unweighted) accidental sum vector.
- Raises:
ValueError – If dimensions of accidental diff vector do not match the weighting vector dimensions of this notation
ValueError – If accidental diff vector is not in the image of the accidental weight mapping of this notation
- Parameters:
acc_diff_vector – The accidental diff vector
- acc_sum_vector_to_acc_diff_vector(acc_sum_vector: Tuple[int, ...]) Tuple[PeriodicIndexT, ...]¶
Transforms an (unweighted) accidental sum vector into a (weighted) accidental diff vector.
- Raises:
ValueError – If dimensions of accidental sum vector do not match the weighting vector dimensions of this notation
- Parameters:
acc_sum_vector – The accidental sum vector
- property acc_symbol_code: SymbolCode¶
The symbol code for the accidentals. Must be set by the subclass constructor
- property acc_weights: Tuple[PeriodicIndexT, ...]¶
The weight vector that transforms the accidental sum vector into the accidental diff vector
- append_natural(natc_symbol: str, natc_pitch_index: PeriodicIndexT)¶
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
- property eq_diff: PeriodicIndexT¶
The pitch difference of the equivalency interval of this notation
- property eq_interval: NatAccNoteInterval¶
The equivalency interval of this notation
- gen_pc_symbol(natc_index: int, acc_sum_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_sum_vector – An (unweighted) accidental sum vector
- get_acc_sum_balance_vector(delta: PeriodicIndexT) Tuple[int, ...]¶
Returns an accidental sum balance vector for a pitch difference delta. By default this function assumes that pitch difference deltas introduced on transposition or interval determination can be counter-balanced by changing the first dimension of the accidental sum vector (e.g. B0 + P5 = F#1). If your subclassed notation does this differently you need to change this behavior by overwriting the method in your class.
- Parameters:
delta – The delta in pitch difference
- get_acc_symbol(acc_sum_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_sum_vector – The (unweighted) accidental sum vector
- get_interval_symbol(nat_diff: int, acc_sum_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_sum_vector – The (unweighted) accidental sum 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: PeriodicIndexT) 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) PeriodicIndexT¶
Returns the pitch class index a natural index refers to
- Parameters:
nat_index – A natural index
- nat_index_to_pitch_index(nat_index: int) PeriodicIndexT¶
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[PeriodicIndexT]¶
A sorted list of natural class pitch class indices that are present in this notation
- property natc_pitch_indices: List[PeriodicIndexT]¶
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_sum_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_sum_vector – The (unweighted) accidental sum 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_sum_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) PeriodicIndexT¶
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], note_interval_fan_cls: type[IntervalFanT], note_seq_cls: type[NoteSeqT])¶
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 or lattice point system.
- Parameters:
tuning – The tuning for which the notation should be constructed
Additional, optional keyword-only arguments: (only relevant if you want to develop your own notation)
- Parameters:
note_cls – The python class that is used for the note object returned from the note method.
note_interval_cls – The python class that is used for the note interval object returned from the interval builder methods.
note_scale_cls – The python class that is used for the note scale object returned from the scale builder methods.
note_interval_seq_cls – The python class that is used for the note interval sequence object returned from the interval sequence builder methods.
note_interval_fan_cls – The python class that is used for the note interval fan object returned from the interval fan builder methods.
note_seq_cls – The python class that is used for the note sequence object returned from the sequence builder methods.
- closest_freq_repr(frequency: Frequency) NoteT¶
Returns the closest note in the notation to a given frequency.
- Parameters:
frequency – The frequency in Hz
- closest_interval(frequency_ratio: FrequencyRatio) IntervalT¶
Returns the interval closest to a given frequency ratio
- Parameters:
frequency_ratio – The frequency ratio to approximate
- closest_interval_fan(frequency_ratios: Iterable[FrequencyRatio]) IntervalFanT¶
Returns the interval fan closest to a given iterable of frequency ratios.
- Parameters:
frequency_ratios – An iterable of frequency ratios
- closest_interval_seq(frequency_ratios: Iterable[FrequencyRatio]) IntervalSeqT¶
Returns the interval sequence closest to a given iterable of frequency ratios.
- Parameters:
frequency_ratios – An iterable of frequency ratios
- closest_scale(frequencies: Iterable[Frequency]) ScaleT¶
Returns the scale closest to a given iterable of frequencies
- Parameters:
frequencies – An iterable of frequencies given in Hz
- closest_seq(frequencies: Iterable[Frequency]) NoteSeqT¶
Returns the note sequence closest to a given iterable of frequencies
- Parameters:
frequencies – An iterable of frequencies given in Hz
- diff_interval_fan(pitch_diffs: Iterable[IndexT] | None = None) IntervalFanT¶
Returns a note interval fan from an iterable of pitch index differences
- Parameters:
pitch_diffs – An iterable containing pitch index differences
- diff_interval_seq(pitch_diffs: Iterable[IndexT] | None = None) IntervalSeqT¶
Returns an interval sequence from an iterable of pitch index differences
- Parameters:
pitch_diffs – An iterable containing pitch index differences
- 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) IntervalT¶
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_interval_fan(pitch_interval_fan) IntervalFanT¶
Guesses a note interval fan from a pitch interval fan using the preferred enharmonic strategy of this notation
- Pitch_interval_fan:
A pitch interval fan object originating from the underlying tuning
- guess_note_interval_seq(pitch_interval_seq) IntervalSeqT¶
Guesses a note interval sequence from a pitch interval sequence using the preferred enharmonic strategy of this notation
- Pitch_interval_seq:
A pitch interval sequence object originating from the underlying tuning
- guess_note_scale(pitch_scale) ScaleT¶
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
- guess_note_seq(pitch_seq) NoteSeqT¶
Guesses a note sequence from a pitch sequence using the preferred enharmonic strategy of this notation
- Pitch_seq:
A pitch sequence object originating from the underlying tuning
- index_scale(pitch_indices: Iterable[IndexT] | None = None) ScaleT¶
Constructs a note scale from a list of pitch indices.
- Parameters:
pitch_indices – A list of pitch indices
- index_seq(pitch_indices: Iterable[IndexT] | None = None) NoteSeqT¶
Constructs a note sequence from a list of pitch indices.
- Parameters:
pitch_indices – A list of pitch indices
- 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_sum_vector: Tuple[int, ...], acc_diff_vector: Tuple[PeriodicIndexT, ...], 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_sum_vector – An (unweighted) vector detailing the different deviations that were introduced through accidentals
acc_diff_vector – An (weighted) vector detailing the different pitch deviations 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[PeriodicIndexT, ...])¶
Deprecated since version 0.4.0: Use
add_acc_diff_vector()instead.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_diff_vector: Tuple[PeriodicIndexT, ...]¶
The (weighted) accidental diff vector of this note
- 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_sum_vector: Tuple[int, ...]¶
The (unweighted) accidental sum vector of this note
- property acc_symbol: str¶
The symbol for the accidental of this note
- property acc_value: PeriodicIndexT¶
The accidental value of this note (e.g. in 31edo 2 for #, -2 for b, 0 for natural)
- property acc_vector: Tuple[PeriodicIndexT, ...]¶
Deprecated since version 0.4.0: Use
acc_diff_vector()instead.The accidental diff vector of this note
- add_acc_diff_vector(acc_diff_vector: Tuple[PeriodicIndexT, ...])¶
Returns a note with altered accidentals by combining the accidental diff vector of this note with a given accidental diff vector.
The accidental diff vector counts the aggregated pitch difference introduced by each set of independent accidentals, for example the pitch difference introduced by all accidentals in the sharp/flat set in the first dimension and the pitch difference introduced by all accidentals in the up/down set in the second dimension
An example in 31-EDO UpDownNotation (where sharps/flats introduce a pitch alteration of 2/-2 respectively)
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> >>> edo31 = EDOTuning(31) >>> n_edo31 = UpDownNotation(edo31) >>> C = n_edo31.note('C', 0) >>> C.add_acc_diff_vector((-2, 1)) UpDownNote(^Cb, 0, 31-EDO) >>> sharpened = C.add_acc_diff_vector((2, 0)) >>> sharpened UpDownNote(C#, 0, 31-EDO) >>> sharpened.pitch_index - C.pitch_index 2 >>> invalid = C.add_acc_diff_vector((1, 0)) Traceback (most recent call last): ... ValueError: accidental diff vector is not in the image of the accidental weight mapping
- Parameters:
acc_diff_vector – The accidental diff vector to be added
- add_acc_sum_vector(acc_sum_vector: Tuple[int, ...])¶
Returns a note with altered accidentals by combining the accidental sum vector of this note with a given accidental sum vector.
The accidental sum vector counts the aggregated values of each set of independent accidentals, for example the sum of all accidentals in the sharp/flat set in the first dimension and the sum of all accidentals in the up/down set in the second dimension.
An example in UpDownNotation:
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> >>> edo31 = EDOTuning(31) >>> n_edo31 = UpDownNotation(edo31) >>> C = n_edo31.note('C', 0) >>> C.add_acc_sum_vector((-2, 1)) UpDownNote(^Cbb, 0, 31-EDO) >>> sharpened = C.add_acc_sum_vector((1, 0)) >>> sharpened UpDownNote(C#, 0, 31-EDO) >>> sharpened.pitch_index - C.pitch_index 2
Observe that in contrast to the accidental diff vector the sum of the vector components of the parameter does not result in the pitch difference.
- Parameters:
acc_sum_vector – The accidental sum vector to be added
- 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: PeriodicIndexT¶
The pitch class index of the natural of this note
- property nat_pitch_index: PeriodicIndexT¶
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: PeriodicIndexT¶
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: PeriodicIndexT | 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: NatAccNoteT, nat_diff: int, acc_sum_vector: Tuple[int, ...], acc_diff_vector: Tuple[PeriodicIndexT, ...], 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_sum_vector – The (unweighted) accidental vector defining the semantic alteration of the standard pitch index difference of a natural index difference
acc_diff_vector – The (weighted) accidental vector defining the pitch diff 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_diff_vector: Tuple[PeriodicIndexT, ...]¶
The (weighted) accidental diff vector of this interval
- property acc_sum_vector: Tuple[int, ...]¶
The (unweighted) accidental sum vector of this interval
- property acc_vector: Tuple[PeriodicIndexT, ...]¶
Deprecated since version 0.4.0: Use
acc_diff_vector()instead.The accidental vector of this interval (signifying the different pitch deviations from the standard natural pitch difference)
- classmethod from_notes(note_a: NatAccNoteT, note_b: NatAccNoteT) 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: NatAccNoteT, target: NatAccNoteT) 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
- is_notated_same(other) bool¶
Returns True, if this interval is notated the same way as the other, False otherwise
- Parameters:
other – Another interval to compare
- 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: IndexT, 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)
- abstractmethod is_notated_same(other) bool¶
(Must be implemented by subclasses) Returns True, if this interval is notated the same way as the other, False otherwise
- Parameters:
other – Another interval of the same notation
- 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
- 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: PeriodicIndexT¶
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: IndexT, ref_note: NoteT)¶
Abstract base class for intervals referring to notations of periodic tunings.
- property ic_index: PeriodicIndexT¶
Returns the interval class index of this interval (often simply called “interval class” or “ic”) as known from pitch class set theory.
The interval class is the shortest distance in pitch class space between two unordered pitch classes.
It is calculated by comparing the absolute value of the simple portion of the interval and its inversion, returning whatever pitch difference is smaller, so e.g. in 12-EDO the ic class for P5 is min(7, 5) = 5
- ic_normalized() Self¶
Returns an interval class normalized version of this interval. The interval normalized version is calculated by converting (if necessary) this interval into a simple interval, normalizing it to a upwards interval and then building the minimum from that result and its inversion.
- inversion() Self¶
Returns the inversion of this interval. The inversion is calculated by subtracting this interval from the equivalency interval.
- property is_compound: bool¶
Returns True if this interval is a compound interval, False otherwise. A compound interval is defined as an interval whose absolute value is strictly greater than the equivalency interval (meaning the equivalency interval itself and its negation are not considered compound)
- property is_simple: bool¶
Returns True if this interval is a simple interval, False otherwise. A simple interval is defined as an interval whose absolute value is lesser or equal than the equivalency interval (meaning the equivalency interval itself and its negation are considered a simple interval)
- to_simple() Self¶
Returns the corresponding simple interval if this is a compound interval (or the interval itself if it is already simple)
The method preserves direction, so if this interval is a downward interval, the resulting interval will also be a downward interval.
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_diff_vectors: List[Tuple[PeriodicIndexT]]¶
A list of (weighted) accidental diff vectors for each note in the scale
- 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_sum_vectors: List[Tuple[int]]¶
A list of (unweighted) accidental sum vectors for each note in the scale
- 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[PeriodicIndexT]¶
A list of accidental values for each note in the scale
- property acc_vectors: List[Tuple[PeriodicIndexT]]¶
Deprecated since version 0.4.0: Use
acc_diff_vectors()instead.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[PeriodicIndexT]¶
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[PeriodicIndexT]¶
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[IndexT]¶
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_interval_seq()instead.Returns this scale represented as a list of note intervals
- transpose(diff: IndexT | NoteIntervalABC) Self¶
Transposes the scale by the given interval
- Parameters:
diff – A note interval or pitch difference
- 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[PeriodicIndexT]¶
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_interval_fan(notation, pitch_interval_fan)¶
Notation.guess_note_interval_fan relays to here
- Parameters:
notation – The notation object that relayed here
pitch_interval_fan – The pitch interval fan object
- guess_note_interval_seq(notation, pitch_interval_seq)¶
Notation.guess_note_interval_seq relays to here
- Parameters:
notation – The notation object that relayed here
pitch_interval_seq – The pitch interval sequence 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
- guess_note_seq(notation, pitch_seq)¶
Notation.guess_note_seq relays to here
- Parameters:
notation – The notation object that relayed here
pitch_seq – The pitch sequence 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)¶
NoteScale.transpose relays to here if the interval argument was not given as a suitable NoteInterval object but as a pitch diff.
- Parameters:
note_scale – The note scale on which the transpose method was called
pitch_diff – The pitch difference
- note_seq_transpose(note_seq, pitch_diff)¶
NoteSeq.transpose relays to here if the interval argument was not given as a suitable NoteInterval object but as a pitch diff.
- Parameters:
note_seq – The note seq on which the transpose method was called
pitch_diff – The pitch difference
- note_transpose(note, pitch_diff)¶
Note.transpose relays to here if the interval argument was not given as a suitable NoteInterval object but as a pitch diff.
- Parameters:
note – The note on which the transpose method was called
pitch_diff – The pitch difference
- 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_interval_fan(notation, pitch_interval_fan)¶
Notation.guess_note_interval_fan relays to here
- Parameters:
notation – The notation object that relayed here
pitch_interval_fan – The pitch interval fan object
- guess_note_interval_seq(notation, pitch_interval_seq)¶
Notation.guess_note_interval_seq relays to here
- Parameters:
notation – The notation object that relayed here
pitch_interval_seq – The pitch interval sequence 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
- guess_note_seq(notation, pitch_seq)¶
Notation.guess_note_seq relays to here
- Parameters:
notation – The notation object that relayed here
pitch_seq – The pitch sequence 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_seq_transpose(note_seq, 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_seq – The note seq 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