Source code for mutwo.parameters.volumes
"""Submodule for the parameter volume.
'Volume' is defined as any object that knows a :attr:`amplitude` attribute.
"""
import typing
import numpy as np # type: ignore
from mutwo import parameters
from mutwo.utilities import constants
from mutwo.utilities import tools
__all__ = ("DirectVolume", "DecibelVolume", "WesternVolume")
[docs]class DirectVolume(parameters.abc.Volume):
"""A simple volume class that gets directly initialised by its amplitude.
:param amplitude: The amplitude of the :class:`DirectVolume` object.
May be used when a converter class needs a volume object, but there is
no need or desire for a complex abstraction of the respective volume.
"""
def __init__(self, amplitude: constants.Real):
self._amplitude = amplitude
@property
def amplitude(self) -> constants.Real:
return self._amplitude
def __repr__(self) -> str:
return "{}({})".format(type(self).__name__, self.amplitude)
[docs]class DecibelVolume(parameters.abc.Volume):
"""A simple volume class that gets directly initialised by decibel.
:param decibel: The decibel of the :class:`DecibelVolume` object (should be
from -120 to 0).
May be used when a converter class needs a volume object, but there is
no need or desire for a complex abstraction of the respective volume.
"""
def __init__(self, decibel: constants.Real):
self._decibel = decibel
@property
def decibel(self) -> constants.Real:
return self._decibel
@property
def amplitude(self) -> constants.Real:
return self.decibel_to_amplitude_ratio(self.decibel)
def __repr__(self) -> str:
return "{}({})".format(type(self).__name__, self.amplitude)
[docs]class WesternVolume(parameters.abc.Volume):
"""Volume with a traditional Western nomenclature.
:param name: Dynamic indicator in traditional Western nomenclature
('f', 'pp', 'mf', 'sfz', etc.). For a list of all supported
indicators, see :const:`mutwo.parameters.volumes_constants.DYNAMIC_INDICATOR`.
>>> from mutwo.parameters import volumes
>>> volumes.WesternVolume('fff')
"""
def __init__(self, name: str):
self.name = name
self._standard_dynamic_indicator_to_decibel_mapping = (
WesternVolume._make_standard_dynamic_indicator_to_decibel_mapping()
)
self._dynamic_indicator_to_decibel_mapping = WesternVolume._make_dynamic_indicator_to_decibel_mapping(
self._standard_dynamic_indicator_to_decibel_mapping
)
self._decibel_to_standard_dynamic_indicator_mapping = {
decibel: dynamic_indicator
for dynamic_indicator, decibel in self._standard_dynamic_indicator_to_decibel_mapping.items()
}
def __repr__(self) -> str:
return "{}({})".format(type(self).__name__, self.name)
# ###################################################################### #
# static private methods #
# ###################################################################### #
@staticmethod
def _make_standard_dynamic_indicator_to_decibel_mapping() -> typing.Dict[
str, float
]:
return {
dynamic_indicator: decibel
for dynamic_indicator, decibel in zip(
parameters.volumes_constants.STANDARD_DYNAMIC_INDICATOR,
np.linspace(
parameters.volumes_constants.MINIMUM_DECIBEL_FOR_STANDARD_DYNAMIC_INDICATOR,
parameters.volumes_constants.MAXIMUM_DECIBEL_FOR_STANDARD_DYNAMIC_INDICATOR,
len(parameters.volumes_constants.STANDARD_DYNAMIC_INDICATOR),
dtype=float,
),
)
}
@staticmethod
def _make_dynamic_indicator_to_decibel_mapping(
standard_dynamic_indicator_to_decibel_mapping: typing.Dict[str, float]
) -> typing.Dict[str, float]:
dynamic_indicator_to_decibel_mapping = {}
dynamic_indicator_to_decibel_mapping.update(
standard_dynamic_indicator_to_decibel_mapping
)
for (
special_dynamic_indicator,
standard_dynamic_indicator,
) in (
parameters.volumes_constants.SPECIAL_DYNAMIC_INDICATOR_TO_STANDARD_DYNAMIC_INDICATOR_MAPPING.items()
):
dynamic_indicator_to_decibel_mapping.update(
{
special_dynamic_indicator: dynamic_indicator_to_decibel_mapping[
standard_dynamic_indicator
]
}
)
return dynamic_indicator_to_decibel_mapping
# ###################################################################### #
# class methods (alternative constructors) #
# ###################################################################### #
[docs] @classmethod
def from_amplitude(cls, amplitude: constants.Real) -> "WesternVolume":
"""Initialise `WesternVolume` from amplitude ratio.
:param amplitude: The amplitude which shall be converted to a `WesternVolume`
object.
>>> from mutwo.parameters import volumes
>>> volumes.WesternVolume.from_amplitude(0.05)
WesternVolume(mp)
"""
decibel = cls.amplitude_ratio_to_decibel(amplitude)
return cls.from_decibel(decibel)
[docs] @classmethod
def from_decibel(cls, decibel: constants.Real) -> "WesternVolume":
"""Initialise `WesternVolume` from decibel.
:param decibel: The decibel which shall be converted to a `WesternVolume`
object.
>>> from mutwo.parameters import volumes
>>> volumes.WesternVolume.from_decibel(-24)
WesternVolume(mf)
"""
volume_object = cls("mf")
closest_decibel: float = tools.find_closest_item(
decibel,
tuple(volume_object._decibel_to_standard_dynamic_indicator_mapping.keys()),
)
indicator = volume_object._decibel_to_standard_dynamic_indicator_mapping[
closest_decibel
]
volume_object.name = indicator
return volume_object
# ###################################################################### #
# properties #
# ###################################################################### #
@property
def name(self) -> str:
"""The western nomenclature name for dynamic.
For a list of all supported indicators, see
:const:`mutwo.parameters.volumes_constants.DYNAMIC_INDICATOR`.
"""
return self._name
@name.setter
def name(self, name: str) -> None:
try:
assert name in parameters.volumes_constants.DYNAMIC_INDICATOR
except AssertionError:
message = (
"unknown dynamic name '{}'. Supported dynamic names are '{}'.".format(
name, parameters.volumes_constants.DYNAMIC_INDICATOR,
)
)
raise ValueError(message)
self._name = name
@property
def decibel(self) -> constants.Real:
return self._dynamic_indicator_to_decibel_mapping[self.name]
@property
def amplitude(self) -> constants.Real:
return self.decibel_to_amplitude_ratio(self.decibel)