from enum import IntEnum from UniTAP.common.timestamp import Timestamp class AudioFileFormat(IntEnum): """ Describe all supported audio file formats for saving audio: - BIN. - WAV. """ UNKNOWN = -1 BIN = 0 WAV = 1 class AudioFormat(IntEnum): """ Describe all supported audio formats: - PCMAudio. """ Unknown = -1 L_PCM = 0xFFFF class AudioMode: """ Class `AudioMode` contains part information of audio: sample rate, count of bits and channel count. """ def __init__(self, sample_rate: int = 44100, bits: int = 16, channel_count: int = 2): self.sample_rate = sample_rate self.bits = bits self.channel_count = channel_count def __str__(self): return f"Sample rate: {self.sample_rate}\n" \ f"Bits: {self.bits}\n" \ f"Channel count: {self.channel_count}\n" def __eq__(self, other): return self.sample_rate == other.sample_rate and \ self.bits == other.bits and \ self.channel_count == other.channel_count def is_valid(self) -> bool: """ Check that information is valid (all values more than 0). Returns: object of bool type. """ return self.sample_rate > 0 and \ self.bits > 0 and \ self.channel_count > 0 class AudioFrameData: """ Class `AudioFrameData` describes captured frame from Sink (RX - receiver) side. Contains information of audio: `AudioMode`, samples, `AudioFormat`, frame counter, `Timestamp`, audio data. """ def __init__(self, audio_mode: AudioMode = AudioMode(), samples: int = 0, sample_format: AudioFormat = AudioFormat.Unknown, frame_counter: int = 0, timestamp: Timestamp = Timestamp(0), data: bytearray = bytearray()): self.__audio_mode = audio_mode self.__samples = samples self.__sample_format = sample_format self.__frame_counter = frame_counter self.__timestamp = timestamp self.__data = data @property def channel_count(self) -> int: """ Returns channel count. Returns: object of int type. """ return self.__audio_mode.channel_count @property def samples(self) -> int: """ Returns samples. Returns: object of int type. """ return self.__samples @property def sample_size(self) -> int: """ Returns sample size. Returns: object of int type. """ return self.__audio_mode.bits @property def sample_rate(self) -> int: """ Returns sample rate. Returns: object of int type. """ return self.__audio_mode.sample_rate @property def sample_format(self) -> AudioFormat: """ Returns sample format. Returns: object of AudioFormat type. """ return self.__sample_format @property def frame_counter(self) -> int: """ Returns frame counter. Returns: object of int type. """ return self.__frame_counter @property def timestamp(self) -> Timestamp: """ Returns timestamp. Returns: object of Timestamp type. """ return self.__timestamp @property def data(self) -> bytearray: """ Returns data. Returns: object of bytearray type. """ return self.__data @channel_count.setter def channel_count(self, channel_count: int): """ Allows setting new value to channel count. Args: channel_count (int) - must be more than 0 """ if channel_count <= 0: raise ValueError(f"Channel count must be more than 0.") self.__audio_mode.channel_count = channel_count @samples.setter def samples(self, samples: int): """ Allows setting new value to samples. Args: samples (int) - must be more than 0 """ if samples <= 0: raise ValueError(f"Samples must be more than 0.") self.__samples = samples @sample_size.setter def sample_size(self, sample_size: int): """ Allows setting new value to sample size. Args: sample_size (int) - must be more than 0 """ if sample_size <= 0: raise ValueError(f"Sample size must be more than 0.") self.__audio_mode.bits = sample_size @sample_rate.setter def sample_rate(self, sample_rate: int): """ Allows setting new value to sample rate. Args: sample_rate (int) - must be more than 0 """ if sample_rate <= 0: raise ValueError(f"Sample rate must be more than 0.") self.__audio_mode.sample_rate = sample_rate @sample_format.setter def sample_format(self, sample_format: int): """ Allows setting new value to sample format. Args: sample_format (int) - must be more than 0 """ if sample_format <= 0: raise ValueError(f"Sample format must be more than 0.") self.__sample_format = AudioFormat(sample_format) @timestamp.setter def timestamp(self, timestamp: int): """ Allows setting new value to timestamp. Args: timestamp (int) - must be more than 0 """ if timestamp <= 0: raise ValueError(f"Timestamp must be more than 0.") self.__timestamp.value = timestamp @frame_counter.setter def frame_counter(self, frame_counter: int): """ Allows setting new value to frame counter. Args: frame_counter (int) - must be more than -1 """ if frame_counter < 0: raise ValueError(f"Frame counter must be more than 0.") self.__frame_counter = frame_counter @data.setter def data(self, value: bytearray): """ Allows setting new value to data. Args: value (bytearray) - length of value must be more than 0 """ if len(value) <= 0: raise ValueError(f"Audio data length must be more than 0.") self.__data = value def __str__(self): return f"Sample rate: {self.sample_rate}\n" \ f"Bits (Sample size): {self.sample_size}\n" \ f"Channel count: {self.channel_count}\n" \ f"Sample format: {self.sample_format.name}\n" \ f"Timestamp: {self.timestamp.to_n_sec} n sec\n" \ f"Frame counter: {self.frame_counter}\n" \ f"Length of data: {self.data} bytes\n"