ffmpeg-normalize 1.30.0__tar.gz → 1.31.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/CHANGELOG.md +15 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/PKG-INFO +82 -7
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/README.md +66 -6
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize/__main__.py +16 -3
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize/_cmd_utils.py +3 -3
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize/_ffmpeg_normalize.py +3 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize/_media_file.py +1 -1
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize/_streams.py +16 -2
- ffmpeg_normalize-1.31.0/ffmpeg_normalize/_version.py +1 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize.egg-info/PKG-INFO +82 -7
- ffmpeg_normalize-1.30.0/ffmpeg_normalize/_version.py +0 -1
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/LICENSE +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize/__init__.py +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize/_errors.py +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize/_logger.py +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize/py.typed +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize.egg-info/SOURCES.txt +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize.egg-info/dependency_links.txt +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize.egg-info/entry_points.txt +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize.egg-info/not-zip-safe +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize.egg-info/requires.txt +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize.egg-info/top_level.txt +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/setup.cfg +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/setup.py +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/test/out.mp4 +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/test/test.mp4 +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/test/test.py +0 -0
- {ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/test/test.wav +0 -0
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## v1.31.0 (2024-12-15)
|
|
5
|
+
|
|
6
|
+
* Update docs and completions.
|
|
7
|
+
|
|
8
|
+
* Implement `--auto-lower-loudness-target`
|
|
9
|
+
|
|
10
|
+
* Fix deprecations and mypy --strict errors.
|
|
11
|
+
|
|
12
|
+
* Feat: add completions.
|
|
13
|
+
|
|
14
|
+
* Docs: update explainer.
|
|
15
|
+
|
|
16
|
+
* Docs: update docs to include lower-only.
|
|
17
|
+
|
|
18
|
+
|
|
4
19
|
## v1.30.0 (2024-11-22)
|
|
5
20
|
|
|
6
21
|
* Change lower-only message to warning.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ffmpeg_normalize
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.31.0
|
|
4
4
|
Summary: Normalize audio via ffmpeg
|
|
5
5
|
Home-page: https://github.com/slhck/ffmpeg-normalize
|
|
6
6
|
Author: Werner Robitza
|
|
@@ -54,6 +54,7 @@ Read on for more info.
|
|
|
54
54
|
- [Requirements](#requirements)
|
|
55
55
|
- [ffmpeg](#ffmpeg)
|
|
56
56
|
- [Installation](#installation)
|
|
57
|
+
- [Shell Completions](#shell-completions)
|
|
57
58
|
- [Usage with Docker](#usage-with-docker)
|
|
58
59
|
- [High LeveL Introduction](#high-level-introduction)
|
|
59
60
|
- [Basic Usage](#basic-usage)
|
|
@@ -130,6 +131,54 @@ Or download this repository, then run `pip3 install .`.
|
|
|
130
131
|
|
|
131
132
|
To later upgrade to the latest version, run `pip3 install --upgrade ffmpeg-normalize`.
|
|
132
133
|
|
|
134
|
+
### Shell Completions
|
|
135
|
+
|
|
136
|
+
This tool provides shell completions for bash and zsh. To install them:
|
|
137
|
+
|
|
138
|
+
<!--
|
|
139
|
+
Note to self: Generate the shtab ones with:
|
|
140
|
+
|
|
141
|
+
shtab --shell=bash -u ffmpeg_normalize.__main__.create_parser > completions/ffmpeg-normalize-shtab.bash
|
|
142
|
+
shtab --shell=zsh -u ffmpeg_normalize.__main__.create_parser > completions/ffmpeg-normalize-shtab.zsh
|
|
143
|
+
|
|
144
|
+
but these are not properly working yet.
|
|
145
|
+
-->
|
|
146
|
+
|
|
147
|
+
#### Bash
|
|
148
|
+
|
|
149
|
+
If you have [`bash-completion`](https://github.com/scop/bash-completion) installed, you can just copy your new completion script to the `/usr/local/etc/bash_completion.d` directory.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
curl -L https://raw.githubusercontent.com/slhck/ffmpeg-normalize/master/completions/ffmpeg-normalize-completion.bash \
|
|
153
|
+
-o /usr/local/etc/bash_completion.d/ffmpeg-normalize
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Without bash-completion, you can manually install the completion script:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# create completions directory if it doesn't exist
|
|
160
|
+
mkdir -p ~/.bash_completions.d
|
|
161
|
+
|
|
162
|
+
# download and install completion script
|
|
163
|
+
curl -L https://raw.githubusercontent.com/slhck/ffmpeg-normalize/master/completions/ffmpeg-normalize-completion.bash \
|
|
164
|
+
-o ~/.bash_completions.d/ffmpeg-normalize
|
|
165
|
+
|
|
166
|
+
# source it in your ~/.bashrc
|
|
167
|
+
echo 'source ~/.bash_completions.d/ffmpeg-normalize' >> ~/.bashrc
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Zsh
|
|
171
|
+
|
|
172
|
+
Download the completion script and place it in the default `site-functions` directory:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
curl -L https://raw.githubusercontent.com/slhck/ffmpeg-normalize/master/completions/ffmpeg-normalize.zsh \
|
|
176
|
+
-o /usr/local/share/zsh/site-functions/
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
You may choose any other directory that is in your `$FPATH` variable.
|
|
180
|
+
Make sure your `.zshrc` file contains `autoload -Uz compinit && compinit`.
|
|
181
|
+
|
|
133
182
|
## Usage with Docker
|
|
134
183
|
|
|
135
184
|
You can use the pre-built image from Docker Hub:
|
|
@@ -281,10 +330,7 @@ For more information on the options (`[options]`) available, run `ffmpeg-normali
|
|
|
281
330
|
|
|
282
331
|
- `--keep-lra-above-loudness-range-target`: Keep input loudness range above loudness range target.
|
|
283
332
|
|
|
284
|
-
|
|
285
|
-
- keep input loudness range target above `LOUDNESS_RANGE_TARGET`.
|
|
286
|
-
|
|
287
|
-
as alternative to `--keep-loudness-range-target` to allow for linear normalization.
|
|
333
|
+
Can be used as an alternative to `--keep-loudness-range-target` to allow for linear normalization.
|
|
288
334
|
|
|
289
335
|
- `-tp TRUE_PEAK, --true-peak TRUE_PEAK`: EBU Maximum True Peak in dBTP (default: -2.0).
|
|
290
336
|
|
|
@@ -296,6 +342,16 @@ For more information on the options (`[options]`) available, run `ffmpeg-normali
|
|
|
296
342
|
|
|
297
343
|
Range is -99.0 - +99.0.
|
|
298
344
|
|
|
345
|
+
- `--lower-only`: Whether the audio should not increase in loudness.
|
|
346
|
+
|
|
347
|
+
If the measured loudness from the first pass is lower than the target loudness then normalization pass will be skipped for the measured audio source.
|
|
348
|
+
|
|
349
|
+
- `--auto-lower-loudness-target`: Automatically lower EBU Integrated Loudness Target.
|
|
350
|
+
|
|
351
|
+
Automatically lower EBU Integrated Loudness Target to prevent falling back to dynamic filtering.
|
|
352
|
+
|
|
353
|
+
Makes sure target loudness is lower than measured loudness minus peak loudness (input_i - input_tp) by a small amount.
|
|
354
|
+
|
|
299
355
|
- `--dual-mono`: Treat mono input files as "dual-mono".
|
|
300
356
|
|
|
301
357
|
If a mono file is intended for playback on a stereo system, its EBU R128 measurement will be perceptually incorrect. If set, this option will compensate for this effect. Multi-channel input files are not affected by this option.
|
|
@@ -304,7 +360,7 @@ For more information on the options (`[options]`) available, run `ffmpeg-normali
|
|
|
304
360
|
|
|
305
361
|
Instead of applying linear EBU R128 normalization, choose a dynamic normalization. This is not usually recommended.
|
|
306
362
|
|
|
307
|
-
Dynamic mode will automatically change the sample rate to 192 kHz. Use
|
|
363
|
+
Dynamic mode will automatically change the sample rate to 192 kHz. Use `-ar`/`--sample-rate` to specify a different output sample rate.
|
|
308
364
|
|
|
309
365
|
### Audio Encoding
|
|
310
366
|
|
|
@@ -440,7 +496,11 @@ For most cases, linear mode is recommended. Dynamic mode should only be used whe
|
|
|
440
496
|
|
|
441
497
|
* When the required gain adjustment to meet the integrated loudness target would result in the true peak exceeding the specified true peak limit. This is because linear processing alone cannot reduce peaks without affecting the entire signal. For example, if a file needs to be amplified by 6 dB to reach the target integrated loudness, but doing so would push the true peak above the specified limit, the filter might switch to dynamic mode to handle this situation. If your content allows for it, you can increase the true peak target to give more headroom for linear processing. If you're consistently running into true peak issues, you might also consider lowering your target integrated loudness level.
|
|
442
498
|
|
|
443
|
-
At this time, the `loudnorm` filter in ffmpeg does not provide a way to force linear mode when the input loudness range exceeds the target or when the true peak would be exceeded.
|
|
499
|
+
At this time, the `loudnorm` filter in ffmpeg does not provide a way to force linear mode when the input loudness range exceeds the target or when the true peak would be exceeded. There are some options to mitigate this:
|
|
500
|
+
|
|
501
|
+
- The `--keep-lra-above-loudness-range-target` option can be used to keep the input loudness range above the specified target, but it will not force linear mode in all cases.
|
|
502
|
+
- Similarly, the `--keep-loudness-range-target` option can be used to keep the input loudness range target.
|
|
503
|
+
- The `--lower-only` option can be used to skip the normalization pass completely if the measured loudness is lower than the target loudness.
|
|
444
504
|
|
|
445
505
|
### The program doesn't work because the "loudnorm" filter can't be found
|
|
446
506
|
|
|
@@ -607,6 +667,21 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
607
667
|
# Changelog
|
|
608
668
|
|
|
609
669
|
|
|
670
|
+
## v1.31.0 (2024-12-15)
|
|
671
|
+
|
|
672
|
+
* Update docs and completions.
|
|
673
|
+
|
|
674
|
+
* Implement `--auto-lower-loudness-target`
|
|
675
|
+
|
|
676
|
+
* Fix deprecations and mypy --strict errors.
|
|
677
|
+
|
|
678
|
+
* Feat: add completions.
|
|
679
|
+
|
|
680
|
+
* Docs: update explainer.
|
|
681
|
+
|
|
682
|
+
* Docs: update docs to include lower-only.
|
|
683
|
+
|
|
684
|
+
|
|
610
685
|
## v1.30.0 (2024-11-22)
|
|
611
686
|
|
|
612
687
|
* Change lower-only message to warning.
|
|
@@ -28,6 +28,7 @@ Read on for more info.
|
|
|
28
28
|
- [Requirements](#requirements)
|
|
29
29
|
- [ffmpeg](#ffmpeg)
|
|
30
30
|
- [Installation](#installation)
|
|
31
|
+
- [Shell Completions](#shell-completions)
|
|
31
32
|
- [Usage with Docker](#usage-with-docker)
|
|
32
33
|
- [High LeveL Introduction](#high-level-introduction)
|
|
33
34
|
- [Basic Usage](#basic-usage)
|
|
@@ -104,6 +105,54 @@ Or download this repository, then run `pip3 install .`.
|
|
|
104
105
|
|
|
105
106
|
To later upgrade to the latest version, run `pip3 install --upgrade ffmpeg-normalize`.
|
|
106
107
|
|
|
108
|
+
### Shell Completions
|
|
109
|
+
|
|
110
|
+
This tool provides shell completions for bash and zsh. To install them:
|
|
111
|
+
|
|
112
|
+
<!--
|
|
113
|
+
Note to self: Generate the shtab ones with:
|
|
114
|
+
|
|
115
|
+
shtab --shell=bash -u ffmpeg_normalize.__main__.create_parser > completions/ffmpeg-normalize-shtab.bash
|
|
116
|
+
shtab --shell=zsh -u ffmpeg_normalize.__main__.create_parser > completions/ffmpeg-normalize-shtab.zsh
|
|
117
|
+
|
|
118
|
+
but these are not properly working yet.
|
|
119
|
+
-->
|
|
120
|
+
|
|
121
|
+
#### Bash
|
|
122
|
+
|
|
123
|
+
If you have [`bash-completion`](https://github.com/scop/bash-completion) installed, you can just copy your new completion script to the `/usr/local/etc/bash_completion.d` directory.
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
curl -L https://raw.githubusercontent.com/slhck/ffmpeg-normalize/master/completions/ffmpeg-normalize-completion.bash \
|
|
127
|
+
-o /usr/local/etc/bash_completion.d/ffmpeg-normalize
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Without bash-completion, you can manually install the completion script:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# create completions directory if it doesn't exist
|
|
134
|
+
mkdir -p ~/.bash_completions.d
|
|
135
|
+
|
|
136
|
+
# download and install completion script
|
|
137
|
+
curl -L https://raw.githubusercontent.com/slhck/ffmpeg-normalize/master/completions/ffmpeg-normalize-completion.bash \
|
|
138
|
+
-o ~/.bash_completions.d/ffmpeg-normalize
|
|
139
|
+
|
|
140
|
+
# source it in your ~/.bashrc
|
|
141
|
+
echo 'source ~/.bash_completions.d/ffmpeg-normalize' >> ~/.bashrc
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### Zsh
|
|
145
|
+
|
|
146
|
+
Download the completion script and place it in the default `site-functions` directory:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
curl -L https://raw.githubusercontent.com/slhck/ffmpeg-normalize/master/completions/ffmpeg-normalize.zsh \
|
|
150
|
+
-o /usr/local/share/zsh/site-functions/
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
You may choose any other directory that is in your `$FPATH` variable.
|
|
154
|
+
Make sure your `.zshrc` file contains `autoload -Uz compinit && compinit`.
|
|
155
|
+
|
|
107
156
|
## Usage with Docker
|
|
108
157
|
|
|
109
158
|
You can use the pre-built image from Docker Hub:
|
|
@@ -255,10 +304,7 @@ For more information on the options (`[options]`) available, run `ffmpeg-normali
|
|
|
255
304
|
|
|
256
305
|
- `--keep-lra-above-loudness-range-target`: Keep input loudness range above loudness range target.
|
|
257
306
|
|
|
258
|
-
|
|
259
|
-
- keep input loudness range target above `LOUDNESS_RANGE_TARGET`.
|
|
260
|
-
|
|
261
|
-
as alternative to `--keep-loudness-range-target` to allow for linear normalization.
|
|
307
|
+
Can be used as an alternative to `--keep-loudness-range-target` to allow for linear normalization.
|
|
262
308
|
|
|
263
309
|
- `-tp TRUE_PEAK, --true-peak TRUE_PEAK`: EBU Maximum True Peak in dBTP (default: -2.0).
|
|
264
310
|
|
|
@@ -270,6 +316,16 @@ For more information on the options (`[options]`) available, run `ffmpeg-normali
|
|
|
270
316
|
|
|
271
317
|
Range is -99.0 - +99.0.
|
|
272
318
|
|
|
319
|
+
- `--lower-only`: Whether the audio should not increase in loudness.
|
|
320
|
+
|
|
321
|
+
If the measured loudness from the first pass is lower than the target loudness then normalization pass will be skipped for the measured audio source.
|
|
322
|
+
|
|
323
|
+
- `--auto-lower-loudness-target`: Automatically lower EBU Integrated Loudness Target.
|
|
324
|
+
|
|
325
|
+
Automatically lower EBU Integrated Loudness Target to prevent falling back to dynamic filtering.
|
|
326
|
+
|
|
327
|
+
Makes sure target loudness is lower than measured loudness minus peak loudness (input_i - input_tp) by a small amount.
|
|
328
|
+
|
|
273
329
|
- `--dual-mono`: Treat mono input files as "dual-mono".
|
|
274
330
|
|
|
275
331
|
If a mono file is intended for playback on a stereo system, its EBU R128 measurement will be perceptually incorrect. If set, this option will compensate for this effect. Multi-channel input files are not affected by this option.
|
|
@@ -278,7 +334,7 @@ For more information on the options (`[options]`) available, run `ffmpeg-normali
|
|
|
278
334
|
|
|
279
335
|
Instead of applying linear EBU R128 normalization, choose a dynamic normalization. This is not usually recommended.
|
|
280
336
|
|
|
281
|
-
Dynamic mode will automatically change the sample rate to 192 kHz. Use
|
|
337
|
+
Dynamic mode will automatically change the sample rate to 192 kHz. Use `-ar`/`--sample-rate` to specify a different output sample rate.
|
|
282
338
|
|
|
283
339
|
### Audio Encoding
|
|
284
340
|
|
|
@@ -414,7 +470,11 @@ For most cases, linear mode is recommended. Dynamic mode should only be used whe
|
|
|
414
470
|
|
|
415
471
|
* When the required gain adjustment to meet the integrated loudness target would result in the true peak exceeding the specified true peak limit. This is because linear processing alone cannot reduce peaks without affecting the entire signal. For example, if a file needs to be amplified by 6 dB to reach the target integrated loudness, but doing so would push the true peak above the specified limit, the filter might switch to dynamic mode to handle this situation. If your content allows for it, you can increase the true peak target to give more headroom for linear processing. If you're consistently running into true peak issues, you might also consider lowering your target integrated loudness level.
|
|
416
472
|
|
|
417
|
-
At this time, the `loudnorm` filter in ffmpeg does not provide a way to force linear mode when the input loudness range exceeds the target or when the true peak would be exceeded.
|
|
473
|
+
At this time, the `loudnorm` filter in ffmpeg does not provide a way to force linear mode when the input loudness range exceeds the target or when the true peak would be exceeded. There are some options to mitigate this:
|
|
474
|
+
|
|
475
|
+
- The `--keep-lra-above-loudness-range-target` option can be used to keep the input loudness range above the specified target, but it will not force linear mode in all cases.
|
|
476
|
+
- Similarly, the `--keep-loudness-range-target` option can be used to keep the input loudness range target.
|
|
477
|
+
- The `--lower-only` option can be used to skip the normalization pass completely if the measured loudness is lower than the target loudness.
|
|
418
478
|
|
|
419
479
|
### The program doesn't work because the "loudnorm" filter can't be found
|
|
420
480
|
|
|
@@ -201,9 +201,7 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
201
201
|
help=textwrap.dedent(
|
|
202
202
|
"""\
|
|
203
203
|
Keep input loudness range above loudness range target.
|
|
204
|
-
|
|
205
|
-
- keep input loudness range target above `LOUDNESS_RANGE_TARGET`.
|
|
206
|
-
as alternative to `--keep-loudness-range-target` to allow for linear normalization.
|
|
204
|
+
Can be used as an alternative to `--keep-loudness-range-target` to allow for linear normalization.
|
|
207
205
|
"""
|
|
208
206
|
),
|
|
209
207
|
)
|
|
@@ -249,6 +247,20 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
249
247
|
),
|
|
250
248
|
)
|
|
251
249
|
|
|
250
|
+
group_ebu.add_argument(
|
|
251
|
+
"--auto-lower-loudness-target",
|
|
252
|
+
action="store_true",
|
|
253
|
+
help=textwrap.dedent(
|
|
254
|
+
"""\
|
|
255
|
+
Automatically lower EBU Integrated Loudness Target to prevent falling
|
|
256
|
+
back to dynamic filtering.
|
|
257
|
+
|
|
258
|
+
Makes sure target loudness is lower than measured loudness minus peak
|
|
259
|
+
loudness (input_i - input_tp) by a small amount (0.1 LUFS).
|
|
260
|
+
"""
|
|
261
|
+
),
|
|
262
|
+
)
|
|
263
|
+
|
|
252
264
|
group_ebu.add_argument(
|
|
253
265
|
"--dual-mono",
|
|
254
266
|
action="store_true",
|
|
@@ -529,6 +541,7 @@ def main() -> None:
|
|
|
529
541
|
true_peak=cli_args.true_peak,
|
|
530
542
|
offset=cli_args.offset,
|
|
531
543
|
lower_only=cli_args.lower_only,
|
|
544
|
+
auto_lower_loudness_target=cli_args.auto_lower_loudness_target,
|
|
532
545
|
dual_mono=cli_args.dual_mono,
|
|
533
546
|
dynamic=cli_args.dynamic,
|
|
534
547
|
audio_codec=cli_args.audio_codec,
|
|
@@ -7,7 +7,7 @@ import shlex
|
|
|
7
7
|
import subprocess
|
|
8
8
|
from platform import system
|
|
9
9
|
from shutil import which
|
|
10
|
-
from typing import Iterator
|
|
10
|
+
from typing import Iterator, Any
|
|
11
11
|
|
|
12
12
|
from ffmpeg_progress_yield import FfmpegProgress
|
|
13
13
|
|
|
@@ -128,12 +128,12 @@ class CommandRunner:
|
|
|
128
128
|
return self.output
|
|
129
129
|
|
|
130
130
|
|
|
131
|
-
def dict_to_filter_opts(opts: dict[str,
|
|
131
|
+
def dict_to_filter_opts(opts: dict[str, Any]) -> str:
|
|
132
132
|
"""
|
|
133
133
|
Convert a dictionary to a ffmpeg filter option string
|
|
134
134
|
|
|
135
135
|
Args:
|
|
136
|
-
opts (dict[str,
|
|
136
|
+
opts (dict[str, Any]): Dictionary of options
|
|
137
137
|
|
|
138
138
|
Returns:
|
|
139
139
|
str: Filter option string
|
|
@@ -61,6 +61,7 @@ class FFmpegNormalize:
|
|
|
61
61
|
true_peak (float, optional): True peak. Defaults to -2.0.
|
|
62
62
|
offset (float, optional): Offset. Defaults to 0.0.
|
|
63
63
|
lower_only (bool, optional): Whether the audio should not increase in loudness. Defaults to False.
|
|
64
|
+
auto_lower_loudness_target (bool, optional): Automatically lower EBU Integrated Loudness Target.
|
|
64
65
|
dual_mono (bool, optional): Dual mono. Defaults to False.
|
|
65
66
|
dynamic (bool, optional): Dynamic. Defaults to False.
|
|
66
67
|
audio_codec (str, optional): Audio codec. Defaults to "pcm_s16le".
|
|
@@ -98,6 +99,7 @@ class FFmpegNormalize:
|
|
|
98
99
|
true_peak: float = -2.0,
|
|
99
100
|
offset: float = 0.0,
|
|
100
101
|
lower_only: bool = False,
|
|
102
|
+
auto_lower_loudness_target: bool = False,
|
|
101
103
|
dual_mono: bool = False,
|
|
102
104
|
dynamic: bool = False,
|
|
103
105
|
audio_codec: str = "pcm_s16le",
|
|
@@ -169,6 +171,7 @@ class FFmpegNormalize:
|
|
|
169
171
|
self.true_peak = check_range(true_peak, -9, 0, name="true_peak")
|
|
170
172
|
self.offset = check_range(offset, -99, 99, name="offset")
|
|
171
173
|
self.lower_only = lower_only
|
|
174
|
+
self.auto_lower_loudness_target = auto_lower_loudness_target
|
|
172
175
|
|
|
173
176
|
# Ensure library user is passing correct types
|
|
174
177
|
assert isinstance(dual_mono, bool), "dual_mono must be bool"
|
|
@@ -281,7 +281,7 @@ class MediaFile:
|
|
|
281
281
|
skip_normalization = True
|
|
282
282
|
|
|
283
283
|
if skip_normalization:
|
|
284
|
-
_logger.
|
|
284
|
+
_logger.warning(
|
|
285
285
|
f"Stream {audio_stream.stream_id} had measured input loudness lower than target, skipping normalization."
|
|
286
286
|
)
|
|
287
287
|
normalization_filter = "acopy"
|
|
@@ -167,7 +167,7 @@ class AudioStream(MediaStream):
|
|
|
167
167
|
}
|
|
168
168
|
return stats
|
|
169
169
|
|
|
170
|
-
def set_second_pass_stats(self, stats: EbuLoudnessStatistics):
|
|
170
|
+
def set_second_pass_stats(self, stats: EbuLoudnessStatistics) -> None:
|
|
171
171
|
"""
|
|
172
172
|
Set the EBU loudness statistics for the second pass.
|
|
173
173
|
|
|
@@ -481,10 +481,24 @@ class AudioStream(MediaStream):
|
|
|
481
481
|
"Specify -ar/--sample-rate to override it."
|
|
482
482
|
)
|
|
483
483
|
|
|
484
|
+
target_level = self.ffmpeg_normalize.target_level
|
|
485
|
+
if self.ffmpeg_normalize.auto_lower_loudness_target:
|
|
486
|
+
safe_target = (
|
|
487
|
+
self.loudness_statistics["ebu_pass1"]["input_i"]
|
|
488
|
+
- self.loudness_statistics["ebu_pass1"]["input_tp"]
|
|
489
|
+
+ self.ffmpeg_normalize.true_peak
|
|
490
|
+
- 0.1
|
|
491
|
+
)
|
|
492
|
+
if safe_target < self.ffmpeg_normalize.target_level:
|
|
493
|
+
target_level = safe_target
|
|
494
|
+
_logger.warning(
|
|
495
|
+
f"Using loudness target {target_level} because --auto-lower-loudness-target given.",
|
|
496
|
+
)
|
|
497
|
+
|
|
484
498
|
stats = self.loudness_statistics["ebu_pass1"]
|
|
485
499
|
|
|
486
500
|
opts = {
|
|
487
|
-
"i":
|
|
501
|
+
"i": target_level,
|
|
488
502
|
"lra": self.media_file.ffmpeg_normalize.loudness_range_target,
|
|
489
503
|
"tp": self.media_file.ffmpeg_normalize.true_peak,
|
|
490
504
|
"offset": self._constrain(
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.31.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ffmpeg-normalize
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.31.0
|
|
4
4
|
Summary: Normalize audio via ffmpeg
|
|
5
5
|
Home-page: https://github.com/slhck/ffmpeg-normalize
|
|
6
6
|
Author: Werner Robitza
|
|
@@ -54,6 +54,7 @@ Read on for more info.
|
|
|
54
54
|
- [Requirements](#requirements)
|
|
55
55
|
- [ffmpeg](#ffmpeg)
|
|
56
56
|
- [Installation](#installation)
|
|
57
|
+
- [Shell Completions](#shell-completions)
|
|
57
58
|
- [Usage with Docker](#usage-with-docker)
|
|
58
59
|
- [High LeveL Introduction](#high-level-introduction)
|
|
59
60
|
- [Basic Usage](#basic-usage)
|
|
@@ -130,6 +131,54 @@ Or download this repository, then run `pip3 install .`.
|
|
|
130
131
|
|
|
131
132
|
To later upgrade to the latest version, run `pip3 install --upgrade ffmpeg-normalize`.
|
|
132
133
|
|
|
134
|
+
### Shell Completions
|
|
135
|
+
|
|
136
|
+
This tool provides shell completions for bash and zsh. To install them:
|
|
137
|
+
|
|
138
|
+
<!--
|
|
139
|
+
Note to self: Generate the shtab ones with:
|
|
140
|
+
|
|
141
|
+
shtab --shell=bash -u ffmpeg_normalize.__main__.create_parser > completions/ffmpeg-normalize-shtab.bash
|
|
142
|
+
shtab --shell=zsh -u ffmpeg_normalize.__main__.create_parser > completions/ffmpeg-normalize-shtab.zsh
|
|
143
|
+
|
|
144
|
+
but these are not properly working yet.
|
|
145
|
+
-->
|
|
146
|
+
|
|
147
|
+
#### Bash
|
|
148
|
+
|
|
149
|
+
If you have [`bash-completion`](https://github.com/scop/bash-completion) installed, you can just copy your new completion script to the `/usr/local/etc/bash_completion.d` directory.
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
curl -L https://raw.githubusercontent.com/slhck/ffmpeg-normalize/master/completions/ffmpeg-normalize-completion.bash \
|
|
153
|
+
-o /usr/local/etc/bash_completion.d/ffmpeg-normalize
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Without bash-completion, you can manually install the completion script:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# create completions directory if it doesn't exist
|
|
160
|
+
mkdir -p ~/.bash_completions.d
|
|
161
|
+
|
|
162
|
+
# download and install completion script
|
|
163
|
+
curl -L https://raw.githubusercontent.com/slhck/ffmpeg-normalize/master/completions/ffmpeg-normalize-completion.bash \
|
|
164
|
+
-o ~/.bash_completions.d/ffmpeg-normalize
|
|
165
|
+
|
|
166
|
+
# source it in your ~/.bashrc
|
|
167
|
+
echo 'source ~/.bash_completions.d/ffmpeg-normalize' >> ~/.bashrc
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Zsh
|
|
171
|
+
|
|
172
|
+
Download the completion script and place it in the default `site-functions` directory:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
curl -L https://raw.githubusercontent.com/slhck/ffmpeg-normalize/master/completions/ffmpeg-normalize.zsh \
|
|
176
|
+
-o /usr/local/share/zsh/site-functions/
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
You may choose any other directory that is in your `$FPATH` variable.
|
|
180
|
+
Make sure your `.zshrc` file contains `autoload -Uz compinit && compinit`.
|
|
181
|
+
|
|
133
182
|
## Usage with Docker
|
|
134
183
|
|
|
135
184
|
You can use the pre-built image from Docker Hub:
|
|
@@ -281,10 +330,7 @@ For more information on the options (`[options]`) available, run `ffmpeg-normali
|
|
|
281
330
|
|
|
282
331
|
- `--keep-lra-above-loudness-range-target`: Keep input loudness range above loudness range target.
|
|
283
332
|
|
|
284
|
-
|
|
285
|
-
- keep input loudness range target above `LOUDNESS_RANGE_TARGET`.
|
|
286
|
-
|
|
287
|
-
as alternative to `--keep-loudness-range-target` to allow for linear normalization.
|
|
333
|
+
Can be used as an alternative to `--keep-loudness-range-target` to allow for linear normalization.
|
|
288
334
|
|
|
289
335
|
- `-tp TRUE_PEAK, --true-peak TRUE_PEAK`: EBU Maximum True Peak in dBTP (default: -2.0).
|
|
290
336
|
|
|
@@ -296,6 +342,16 @@ For more information on the options (`[options]`) available, run `ffmpeg-normali
|
|
|
296
342
|
|
|
297
343
|
Range is -99.0 - +99.0.
|
|
298
344
|
|
|
345
|
+
- `--lower-only`: Whether the audio should not increase in loudness.
|
|
346
|
+
|
|
347
|
+
If the measured loudness from the first pass is lower than the target loudness then normalization pass will be skipped for the measured audio source.
|
|
348
|
+
|
|
349
|
+
- `--auto-lower-loudness-target`: Automatically lower EBU Integrated Loudness Target.
|
|
350
|
+
|
|
351
|
+
Automatically lower EBU Integrated Loudness Target to prevent falling back to dynamic filtering.
|
|
352
|
+
|
|
353
|
+
Makes sure target loudness is lower than measured loudness minus peak loudness (input_i - input_tp) by a small amount.
|
|
354
|
+
|
|
299
355
|
- `--dual-mono`: Treat mono input files as "dual-mono".
|
|
300
356
|
|
|
301
357
|
If a mono file is intended for playback on a stereo system, its EBU R128 measurement will be perceptually incorrect. If set, this option will compensate for this effect. Multi-channel input files are not affected by this option.
|
|
@@ -304,7 +360,7 @@ For more information on the options (`[options]`) available, run `ffmpeg-normali
|
|
|
304
360
|
|
|
305
361
|
Instead of applying linear EBU R128 normalization, choose a dynamic normalization. This is not usually recommended.
|
|
306
362
|
|
|
307
|
-
Dynamic mode will automatically change the sample rate to 192 kHz. Use
|
|
363
|
+
Dynamic mode will automatically change the sample rate to 192 kHz. Use `-ar`/`--sample-rate` to specify a different output sample rate.
|
|
308
364
|
|
|
309
365
|
### Audio Encoding
|
|
310
366
|
|
|
@@ -440,7 +496,11 @@ For most cases, linear mode is recommended. Dynamic mode should only be used whe
|
|
|
440
496
|
|
|
441
497
|
* When the required gain adjustment to meet the integrated loudness target would result in the true peak exceeding the specified true peak limit. This is because linear processing alone cannot reduce peaks without affecting the entire signal. For example, if a file needs to be amplified by 6 dB to reach the target integrated loudness, but doing so would push the true peak above the specified limit, the filter might switch to dynamic mode to handle this situation. If your content allows for it, you can increase the true peak target to give more headroom for linear processing. If you're consistently running into true peak issues, you might also consider lowering your target integrated loudness level.
|
|
442
498
|
|
|
443
|
-
At this time, the `loudnorm` filter in ffmpeg does not provide a way to force linear mode when the input loudness range exceeds the target or when the true peak would be exceeded.
|
|
499
|
+
At this time, the `loudnorm` filter in ffmpeg does not provide a way to force linear mode when the input loudness range exceeds the target or when the true peak would be exceeded. There are some options to mitigate this:
|
|
500
|
+
|
|
501
|
+
- The `--keep-lra-above-loudness-range-target` option can be used to keep the input loudness range above the specified target, but it will not force linear mode in all cases.
|
|
502
|
+
- Similarly, the `--keep-loudness-range-target` option can be used to keep the input loudness range target.
|
|
503
|
+
- The `--lower-only` option can be used to skip the normalization pass completely if the measured loudness is lower than the target loudness.
|
|
444
504
|
|
|
445
505
|
### The program doesn't work because the "loudnorm" filter can't be found
|
|
446
506
|
|
|
@@ -607,6 +667,21 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
607
667
|
# Changelog
|
|
608
668
|
|
|
609
669
|
|
|
670
|
+
## v1.31.0 (2024-12-15)
|
|
671
|
+
|
|
672
|
+
* Update docs and completions.
|
|
673
|
+
|
|
674
|
+
* Implement `--auto-lower-loudness-target`
|
|
675
|
+
|
|
676
|
+
* Fix deprecations and mypy --strict errors.
|
|
677
|
+
|
|
678
|
+
* Feat: add completions.
|
|
679
|
+
|
|
680
|
+
* Docs: update explainer.
|
|
681
|
+
|
|
682
|
+
* Docs: update docs to include lower-only.
|
|
683
|
+
|
|
684
|
+
|
|
610
685
|
## v1.30.0 (2024-11-22)
|
|
611
686
|
|
|
612
687
|
* Change lower-only message to warning.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.30.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ffmpeg_normalize-1.30.0 → ffmpeg_normalize-1.31.0}/ffmpeg_normalize.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|