"""
Typed unit wrappers for temporal quantities.
"""
import numbers
import numpy as np
from ..topos.types import Unit, _to_fraction_array
__all__ = [
'seconds', 'real_onset', 'real_duration',
'metric_onset', 'metric_duration', 'beat', 'bpm', 'tempo',
]
class Seconds(Unit):
def __init__(self, magnitude):
super().__init__(magnitude, 'seconds', 's')
class RealOnset(Unit):
def __init__(self, magnitude):
super().__init__(magnitude, 'real_onset', 's')
class RealDuration(Unit):
def __init__(self, magnitude):
super().__init__(magnitude, 'real_duration', 's')
class MetricOnset(Unit):
def __init__(self, magnitude):
magnitude = _to_fraction_array(magnitude)
super().__init__(magnitude, 'metric_onset', 'note')
@property
def numerator(self):
try:
return self.magnitude.item().numerator
except ValueError:
raise AttributeError("numerator only for scalar")
@property
def denominator(self):
try:
return self.magnitude.item().denominator
except ValueError:
raise AttributeError("denominator only for scalar")
class MetricDuration(Unit):
def __init__(self, magnitude):
magnitude = _to_fraction_array(magnitude)
super().__init__(magnitude, 'metric_duration', 'note')
@property
def numerator(self):
try:
return self.magnitude.item().numerator
except ValueError:
raise AttributeError("numerator only for scalar")
@property
def denominator(self):
try:
return self.magnitude.item().denominator
except ValueError:
raise AttributeError("denominator only for scalar")
class Beat(Unit):
def __init__(self, magnitude):
magnitude = _to_fraction_array(magnitude)
super().__init__(magnitude, 'beat', 'beat')
@property
def numerator(self):
try:
return self.magnitude.item().numerator
except ValueError:
raise AttributeError("numerator only for scalar")
@property
def denominator(self):
try:
return self.magnitude.item().denominator
except ValueError:
raise AttributeError("denominator only for scalar")
class Bpm(Unit):
def __init__(self, magnitude):
super().__init__(magnitude, 'bpm', 'bpm')
class Tempo:
def __init__(self, beat_val, bpm_val):
self.beat = Beat(beat_val) if not isinstance(beat_val, Beat) else beat_val
self.bpm = Bpm(bpm_val) if not isinstance(bpm_val, Bpm) else bpm_val
def __repr__(self):
return f"tempo({self.beat} = {self.bpm})"
[docs]
def seconds(value):
return Seconds(value)
[docs]
def real_onset(value):
return RealOnset(value)
[docs]
def real_duration(value):
return RealDuration(value)
[docs]
def metric_onset(value):
return MetricOnset(value)
[docs]
def metric_duration(value):
return MetricDuration(value)
[docs]
def beat(value):
return Beat(value)
[docs]
def bpm(value):
return Bpm(value)
[docs]
def tempo(beat_val, bpm_val):
return Tempo(beat_val, bpm_val)
numbers.Real.register(Seconds)
numbers.Real.register(RealOnset)
numbers.Real.register(RealDuration)
numbers.Real.register(Bpm)
numbers.Rational.register(MetricOnset)
numbers.Rational.register(MetricDuration)
numbers.Rational.register(Beat)