# HG changeset patch # User Amine Sehili # Date 1564600047 -3600 # Node ID ee6d2294cdd5d31202754002d92dc0f1fb9a8329 # Parent f55007434c6b2cd8dab81eb7985ec79ce8f2d604 Add metadata support to AudioRegion diff -r f55007434c6b -r ee6d2294cdd5 auditok/core.py --- a/auditok/core.py Mon Jul 29 20:37:31 2019 +0100 +++ b/auditok/core.py Wed Jul 31 20:07:27 2019 +0100 @@ -267,7 +267,9 @@ """ start = start_frame * frame_duration data = b"".join(data_frames) - return AudioRegion(data, start, sampling_rate, sample_width, channels) + duration = len(data) / (sampling_rate * sample_width * channels) + meta = {"start": start, "end": start + duration} + return AudioRegion(data, sampling_rate, sample_width, channels, meta) def _check_convert_index(index, types, err_msg): @@ -308,8 +310,26 @@ return super(_MillisView, self).__getitem__(index) +class _AudioRegionMetadata(dict): + def __getattr__(self, name): + if name in self: + return self[name] + else: + err_msg = "AudioRegion metadata has no entry '{}'" + raise AttributeError(err_msg.format(name)) + + def __setattr__(self, name, value): + self[name] = value + + def __str__(self): + return "\n".join("{}: {}".format(k, v) for k, v in self.items()) + + def __repr__(self): + return str(self) + + class AudioRegion(object): - def __init__(self, data, start, sampling_rate, sample_width, channels): + def __init__(self, data, sampling_rate, sample_width, channels, meta=None): """ A class for detected audio events. @@ -317,8 +337,6 @@ data: bytes audio data - start: float - start time in seconds samling_rate: int sampling rate of audio data sample_width: int @@ -328,17 +346,29 @@ """ check_audio_data(data, sample_width, channels) self._data = data - self._start = start self._sampling_rate = sampling_rate self._sample_width = sample_width self._channels = channels + if meta is not None: + self._meta = _AudioRegionMetadata(meta) + else: + self._meta = None + self._seconds_view = _SecondsView(self) self.s = self.sec self._millis_view = _MillisView(self) self.ms = self.millis + @property + def meta(self): + return self._meta + + @meta.setter + def meta(self, new_meta): + self._meta = _AudioRegionMetadata(new_meta) + @classmethod def load(cls, file, skip=0, max_read=None, **kwargs): audio_source = get_audio_source(file, **kwargs) @@ -354,7 +384,6 @@ audio_source.close() return cls( data, - 0, audio_source.sampling_rate, audio_source.sample_width, audio_source.channels, @@ -369,14 +398,6 @@ return self._millis_view @property - def start(self): - return self._start - - @property - def end(self): - return self.start + self.duration - - @property def duration(self): """ Returns region duration in seconds. @@ -438,24 +459,9 @@ file: str, file-like object path to output file or a file-like object. If ´str´, it may contain - ´{start}´, ´{end}´ and ´{duration}´ place holders, they'll be - replaced by region's ´start´, ´end´ and ´duration´ respectively. - Example: + and ´{duration}´ place holders as well as any place holder that + this region's metadata might contain (e.g., ´{meta.start}´). - .. code:: python - region = AudioRegion(b'\0' * 2 * 24000, - start=2.25, - sampling_rate=16000, - sample_width=2, - channels=1) - region.duration - 1.5 - region.end - 3.75 - region.save('audio_{start}-{end}.wav') - audio_2.25-3.75.wav - region.save('audio_{duration:.3f}_{start:.3f}-{end:.3f}.wav') - audio_1.500_2.250-3.750.wav format: str type of audio file. If None (default), file type is guessed from @@ -478,13 +484,22 @@ :Raises: IOError if ´file´ exists and ´exists_ok´ is False. + + Example: + + .. code:: python + region = AudioRegion(b'\0' * 2 * 24000, + sampling_rate=16000, + sample_width=2, + channels=1) + region.meta = {"start": 2.25, "end": 2.25 + region.duration} + region.save('audio_{meta.start}-{meta.end}.wav') + audio_2.25-3.75.wav + region.save('region_{meta.start:.3f}_{duration:.3f}.wav') + audio_2.250_1.500.wav """ if isinstance(file, str): - file = file.format( - start=round(self.start, 6), - end=round(self.end, 6), - duration=round(self.duration, 6), - ) + file = file.format(duration=self.duration, meta=self.meta) if not exists_ok and os.path.exists(file): raise FileExistsError("file '{file}' exists".format(file=file)) to_file( @@ -507,18 +522,16 @@ def __bytes__(self): return self._data - def __repr__(self): + def __str__(self): return ( - "AudioRegion(data, start={:.3f}, end={:.3f}, " + "AudioRegion(duration={:.3f}, " "sampling_rate={}, sample_width={}, channels={})".format( - self.start, self.end, self.sr, self.sw, self.ch + self.duration, self.sr, self.sw, self.ch ) ) - def __str__(self): - return "AudioRegion(start={:.3f}, end={:.3f}, duration={:.3f}".format( - self.start, self.end, self.duration - ) + def __repr__(self): + return str(self) def __add__(self, other): """ @@ -547,7 +560,7 @@ "number of channels ({} != {})".format(self.ch, other.ch) ) data = self._data + other._data - return AudioRegion(data, self.start, self.sr, self.sw, self.ch) + return AudioRegion(data, self.sr, self.sw, self.ch) def __radd__(self, other): """ @@ -565,7 +578,7 @@ err_msg = "Can't multiply AudioRegion by a non-int of type '{}'" raise TypeError(err_msg.format(type(n))) data = self._data * n - return AudioRegion(data, self.start, self.sr, self.sw, self.ch) + return AudioRegion(data, self.sr, self.sw, self.ch) def __rmul__(self, n): return self * n @@ -602,8 +615,7 @@ offset = None data = self._data[onset:offset] - new_start = self.start + start_sample / self.sampling_rate - return AudioRegion(data, new_start, self.sr, self.sw, self.ch) + return AudioRegion(data, self.sr, self.sw, self.ch) class StreamTokenizer: diff -r f55007434c6b -r ee6d2294cdd5 tests/test_core.py --- a/tests/test_core.py Mon Jul 29 20:37:31 2019 +0100 +++ b/tests/test_core.py Wed Jul 31 20:07:27 2019 +0100 @@ -21,10 +21,7 @@ for b in byte_seq: duration = round(random() * 10, 6) data = b * int(duration * sampling_rate) * sample_width * channels - start = round(random() * 13, 3) - region = AudioRegion( - data, start, sampling_rate, sample_width, channels - ) + region = AudioRegion(data, sampling_rate, sample_width, channels) regions.append(region) return regions @@ -611,7 +608,6 @@ audio_region=( AudioRegion( open("tests/data/test_split_10HZ_stereo.raw", "rb").read(), - 0, 10, 2, 2, @@ -916,17 +912,16 @@ expected_duration_s, expected_duration_ms, ): - region = AudioRegion( - data, start, sampling_rate, sample_width, channels - ) + meta = {"start": start, "end": expected_end} + region = AudioRegion(data, sampling_rate, sample_width, channels, meta) self.assertEqual(region.sampling_rate, sampling_rate) self.assertEqual(region.sr, sampling_rate) self.assertEqual(region.sample_width, sample_width) self.assertEqual(region.sw, sample_width) self.assertEqual(region.channels, channels) self.assertEqual(region.ch, channels) - self.assertEqual(region.start, start) - self.assertEqual(region.end, expected_end) + self.assertEqual(region.meta.start, start) + self.assertEqual(region.meta.end, expected_end) self.assertEqual(region.duration, expected_duration_s) self.assertEqual(len(region), expected_duration_ms) self.assertEqual(bytes(region), data) @@ -934,11 +929,7 @@ def test_creation_invalid_data_exception(self): with self.assertRaises(AudioParameterError) as audio_param_err: _ = AudioRegion( - data=b"ABCDEFGHI", - start=0, - sampling_rate=8, - sample_width=2, - channels=1, + data=b"ABCDEFGHI", sampling_rate=8, sample_width=2, channels=1 ) self.assertEqual( "The length of audio data must be an integer " @@ -948,29 +939,31 @@ @genty_dataset( simple=("output.wav", 1.230, "output.wav"), - start=("output_{start}.wav", 1.230, "output_1.23.wav"), - start_2=("output_{start}.wav", 1.233712, "output_1.233712.wav"), - start_3=("output_{start}.wav", 1.2300001, "output_1.23.wav"), - start_4=("output_{start:.3f}.wav", 1.233712, "output_1.234.wav"), + start=("output_{meta.start:g}.wav", 1.230, "output_1.23.wav"), + start_2=("output_{meta.start}.wav", 1.233712, "output_1.233712.wav"), + start_3=("output_{meta.start:.2f}.wav", 1.2300001, "output_1.23.wav"), + start_4=("output_{meta.start:.3f}.wav", 1.233712, "output_1.234.wav"), start_5=( - "output_{start:.8f}.wav", - 1.233712345, + "output_{meta.start:.8f}.wav", + 1.233712, "output_1.23371200.wav", ), start_end_duration=( - "output_{start}_{end}_{duration}.wav", + "output_{meta.start}_{meta.end}_{duration}.wav", 1.455, "output_1.455_2.455_1.0.wav", ), start_end_duration_2=( - "output_{start}_{end}_{duration}.wav", + "output_{meta.start}_{meta.end}_{duration}.wav", 1.455321, "output_1.455321_2.455321_1.0.wav", ), ) def test_save(self, format, start, expected): with TemporaryDirectory() as tmpdir: - region = AudioRegion(b"0" * 160, start, 160, 1, 1) + region = AudioRegion(b"0" * 160, 160, 1, 1) + meta = {"start": start, "end": start + region.duration} + region.meta = meta format = os.path.join(tmpdir, format) filename = region.save(format)[len(tmpdir) + 1 :] self.assertEqual(filename, expected) @@ -979,279 +972,252 @@ with TemporaryDirectory() as tmpdir: filename = os.path.join(tmpdir, "output.wav") open(filename, "w").close() - region = AudioRegion(b"0" * 160, 0, 160, 1, 1) + region = AudioRegion(b"0" * 160, 160, 1, 1) with self.assertRaises(FileExistsError): region.save(filename, exists_ok=False) @genty_dataset( first_half=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), slice(0, 500), + b"a" * 80, + ), + second_half=( + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(500, None), + b"b" * 80, + ), + second_half_negative=( + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(-500, None), + b"b" * 80, + ), + middle=( + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(200, 750), + b"a" * 48 + b"b" * 40, + ), + middle_negative=( + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(-800, -250), + b"a" * 48 + b"b" * 40, + ), + middle_sw2=( + AudioRegion(b"a" * 160 + b"b" * 160, 160, 2, 1), + slice(200, 750), + b"a" * 96 + b"b" * 80, + ), + middle_ch2=( + AudioRegion(b"a" * 160 + b"b" * 160, 160, 1, 2), + slice(200, 750), + b"a" * 96 + b"b" * 80, + ), + middle_sw2_ch2=( + AudioRegion(b"a" * 320 + b"b" * 320, 160, 2, 2), + slice(200, 750), + b"a" * 192 + b"b" * 160, + ), + but_first_sample=( + AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1), + slice(1, None), + b"a" * (4000 - 8) + b"b" * 4000, + ), + but_first_sample_negative=( + AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1), + slice(-999, None), + b"a" * (4000 - 8) + b"b" * 4000, + ), + but_last_sample=( + AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1), + slice(0, 999), + b"a" * 4000 + b"b" * (4000 - 8), + ), + but_last_sample_negative=( + AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1), + slice(0, -1), + b"a" * 4000 + b"b" * (4000 - 8), + ), + big_negative_start=( + AudioRegion(b"a" * 160, 160, 1, 1), + slice(-5000, None), + b"a" * 160, + ), + big_negative_stop=( + AudioRegion(b"a" * 160, 160, 1, 1), + slice(None, -1500), + b"", + ), + empty=( + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(0, 0), + b"", + ), + empty_start_stop_reversed=( + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(200, 100), + b"", + ), + empty_big_positive_start=( + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(2000, 3000), + b"", + ), + empty_negative_reversed=( + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(-100, -200), + b"", + ), + empty_big_negative_stop=( + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(0, -2000), + b"", + ), + arbitrary_sampling_rate=( + AudioRegion(b"a" * 124 + b"b" * 376, 1234, 1, 1), + slice(100, 200), + b"a" + b"b" * 123, + ), + ) + def test_region_temporal_slicing(self, region, slice_, expected_data): + sub_region = region.millis[slice_] + self.assertEqual(bytes(sub_region), expected_data) + start_sec = slice_.start / 1000 if slice_.start is not None else None + stop_sec = slice_.stop / 1000 if slice_.stop is not None else None + sub_region = region.sec[start_sec:stop_sec] + self.assertEqual(bytes(sub_region), expected_data) + + @genty_dataset( + first_half=( + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(0, 80), 0, b"a" * 80, ), second_half=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(500, None), + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(80, None), 0.5, b"b" * 80, ), second_half_negative=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(-500, None), + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(-80, None), 0.5, b"b" * 80, ), middle=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(200, 750), + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(160 // 5, 160 // 4 * 3), 0.2, b"a" * 48 + b"b" * 40, ), middle_negative=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(-800, -250), + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(-160 // 5 * 4, -160 // 4), 0.2, b"a" * 48 + b"b" * 40, ), middle_sw2=( - AudioRegion(b"a" * 160 + b"b" * 160, 0, 160, 2, 1), - slice(200, 750), + AudioRegion(b"a" * 160 + b"b" * 160, 160, 2, 1), + slice(160 // 5, 160 // 4 * 3), 0.2, b"a" * 96 + b"b" * 80, ), middle_ch2=( - AudioRegion(b"a" * 160 + b"b" * 160, 0, 160, 1, 2), - slice(200, 750), + AudioRegion(b"a" * 160 + b"b" * 160, 160, 1, 2), + slice(160 // 5, 160 // 4 * 3), 0.2, b"a" * 96 + b"b" * 80, ), middle_sw2_ch2=( - AudioRegion(b"a" * 320 + b"b" * 320, 0, 160, 2, 2), - slice(200, 750), + AudioRegion(b"a" * 320 + b"b" * 320, 160, 2, 2), + slice(160 // 5, 160 // 4 * 3), 0.2, b"a" * 192 + b"b" * 160, ), but_first_sample=( - AudioRegion(b"a" * 4000 + b"b" * 4000, 0, 8000, 1, 1), + AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1), slice(1, None), - 0.001, - b"a" * (4000 - 8) + b"b" * 4000, + 1 / 8000, + b"a" * (4000 - 1) + b"b" * 4000, ), but_first_sample_negative=( - AudioRegion(b"a" * 4000 + b"b" * 4000, 0, 8000, 1, 1), - slice(-999, None), - 0.001, - b"a" * (4000 - 8) + b"b" * 4000, + AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1), + slice(-7999, None), + 1 / 8000, + b"a" * (4000 - 1) + b"b" * 4000, ), but_last_sample=( - AudioRegion(b"a" * 4000 + b"b" * 4000, 0, 8000, 1, 1), - slice(0, 999), + AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1), + slice(0, 7999), 0, - b"a" * 4000 + b"b" * (4000 - 8), + b"a" * 4000 + b"b" * (4000 - 1), ), but_last_sample_negative=( - AudioRegion(b"a" * 4000 + b"b" * 4000, 0, 8000, 1, 1), + AudioRegion(b"a" * 4000 + b"b" * 4000, 8000, 1, 1), slice(0, -1), 0, - b"a" * 4000 + b"b" * (4000 - 8), + b"a" * 4000 + b"b" * (4000 - 1), ), big_negative_start=( - AudioRegion(b"a" * 160, 0, 160, 1, 1), - slice(-5000, None), + AudioRegion(b"a" * 160, 160, 1, 1), + slice(-1600, None), 0, b"a" * 160, ), big_negative_stop=( - AudioRegion(b"a" * 160, 0, 160, 1, 1), - slice(None, -1500), + AudioRegion(b"a" * 160, 160, 1, 1), + slice(None, -1600), 0, b"", ), empty=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), slice(0, 0), 0, b"", ), empty_start_stop_reversed=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(200, 100), - 0.2, + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(80, 40), + 0.5, b"", ), empty_big_positive_start=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(2000, 3000), - 2, + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(1600, 3000), + 10, b"", ), empty_negative_reversed=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(-100, -200), + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), + slice(-16, -32), 0.9, b"", ), empty_big_negative_stop=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), + AudioRegion(b"a" * 80 + b"b" * 80, 160, 1, 1), slice(0, -2000), 0, b"", ), arbitrary_sampling_rate=( - AudioRegion(b"a" * 124 + b"b" * 376, 0, 1234, 1, 1), - slice(100, 200), - 123 / 1234, - b"a" + b"b" * 123, - ), - ) - def test_region_temporal_slicing( - self, region, slice_, expected_start, expected_data - ): - sub_region = region.millis[slice_] - self.assertEqual(sub_region.start, expected_start) - self.assertEqual(bytes(sub_region), expected_data) - - start_sec = slice_.start / 1000 if slice_.start is not None else None - stop_sec = slice_.stop / 1000 if slice_.stop is not None else None - - sub_region = region.sec[start_sec:stop_sec] - self.assertEqual(sub_region.start, expected_start) - self.assertEqual(bytes(sub_region), expected_data) - - @genty_dataset( - first_half=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(0, 80), - 0, - b"a" * 80, - ), - second_half=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(80, None), - 0.5, - b"b" * 80, - ), - second_half_negative=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(-80, None), - 0.5, - b"b" * 80, - ), - middle=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(160 // 5, 160 // 4 * 3), - 0.2, - b"a" * 48 + b"b" * 40, - ), - middle_negative=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(-160 // 5 * 4, -160 // 4), - 0.2, - b"a" * 48 + b"b" * 40, - ), - middle_sw2=( - AudioRegion(b"a" * 160 + b"b" * 160, 0, 160, 2, 1), - slice(160 // 5, 160 // 4 * 3), - 0.2, - b"a" * 96 + b"b" * 80, - ), - middle_ch2=( - AudioRegion(b"a" * 160 + b"b" * 160, 0, 160, 1, 2), - slice(160 // 5, 160 // 4 * 3), - 0.2, - b"a" * 96 + b"b" * 80, - ), - middle_sw2_ch2=( - AudioRegion(b"a" * 320 + b"b" * 320, 0, 160, 2, 2), - slice(160 // 5, 160 // 4 * 3), - 0.2, - b"a" * 192 + b"b" * 160, - ), - but_first_sample=( - AudioRegion(b"a" * 4000 + b"b" * 4000, 0, 8000, 1, 1), - slice(1, None), - 1 / 8000, - b"a" * (4000 - 1) + b"b" * 4000, - ), - but_first_sample_negative=( - AudioRegion(b"a" * 4000 + b"b" * 4000, 0, 8000, 1, 1), - slice(-7999, None), - 1 / 8000, - b"a" * (4000 - 1) + b"b" * 4000, - ), - but_last_sample=( - AudioRegion(b"a" * 4000 + b"b" * 4000, 0, 8000, 1, 1), - slice(0, 7999), - 0, - b"a" * 4000 + b"b" * (4000 - 1), - ), - but_last_sample_negative=( - AudioRegion(b"a" * 4000 + b"b" * 4000, 0, 8000, 1, 1), - slice(0, -1), - 0, - b"a" * 4000 + b"b" * (4000 - 1), - ), - big_negative_start=( - AudioRegion(b"a" * 160, 0, 160, 1, 1), - slice(-1600, None), - 0, - b"a" * 160, - ), - big_negative_stop=( - AudioRegion(b"a" * 160, 0, 160, 1, 1), - slice(None, -1600), - 0, - b"", - ), - empty=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(0, 0), - 0, - b"", - ), - empty_start_stop_reversed=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(80, 40), - 0.5, - b"", - ), - empty_big_positive_start=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(1600, 3000), - 10, - b"", - ), - empty_negative_reversed=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(-16, -32), - 0.9, - b"", - ), - empty_big_negative_stop=( - AudioRegion(b"a" * 80 + b"b" * 80, 0, 160, 1, 1), - slice(0, -2000), - 0, - b"", - ), - arbitrary_sampling_rate=( - AudioRegion(b"a" * 124 + b"b" * 376, 0, 1235, 1, 1), + AudioRegion(b"a" * 124 + b"b" * 376, 1235, 1, 1), slice(100, 200), 100 / 1235, b"a" * 24 + b"b" * 76, ), arbitrary_sampling_rate_middle_sw2_ch2=( - AudioRegion(b"a" * 124 + b"b" * 376, 0, 1235, 2, 2), + AudioRegion(b"a" * 124 + b"b" * 376, 1235, 2, 2), slice(25, 50), 25 / 1235, b"a" * 24 + b"b" * 76, ), ) def test_region_sample_slicing( - self, region, slice_, expected_start, expected_data + self, region, slice_, time_shift, expected_data ): sub_region = region[slice_] - self.assertEqual(sub_region.start, expected_start) self.assertEqual(bytes(sub_region), expected_data) @genty_dataset( @@ -1264,15 +1230,9 @@ region_1, region_2 = _make_random_length_regions( [b"a", b"b"], sampling_rate, sample_width, channels ) - - expected_start = region_1.start expected_duration = region_1.duration + region_2.duration - expected_end = expected_start + expected_duration expected_data = bytes(region_1) + bytes(region_2) concat_region = region_1 + region_2 - - self.assertEqual(concat_region.start, expected_start) - self.assertAlmostEqual(concat_region.end, expected_end, places=6) self.assertAlmostEqual( concat_region.duration, expected_duration, places=6 ) @@ -1288,14 +1248,10 @@ regions = _make_random_length_regions( [b"a", b"b", b"c"], sampling_rate, sample_width, channels ) - expected_start = regions[0].start expected_duration = sum(r.duration for r in regions) - expected_end = expected_start + expected_duration expected_data = b"".join(bytes(r) for r in regions) concat_region = sum(regions) - self.assertEqual(concat_region.start, expected_start) - self.assertAlmostEqual(concat_region.end, expected_end, places=6) self.assertAlmostEqual( concat_region.duration, expected_duration, places=6 ) @@ -1303,8 +1259,8 @@ def test_concatenation_different_sampling_rate_error(self): - region_1 = AudioRegion(b"a" * 100, 0, 8000, 1, 1) - region_2 = AudioRegion(b"b" * 100, 0, 3000, 1, 1) + region_1 = AudioRegion(b"a" * 100, 8000, 1, 1) + region_2 = AudioRegion(b"b" * 100, 3000, 1, 1) with self.assertRaises(ValueError) as val_err: region_1 + region_2 @@ -1316,8 +1272,8 @@ def test_concatenation_different_sample_width_error(self): - region_1 = AudioRegion(b"a" * 100, 0, 8000, 2, 1) - region_2 = AudioRegion(b"b" * 100, 0, 8000, 4, 1) + region_1 = AudioRegion(b"a" * 100, 8000, 2, 1) + region_2 = AudioRegion(b"b" * 100, 8000, 4, 1) with self.assertRaises(ValueError) as val_err: region_1 + region_2 @@ -1329,8 +1285,8 @@ def test_concatenation_different_number_of_channels_error(self): - region_1 = AudioRegion(b"a" * 100, 0, 8000, 1, 1) - region_2 = AudioRegion(b"b" * 100, 0, 8000, 1, 2) + region_1 = AudioRegion(b"a" * 100, 8000, 1, 1) + region_2 = AudioRegion(b"b" * 100, 8000, 1, 2) with self.assertRaises(ValueError) as val_err: region_1 + region_2 @@ -1350,7 +1306,7 @@ ): sw = 2 data = b"0" * int(duration * 8000 * sw) - region = AudioRegion(data, 0, 8000, sw, 1) + region = AudioRegion(data, 8000, sw, 1) m_region = 1 * region * 3 self.assertEqual(bytes(m_region), data * 3) self.assertEqual(m_region.sr, 8000) @@ -1362,6 +1318,6 @@ @genty_dataset(_str=("x", "str"), _float=(1.4, "float")) def test_multiplication_non_int(self, factor, _type): with self.assertRaises(TypeError) as type_err: - AudioRegion(b"0" * 80, 0, 8000, 1, 1) * factor + AudioRegion(b"0" * 80, 8000, 1, 1) * factor err_msg = "Can't multiply AudioRegion by a non-int of type '{}'" self.assertEqual(err_msg.format(_type), str(type_err.exception))