Source code for auglib.core.time

import typing

import pandas as pd

import audobject

from auglib.core import observe


[docs]class Time(audobject.Object): r"""Represent timestamp or timespan. Different time formats are supported, but calling the object always returns the value expressed as number of samples. Args: value: timestamp or timespan unit: literal specifying the format (see :meth:`auglib.utils.to_samples`) Raises: ValueError: if ``unit`` is not supported Examples: >>> Time(0.5, "seconds")(sampling_rate=8) 4 >>> Time(1000, "ms")(sampling_rate=8) 8 >>> Time(16, "samples")() 16 >>> Time(0.5, "relative")(length=64) 32 >>> # generate randomized values >>> seed(0) >>> t = Time(observe.FloatUni(0.25, 0.75), "relative") >>> t(length=64) 33 >>> t(length=64) 38 """ def __init__( self, value: typing.Union[int, float, observe.Base], unit: str, ): self.value = value self.unit = unit.strip() if self.unit not in ("samples", "relative"): # raises ValueError if unit is not supported pd.to_timedelta(0, unit=self.unit)
[docs] def __call__( self, *, sampling_rate: int = None, length: int = None, allow_negative: bool = False, ) -> int: r"""Convert timestamp or timespan to number of samples. If ``unit`` is set to ``'samples'``, no argument must be given. In case of ``'relative'``, a value for ``length`` has to be provided. In any other case, a value for ``sampling_rate`` is required. Args: sampling_rate: sampling rate in Hz length: reference point if unit is ``relative`` (in number of samples) allow_negative: allow negative values Returns: number of samples Raises: ValueError: if ``allow_negative`` is ``False`` and computed value is negative ValueError: if ``length`` is not provided, but ``unit`` is ``'samples'`` ValueError: if ``sampling_rate`` is not provided, but ``unit`` is not ``'samples'`` or ``'relative'`` ValueError: if ``sampling_rate`` is not an integer or not greater than zero """ if sampling_rate is not None: if not isinstance(sampling_rate, int) or sampling_rate <= 0: raise ValueError( "Sampling rate must be an integer and greater than zero, " f"not {sampling_rate} Hz" ) value = observe.observe(self.value) if self.unit == "samples": num_samples = int(value) elif self.unit == "relative": if length is None: raise ValueError( "Unit is set to 'relative', " "but no value is provided for 'length'." ) num_samples = int(length * value) else: if sampling_rate is None: raise ValueError( f"Unit is set to '{self.unit}', " f"but no value is provided for 'sampling_rate'." ) value = pd.to_timedelta(value, unit=self.unit).total_seconds() num_samples = int(value * sampling_rate) if num_samples < 0 and not allow_negative: raise ValueError( f"Number of samples takes on negative value " f"'{num_samples}'. " f"If this is expected, " f"set 'allow_negative=True' " f"to avoid this error.", ) return num_samples