Skip to content

Commit d28737c

Browse files
authored
Added album normalization as recommended in AES77 (#168)
* Added album normalization as recommended in AES77 * Moved out the common case in handling of album calculation
1 parent 1ad7128 commit d28737c

File tree

5 files changed

+65
-15
lines changed

5 files changed

+65
-15
lines changed

config/presets/loudgain.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[Global]
22
TagMode=i
33
Album=true
4+
AlbumAsAES77=false
45
TargetLoudness=-18
56
ClipMode=a
67
MaxPeakLevel=-1.0

src/easymode.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ static Config configs[] = {
4848
.true_peak = false,
4949
.clip_mode = 'p',
5050
.do_album = true,
51+
.album_as_aes77 = false,
5152
.tab_output = OutputType::NONE,
5253
.sep_header = false,
5354
.sort_alphanum = false,
@@ -68,6 +69,7 @@ static Config configs[] = {
6869
.true_peak = false,
6970
.clip_mode = 'p',
7071
.do_album = true,
72+
.album_as_aes77 = false,
7173
.tab_output = OutputType::NONE,
7274
.sep_header = false,
7375
.sort_alphanum = false,
@@ -88,6 +90,7 @@ static Config configs[] = {
8890
.true_peak = false,
8991
.clip_mode = 'p',
9092
.do_album = true,
93+
.album_as_aes77 = false,
9194
.tab_output = OutputType::NONE,
9295
.sep_header = false,
9396
.sort_alphanum = false,
@@ -108,6 +111,7 @@ static Config configs[] = {
108111
.true_peak = false,
109112
.clip_mode = 'p',
110113
.do_album = true,
114+
.album_as_aes77 = false,
111115
.tab_output = OutputType::NONE,
112116
.sep_header = false,
113117
.sort_alphanum = false,
@@ -128,6 +132,7 @@ static Config configs[] = {
128132
.true_peak = false,
129133
.clip_mode = 'p',
130134
.do_album = true,
135+
.album_as_aes77 = false,
131136
.tab_output = OutputType::NONE,
132137
.sep_header = false,
133138
.sort_alphanum = false,
@@ -148,6 +153,7 @@ static Config configs[] = {
148153
.true_peak = false,
149154
.clip_mode = 'p',
150155
.do_album = true,
156+
.album_as_aes77 = false,
151157
.tab_output = OutputType::NONE,
152158
.sep_header = false,
153159
.sort_alphanum = false,
@@ -168,6 +174,7 @@ static Config configs[] = {
168174
.true_peak = false,
169175
.clip_mode = 'p',
170176
.do_album = true,
177+
.album_as_aes77 = false,
171178
.tab_output = OutputType::NONE,
172179
.sep_header = false,
173180
.sort_alphanum = false,
@@ -188,6 +195,7 @@ static Config configs[] = {
188195
.true_peak = false,
189196
.clip_mode = 'p',
190197
.do_album = true,
198+
.album_as_aes77 = false,
191199
.tab_output = OutputType::NONE,
192200
.sep_header = false,
193201
.sort_alphanum = false,
@@ -208,6 +216,7 @@ static Config configs[] = {
208216
.true_peak = false,
209217
.clip_mode = 'p',
210218
.do_album = true,
219+
.album_as_aes77 = false,
211220
.tab_output = OutputType::NONE,
212221
.sep_header = false,
213222
.sort_alphanum = false,
@@ -228,6 +237,7 @@ static Config configs[] = {
228237
.true_peak = false,
229238
.clip_mode = 'p',
230239
.do_album = true,
240+
.album_as_aes77 = false,
231241
.tab_output = OutputType::NONE,
232242
.sep_header = false,
233243
.sort_alphanum = false,
@@ -248,6 +258,7 @@ static Config configs[] = {
248258
.true_peak = false,
249259
.clip_mode = 'p',
250260
.do_album = true,
261+
.album_as_aes77 = false,
251262
.tab_output = OutputType::NONE,
252263
.sep_header = false,
253264
.sort_alphanum = false,
@@ -268,6 +279,7 @@ static Config configs[] = {
268279
.true_peak = false,
269280
.clip_mode = 'p',
270281
.do_album = true,
282+
.album_as_aes77 = false,
271283
.tab_output = OutputType::NONE,
272284
.sep_header = false,
273285
.sort_alphanum = false,
@@ -288,6 +300,7 @@ static Config configs[] = {
288300
.true_peak = false,
289301
.clip_mode = 'p',
290302
.do_album = true,
303+
.album_as_aes77 = false,
291304
.tab_output = OutputType::NONE,
292305
.sep_header = false,
293306
.sort_alphanum = false,
@@ -308,6 +321,7 @@ static Config configs[] = {
308321
.true_peak = false,
309322
.clip_mode = 'p',
310323
.do_album = true,
324+
.album_as_aes77 = false,
311325
.tab_output = OutputType::NONE,
312326
.sep_header = false,
313327
.sort_alphanum = false,
@@ -468,6 +482,15 @@ int global_handler([[maybe_unused]] void *user, const char *section, const char
468482
else
469483
quit(EXIT_FAILURE);
470484
}
485+
else if (MATCH(name, "AlbumAsAES77")) {
486+
bool as_aes77;
487+
if (convert_bool(value, as_aes77)) {
488+
for (Config &config : configs)
489+
config.album_as_aes77 = as_aes77;
490+
}
491+
else
492+
quit(EXIT_FAILURE);
493+
}
471494
else if (MATCH(name, "TagMode")) {
472495
char tag_mode;
473496
if (parse_tag_mode_easy(value, tag_mode)) {
@@ -570,6 +593,8 @@ int format_handler([[maybe_unused]] void *user, const char *section, const char
570593
// Parse setting keys
571594
if (MATCH(name, "Album"))
572595
convert_bool(value, configs[static_cast<int>(file_type)].do_album);
596+
else if (MATCH(name, "AlbumAsAES77"))
597+
convert_bool(value, configs[static_cast<int>(file_type)].album_as_aes77);
573598
else if (MATCH(name, "TagMode"))
574599
parse_tag_mode_easy(value, configs[static_cast<int>(file_type)].tag_mode);
575600
else if (MATCH(name, "ClipMode"))

src/rsgain.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,10 @@ static void custom_mode(int argc, char *argv[])
182182
unsigned int nb_files = 0;
183183
opterr = 0;
184184

185-
const char *short_opts = "+ac:m:tdl:O::qps:LSI:o:h?";
185+
const char *short_opts = "+aec:m:tdl:O::qps:LSI:o:h?";
186186
static struct option long_opts[] = {
187187
{ "album", no_argument, nullptr, 'a' },
188+
{ "album-aes77", no_argument, nullptr, 'e' },
188189
{ "skip-existing", no_argument, nullptr, 'S' },
189190

190191
{ "clip-mode", required_argument, nullptr, 'c' },
@@ -214,6 +215,7 @@ static void custom_mode(int argc, char *argv[])
214215
.true_peak = false,
215216
.clip_mode = 'n',
216217
.do_album = false,
218+
.album_as_aes77 = false,
217219
.tab_output = OutputType::NONE,
218220
.sep_header = false,
219221
.sort_alphanum = false,
@@ -231,6 +233,11 @@ static void custom_mode(int argc, char *argv[])
231233
config.do_album = true;
232234
break;
233235

236+
case 'e':
237+
config.do_album = true;
238+
config.album_as_aes77 = true;
239+
break;
240+
234241
case 'S':
235242
config.skip_existing = true;
236243
break;
@@ -430,6 +437,7 @@ static inline void help_custom() {
430437
rsgain::print("\n");
431438

432439
CMD_HELP("--album", "-a", "Calculate album gain and peak");
440+
CMD_HELP("--album-aes77", "-e", "Use the loudest track as the album loudness as recommended in AES77");
433441
CMD_HELP("--skip-existing", "-S", "Don't scan files with existing ReplayGain information");
434442
rsgain::print("\n");
435443

src/rsgain.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct Config {
2727
bool true_peak;
2828
char clip_mode;
2929
bool do_album;
30+
bool album_as_aes77;
3031
OutputType tab_output;
3132
bool sep_header;
3233
bool sort_alphanum;

src/scan.cpp

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -672,20 +672,35 @@ void ScanJob::Track::calculate_loudness(const Config &config)
672672
void ScanJob::calculate_album_loudness()
673673
{
674674
double album_loudness, album_peak;
675-
size_t nb_states = tracks.size();
676-
std::vector<ebur128_state*> states(nb_states);
677-
for (const Track &track : tracks)
678-
if (track.result.track_loudness != -HUGE_VAL)
679-
states.emplace_back(track.ebur128.get());
680-
681-
if (ebur128_loudness_global_multiple(states.data(), states.size(), &album_loudness) != EBUR128_SUCCESS)
682-
album_loudness = config.target_loudness;
683-
684-
album_peak = std::max_element(tracks.begin(),
685-
tracks.end(),
686-
[](const auto &a, const auto &b) { return a.result.track_peak < b.result.track_peak; }
687-
)->result.track_peak;
688-
675+
if (config.album_as_aes77) {
676+
album_loudness = -HUGE_VAL;
677+
album_peak = 0.0;
678+
for (const Track &track : tracks) {
679+
if (album_loudness < track.result.track_loudness) {
680+
album_loudness = track.result.track_loudness;
681+
}
682+
if (album_peak < track.result.track_peak) {
683+
album_peak = track.result.track_peak;
684+
}
685+
}
686+
}
687+
688+
else {
689+
size_t nb_states = tracks.size();
690+
std::vector<ebur128_state*> states(nb_states);
691+
for (const Track &track : tracks)
692+
if (track.result.track_loudness != -HUGE_VAL)
693+
states.emplace_back(track.ebur128.get());
694+
695+
if (ebur128_loudness_global_multiple(states.data(), states.size(), &album_loudness) != EBUR128_SUCCESS)
696+
album_loudness = config.target_loudness;
697+
698+
album_peak = std::max_element(tracks.begin(),
699+
tracks.end(),
700+
[](const auto &a, const auto &b) { return a.result.track_peak < b.result.track_peak; }
701+
)->result.track_peak;
702+
}
703+
689704
double album_gain = (type == FileType::OPUS && config.opus_mode == 's' ? -23.0 : config.target_loudness)
690705
- album_loudness;
691706
for (Track &track : tracks) {

0 commit comments

Comments
 (0)