Skip to content

Commit

Permalink
Add 'AudioClip.max_volume(stereo=True)' support for more than 2 chann…
Browse files Browse the repository at this point in the history
…els (#1464)
  • Loading branch information
mondeja authored Jan 19, 2021
1 parent 3685041 commit 15a9af8
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Changed deprecated `tostring` method by `tobytes` in `video.io.gif_writers::write_gif` [\#1429](https://github.com/Zulko/moviepy/pull/1429)
- Fixed calling `audio_normalize` on a clip with no sound causing `ZeroDivisionError` [\#1401](https://github.com/Zulko/moviepy/pull/1401)
- Fixed `freeze` FX was freezing at time minus 1 second as the end [\#1461](https://github.com/Zulko/moviepy/pull/1461)
- `AudioClip.max_volume(stereo=True)` now can return more than 2 channels [\#1464](https://github.com/Zulko/moviepy/pull/1464)


## [v2.0.0.dev2](https://github.com/zulko/moviepy/tree/v2.0.0.dev2) (2020-10-05)
Expand Down
17 changes: 8 additions & 9 deletions moviepy/audio/AudioClip.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,16 @@ def to_soundarray(
return snd_array

def max_volume(self, stereo=False, chunksize=50000, logger=None):
# max volume separated by channels if ``stereo`` and not mono
stereo = stereo and self.nchannels > 1

stereo = stereo and (self.nchannels == 2)

maxi = np.array([0, 0]) if stereo else 0
# zero for each channel
maxi = np.zeros(self.nchannels)
for chunk in self.iter_chunks(chunksize=chunksize, logger=logger):
maxi = (
np.maximum(maxi, abs(chunk).max(axis=0))
if stereo
else max(maxi, abs(chunk).max())
)
return maxi
maxi = np.maximum(maxi, abs(chunk).max(axis=0))

# if mono returns float, otherwise array of volumes by channel
return maxi if stereo else maxi[0]

@requires_duration
@convert_path_to_string("filename")
Expand Down
46 changes: 46 additions & 0 deletions tests/test_AudioClips.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,5 +97,51 @@ def test_audiofileclip_concat():
concat.write_audiofile(os.path.join(TMP_DIR, "concat_audio_file.mp3"))


def test_audioclip_mono_max_volume():
# mono
make_frame_440 = lambda t: np.sin(440 * 2 * np.pi * t)
clip = AudioClip(make_frame_440, duration=1, fps=44100)
max_volume = clip.max_volume()
assert isinstance(max_volume, float)
assert max_volume > 0


@pytest.mark.parametrize(("nchannels"), (2, 4, 8, 16))
@pytest.mark.parametrize(("channel_muted"), ("left", "right"))
def test_audioclip_stereo_max_volume(nchannels, channel_muted):
def make_frame(t):
frame = []
# build channels (one of each pair muted)
for i in range(int(nchannels / 2)):
if channel_muted == "left":
# if muted channel is left, [0, sound, 0, sound...]
frame.append(np.sin(t * 0))
frame.append(np.sin(440 * 2 * np.pi * t))
else:
# if muted channel is right, [sound, 0, sound, 0...]
frame.append(np.sin(440 * 2 * np.pi * t))
frame.append(np.sin(t * 0))
return np.array(frame).T

clip = AudioClip(make_frame, fps=44100, duration=1)
max_volume = clip.max_volume(stereo=True)
# if `stereo == True`, `AudioClip.max_volume` returns a Numpy array`
assert isinstance(max_volume, np.ndarray)
assert len(max_volume) == nchannels

# check channels muted and with sound
for i, channel_max_volume in enumerate(max_volume):
if i % 2 == 0:
if channel_muted == "left":
assert channel_max_volume == 0
else:
assert channel_max_volume > 0
else:
if channel_muted == "right":
assert channel_max_volume == 0
else:
assert channel_max_volume > 0


if __name__ == "__main__":
pytest.main()

0 comments on commit 15a9af8

Please sign in to comment.