Periodic package API documentation¶
- xenharmlib.periodic.cutouts(scale: ScaleT, mask_expr: int | Tuple[int, ...]) Generator[ScaleT]¶
Returns a generator yielding partial scales obtained by sliding a mask over the periodical extension of the scale until periodic equivalence is detected.
The function can be used to generate all triads or seven chord scales from a key scale. For example:
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib import periodic >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> c_maj = n_edo12.pc_scale(['C', 'D', 'E', 'F', 'G', 'A', 'B']) >>> >>> for chord_scale in periodic.cutouts(c_maj, (0, 2, 4)): ... print(chord_scale) UpDownNoteScale([C0, E0, G0], 12-EDO) UpDownNoteScale([D0, F0, A0], 12-EDO) UpDownNoteScale([E0, G0, B0], 12-EDO) UpDownNoteScale([F0, A0, C1], 12-EDO) UpDownNoteScale([G0, B0, D1], 12-EDO) UpDownNoteScale([A0, C1, E1], 12-EDO) UpDownNoteScale([B0, D1, F1], 12-EDO)
- Parameters:
scale – The scale from which the partials are taken
mask_expr – An index mask expression defining the template that the generator slides over the scale.
- xenharmlib.periodic.find_iseq(scale, interval_seq) List[Tuple[int, ...]]¶
Searches an interval sequence in the periodic extension of the given scale and returns a list of periodic index masks indicating the partial scales which fit the sequence.
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib import periodic >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> >>> c_major_scale = n_edo12.natural_scale() >>> c_major_triad = c_major_scale.partial((0, 2, 4)) >>> major_triad = c_major_triad.to_interval_seq() >>> >>> periodic.find_iseq(c_major_scale, major_triad) [(0, 2, 4), (3, 5, 7), (4, 6, 8)]
- Parameters:
scale – A period normalized scale
interval_seq – An interval sequence
- xenharmlib.periodic.index(scale: PeriodicScale[FreqReprT], element: FreqReprT) int¶
Returns the index where an element is found in the periodic extension of a period normalized scale
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib import periodic >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> >>> c_maj = n_edo12.pc_scale(['C', 'D', 'E', 'F', 'G', 'A', 'B']) >>> periodic.index(c_maj, n_edo12.note('D', 1)) 8
- Parameters:
scale – A period normalized scale
element – The element to be found
- Raises:
ValueError – If given scale is not period normalized
ValueError – If element was not found in periodic extension
- xenharmlib.periodic.index_mask(parent: ScaleT, partial: ScaleT) Tuple[int, ...]¶
Searches for a partial scale in a scale and returns the periodic index mask of where the partial scale can be found.
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib import periodic >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> c_maj = n_edo12.pc_scale(['C', 'D', 'E', 'F', 'G', 'A', 'B']) >>> Bdim = n_edo12.pc_scale(['B', 'D', 'F']) >>> periodic.index_mask(c_maj, Bdim) (6, 8, 10)
- Parameters:
parent – The parent scale to search in
partial – The partial scale that should be found
- Raises:
IncompatibleOriginContexts – If parent scale and partial scale are not from the same origin context
ValueError – If parent scale is not period normalized
ValueError – If partial scale was not found in periodic extension of the reference scale
- xenharmlib.periodic.is_in(scale: PeriodicScale[FreqReprT], element: FreqReprT) bool¶
Returns bool if element exists in periodic extension of a period normalized scale
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib import periodic >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> >>> c_maj = n_edo12.pc_scale(['C', 'D', 'E', 'F', 'G', 'A', 'B']) >>> periodic.is_in(c_maj, n_edo12.note('D', 1)) True
- Parameters:
scale – A period normalized scale
element – The element to be found
- Raises:
ValueError – If given scale is not period normalized
IncompatibleOriginContexts – If element and scale have different origin contexts
- xenharmlib.periodic.mod_connectors(scale_a, scale_b, cutout_pattern)¶
Returns partial scales of a specific structure (such as I-III-V) that are shared between two scales. These partial scales can be interpreted as chords that connect two different keys (“modulation connectors”). If you e.g. want to pivot from C major to G minor using standard triads you can get the key-connecting chords like this:
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib.periodic import mod_connectors >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> >>> c_maj = n_edo12.pc_scale(['C', 'D', 'E', 'F', 'G', 'A', 'B']) >>> g_min = n_edo12.pc_scale(['G', 'A', 'Bb', 'C', 'D', 'Eb', 'F']) >>> >>> for connector in mod_connectors(c_maj, g_min, (0, 2, 4)): ... print(connector) UpDownNoteScale([D0, F0, A0], 12-EDO) UpDownNoteScale([F0, A0, C1], 12-EDO)
Since in theory every shared partial scale has infinite equivalents on the periodic extension the scales are normalized to the first occurence in the first scale
- Parameters:
scale_a – The first scale
scale_b – The second scale
cutout_pattern – A mask expression used to iteratively cut out partial scales from the two scales.
- xenharmlib.periodic.pairs(scale: PeriodicScale[FreqReprT], distance: int = 1) Generator[Tuple[FreqReprT, FreqReprT]]¶
Returns a generator yielding tuples of neighboring elements of the periodic extension of a scale (either direct neighbors or neighbors with a bigger fixed distance)
- Parameters:
scale – The origin scale
distance – The distance of the two elements (optional, defaults to 1 meaning “direct neighbors”)
- xenharmlib.periodic.partial(scale: ScaleT, mask_expr: int | Tuple[int | EllipsisType, ...]) ScaleT¶
Returns a new scale consisting of a selection of indices of the periodic extension of the given 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 the origin scale
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).
Indices in the mask expression can be greater or smaller than the available indices in the origin scale. In this case the elements are taken from the periodic extension, e.g.
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib import periodic >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> >>> c_maj = n_edo12.pc_scale(['C', 'D', 'E', 'F', 'G', 'A', 'B']) >>> periodic.partial(c_maj, (-1, 1, 3)) UpDownNoteScale([B-1, D0, F0], 12-EDO) >>> periodic.partial(c_maj, (5, ..., 12)) UpDownNoteScale([A0, B0, C1, D1, E1, F1, G1, A1], 12-EDO)
If only one element should be selected a simple integer can be used
- Parameters:
scale – A period normalized scale
mask_expr – An index mask expression which defines the selection of indices from the periodic extension of the origin scale.
- Raises:
ValueError – If given scale is not period normalized
- xenharmlib.periodic.scalar_transpose(ref_scale: ScaleT, transposable: ScaleT | FreqReprT, steps: int) ScaleT | FreqReprT¶
Scalar transposition moves a note, pitch or scale along the steps of a reference scale. This is in contrast to normal transposition which moves a note along the steps of the complete scale (e.g. the chromatic scale in 12-EDO):
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib import periodic >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> >>> c_maj = n_edo12.pc_scale(['C', 'D', 'E', 'F', 'G', 'A', 'B']) >>> periodic.scalar_transpose(c_maj, n_edo12.note('D', 1), 3) UpDownNote(G, 1, 12-EDO)
When scalar transposition is applied to collections of notes or pitches interval content can change, for example if a C major triad is transposed 1 step in reference to the C major scale the result will be D minor(!):
>>> triad = n_edo12.pc_scale(['C', 'E', 'G']) >>> periodic.scalar_transpose(c_maj, triad, 1) UpDownNoteScale([D0, F0, A0], 12-EDO)
- Parameters:
ref_scale – A period normalized reference scale
transposable – The object to be transposed
steps – The number of scale steps the object should be transposed
- Raises:
IncompatibleOriginContexts – If reference scale and tranposable are not from the same origin context
ValueError – If reference scale is not period normalized
ValueError – If transposable object was not found in periodic extension of the reference scale
- xenharmlib.periodic.scale_element(scale: PeriodicScale[FreqReprT], index: int) FreqReprT¶
Gets an element at a given index from the periodic extension of a period normalized scale.
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib import periodic >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> >>> c_maj = n_edo12.pc_scale(['C', 'D', 'E', 'F', 'G', 'A', 'B']) >>> periodic.scale_element(c_maj, 8) UpDownNote(D, 1, 12-EDO)
- Parameters:
scale – A period normalized scale
index – An index of the periodic extension of the scale
- Raises:
ValueError – If given scale is not period normalized
- xenharmlib.periodic.spec_interval(scale: PeriodicScale, source_index: int, target_index: int) Interval¶
Returns the specific interval for a generic interval of the periodic extension of the scale.
>>> from xenharmlib import EDOTuning >>> from xenharmlib import UpDownNotation >>> from xenharmlib import periodic >>> >>> edo12 = EDOTuning(12) >>> n_edo12 = UpDownNotation(edo12) >>> >>> c_maj = n_edo12.pc_scale(['C', 'D', 'E', 'F', 'G', 'A', 'B']) >>> periodic.spec_interval(c_maj, 6, 7) UpDownNoteInterval(m, 2, 12-EDO)
- Parameters:
scale – A period normalized scale
source_index – Periodic source index for the interval
target_index – Periodic target index for the interval