Source code for musicscore.quantize

from typing import Optional, List

from musicscore.quarterduration import QuarterDuration
from musicscore.util import isinstance_as_string


[docs]class QuantizeMixin: _ATTRIBUTES = {"get_quantized"} def __init__(self, get_quantized=None, *args, **kwargs): super().__init__(*args, **kwargs) self._possible_subdivisions = {} self._get_quantized = None self.get_quantized = get_quantized def _get_beat_quarter_duration(self): if isinstance_as_string(self, "Beat"): beat_quarter_duration = self.quarter_duration else: beat_quarter_duration = QuarterDuration(1) return beat_quarter_duration @property def get_quantized(self) -> bool: """ :obj:`~musicscore.quantize.QuantizeMixin` property - If ``get_quantized`` is set to None the first ``get_quantized`` of ancestors which is ``False`` or ``True`` will be returned. - If :obj:`musicscore.score.Score.get_quantized` is set to None it will be converted to ``False`` - :obj:`musicscore.measure.Measure.finalize()` loops over all beats. If :obj:`musicscore.beat.Beat.get_quantized` returns ``True`` :obj:`musicscore.beat.Beat.quantize_quarter_durations()` is called. :type: Optional[bool] :rtype: bool """ if self._get_quantized is None: if self.up: return self.up.get_quantized else: return False return self._get_quantized @get_quantized.setter def get_quantized(self, val): self._get_quantized = val
[docs] def get_possible_subdivisions( self, beat_quarter_duration: Optional[QuarterDuration] = None ) -> List[int]: """ :obj:`~musicscore.quantize.QuantizeMixin` method This method is used by :obj:`~musicscore.beat.Beat`'s :obj:`~musicscore.beat.Beat.quantize_quarter_durations()`. Possible subdivisions dictionary can be set with :obj:`~musicscore.quantize.QuantizeMixin.set_possible_subdivisions()`. Keys in the subdivisions dictionary correspond to beat quarter durations (e.g. 1, 1/2 etc.) For example if get_possible_subdivisions()[1] == [3, 5, 8] a beat with a quarter duration of 1 can after quantization consists only of eighth triplets, quintuplets and 32ths. If this dictionary is not set or ``beat_quarter_duration`` as key does not exist, the parent's possible subdivisions dictionary will be checked. :obj:`~musicscore.score.Score` has a default :obj:`~musicscore.score.POSSIBLE_SUBDIVISIONS` dictionary which will be used if no other musicscore node on the path from self to root has its own possible subdivisions dictionary with ``beat_quarter_duration`` as a key. For setting possible subdivisions dictionary use always :obj:`~musicscore.quantize.QuantizeMixin.set_possible_subdivisions()`. :param beat_quarter_duration: Used as key in possible subdivisions dictionary. If ``None`` and self is a :obj:`~musicscore.beat.Beat` ``self.quarter_duration`` is used. If ``None`` and self is not a :obj:`~musicscore.beat.Beat` it is set to 1. :return: A list of possible subdivisions of a :obj:`~musicscore.beat.Beat`. This is used by beat's :obj:`~musicscore.beat.Beat.quantize_quarter_durations()` :rtype: List[int] """ if beat_quarter_duration is None: beat_quarter_duration = self._get_beat_quarter_duration() subdivisions = self._possible_subdivisions.get(beat_quarter_duration) if ( subdivisions is None and self.up is not None and self.up.get_possible_subdivisions(beat_quarter_duration) is not None ): subdivisions = self.up.get_possible_subdivisions(beat_quarter_duration)[:] return subdivisions
[docs] def set_possible_subdivisions( self, subdivisions: list[int], beat_quarter_duration: Optional[QuarterDuration] = None, ) -> None: """ :obj:`~musicscore.quantize.QuantizeMixin` method This method is used to set or change possible subdivisions dictionary of a beat or its ascendants. For example if get_possible_subdivisions()[1] == [3, 5, 8] a beat with a quarter duration of 1 can after quantization consists only of eighth triplets, quintuplets and 32ths. :param subdivisions: list of possible subdivisions to be used in :obj:`musicscore.beat.Beat.quantize_quarter_durations()` :param beat_quarter_duration: If ``None`` and self is a :obj:`~musicscore.beat.Beat` ``self.quarter_duration`` is used. If ``None`` and self is not a :obj:`~musicscore.beat.Beat` it is set to 1. :return: None """ if beat_quarter_duration is None: beat_quarter_duration = self._get_beat_quarter_duration() elif ( isinstance_as_string(self, "Beat") and beat_quarter_duration != self.quarter_duration ): raise ValueError( f"beat_quarter_duration '{beat_quarter_duration}' must be None or equal to the beat quarter_duration '{self.quarter_duration}'" ) if not isinstance(beat_quarter_duration, QuarterDuration): beat_quarter_duration = QuarterDuration(beat_quarter_duration) try: subdivisions = list(subdivisions) except TypeError: subdivisions = [subdivisions] self._possible_subdivisions[beat_quarter_duration] = subdivisions