Source code for abjadext.nauert.quantizer

import abjad

from .attackpointoptimizers import AttackPointOptimizer
from .gracehandlers import GraceHandler
from .heuristics import Heuristic
from .jobhandlers import JobHandler
from .qeventsequence import QEventSequence
from .qschemas import MeasurewiseQSchema, QSchema


[docs]def quantize( q_event_sequence: QEventSequence, q_schema: QSchema | None = None, grace_handler: GraceHandler | None = None, heuristic: Heuristic | None = None, job_handler: JobHandler | None = None, attack_point_optimizer: AttackPointOptimizer | None = None, attach_tempos: bool = True, ) -> abjad.Voice: r""" Quantizer function. Quantizes sequences of attack-points, encapsulated by ``QEventSequences``, into score trees. .. container:: example >>> durations = [1000] * 8 >>> pitches = range(8) >>> q_event_sequence = \ ... nauert.QEventSequence.from_millisecond_pitch_pairs( ... tuple(zip(durations, pitches))) .. container:: example Quantization defaults to outputting into a 4/4, quarter=60 musical structure: >>> result = nauert.quantize(q_event_sequence) >>> staff = abjad.Staff([result]) >>> score = abjad.Score([staff]) >>> abjad.show(score) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(score) >>> print(string) \new Score << \new Staff { \new Voice { { \tempo 4=60 \time 4/4 c'4 cs'4 d'4 ef'4 } { e'4 f'4 fs'4 g'4 } } } >> .. container:: example However, the behavior of the ``quantize`` function can be modified at call-time. Passing a ``QSchema`` instance will alter the macro-structure of the output. Here, we quantize using settings specified by a ``MeasurewiseQSchema``, which will cause the ``quantize`` function to group the output into measures with different tempi and time signatures: >>> measurewise_q_schema = nauert.MeasurewiseQSchema( ... {"tempo": ((1, 4), 78), "time_signature": (2, 4)}, ... {"tempo": ((1, 8), 57), "time_signature": (5, 4)}, ... ) >>> result = nauert.quantize( ... q_event_sequence, ... q_schema=measurewise_q_schema, ... ) >>> staff = abjad.Staff([result]) >>> score = abjad.Score([staff]) >>> abjad.show(score) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(score) >>> print(string) \new Score << \new Staff { \new Voice { { \tempo 4=78 \time 2/4 c'4 ~ \times 4/5 { c'16. cs'8.. ~ } } { \times 4/7 { \tempo 8=57 \time 5/4 cs'16. d'8 ~ } \times 4/5 { d'16 ef'16. ~ } \times 2/3 { ef'16 e'8 ~ } \times 4/7 { e'16 f'8 ~ f'32 ~ } f'32 fs'16. ~ \times 4/5 { fs'32 g'8 ~ } \times 4/7 { g'32 r32 r16 r16 r16 r16 r16 r16 } r4 } } } >> .. container:: example Here we quantize using settings specified by a ``BeatwiseQSchema``, which keeps the output of the ``quantize`` function "flattened", without measures or explicit time signatures. The default beat-wise settings of quarter=60 persists until the third "beatspan": >>> beatwise_q_schema = nauert.BeatwiseQSchema( ... { ... 2: {"tempo": ((1, 4), 120)}, ... 5: {"tempo": ((1, 4), 90)}, ... 7: {"tempo": ((1, 4), 30)}, ... }) >>> result = nauert.quantize( ... q_event_sequence, ... q_schema=beatwise_q_schema, ... ) >>> staff = abjad.Staff([result]) >>> score = abjad.Score([staff]) >>> abjad.show(score) # doctest: +SKIP .. docs:: >>> string = abjad.lilypond(score) >>> print(string) \new Score << \new Staff { \new Voice { \tempo 4=60 c'4 cs'4 \tempo 4=120 d'2 ef'4 ~ \tempo 4=90 ef'8. e'4 ~ e'16 ~ \times 2/3 { \tempo 4=30 e'32 f'8. fs'8 ~ fs'32 ~ } \times 2/3 { fs'32 g'8. r32 r8 } } } >> Note that ``TieChains`` are generally fused together in the above example, but break at tempo changes. .. container:: The use of `BeatwiseQSchema` and `MeasurewiseAttackPointOptimizer` is not supported. Please raise an issue if you would like this to be supported in the future. >>> q_schema = nauert.BeatwiseQSchema() >>> attack_point_optimizer = nauert.MeasurewiseAttackPointOptimizer() >>> result = nauert.quantize( ... q_event_sequence, ... attack_point_optimizer=attack_point_optimizer, ... q_schema=q_schema, ... ) Traceback (most recent call last): ... TypeError: BeatwiseQTarget is not supposed to be used together with MeasurewiseAttackPointOptimizer. Other keyword arguments are: * ``grace_handler``: a ``GraceHandler`` instance controls whether and how grace notes are used in the output. Options currently include ``CollapsingGraceHandler``, ``ConcatenatingGraceHandler`` and ``DiscardingGraceHandler``. * ``heuristic``: a ``Heuristic`` instance controls how output rhythms are selected from a pool of candidates. Options currently include the ``DistanceHeuristic`` class. * ``job_handler``: a ``JobHandler`` instance controls whether or not parallel processing is used during the quantization process. Options include the ``SerialJobHandler`` and ``ParallelJobHandler`` classes. * ``attack_point_optimizer``: an ``AttackPointOptimizer`` instance controls whether and how logical ties are re-notated. Options currently include ``MeasurewiseAttackPointOptimizer``, ``NaiveAttackPointOptimizer`` and ``NullAttackPointOptimizer``. Refer to the reference pages for ``BeatwiseQSchema`` and ``MeasurewiseQSchema`` for more information on controlling the ``quantize`` function's output, and to the reference on ``SearchTree`` for information on controlling the rhythmic complexity of that same output. """ q_event_sequence = QEventSequence(q_event_sequence) if q_schema is None: q_schema = MeasurewiseQSchema() assert isinstance(q_schema, QSchema) q_target = q_schema(q_event_sequence.duration_in_ms) notation = q_target( q_event_sequence, grace_handler=grace_handler, heuristic=heuristic, job_handler=job_handler, attack_point_optimizer=attack_point_optimizer, attach_tempos=attach_tempos, ) return notation