From f1dfaed57f2faf8bbd96e16c7354e0ab1095ae1d Mon Sep 17 00:00:00 2001 From: sammlapp Date: Mon, 8 Apr 2024 13:19:15 -0400 Subject: [PATCH] fix extend_to resolves #972 and #948 changes the behavior of extend_to() so that it doesn't trim audio --- opensoundscape/audio.py | 41 +++++++++++++++++++++-------------------- tests/test_audio.py | 17 ++++++++++++++--- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/opensoundscape/audio.py b/opensoundscape/audio.py index 926bdf4f..c3faed55 100644 --- a/opensoundscape/audio.py +++ b/opensoundscape/audio.py @@ -587,41 +587,42 @@ def loop(self, length=None, n=None): def extend_to(self, duration): """Extend audio file to desired duration by adding silence to the end - If duration is less than the Audio's .duration, the Audio object is trimmed. + If `duration` is less than or equal to the Audio's self.duration, the Audio remains unchanged. + Otherwise, silence is added to the end of the Audio object to achieve the desired - duration. + `duration`. Args: - duration: the final duration in seconds of the audio object + duration: the minimum final duration in seconds of the audio object Returns: a new Audio object of the desired duration """ - target_n_samples = round(duration * self.sample_rate) + minimum_n_samples = round(duration * self.sample_rate) current_n_samples = len(self.samples) - if target_n_samples > current_n_samples: + if minimum_n_samples <= current_n_samples: + return self._spawn() + + else: # add 0's to the end of the sample array new_samples = np.pad( - self.samples, pad_width=(0, target_n_samples - current_n_samples) + self.samples, pad_width=(0, minimum_n_samples - current_n_samples) ) - elif target_n_samples < current_n_samples: - # trim to desired samples (similar to self.trim()) - new_samples = self.samples[0:target_n_samples] - # update metadata to reflect new duration - if self.metadata is None: - metadata = None - else: - metadata = self.metadata.copy() - if "duration" in metadata: - metadata["duration"] = len(new_samples) / self.sample_rate + # update metadata to reflect new duration + if self.metadata is None: + metadata = None + else: + metadata = self.metadata.copy() + if "duration" in metadata: + metadata["duration"] = len(new_samples) / self.sample_rate - return self._spawn( - samples=new_samples, - metadata=metadata, - ) + return self._spawn( + samples=new_samples, + metadata=metadata, + ) def extend_by(self, duration): """Extend audio file by adding `duration` seconds of silence to the end diff --git a/tests/test_audio.py b/tests/test_audio.py index 39dff9d8..5853d25d 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -523,12 +523,23 @@ def test_extend_to_correct_metadata(silence_10s_mp3_str): def test_extend_to_shorter_duration(silence_10s_mp3_str): - # extending 10s to 6s should simply trim the audio + # extending 10s to 6s should retain 10s audio = Audio.from_file(silence_10s_mp3_str, sample_rate=10000) a2 = audio.extend_to(6) - assert math.isclose(a2.duration, 6) + assert math.isclose(a2.duration, 10) # duration in metadata should be updated: - assert math.isclose(a2.metadata["duration"], 6) + assert math.isclose(a2.metadata["duration"], 10) + # other metadata should be retained: + assert a2.metadata["subtype"] == audio.metadata["subtype"] + + +def test_extend_to_correct_duration_ok(silence_10s_mp3_str): + # extending 10s to 10 shouldn't raise error (#972) + audio = Audio.from_file(silence_10s_mp3_str, sample_rate=10000) + a2 = audio.extend_to(10) + assert math.isclose(a2.duration, 10) + # duration in metadata should be updated: + assert math.isclose(a2.metadata["duration"], 10) # other metadata should be retained: assert a2.metadata["subtype"] == audio.metadata["subtype"]