Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add options to fix clipping and apply peak normalization to the generated soundscape #132

Merged
merged 25 commits into from
Sep 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6da1890
bump version to 1.6.3
justinsalamon Sep 24, 2020
05261f8
Remove unused imports and clean up formatting
justinsalamon Sep 24, 2020
2400ef7
Implement peak normalize
justinsalamon Sep 24, 2020
68be280
First pass at fix_clipping and peak_normalization, tests failing
justinsalamon Sep 24, 2020
c4b8f26
fix bug in code for saving isolated events audio
justinsalamon Sep 24, 2020
9ae18af
test peak_normalize
justinsalamon Sep 24, 2020
627f7cf
Warn user when ref_db changes due to clipping prevention
justinsalamon Sep 24, 2020
8de1713
Return ref_db_change
justinsalamon Sep 25, 2020
9de26b6
update regression jams with new generate fields
justinsalamon Sep 25, 2020
f912321
Store all generation parmas in the jams sandbox
justinsalamon Sep 25, 2020
c71be95
Add ability to exclude sandbox keys from jams comparison
justinsalamon Sep 25, 2020
69878f4
exclude sandbox keys not relevant to tests
justinsalamon Sep 25, 2020
af3faef
add new sandbox fields to prevent unit test fail on load
justinsalamon Sep 25, 2020
b5bc632
add tests for clipping and normalization
justinsalamon Sep 25, 2020
836a9fa
Remove pyrsistent==0.15.4 dep since we've dropped 2.7 and 3.4
justinsalamon Sep 25, 2020
b7079c4
Update changelog
justinsalamon Sep 25, 2020
6db0f28
start working on more tests, commented out for now
justinsalamon Sep 25, 2020
bcd7f3f
make generate from jams backward compatible with files that don't hav…
justinsalamon Sep 25, 2020
504aef9
test generating from file that doesn't have fix_clipping and peak_nor…
justinsalamon Sep 25, 2020
619c26d
regression
justinsalamon Sep 25, 2020
2d72ad0
Almost done with tests...
justinsalamon Sep 25, 2020
e964660
Fixing generate_from_jams so it saves to the ann.
Sep 26, 2020
77779ca
move transformer creation into conditional reverb block. MUST apply r…
justinsalamon Sep 28, 2020
d779ef3
Use os.makedirs(..., exist_ok=True), update some inline comments
justinsalamon Sep 28, 2020
3e10f95
Updating profile script.
Sep 28, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

Changelog
---------
v1.6.3
~~~~~~
- Scaper.generate now accepts two new optional arguments for controlling audio clipping and normalization:
- fix_clipping: if True and the soundscape audio is clipping, it will be peak normalized and all isolated events will be scaled accordingly.
- peak_normalization: if True, sounscape audio will be peak normalized regardless of whether it's clipping or not and all isolated events will be scaled accordingly.
- All generate arguments are now documented in the scaper sandbox inside the JAMS annotation.
- Furthermore, we also document in the JAMS: the scale factor used for peak normalization, the change in ref_db, and the actual ref_db of the generated audio.
justinsalamon marked this conversation as resolved.
Show resolved Hide resolved

v1.6.2
~~~~~~
- Switching from FFMpeg LUFS calculation to pyloudnorm for better performance: runtime is reduced by approximately 30%
Expand Down
51 changes: 40 additions & 11 deletions scaper/audio.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
# CREATED: 4/23/17 15:37 by Justin Salamon <[email protected]>

'''
Utility functions for audio processing using FFMPEG (beyond sox). Based on:
https://github.com/mathos/neg23/
'''

import subprocess
import sox
import numpy as np
import pyloudnorm
import soundfile
import tempfile
from .scaper_exceptions import ScaperError
from .util import _close_temp_files


def get_integrated_lufs(audio_array, samplerate, min_duration=0.5,
filter_class='K-weighting', block_size=0.400):
Expand Down Expand Up @@ -104,5 +96,42 @@ def match_sample_length(audio_path, duration_in_samples):

audio = np.pad(audio, pad_width, 'constant')

soundfile.write(audio_path, audio, sr,
subtype=audio_info.subtype, format=audio_info.format)
soundfile.write(audio_path, audio, sr,
subtype=audio_info.subtype, format=audio_info.format)


def peak_normalize(soundscape_audio, event_audio_list):
"""
Compute the scale factor required to peak normalize the audio such that
max(abs(soundscape_audio)) = 1.

Parameters
----------
soundscape_audio : np.ndarray
The soudnscape audio.
event_audio_list : list
List of np.ndarrays containing the audio samples of each isolated
foreground event.

Returns
-------
scaled_soundscape_audio : np.ndarray
The peak normalized soundscape audio.
scaled_event_audio_list : list
List of np.ndarrays containing the scaled audio samples of
each isolated foreground event. All events are scaled by scale_factor.
scale_factor : float
The scale factor used to peak normalize the soundscape audio.
"""
eps = 1e-10
max_sample = np.max(np.abs(soundscape_audio))
justinsalamon marked this conversation as resolved.
Show resolved Hide resolved
scale_factor = 1.0 / (max_sample + eps)

# scale the event audio and the soundscape audio:
scaled_soundscape_audio = soundscape_audio * scale_factor

scaled_event_audio_list = []
for event_audio in event_audio_list:
scaled_event_audio_list.append(event_audio * scale_factor)

return scaled_soundscape_audio, scaled_event_audio_list, scale_factor
Loading