ffmpeg-normalize 1.28.2__tar.gz → 1.29.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.
Files changed (28) hide show
  1. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/CHANGELOG.md +16 -0
  2. {ffmpeg-normalize-1.28.2/ffmpeg_normalize.egg-info → ffmpeg-normalize-1.29.0}/PKG-INFO +87 -38
  3. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/README.md +70 -37
  4. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize/__main__.py +12 -0
  5. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize/_ffmpeg_normalize.py +3 -0
  6. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize/_media_file.py +2 -0
  7. ffmpeg-normalize-1.29.0/ffmpeg_normalize/_version.py +1 -0
  8. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0/ffmpeg_normalize.egg-info}/PKG-INFO +87 -38
  9. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize.egg-info/requires.txt +3 -1
  10. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/setup.py +1 -1
  11. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/test/test.py +15 -0
  12. ffmpeg-normalize-1.28.2/ffmpeg_normalize/_version.py +0 -1
  13. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/LICENSE +0 -0
  14. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize/__init__.py +0 -0
  15. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize/_cmd_utils.py +0 -0
  16. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize/_errors.py +0 -0
  17. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize/_logger.py +0 -0
  18. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize/_streams.py +0 -0
  19. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize/py.typed +0 -0
  20. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize.egg-info/SOURCES.txt +0 -0
  21. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize.egg-info/dependency_links.txt +0 -0
  22. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize.egg-info/entry_points.txt +0 -0
  23. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize.egg-info/not-zip-safe +0 -0
  24. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/ffmpeg_normalize.egg-info/top_level.txt +0 -0
  25. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/setup.cfg +0 -0
  26. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/test/out.mp4 +0 -0
  27. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/test/test.mp4 +0 -0
  28. {ffmpeg-normalize-1.28.2 → ffmpeg-normalize-1.29.0}/test/test.wav +0 -0
@@ -1,6 +1,22 @@
1
1
  # Changelog
2
2
 
3
3
 
4
+ ## v1.29.0 (2024-10-14)
5
+
6
+ * Add option to set audio channels directly.
7
+
8
+
9
+ ## v1.28.3 (2024-08-16)
10
+
11
+ * Make colorama dependency windows-only.
12
+
13
+ * Update.
14
+
15
+ * Update badges.
16
+
17
+ * Docs: add @kanjieater as a contributor.
18
+
19
+
4
20
  ## v1.28.2 (2024-06-22)
5
21
 
6
22
  * Provide an entrypoint for the Docker image.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ffmpeg-normalize
3
- Version: 1.28.2
3
+ Version: 1.29.0
4
4
  Summary: Normalize audio via ffmpeg
5
5
  Home-page: https://github.com/slhck/ffmpeg-normalize
6
6
  Author: Werner Robitza
@@ -25,13 +25,13 @@ License-File: LICENSE
25
25
 
26
26
  # ffmpeg-normalize
27
27
 
28
- <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
29
- [![All Contributors](https://img.shields.io/badge/all_contributors-18-orange.svg?style=flat-square)](#contributors-)
30
- <!-- ALL-CONTRIBUTORS-BADGE:END -->
31
-
32
28
  [![PyPI version](https://img.shields.io/pypi/v/ffmpeg-normalize.svg)](https://pypi.org/project/ffmpeg-normalize)
29
+ ![Docker Image Version](https://img.shields.io/docker/v/slhck/ffmpeg-normalize?sort=semver&label=Docker%20image)
30
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/slhck/ffmpeg-normalize/python-package.yml)
33
31
 
34
- [![Python package](https://github.com/slhck/ffmpeg-normalize/actions/workflows/python-package.yml/badge.svg)](https://github.com/slhck/ffmpeg-normalize/actions/workflows/python-package.yml)
32
+ <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
33
+ [![All Contributors](https://img.shields.io/badge/all_contributors-19-orange.svg?style=flat-square)](#contributors-)
34
+ <!-- ALL-CONTRIBUTORS-BADGE:END -->
35
35
 
36
36
  A utility for batch-normalizing audio using ffmpeg.
37
37
 
@@ -54,9 +54,8 @@ Read on for more info.
54
54
  - [ffmpeg](#ffmpeg)
55
55
  - [Installation](#installation)
56
56
  - [Usage with Docker](#usage-with-docker)
57
- - [From Docker Hub](#from-docker-hub)
58
- - [Usage](#usage)
59
- - [Description](#description)
57
+ - [High LeveL Introduction](#high-level-introduction)
58
+ - [Basic Usage](#basic-usage)
60
59
  - [Examples](#examples)
61
60
  - [Detailed Options](#detailed-options)
62
61
  - [File Input/Output](#file-inputoutput)
@@ -69,10 +68,11 @@ Read on for more info.
69
68
  - [Environment Variables](#environment-variables)
70
69
  - [API](#api)
71
70
  - [FAQ](#faq)
71
+ - [What options should I choose for the EBU R128 filter? What is linear and dynamic mode?](#what-options-should-i-choose-for-the-ebu-r128-filter-what-is-linear-and-dynamic-mode)
72
72
  - [The program doesn't work because the "loudnorm" filter can't be found](#the-program-doesnt-work-because-the-loudnorm-filter-cant-be-found)
73
73
  - [Should I use this to normalize my music collection?](#should-i-use-this-to-normalize-my-music-collection)
74
74
  - [Why are my output files MKV?](#why-are-my-output-files-mkv)
75
- - ["Could not write header for output file" error](#could-not-write-header-for-output-file-error)
75
+ - [I get a "Could not write header for output file" error](#i-get-a-could-not-write-header-for-output-file-error)
76
76
  - [The conversion does not work and I get a cryptic ffmpeg error!](#the-conversion-does-not-work-and-i-get-a-cryptic-ffmpeg-error)
77
77
  - [What are the different normalization algorithms?](#what-are-the-different-normalization-algorithms)
78
78
  - [Couldn't I just run `loudnorm` with ffmpeg?](#couldnt-i-just-run-loudnorm-with-ffmpeg)
@@ -87,7 +87,7 @@ Read on for more info.
87
87
 
88
88
  ## Requirements
89
89
 
90
- You need Python 3.8 or higher.
90
+ You need Python 3.8 or higher, and ffmpeg.
91
91
 
92
92
  ### ffmpeg
93
93
 
@@ -126,9 +126,9 @@ pip3 install ffmpeg-normalize
126
126
 
127
127
  Or download this repository, then run `pip3 install .`.
128
128
 
129
- ## Usage with Docker
129
+ To later upgrade to the latest version, run `pip3 install --upgrade ffmpeg-normalize`.
130
130
 
131
- ### From Docker Hub
131
+ ## Usage with Docker
132
132
 
133
133
  You can use the pre-built image from Docker Hub:
134
134
 
@@ -138,7 +138,7 @@ docker run -v "$(pwd):/tmp" -it slhck/ffmpeg-normalize
138
138
 
139
139
  Alternatively, download this repository and run
140
140
 
141
- ```
141
+ ```bash
142
142
  docker build -t ffmpeg-normalize .
143
143
  ```
144
144
 
@@ -156,45 +156,31 @@ docker run -v "$(pwd):/tmp" -it ffmpeg-normalize /tmp/yourfile.mp4 -o /tmp/your
156
156
 
157
157
  You will then find the normalized file in your current directory.
158
158
 
159
- ## Usage
160
-
161
- ```bash
162
- ffmpeg-normalize input [input ...][-h][-o OUTPUT [OUTPUT ...]] [options]
163
- ```
164
-
165
- Example:
166
-
167
- ```bash
168
- ffmpeg-normalize 1.wav 2.wav -o 1-normalized.m4a 2-normalized.m4a -c:a aac -b:a 192k
169
- ```
170
-
171
- For more information on the options (`[options]`) available, run `ffmpeg-normalize -h`, or read on.
172
-
173
- ## Description
159
+ ## High LeveL Introduction
174
160
 
175
161
  Please read this section for a high level introduction.
176
162
 
177
163
  **What does the program do?**
178
164
 
179
- The program takes one or more input files and, by default, writes them to a folder called `normalized`, using an `.mkv` container. All audio streams will be normalized so that they have the same (perceived) volume.
165
+ The program takes one or more input files and, by default, writes them to a folder called `normalized`, using an `.mkv` container. All audio streams will be normalized so that they have the same (perceived) volume according to the EBU R128 standard. This is done by analyzing the audio streams and applying a filter to bring them to a target level. Under the hood, the program uses ffmpeg's `loudnorm` filter to do this.
180
166
 
181
167
  **How do I specify the input?**
182
168
 
183
- Just give the program one or more input files as arguments. It works with most media files.
169
+ Just give the program one or more input files as arguments. It works with most media files, including video files.
184
170
 
185
171
  **How do I specify the output?**
186
172
 
187
- You can specify one output file name for each input file with the `-o` option. In this case, the container format (e.g. `.wav`) will be inferred from the file name extension that you've given.
173
+ You don't have to specify an output file name (the default is `normalized/<input>.mkv`), but if you want to override it, you can specify one output file name for each input file with the `-o` option. In this case, the container format (e.g. `.wav`) will be inferred from the file name extension that you've given.
188
174
 
189
175
  Example:
190
176
 
191
- ```
192
- ffmpeg-normalize 1.wav 2.wav -o 1n.wav 2n.wav
177
+ ```bash
178
+ ffmpeg-normalize 1.wav 2.wav -o 1-normalized.wav 2-normalized.wav
193
179
  ```
194
180
 
195
- If you don't specify the output file name for an input file, the container format will be MKV, and the output will be written to `normalized/<input>.mkv`.
181
+ Note that if you don't specify the output file name for an input file, the container format will be MKV, and the output will be written to `normalized/<input>.mkv`. The reason for choosing the MKV container is that it can handle almost any codec combination.
196
182
 
197
- Using the `-ext` option, you can supply a different output extension common to all output files, e.g. `-ext m4a`.
183
+ Using the `-ext` option, you can supply a different output extension common to all output files, e.g. `-ext m4a`. However, you need to make sure that the container supports the codecs used for the output (see below).
198
184
 
199
185
  **What will get normalized?**
200
186
 
@@ -202,7 +188,7 @@ By default, all streams from the input file will be written to the output file.
202
188
 
203
189
  **How will the normalization be done?**
204
190
 
205
- The normalization will be performed with the [`loudnorm` filter](https://ffmpeg.org/ffmpeg-filters.html#loudnorm) from FFmpeg, which was [originally written by Kyle Swanson](https://k.ylo.ph/2016/04/04/loudnorm.html). It will bring the audio to a specified target level. This ensures that multiple files normalized with this filter will have the same perceived loudness.
191
+ The normalization will be performed according to the EBU R128 algorithm with the [`loudnorm` filter](https://ffmpeg.org/ffmpeg-filters.html#loudnorm) from FFmpeg, which was [originally written by Kyle Swanson](https://k.ylo.ph/2016/04/04/loudnorm.html). It will bring the audio to a specified target level. This ensures that multiple files normalized with this filter will have the same perceived loudness.
206
192
 
207
193
  **What codec is chosen?**
208
194
 
@@ -210,6 +196,22 @@ The default audio encoding method is uncompressed PCM (`pcm_s16le`) to avoid int
210
196
 
211
197
  Some containers (like MP4) also cannot handle PCM audio. If you want to use such containers and/or keep the file size down, use `-c:a` and specify an audio codec (e.g., `-c:a aac` for ffmpeg's built-in AAC encoder).
212
198
 
199
+ ## Basic Usage
200
+
201
+ Supply one or more input files, and optionally, output file names:
202
+
203
+ ```bash
204
+ ffmpeg-normalize input [input ...][-h][-o OUTPUT [OUTPUT ...]] [options]
205
+ ```
206
+
207
+ Example:
208
+
209
+ ```bash
210
+ ffmpeg-normalize 1.wav 2.wav -o 1-normalized.m4a 2-normalized.m4a -c:a aac -b:a 192k
211
+ ```
212
+
213
+ For more information on the options (`[options]`) available, run `ffmpeg-normalize -h`, or read on.
214
+
213
215
  ## Examples
214
216
 
215
217
  [Read the examples on the wiki.](https://github.com/slhck/ffmpeg-normalize/wiki/examples)
@@ -318,6 +320,8 @@ Some containers (like MP4) also cannot handle PCM audio. If you want to use such
318
320
 
319
321
  Will use input sample rate by default, except for EBU normalization, which will change the input sample rate to 192 kHz.
320
322
 
323
+ - `-ac`, `--audio-channels`: Set the number of audio channels. If not specified, the input channel layout will be used. This is equivalent to `-ac` in ffmpeg.
324
+
321
325
  - `-koa, --keep-original-audio`: Copy original, non-normalized audio streams to output file
322
326
 
323
327
  - `-prf PRE_FILTER, --pre-filter PRE_FILTER`: Add an audio filter chain before applying normalization.
@@ -400,6 +404,32 @@ For more information see the [API documentation](https://htmlpreview.github.io/?
400
404
 
401
405
  ## FAQ
402
406
 
407
+ ### What options should I choose for the EBU R128 filter? What is linear and dynamic mode?
408
+
409
+ EBU R128 is a method for normalizing audio loudness across different tracks or programs. It works by analyzing the audio content and adjusting it to meet specific loudness targets. The main components are:
410
+
411
+ * Integrated Loudness (I): The overall loudness of the entire audio.
412
+ * Loudness Range (LRA): The variation in loudness over time.
413
+ * True Peak (TP): The maximum level of the audio signal.
414
+
415
+ The normalization process involves measuring these values (input) and then applying gain adjustments to meet target levels (output), typically -23 LUFS for integrated loudness. You can also specify a target loudness range (LRA) and true peak level (TP).
416
+
417
+ **Linear mode** applies a constant gain adjustment across the entire audio file. This is generally preferred because:
418
+
419
+ * It preserves the original dynamic range of the audio.
420
+ * It maintains the relative loudness between different parts of the audio.
421
+ * It avoids potential artifacts or pumping effects that can occur with dynamic processing.
422
+
423
+ **Dynamic mode**, on the other hand, can change the volume dynamically throughout the file. While this can achieve more consistent loudness, it may alter the original artistic intent and potentially introduce audible artifacts (possibly due to some bugs in the ffmpeg filter).
424
+
425
+ For most cases, linear mode is recommended. Dynamic mode should only be used when linear mode is not suitable or when a specific effect is desired. In some cases, `loudnorm` will still fall back to dynamic mode, and a warning will be printed to the console. Here's when this can happen:
426
+
427
+ * When the input loudness range (LRA) is larger than the target loudness range: If the input file has a loudness range that exceeds the specified loudness range target, the loudnorm filter will automatically switch to dynamic mode. This is because linear normalization alone cannot reduce the loudness range without dynamic processing (limiting). The `--keep-loudness-range-target` option can be used to keep the input loudness range target above the specified target.
428
+
429
+ * 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.
430
+
431
+ 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. The `--keep-loudness-range-target` option can be used to keep the input loudness range target above the specified target, but it will not force linear mode in all cases. We are working on a solution to handle this automatically!
432
+
403
433
  ### The program doesn't work because the "loudnorm" filter can't be found
404
434
 
405
435
  Make sure you run a recent ffmpeg version and that `loudnorm` is part of the output when you run `ffmpeg -filters`. Many distributions package outdated ffmpeg versions, or (even worse), Libav's `ffmpeg` disguising as a real `ffmpeg` from the FFmpeg project.
@@ -412,13 +442,15 @@ If you have to use an outdated ffmpeg version, you can only use `rms` or `peak`
412
442
 
413
443
  ### Should I use this to normalize my music collection?
414
444
 
445
+ Generally, no.
446
+
415
447
  When you run `ffmpeg-normalize` and re-encode files with MP3 or AAC, you will inevitably introduce [generation loss](https://en.wikipedia.org/wiki/Generation_loss). Therefore, I do not recommend running this on your precious music collection, unless you have a backup of the originals or accept potential quality reduction. If you just want to normalize the subjective volume of the files without changing the actual content, consider using [MP3Gain](http://mp3gain.sourceforge.net/) and [aacgain](http://aacgain.altosdesign.com/).
416
448
 
417
449
  ### Why are my output files MKV?
418
450
 
419
451
  I chose MKV as a default output container since it handles almost every possible combination of audio, video, and subtitle codecs. If you know which audio/video codec you want, and which container is supported, use the output options to specify the encoder and output file name manually.
420
452
 
421
- ### "Could not write header for output file" error
453
+ ### I get a "Could not write header for output file" error
422
454
 
423
455
  See the [next section](#the-conversion-does-not-work-and-i-get-a-cryptic-ffmpeg-error).
424
456
 
@@ -514,6 +546,7 @@ If you found this program useful and feel like giving back, feel free to send a
514
546
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/sian1468"><img src="https://avatars.githubusercontent.com/u/58017832?v=4?s=100" width="100px;" alt="sian1468"/><br /><sub><b>sian1468</b></sub></a><br /><a href="https://github.com/slhck/ffmpeg-normalize/commits?author=sian1468" title="Tests">⚠️</a></td>
515
547
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/psavva"><img src="https://avatars.githubusercontent.com/u/1454758?v=4?s=100" width="100px;" alt="Panayiotis Savva"/><br /><sub><b>Panayiotis Savva</b></sub></a><br /><a href="https://github.com/slhck/ffmpeg-normalize/commits?author=psavva" title="Code">💻</a></td>
516
548
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/HighMans"><img src="https://avatars.githubusercontent.com/u/42877729?v=4?s=100" width="100px;" alt="HighMans"/><br /><sub><b>HighMans</b></sub></a><br /><a href="https://github.com/slhck/ffmpeg-normalize/commits?author=HighMans" title="Code">💻</a></td>
549
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/kanjieater"><img src="https://avatars.githubusercontent.com/u/32607317?v=4?s=100" width="100px;" alt="kanjieater"/><br /><sub><b>kanjieater</b></sub></a><br /><a href="#ideas-kanjieater" title="Ideas, Planning, & Feedback">🤔</a></td>
517
550
  </tr>
518
551
  </tbody>
519
552
  <tfoot>
@@ -561,6 +594,22 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
561
594
  # Changelog
562
595
 
563
596
 
597
+ ## v1.29.0 (2024-10-14)
598
+
599
+ * Add option to set audio channels directly.
600
+
601
+
602
+ ## v1.28.3 (2024-08-16)
603
+
604
+ * Make colorama dependency windows-only.
605
+
606
+ * Update.
607
+
608
+ * Update badges.
609
+
610
+ * Docs: add @kanjieater as a contributor.
611
+
612
+
564
613
  ## v1.28.2 (2024-06-22)
565
614
 
566
615
  * Provide an entrypoint for the Docker image.
@@ -1,12 +1,12 @@
1
1
  # ffmpeg-normalize
2
2
 
3
- <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
4
- [![All Contributors](https://img.shields.io/badge/all_contributors-18-orange.svg?style=flat-square)](#contributors-)
5
- <!-- ALL-CONTRIBUTORS-BADGE:END -->
6
-
7
3
  [![PyPI version](https://img.shields.io/pypi/v/ffmpeg-normalize.svg)](https://pypi.org/project/ffmpeg-normalize)
4
+ ![Docker Image Version](https://img.shields.io/docker/v/slhck/ffmpeg-normalize?sort=semver&label=Docker%20image)
5
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/slhck/ffmpeg-normalize/python-package.yml)
8
6
 
9
- [![Python package](https://github.com/slhck/ffmpeg-normalize/actions/workflows/python-package.yml/badge.svg)](https://github.com/slhck/ffmpeg-normalize/actions/workflows/python-package.yml)
7
+ <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
8
+ [![All Contributors](https://img.shields.io/badge/all_contributors-19-orange.svg?style=flat-square)](#contributors-)
9
+ <!-- ALL-CONTRIBUTORS-BADGE:END -->
10
10
 
11
11
  A utility for batch-normalizing audio using ffmpeg.
12
12
 
@@ -29,9 +29,8 @@ Read on for more info.
29
29
  - [ffmpeg](#ffmpeg)
30
30
  - [Installation](#installation)
31
31
  - [Usage with Docker](#usage-with-docker)
32
- - [From Docker Hub](#from-docker-hub)
33
- - [Usage](#usage)
34
- - [Description](#description)
32
+ - [High LeveL Introduction](#high-level-introduction)
33
+ - [Basic Usage](#basic-usage)
35
34
  - [Examples](#examples)
36
35
  - [Detailed Options](#detailed-options)
37
36
  - [File Input/Output](#file-inputoutput)
@@ -44,10 +43,11 @@ Read on for more info.
44
43
  - [Environment Variables](#environment-variables)
45
44
  - [API](#api)
46
45
  - [FAQ](#faq)
46
+ - [What options should I choose for the EBU R128 filter? What is linear and dynamic mode?](#what-options-should-i-choose-for-the-ebu-r128-filter-what-is-linear-and-dynamic-mode)
47
47
  - [The program doesn't work because the "loudnorm" filter can't be found](#the-program-doesnt-work-because-the-loudnorm-filter-cant-be-found)
48
48
  - [Should I use this to normalize my music collection?](#should-i-use-this-to-normalize-my-music-collection)
49
49
  - [Why are my output files MKV?](#why-are-my-output-files-mkv)
50
- - ["Could not write header for output file" error](#could-not-write-header-for-output-file-error)
50
+ - [I get a "Could not write header for output file" error](#i-get-a-could-not-write-header-for-output-file-error)
51
51
  - [The conversion does not work and I get a cryptic ffmpeg error!](#the-conversion-does-not-work-and-i-get-a-cryptic-ffmpeg-error)
52
52
  - [What are the different normalization algorithms?](#what-are-the-different-normalization-algorithms)
53
53
  - [Couldn't I just run `loudnorm` with ffmpeg?](#couldnt-i-just-run-loudnorm-with-ffmpeg)
@@ -62,7 +62,7 @@ Read on for more info.
62
62
 
63
63
  ## Requirements
64
64
 
65
- You need Python 3.8 or higher.
65
+ You need Python 3.8 or higher, and ffmpeg.
66
66
 
67
67
  ### ffmpeg
68
68
 
@@ -101,9 +101,9 @@ pip3 install ffmpeg-normalize
101
101
 
102
102
  Or download this repository, then run `pip3 install .`.
103
103
 
104
- ## Usage with Docker
104
+ To later upgrade to the latest version, run `pip3 install --upgrade ffmpeg-normalize`.
105
105
 
106
- ### From Docker Hub
106
+ ## Usage with Docker
107
107
 
108
108
  You can use the pre-built image from Docker Hub:
109
109
 
@@ -113,7 +113,7 @@ docker run -v "$(pwd):/tmp" -it slhck/ffmpeg-normalize
113
113
 
114
114
  Alternatively, download this repository and run
115
115
 
116
- ```
116
+ ```bash
117
117
  docker build -t ffmpeg-normalize .
118
118
  ```
119
119
 
@@ -131,45 +131,31 @@ docker run -v "$(pwd):/tmp" -it ffmpeg-normalize /tmp/yourfile.mp4 -o /tmp/your
131
131
 
132
132
  You will then find the normalized file in your current directory.
133
133
 
134
- ## Usage
135
-
136
- ```bash
137
- ffmpeg-normalize input [input ...][-h][-o OUTPUT [OUTPUT ...]] [options]
138
- ```
139
-
140
- Example:
141
-
142
- ```bash
143
- ffmpeg-normalize 1.wav 2.wav -o 1-normalized.m4a 2-normalized.m4a -c:a aac -b:a 192k
144
- ```
145
-
146
- For more information on the options (`[options]`) available, run `ffmpeg-normalize -h`, or read on.
147
-
148
- ## Description
134
+ ## High LeveL Introduction
149
135
 
150
136
  Please read this section for a high level introduction.
151
137
 
152
138
  **What does the program do?**
153
139
 
154
- The program takes one or more input files and, by default, writes them to a folder called `normalized`, using an `.mkv` container. All audio streams will be normalized so that they have the same (perceived) volume.
140
+ The program takes one or more input files and, by default, writes them to a folder called `normalized`, using an `.mkv` container. All audio streams will be normalized so that they have the same (perceived) volume according to the EBU R128 standard. This is done by analyzing the audio streams and applying a filter to bring them to a target level. Under the hood, the program uses ffmpeg's `loudnorm` filter to do this.
155
141
 
156
142
  **How do I specify the input?**
157
143
 
158
- Just give the program one or more input files as arguments. It works with most media files.
144
+ Just give the program one or more input files as arguments. It works with most media files, including video files.
159
145
 
160
146
  **How do I specify the output?**
161
147
 
162
- You can specify one output file name for each input file with the `-o` option. In this case, the container format (e.g. `.wav`) will be inferred from the file name extension that you've given.
148
+ You don't have to specify an output file name (the default is `normalized/<input>.mkv`), but if you want to override it, you can specify one output file name for each input file with the `-o` option. In this case, the container format (e.g. `.wav`) will be inferred from the file name extension that you've given.
163
149
 
164
150
  Example:
165
151
 
166
- ```
167
- ffmpeg-normalize 1.wav 2.wav -o 1n.wav 2n.wav
152
+ ```bash
153
+ ffmpeg-normalize 1.wav 2.wav -o 1-normalized.wav 2-normalized.wav
168
154
  ```
169
155
 
170
- If you don't specify the output file name for an input file, the container format will be MKV, and the output will be written to `normalized/<input>.mkv`.
156
+ Note that if you don't specify the output file name for an input file, the container format will be MKV, and the output will be written to `normalized/<input>.mkv`. The reason for choosing the MKV container is that it can handle almost any codec combination.
171
157
 
172
- Using the `-ext` option, you can supply a different output extension common to all output files, e.g. `-ext m4a`.
158
+ Using the `-ext` option, you can supply a different output extension common to all output files, e.g. `-ext m4a`. However, you need to make sure that the container supports the codecs used for the output (see below).
173
159
 
174
160
  **What will get normalized?**
175
161
 
@@ -177,7 +163,7 @@ By default, all streams from the input file will be written to the output file.
177
163
 
178
164
  **How will the normalization be done?**
179
165
 
180
- The normalization will be performed with the [`loudnorm` filter](https://ffmpeg.org/ffmpeg-filters.html#loudnorm) from FFmpeg, which was [originally written by Kyle Swanson](https://k.ylo.ph/2016/04/04/loudnorm.html). It will bring the audio to a specified target level. This ensures that multiple files normalized with this filter will have the same perceived loudness.
166
+ The normalization will be performed according to the EBU R128 algorithm with the [`loudnorm` filter](https://ffmpeg.org/ffmpeg-filters.html#loudnorm) from FFmpeg, which was [originally written by Kyle Swanson](https://k.ylo.ph/2016/04/04/loudnorm.html). It will bring the audio to a specified target level. This ensures that multiple files normalized with this filter will have the same perceived loudness.
181
167
 
182
168
  **What codec is chosen?**
183
169
 
@@ -185,6 +171,22 @@ The default audio encoding method is uncompressed PCM (`pcm_s16le`) to avoid int
185
171
 
186
172
  Some containers (like MP4) also cannot handle PCM audio. If you want to use such containers and/or keep the file size down, use `-c:a` and specify an audio codec (e.g., `-c:a aac` for ffmpeg's built-in AAC encoder).
187
173
 
174
+ ## Basic Usage
175
+
176
+ Supply one or more input files, and optionally, output file names:
177
+
178
+ ```bash
179
+ ffmpeg-normalize input [input ...][-h][-o OUTPUT [OUTPUT ...]] [options]
180
+ ```
181
+
182
+ Example:
183
+
184
+ ```bash
185
+ ffmpeg-normalize 1.wav 2.wav -o 1-normalized.m4a 2-normalized.m4a -c:a aac -b:a 192k
186
+ ```
187
+
188
+ For more information on the options (`[options]`) available, run `ffmpeg-normalize -h`, or read on.
189
+
188
190
  ## Examples
189
191
 
190
192
  [Read the examples on the wiki.](https://github.com/slhck/ffmpeg-normalize/wiki/examples)
@@ -293,6 +295,8 @@ Some containers (like MP4) also cannot handle PCM audio. If you want to use such
293
295
 
294
296
  Will use input sample rate by default, except for EBU normalization, which will change the input sample rate to 192 kHz.
295
297
 
298
+ - `-ac`, `--audio-channels`: Set the number of audio channels. If not specified, the input channel layout will be used. This is equivalent to `-ac` in ffmpeg.
299
+
296
300
  - `-koa, --keep-original-audio`: Copy original, non-normalized audio streams to output file
297
301
 
298
302
  - `-prf PRE_FILTER, --pre-filter PRE_FILTER`: Add an audio filter chain before applying normalization.
@@ -375,6 +379,32 @@ For more information see the [API documentation](https://htmlpreview.github.io/?
375
379
 
376
380
  ## FAQ
377
381
 
382
+ ### What options should I choose for the EBU R128 filter? What is linear and dynamic mode?
383
+
384
+ EBU R128 is a method for normalizing audio loudness across different tracks or programs. It works by analyzing the audio content and adjusting it to meet specific loudness targets. The main components are:
385
+
386
+ * Integrated Loudness (I): The overall loudness of the entire audio.
387
+ * Loudness Range (LRA): The variation in loudness over time.
388
+ * True Peak (TP): The maximum level of the audio signal.
389
+
390
+ The normalization process involves measuring these values (input) and then applying gain adjustments to meet target levels (output), typically -23 LUFS for integrated loudness. You can also specify a target loudness range (LRA) and true peak level (TP).
391
+
392
+ **Linear mode** applies a constant gain adjustment across the entire audio file. This is generally preferred because:
393
+
394
+ * It preserves the original dynamic range of the audio.
395
+ * It maintains the relative loudness between different parts of the audio.
396
+ * It avoids potential artifacts or pumping effects that can occur with dynamic processing.
397
+
398
+ **Dynamic mode**, on the other hand, can change the volume dynamically throughout the file. While this can achieve more consistent loudness, it may alter the original artistic intent and potentially introduce audible artifacts (possibly due to some bugs in the ffmpeg filter).
399
+
400
+ For most cases, linear mode is recommended. Dynamic mode should only be used when linear mode is not suitable or when a specific effect is desired. In some cases, `loudnorm` will still fall back to dynamic mode, and a warning will be printed to the console. Here's when this can happen:
401
+
402
+ * When the input loudness range (LRA) is larger than the target loudness range: If the input file has a loudness range that exceeds the specified loudness range target, the loudnorm filter will automatically switch to dynamic mode. This is because linear normalization alone cannot reduce the loudness range without dynamic processing (limiting). The `--keep-loudness-range-target` option can be used to keep the input loudness range target above the specified target.
403
+
404
+ * 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.
405
+
406
+ 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. The `--keep-loudness-range-target` option can be used to keep the input loudness range target above the specified target, but it will not force linear mode in all cases. We are working on a solution to handle this automatically!
407
+
378
408
  ### The program doesn't work because the "loudnorm" filter can't be found
379
409
 
380
410
  Make sure you run a recent ffmpeg version and that `loudnorm` is part of the output when you run `ffmpeg -filters`. Many distributions package outdated ffmpeg versions, or (even worse), Libav's `ffmpeg` disguising as a real `ffmpeg` from the FFmpeg project.
@@ -387,13 +417,15 @@ If you have to use an outdated ffmpeg version, you can only use `rms` or `peak`
387
417
 
388
418
  ### Should I use this to normalize my music collection?
389
419
 
420
+ Generally, no.
421
+
390
422
  When you run `ffmpeg-normalize` and re-encode files with MP3 or AAC, you will inevitably introduce [generation loss](https://en.wikipedia.org/wiki/Generation_loss). Therefore, I do not recommend running this on your precious music collection, unless you have a backup of the originals or accept potential quality reduction. If you just want to normalize the subjective volume of the files without changing the actual content, consider using [MP3Gain](http://mp3gain.sourceforge.net/) and [aacgain](http://aacgain.altosdesign.com/).
391
423
 
392
424
  ### Why are my output files MKV?
393
425
 
394
426
  I chose MKV as a default output container since it handles almost every possible combination of audio, video, and subtitle codecs. If you know which audio/video codec you want, and which container is supported, use the output options to specify the encoder and output file name manually.
395
427
 
396
- ### "Could not write header for output file" error
428
+ ### I get a "Could not write header for output file" error
397
429
 
398
430
  See the [next section](#the-conversion-does-not-work-and-i-get-a-cryptic-ffmpeg-error).
399
431
 
@@ -489,6 +521,7 @@ If you found this program useful and feel like giving back, feel free to send a
489
521
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/sian1468"><img src="https://avatars.githubusercontent.com/u/58017832?v=4?s=100" width="100px;" alt="sian1468"/><br /><sub><b>sian1468</b></sub></a><br /><a href="https://github.com/slhck/ffmpeg-normalize/commits?author=sian1468" title="Tests">⚠️</a></td>
490
522
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/psavva"><img src="https://avatars.githubusercontent.com/u/1454758?v=4?s=100" width="100px;" alt="Panayiotis Savva"/><br /><sub><b>Panayiotis Savva</b></sub></a><br /><a href="https://github.com/slhck/ffmpeg-normalize/commits?author=psavva" title="Code">💻</a></td>
491
523
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/HighMans"><img src="https://avatars.githubusercontent.com/u/42877729?v=4?s=100" width="100px;" alt="HighMans"/><br /><sub><b>HighMans</b></sub></a><br /><a href="https://github.com/slhck/ffmpeg-normalize/commits?author=HighMans" title="Code">💻</a></td>
524
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/kanjieater"><img src="https://avatars.githubusercontent.com/u/32607317?v=4?s=100" width="100px;" alt="kanjieater"/><br /><sub><b>kanjieater</b></sub></a><br /><a href="#ideas-kanjieater" title="Ideas, Planning, & Feedback">🤔</a></td>
492
525
  </tr>
493
526
  </tbody>
494
527
  <tfoot>
@@ -303,6 +303,17 @@ def create_parser() -> argparse.ArgumentParser:
303
303
  """
304
304
  ),
305
305
  )
306
+ group_acodec.add_argument(
307
+ "-ac",
308
+ "--audio-channels",
309
+ type=int,
310
+ help=textwrap.dedent(
311
+ """\
312
+ Set the number of audio channels.
313
+ If not specified, the input channel layout will be used.
314
+ """
315
+ ),
316
+ )
306
317
  group_acodec.add_argument(
307
318
  "-koa",
308
319
  "--keep-original-audio",
@@ -506,6 +517,7 @@ def main() -> None:
506
517
  audio_codec=cli_args.audio_codec,
507
518
  audio_bitrate=cli_args.audio_bitrate,
508
519
  sample_rate=cli_args.sample_rate,
520
+ audio_channels=cli_args.audio_channels,
509
521
  keep_original_audio=cli_args.keep_original_audio,
510
522
  pre_filter=cli_args.pre_filter,
511
523
  post_filter=cli_args.post_filter,
@@ -63,6 +63,7 @@ class FFmpegNormalize:
63
63
  audio_codec (str, optional): Audio codec. Defaults to "pcm_s16le".
64
64
  audio_bitrate (float, optional): Audio bitrate. Defaults to None.
65
65
  sample_rate (int, optional): Sample rate. Defaults to None.
66
+ audio_channels (int | None, optional): Audio channels. Defaults to None.
66
67
  keep_original_audio (bool, optional): Keep original audio. Defaults to False.
67
68
  pre_filter (str, optional): Pre filter. Defaults to None.
68
69
  post_filter (str, optional): Post filter. Defaults to None.
@@ -98,6 +99,7 @@ class FFmpegNormalize:
98
99
  audio_codec: str = "pcm_s16le",
99
100
  audio_bitrate: float | None = None,
100
101
  sample_rate: float | int | None = None,
102
+ audio_channels: int | None = None,
101
103
  keep_original_audio: bool = False,
102
104
  pre_filter: str | None = None,
103
105
  post_filter: str | None = None,
@@ -170,6 +172,7 @@ class FFmpegNormalize:
170
172
  self.dual_mono = dual_mono
171
173
  self.dynamic = dynamic
172
174
  self.sample_rate = None if sample_rate is None else int(sample_rate)
175
+ self.audio_channels = None if audio_channels is None else int(audio_channels)
173
176
 
174
177
  self.audio_codec = audio_codec
175
178
  self.audio_bitrate = audio_bitrate
@@ -355,6 +355,8 @@ class MediaFile:
355
355
  cmd.extend(["-b:a", str(self.ffmpeg_normalize.audio_bitrate)])
356
356
  if self.ffmpeg_normalize.sample_rate:
357
357
  cmd.extend(["-ar", str(self.ffmpeg_normalize.sample_rate)])
358
+ if self.ffmpeg_normalize.audio_channels:
359
+ cmd.extend(["-ac", str(self.ffmpeg_normalize.audio_channels)])
358
360
 
359
361
  # ... and subtitles
360
362
  if not self.ffmpeg_normalize.subtitle_disable:
@@ -0,0 +1 @@
1
+ __version__ = "1.29.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ffmpeg-normalize
3
- Version: 1.28.2
3
+ Version: 1.29.0
4
4
  Summary: Normalize audio via ffmpeg
5
5
  Home-page: https://github.com/slhck/ffmpeg-normalize
6
6
  Author: Werner Robitza
@@ -25,13 +25,13 @@ License-File: LICENSE
25
25
 
26
26
  # ffmpeg-normalize
27
27
 
28
- <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
29
- [![All Contributors](https://img.shields.io/badge/all_contributors-18-orange.svg?style=flat-square)](#contributors-)
30
- <!-- ALL-CONTRIBUTORS-BADGE:END -->
31
-
32
28
  [![PyPI version](https://img.shields.io/pypi/v/ffmpeg-normalize.svg)](https://pypi.org/project/ffmpeg-normalize)
29
+ ![Docker Image Version](https://img.shields.io/docker/v/slhck/ffmpeg-normalize?sort=semver&label=Docker%20image)
30
+ ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/slhck/ffmpeg-normalize/python-package.yml)
33
31
 
34
- [![Python package](https://github.com/slhck/ffmpeg-normalize/actions/workflows/python-package.yml/badge.svg)](https://github.com/slhck/ffmpeg-normalize/actions/workflows/python-package.yml)
32
+ <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
33
+ [![All Contributors](https://img.shields.io/badge/all_contributors-19-orange.svg?style=flat-square)](#contributors-)
34
+ <!-- ALL-CONTRIBUTORS-BADGE:END -->
35
35
 
36
36
  A utility for batch-normalizing audio using ffmpeg.
37
37
 
@@ -54,9 +54,8 @@ Read on for more info.
54
54
  - [ffmpeg](#ffmpeg)
55
55
  - [Installation](#installation)
56
56
  - [Usage with Docker](#usage-with-docker)
57
- - [From Docker Hub](#from-docker-hub)
58
- - [Usage](#usage)
59
- - [Description](#description)
57
+ - [High LeveL Introduction](#high-level-introduction)
58
+ - [Basic Usage](#basic-usage)
60
59
  - [Examples](#examples)
61
60
  - [Detailed Options](#detailed-options)
62
61
  - [File Input/Output](#file-inputoutput)
@@ -69,10 +68,11 @@ Read on for more info.
69
68
  - [Environment Variables](#environment-variables)
70
69
  - [API](#api)
71
70
  - [FAQ](#faq)
71
+ - [What options should I choose for the EBU R128 filter? What is linear and dynamic mode?](#what-options-should-i-choose-for-the-ebu-r128-filter-what-is-linear-and-dynamic-mode)
72
72
  - [The program doesn't work because the "loudnorm" filter can't be found](#the-program-doesnt-work-because-the-loudnorm-filter-cant-be-found)
73
73
  - [Should I use this to normalize my music collection?](#should-i-use-this-to-normalize-my-music-collection)
74
74
  - [Why are my output files MKV?](#why-are-my-output-files-mkv)
75
- - ["Could not write header for output file" error](#could-not-write-header-for-output-file-error)
75
+ - [I get a "Could not write header for output file" error](#i-get-a-could-not-write-header-for-output-file-error)
76
76
  - [The conversion does not work and I get a cryptic ffmpeg error!](#the-conversion-does-not-work-and-i-get-a-cryptic-ffmpeg-error)
77
77
  - [What are the different normalization algorithms?](#what-are-the-different-normalization-algorithms)
78
78
  - [Couldn't I just run `loudnorm` with ffmpeg?](#couldnt-i-just-run-loudnorm-with-ffmpeg)
@@ -87,7 +87,7 @@ Read on for more info.
87
87
 
88
88
  ## Requirements
89
89
 
90
- You need Python 3.8 or higher.
90
+ You need Python 3.8 or higher, and ffmpeg.
91
91
 
92
92
  ### ffmpeg
93
93
 
@@ -126,9 +126,9 @@ pip3 install ffmpeg-normalize
126
126
 
127
127
  Or download this repository, then run `pip3 install .`.
128
128
 
129
- ## Usage with Docker
129
+ To later upgrade to the latest version, run `pip3 install --upgrade ffmpeg-normalize`.
130
130
 
131
- ### From Docker Hub
131
+ ## Usage with Docker
132
132
 
133
133
  You can use the pre-built image from Docker Hub:
134
134
 
@@ -138,7 +138,7 @@ docker run -v "$(pwd):/tmp" -it slhck/ffmpeg-normalize
138
138
 
139
139
  Alternatively, download this repository and run
140
140
 
141
- ```
141
+ ```bash
142
142
  docker build -t ffmpeg-normalize .
143
143
  ```
144
144
 
@@ -156,45 +156,31 @@ docker run -v "$(pwd):/tmp" -it ffmpeg-normalize /tmp/yourfile.mp4 -o /tmp/your
156
156
 
157
157
  You will then find the normalized file in your current directory.
158
158
 
159
- ## Usage
160
-
161
- ```bash
162
- ffmpeg-normalize input [input ...][-h][-o OUTPUT [OUTPUT ...]] [options]
163
- ```
164
-
165
- Example:
166
-
167
- ```bash
168
- ffmpeg-normalize 1.wav 2.wav -o 1-normalized.m4a 2-normalized.m4a -c:a aac -b:a 192k
169
- ```
170
-
171
- For more information on the options (`[options]`) available, run `ffmpeg-normalize -h`, or read on.
172
-
173
- ## Description
159
+ ## High LeveL Introduction
174
160
 
175
161
  Please read this section for a high level introduction.
176
162
 
177
163
  **What does the program do?**
178
164
 
179
- The program takes one or more input files and, by default, writes them to a folder called `normalized`, using an `.mkv` container. All audio streams will be normalized so that they have the same (perceived) volume.
165
+ The program takes one or more input files and, by default, writes them to a folder called `normalized`, using an `.mkv` container. All audio streams will be normalized so that they have the same (perceived) volume according to the EBU R128 standard. This is done by analyzing the audio streams and applying a filter to bring them to a target level. Under the hood, the program uses ffmpeg's `loudnorm` filter to do this.
180
166
 
181
167
  **How do I specify the input?**
182
168
 
183
- Just give the program one or more input files as arguments. It works with most media files.
169
+ Just give the program one or more input files as arguments. It works with most media files, including video files.
184
170
 
185
171
  **How do I specify the output?**
186
172
 
187
- You can specify one output file name for each input file with the `-o` option. In this case, the container format (e.g. `.wav`) will be inferred from the file name extension that you've given.
173
+ You don't have to specify an output file name (the default is `normalized/<input>.mkv`), but if you want to override it, you can specify one output file name for each input file with the `-o` option. In this case, the container format (e.g. `.wav`) will be inferred from the file name extension that you've given.
188
174
 
189
175
  Example:
190
176
 
191
- ```
192
- ffmpeg-normalize 1.wav 2.wav -o 1n.wav 2n.wav
177
+ ```bash
178
+ ffmpeg-normalize 1.wav 2.wav -o 1-normalized.wav 2-normalized.wav
193
179
  ```
194
180
 
195
- If you don't specify the output file name for an input file, the container format will be MKV, and the output will be written to `normalized/<input>.mkv`.
181
+ Note that if you don't specify the output file name for an input file, the container format will be MKV, and the output will be written to `normalized/<input>.mkv`. The reason for choosing the MKV container is that it can handle almost any codec combination.
196
182
 
197
- Using the `-ext` option, you can supply a different output extension common to all output files, e.g. `-ext m4a`.
183
+ Using the `-ext` option, you can supply a different output extension common to all output files, e.g. `-ext m4a`. However, you need to make sure that the container supports the codecs used for the output (see below).
198
184
 
199
185
  **What will get normalized?**
200
186
 
@@ -202,7 +188,7 @@ By default, all streams from the input file will be written to the output file.
202
188
 
203
189
  **How will the normalization be done?**
204
190
 
205
- The normalization will be performed with the [`loudnorm` filter](https://ffmpeg.org/ffmpeg-filters.html#loudnorm) from FFmpeg, which was [originally written by Kyle Swanson](https://k.ylo.ph/2016/04/04/loudnorm.html). It will bring the audio to a specified target level. This ensures that multiple files normalized with this filter will have the same perceived loudness.
191
+ The normalization will be performed according to the EBU R128 algorithm with the [`loudnorm` filter](https://ffmpeg.org/ffmpeg-filters.html#loudnorm) from FFmpeg, which was [originally written by Kyle Swanson](https://k.ylo.ph/2016/04/04/loudnorm.html). It will bring the audio to a specified target level. This ensures that multiple files normalized with this filter will have the same perceived loudness.
206
192
 
207
193
  **What codec is chosen?**
208
194
 
@@ -210,6 +196,22 @@ The default audio encoding method is uncompressed PCM (`pcm_s16le`) to avoid int
210
196
 
211
197
  Some containers (like MP4) also cannot handle PCM audio. If you want to use such containers and/or keep the file size down, use `-c:a` and specify an audio codec (e.g., `-c:a aac` for ffmpeg's built-in AAC encoder).
212
198
 
199
+ ## Basic Usage
200
+
201
+ Supply one or more input files, and optionally, output file names:
202
+
203
+ ```bash
204
+ ffmpeg-normalize input [input ...][-h][-o OUTPUT [OUTPUT ...]] [options]
205
+ ```
206
+
207
+ Example:
208
+
209
+ ```bash
210
+ ffmpeg-normalize 1.wav 2.wav -o 1-normalized.m4a 2-normalized.m4a -c:a aac -b:a 192k
211
+ ```
212
+
213
+ For more information on the options (`[options]`) available, run `ffmpeg-normalize -h`, or read on.
214
+
213
215
  ## Examples
214
216
 
215
217
  [Read the examples on the wiki.](https://github.com/slhck/ffmpeg-normalize/wiki/examples)
@@ -318,6 +320,8 @@ Some containers (like MP4) also cannot handle PCM audio. If you want to use such
318
320
 
319
321
  Will use input sample rate by default, except for EBU normalization, which will change the input sample rate to 192 kHz.
320
322
 
323
+ - `-ac`, `--audio-channels`: Set the number of audio channels. If not specified, the input channel layout will be used. This is equivalent to `-ac` in ffmpeg.
324
+
321
325
  - `-koa, --keep-original-audio`: Copy original, non-normalized audio streams to output file
322
326
 
323
327
  - `-prf PRE_FILTER, --pre-filter PRE_FILTER`: Add an audio filter chain before applying normalization.
@@ -400,6 +404,32 @@ For more information see the [API documentation](https://htmlpreview.github.io/?
400
404
 
401
405
  ## FAQ
402
406
 
407
+ ### What options should I choose for the EBU R128 filter? What is linear and dynamic mode?
408
+
409
+ EBU R128 is a method for normalizing audio loudness across different tracks or programs. It works by analyzing the audio content and adjusting it to meet specific loudness targets. The main components are:
410
+
411
+ * Integrated Loudness (I): The overall loudness of the entire audio.
412
+ * Loudness Range (LRA): The variation in loudness over time.
413
+ * True Peak (TP): The maximum level of the audio signal.
414
+
415
+ The normalization process involves measuring these values (input) and then applying gain adjustments to meet target levels (output), typically -23 LUFS for integrated loudness. You can also specify a target loudness range (LRA) and true peak level (TP).
416
+
417
+ **Linear mode** applies a constant gain adjustment across the entire audio file. This is generally preferred because:
418
+
419
+ * It preserves the original dynamic range of the audio.
420
+ * It maintains the relative loudness between different parts of the audio.
421
+ * It avoids potential artifacts or pumping effects that can occur with dynamic processing.
422
+
423
+ **Dynamic mode**, on the other hand, can change the volume dynamically throughout the file. While this can achieve more consistent loudness, it may alter the original artistic intent and potentially introduce audible artifacts (possibly due to some bugs in the ffmpeg filter).
424
+
425
+ For most cases, linear mode is recommended. Dynamic mode should only be used when linear mode is not suitable or when a specific effect is desired. In some cases, `loudnorm` will still fall back to dynamic mode, and a warning will be printed to the console. Here's when this can happen:
426
+
427
+ * When the input loudness range (LRA) is larger than the target loudness range: If the input file has a loudness range that exceeds the specified loudness range target, the loudnorm filter will automatically switch to dynamic mode. This is because linear normalization alone cannot reduce the loudness range without dynamic processing (limiting). The `--keep-loudness-range-target` option can be used to keep the input loudness range target above the specified target.
428
+
429
+ * 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.
430
+
431
+ 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. The `--keep-loudness-range-target` option can be used to keep the input loudness range target above the specified target, but it will not force linear mode in all cases. We are working on a solution to handle this automatically!
432
+
403
433
  ### The program doesn't work because the "loudnorm" filter can't be found
404
434
 
405
435
  Make sure you run a recent ffmpeg version and that `loudnorm` is part of the output when you run `ffmpeg -filters`. Many distributions package outdated ffmpeg versions, or (even worse), Libav's `ffmpeg` disguising as a real `ffmpeg` from the FFmpeg project.
@@ -412,13 +442,15 @@ If you have to use an outdated ffmpeg version, you can only use `rms` or `peak`
412
442
 
413
443
  ### Should I use this to normalize my music collection?
414
444
 
445
+ Generally, no.
446
+
415
447
  When you run `ffmpeg-normalize` and re-encode files with MP3 or AAC, you will inevitably introduce [generation loss](https://en.wikipedia.org/wiki/Generation_loss). Therefore, I do not recommend running this on your precious music collection, unless you have a backup of the originals or accept potential quality reduction. If you just want to normalize the subjective volume of the files without changing the actual content, consider using [MP3Gain](http://mp3gain.sourceforge.net/) and [aacgain](http://aacgain.altosdesign.com/).
416
448
 
417
449
  ### Why are my output files MKV?
418
450
 
419
451
  I chose MKV as a default output container since it handles almost every possible combination of audio, video, and subtitle codecs. If you know which audio/video codec you want, and which container is supported, use the output options to specify the encoder and output file name manually.
420
452
 
421
- ### "Could not write header for output file" error
453
+ ### I get a "Could not write header for output file" error
422
454
 
423
455
  See the [next section](#the-conversion-does-not-work-and-i-get-a-cryptic-ffmpeg-error).
424
456
 
@@ -514,6 +546,7 @@ If you found this program useful and feel like giving back, feel free to send a
514
546
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/sian1468"><img src="https://avatars.githubusercontent.com/u/58017832?v=4?s=100" width="100px;" alt="sian1468"/><br /><sub><b>sian1468</b></sub></a><br /><a href="https://github.com/slhck/ffmpeg-normalize/commits?author=sian1468" title="Tests">⚠️</a></td>
515
547
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/psavva"><img src="https://avatars.githubusercontent.com/u/1454758?v=4?s=100" width="100px;" alt="Panayiotis Savva"/><br /><sub><b>Panayiotis Savva</b></sub></a><br /><a href="https://github.com/slhck/ffmpeg-normalize/commits?author=psavva" title="Code">💻</a></td>
516
548
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/HighMans"><img src="https://avatars.githubusercontent.com/u/42877729?v=4?s=100" width="100px;" alt="HighMans"/><br /><sub><b>HighMans</b></sub></a><br /><a href="https://github.com/slhck/ffmpeg-normalize/commits?author=HighMans" title="Code">💻</a></td>
549
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/kanjieater"><img src="https://avatars.githubusercontent.com/u/32607317?v=4?s=100" width="100px;" alt="kanjieater"/><br /><sub><b>kanjieater</b></sub></a><br /><a href="#ideas-kanjieater" title="Ideas, Planning, & Feedback">🤔</a></td>
517
550
  </tr>
518
551
  </tbody>
519
552
  <tfoot>
@@ -561,6 +594,22 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
561
594
  # Changelog
562
595
 
563
596
 
597
+ ## v1.29.0 (2024-10-14)
598
+
599
+ * Add option to set audio channels directly.
600
+
601
+
602
+ ## v1.28.3 (2024-08-16)
603
+
604
+ * Make colorama dependency windows-only.
605
+
606
+ * Update.
607
+
608
+ * Update badges.
609
+
610
+ * Docs: add @kanjieater as a contributor.
611
+
612
+
564
613
  ## v1.28.2 (2024-06-22)
565
614
 
566
615
  * Provide an entrypoint for the Docker image.
@@ -1,4 +1,6 @@
1
1
  tqdm
2
- colorama
3
2
  ffmpeg-progress-yield
4
3
  colorlog
4
+
5
+ [:platform_system == "Windows"]
6
+ colorama
@@ -34,7 +34,7 @@ setup(
34
34
  },
35
35
  install_requires=[
36
36
  "tqdm",
37
- "colorama",
37
+ "colorama;platform_system=='Windows'",
38
38
  "ffmpeg-progress-yield",
39
39
  "colorlog",
40
40
  ],
@@ -460,3 +460,18 @@ class TestFFmpegNormalize:
460
460
  ["test/test.mp4", "-ext", "wav", "-vn", "-f", "q"]
461
461
  )
462
462
  assert "only supports one stream" not in stderr
463
+
464
+ def test_audio_channels(self):
465
+ ffmpeg_normalize_call(
466
+ ["test/test.mp4", "-ac", "1", "-o", "normalized/test.wav"]
467
+ )
468
+ assert os.path.isfile("normalized/test.wav")
469
+ stream_info = _get_stream_info("normalized/test.wav")[0]
470
+ assert stream_info["channels"] == 1
471
+
472
+ ffmpeg_normalize_call(
473
+ ["test/test.mp4", "-ac", "2", "-o", "normalized/test2.wav"]
474
+ )
475
+ assert os.path.isfile("normalized/test2.wav")
476
+ stream_info = _get_stream_info("normalized/test2.wav")[0]
477
+ assert stream_info["channels"] == 2
@@ -1 +0,0 @@
1
- __version__ = "1.28.2"