Mercurial > hg > auditok
changeset 318:bf4a8834c5ec
Refactor io
author | Amine Sehili <amine.sehili@gmail.com> |
---|---|
date | Fri, 18 Oct 2019 21:36:51 +0100 |
parents | 18a9f0dcdaae |
children | 8ed121db987c |
files | auditok/io.py |
diffstat | 1 files changed, 46 insertions(+), 56 deletions(-) [+] |
line wrap: on
line diff
--- a/auditok/io.py Fri Oct 18 20:59:16 2019 +0100 +++ b/auditok/io.py Fri Oct 18 21:36:51 2019 +0100 @@ -27,7 +27,7 @@ import sys import wave import warnings -import audioop +from abc import ABC, abstractmethod from array import array from functools import partial from .exceptions import AudioIOError, AudioParameterError @@ -67,7 +67,6 @@ DEFAULT_SAMPLING_RATE = 16000 DEFAULT_SAMPLE_WIDTH = 2 DEFAULT_NB_CHANNELS = 1 -DATA_FORMAT = {1: "b", 2: "h", 4: "i"} def check_audio_data(data, sample_width, channels): @@ -129,7 +128,7 @@ return sampling_rate, sample_width, channels -class AudioSource: +class AudioSource(ABC): """ Base class for audio source objects. @@ -165,18 +164,19 @@ self._sample_width = sample_width self._channels = channels + @abstractmethod def is_open(self): """ Return True if audio source is open, False otherwise """ - raise NotImplementedError + @abstractmethod def open(self): """ Open audio source """ - raise NotImplementedError + @abstractmethod def close(self): """ Close audio source """ - raise NotImplementedError + @abstractmethod def read(self, size): """ Read and return `size` audio samples at most. @@ -195,10 +195,14 @@ - 'left_samples' if `size` > 'left_samples' """ - raise NotImplementedError def get_sampling_rate(self): """ Return the number of samples per second of audio stream """ + warnings.warn( + "'get_sampling_rate' is deprecated, use 'sampling_rate' " + "property instead", + DeprecationWarning, + ) return self.sampling_rate @property @@ -213,6 +217,11 @@ def get_sample_width(self): """ Return the number of bytes used to represent one audio sample """ + warnings.warn( + "'get_sample_width' is deprecated, use 'sample_width' " + "property instead", + DeprecationWarning, + ) return self.sample_width @property @@ -227,6 +236,11 @@ def get_channels(self): """ Return the number of channels of this audio source """ + warnings.warn( + "'get_channels' is deprecated, use 'channels' " + "property instead", + DeprecationWarning, + ) return self.channels @property @@ -252,35 +266,39 @@ def rewindable(self): return True + @abstractmethod def rewind(self): """ Go back to the beginning of audio stream """ raise NotImplementedError @property + @abstractmethod def position(self): - """Stream position in number of samples""" - raise NotImplementedError + """Return stream position in number of samples""" @position.setter + @abstractmethod def position(self, position): - raise NotImplementedError + """Set stream position in number of samples""" @property def position_s(self): - """Stream position in seconds""" + """Return stream position in seconds""" return self.position / self.sampling_rate @position_s.setter def position_s(self, position_s): + """Set stream position in seconds""" self.position = int(self.sampling_rate * position_s) @property def position_ms(self): - """Stream position in milliseconds""" + """Return stream position in milliseconds""" return (self.position * 1000) // self.sampling_rate @position_ms.setter def position_ms(self, position_ms): + """Set stream position in milliseconds""" if not isinstance(position_ms, int): raise ValueError("position_ms should be an int") self.position = int(self.sampling_rate * position_ms / 1000) @@ -338,14 +356,14 @@ def __init__( self, - data_buffer, + data, sampling_rate=DEFAULT_SAMPLING_RATE, sample_width=DEFAULT_SAMPLE_WIDTH, channels=DEFAULT_NB_CHANNELS, ): AudioSource.__init__(self, sampling_rate, sample_width, channels) - check_audio_data(data_buffer, sample_width, channels) - self._buffer = data_buffer + check_audio_data(data, sample_width, channels) + self._data = data self._sample_size_all_channels = sample_width * channels self._current_position_bytes = 0 self._is_open = False @@ -368,7 +386,7 @@ else: bytes_to_read = self._sample_size_all_channels * size offset = self._current_position_bytes + bytes_to_read - data = self._buffer[self._current_position_bytes : offset] + data = self._data[self._current_position_bytes : offset] if data: self._current_position_bytes += len(data) return data @@ -376,34 +394,7 @@ @property def data(self): - return self._buffer - - def get_data_buffer(self): - """ Return all audio data as one string buffer. """ - return self._buffer - - def set_data(self, data_buffer): - """ Set new data for this audio stream. - - :Parameters: - - `data_buffer` : str, basestring, Bytes - a string buffer with a length multiple of (sample_width * channels) - """ - check_audio_data(data_buffer, self.sample_width, self.channels) - self._buffer = data_buffer - self._current_position_bytes = 0 - - def append_data(self, data_buffer): - """ Append data to this audio stream - - :Parameters: - - `data_buffer` : str, basestring, Bytes - a buffer with a length multiple of (sample_width * channels) - """ - check_audio_data(data_buffer, self.sample_width, self.channels) - self._buffer += data_buffer + return self._data def rewind(self): self.position = 0 @@ -436,7 +427,7 @@ self.position = int(self.sampling_rate * position_ms / 1000) -class _FileAudioSource(AudioSource): +class FileAudioSource(AudioSource): def __init__(self, sampling_rate, sample_width, channels): AudioSource.__init__(self, sampling_rate, sample_width, channels) self._audio_stream = None @@ -453,8 +444,9 @@ self._audio_stream.close() self._audio_stream = None + @abstractmethod def _read_from_stream(self, size): - raise NotImplementedError + """Read data from stream""" def read(self, size): if not self.is_open(): @@ -465,9 +457,9 @@ return data -class RawAudioSource(_FileAudioSource, Rewindable): +class RawAudioSource(FileAudioSource): def __init__(self, file, sampling_rate, sample_width, channels): - _FileAudioSource.__init__(self, sampling_rate, sample_width, channels) + FileAudioSource.__init__(self, sampling_rate, sample_width, channels) self._file = file self._audio_stream = None self._sample_size = sample_width * channels @@ -485,7 +477,7 @@ return data -class WaveAudioSource(_FileAudioSource, Rewindable): +class WaveAudioSource(FileAudioSource): """ A class for an `AudioSource` that reads data from a wave file. This class should be used for large wave files to avoid loading @@ -501,7 +493,7 @@ self._filename = filename self._audio_stream = None stream = wave.open(self._filename, "rb") - _FileAudioSource.__init__( + FileAudioSource.__init__( self, stream.getframerate(), stream.getsampwidth(), @@ -578,7 +570,7 @@ return None -class StdinAudioSource(_FileAudioSource): +class StdinAudioSource(FileAudioSource): """ A class for an :class:`AudioSource` that reads data from standard input. """ @@ -590,7 +582,7 @@ channels=DEFAULT_NB_CHANNELS, ): - _FileAudioSource.__init__(self, sampling_rate, sample_width, channels) + FileAudioSource.__init__(self, sampling_rate, sample_width, channels) self._is_open = False self._sample_size = sample_width * channels self._stream = sys.stdin.buffer @@ -613,8 +605,6 @@ def make_tqdm_progress_bar(iterable, total, duration, **tqdm_kwargs): - - tqdm_kwargs = tqdm_kwargs.copy() fmt = tqdm_kwargs.get("bar_format", DEFAULT_BAR_FORMAT_TQDM) fmt = fmt.replace("{duration}", "{:.3f}".format(duration)) tqdm_kwargs["bar_format"] = fmt @@ -838,7 +828,7 @@ open_function = func_dict.get(audio_format, AudioSegment.from_file) segment = open_function(filename) return BufferAudioSource( - data_buffer=segment._data, + data=segment.raw_data, sampling_rate=segment.frame_rate, sample_width=segment.sample_width, channels=segment.channels, @@ -1005,4 +995,4 @@ ) else: err_message = "cannot write file format {} (file name: {})" - raise AudioIOError(err_message.format(audio_format, file)) + raise AudioIOError(err_message.format(audio_format, file)) \ No newline at end of file