Discussion:
[PATCH] player.c: replay gain scaling works without peak
Johannes Weißl
2011-03-30 00:43:22 UTC
Permalink
Peak is not required for just adding gain (and can even be disabled by
replaygain_limit option).
---
player.c | 16 +++++++++-------
1 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/player.c b/player.c
index e633656..be24c70 100644
--- a/player.c
+++ b/player.c
@@ -344,7 +344,7 @@ static void update_rg_scale(void)
peak = player_info.ti->rg_album_peak;
}

- if (isnan(gain) || isnan(peak)) {
+ if (isnan(gain)) {
if (replaygain == RG_TRACK_PREFERRED) {
gain = player_info.ti->rg_album_gain;
peak = player_info.ti->rg_album_peak;
@@ -354,11 +354,11 @@ static void update_rg_scale(void)
}
}

- if (isnan(gain) || isnan(peak)) {
- d_print("gain or peak not available\n");
+ if (isnan(gain)) {
+ d_print("gain not available\n");
return;
}
- if (peak < 0.05) {
+ if (!isnan(peak) && peak < 0.05) {
d_print("peak (%g) is too small\n", peak);
return;
}
@@ -367,9 +367,11 @@ static void update_rg_scale(void)

scale = pow(10.0, db / 20.0);
replaygain_scale = scale;
- limit = 1.0 / peak;
- if (replaygain_limit && replaygain_scale > limit)
- replaygain_scale = limit;
+ if (replaygain_limit && !isnan(peak)) {
+ limit = 1.0 / peak;
+ if (replaygain_scale > limit)
+ replaygain_scale = limit;
+ }

d_print("gain = %f, peak = %f, db = %f, scale = %f, limit = %f, replaygain_scale = %f\n",
gain, peak, db, scale, limit, replaygain_scale);
--
1.7.4.1
Johannes Weißl
2011-03-30 01:29:15 UTC
Permalink
some code and comments are from MPD
---
mad.c | 15 +++++++++++
misc.c | 18 ++++++++++++++
misc.h | 12 +++++++++
nomad.c | 82 ++++++++++++++++++++++++++++++++++++++++++++------------------
nomad.h | 1 +
5 files changed, 104 insertions(+), 24 deletions(-)

diff --git a/mad.c b/mad.c
index 0ae0199..b16bfae 100644
--- a/mad.c
+++ b/mad.c
@@ -25,6 +25,8 @@
#include "read_wrapper.h"
#include "debug.h"

+#include <stdio.h>
+#include <math.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
@@ -121,6 +123,7 @@ static int mad_read_comments(struct input_plugin_data *ip_data,
int fd, rc, save, i;
APETAG(ape);
GROWING_KEYVALS(c);
+ float rg_track_peak, rg_track_gain;

fd = open(ip_data->filename, O_RDONLY);
if (fd == -1) {
@@ -168,6 +171,18 @@ next:
out:
ape_free(&ape);

+ /* add last so the other tags get preference */
+ if (nomad_lame_replaygain(ip_data->private, &rg_track_peak, &rg_track_gain) == 0) {
+ char buf[64];
+
+ if (!isnan(rg_track_peak)) {
+ sprintf(buf, "%f", rg_track_peak);
+ comments_add_const(&c, "replaygain_track_peak", buf);
+ }
+ sprintf(buf, "%+.1f dB", rg_track_gain);
+ comments_add_const(&c, "replaygain_track_gain", buf);
+ }
+
keyvals_terminate(&c);
*comments = c.keyvals;
return 0;
diff --git a/misc.c b/misc.c
index 6e77fd5..551a75e 100644
--- a/misc.c
+++ b/misc.c
@@ -166,3 +166,21 @@ int misc_init(void)
make_dir(cmus_config_dir);
return 0;
}
+
+int replaygain_decode(unsigned int field, int *gain)
+{
+ unsigned int name_code, originator_code, sign_bit, val;
+
+ name_code = (field >> 13) & 0x7;
+ if (!name_code || name_code > 2)
+ return 0;
+ originator_code = (field >> 10) & 0x7;
+ if (!originator_code)
+ return 0;
+ sign_bit = (field >> 9) & 0x1;
+ val = field & 0x1ff;
+ if (sign_bit && !val)
+ return 0;
+ *gain = (sign_bit ? -1 : 1) * val;
+ return name_code;
+}
diff --git a/misc.h b/misc.h
index f12d857..bb1f384 100644
--- a/misc.h
+++ b/misc.h
@@ -29,4 +29,16 @@ int strptrcmp(const void *a, const void *b);
int misc_init(void);
const char *escape(const char *str);

+/*
+ * @field contains Replay Gain data format in bit representation
+ * @gain pointer where to store gain value * 10
+ *
+ * Returns 0 if @field doesn't contain a valid gain value,
+ * 1 for track (= radio) adjustment
+ * 2 for album (= audiophile) adjustment
+ *
+ * http://replaygain.hydrogenaudio.org/rg_data_format.html
+ */
+int replaygain_decode(unsigned int field, int *gain);
+
#endif
diff --git a/nomad.c b/nomad.c
index bc578b6..1f3367d 100644
--- a/nomad.c
+++ b/nomad.c
@@ -30,8 +30,12 @@
#include "id3.h"
#include "xmalloc.h"
#include "debug.h"
+#include "misc.h"

#include <mad.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
@@ -76,12 +80,9 @@ struct nomad {

struct {
char encoder[10]; /* 9 byte encoder name/version ("LAME3.97b") */
-#if 0
- /* See related comment in parse_lame() */
float peak; /* replaygain peak */
float trackGain; /* replaygain track gain */
float albumGain; /* replaygain album gain */
-#endif
int encoderDelay; /* # of added samples at start of mp3 */
int encoderPadding; /* # of added samples at end of mp3 */
} lame;
@@ -143,7 +144,9 @@ static inline double timer_to_seconds(mad_timer_t timer)

static int parse_lame(struct nomad *nomad, struct mad_bitptr ptr, int bitlen)
{
- int i;
+ int i, adj = 0;
+ unsigned int version_major, version_minor;
+ float val;

/* Unlike the xing header, the lame tag has a fixed length. Fail if
* not all 36 bytes (288 bits) are there. */
@@ -157,35 +160,55 @@ static int parse_lame(struct nomad *nomad, struct mad_bitptr ptr, int bitlen)
* wouldn't want to go reading a tag that's not there. */
if (strncmp(nomad->lame.encoder, "LAME", 4) != 0) return 0;

-#if 0
- /* Apparently lame versions <3.97b1 do not calculate replaygain. I'm
- * using lame 3.97b2, and while it does calculate replaygain, it's
- * setting the values to 0. Using --replaygain-(fast|accurate) doesn't
- * make any difference. Leaving this code unused until we have a way
- * of testing it. -- jat */
-
- mad_bit_read(&ptr, 16);
+ if (sscanf(nomad->lame.encoder + 4, "%u.%u", &version_major, &version_minor) != 2)
+ return 0;

- mad_bit_read(&ptr, 32); /* peak */
+#if defined(DEBUG_LAME)
+ d_print("detected LAME version %s\n", nomad->lame.encoder + 4);
+#endif

- mad_bit_read(&ptr, 6); /* header */
- bits = mad_bit_read(&ptr, 1); /* sign bit */
- nomad->lame.trackGain = mad_bit_read(&ptr, 9); /* gain*10 */
- nomad->lame.trackGain = (&bits ? -nomad->lame.trackGain : nomad->lame.trackGain) / 10;
+ mad_bit_read(&ptr, 16);

- mad_bit_read(&ptr, 6); /* header */
- bits = mad_bit_read(&ptr, 1); /* sign bit */
- nomad->lame.albumGain = mad_bit_read(&ptr, 9); /* gain*10 */
- nomad->lame.albumGain = (bits ? -nomad->lame.albumGain : nomad->lame.albumGain) / 10;
+ /* The reference volume was changed from the 83dB used in the
+ * ReplayGain spec to 89dB in lame 3.95.1. Bump the gain for older
+ * versions, since everyone else uses 89dB instead of 83dB.
+ * Unfortunately, lame didn't differentiate between 3.95 and 3.95.1, so
+ * it's impossible to make the proper adjustment for 3.95.
+ * Fortunately, 3.95 was only out for about a day before 3.95.1 was
+ * released. -- tmz */
+ if (version_major < 3 || (version_major == 3 && version_minor < 95))
+ adj = 6;
+
+ val = mad_bit_read(&ptr, 32) / (float) (1 << 23);
+ /* peak value of 0.0 means lame didn't calculate the peak at all
+ * (--replaygain-fast), even silence has a value > 0.0 */
+ if (val)
+ nomad->lame.peak = val;
+ for (i = 0; i < 2; i++) {
+ int gain, gain_type;
+ gain_type = replaygain_decode(mad_bit_read(&ptr, 16), &gain);
+ val = gain / 10.f + adj;
+ if (gain_type == 1)
+ nomad->lame.trackGain = val;
+ /* LAME currently doesn't store any album gain!
+ else if (gain_type == 2)
+ nomad->lame.albumGain = val;
+ */
+ }

mad_bit_read(&ptr, 16);
-#else
- mad_bit_read(&ptr, 96);
-#endif

nomad->lame.encoderDelay = mad_bit_read(&ptr, 12);
nomad->lame.encoderPadding = mad_bit_read(&ptr, 12);
#if defined(DEBUG_LAME)
+ if (adj > 0)
+ d_print("adjusted gains by %+d dB (old LAME)\n", adj);
+ if (!isnan(nomad->lame.peak))
+ d_print("peak: %f\n", nomad->lame.peak);
+ if (!isnan(nomad->lame.trackGain))
+ d_print("trackGain: %+.1f dB\n", nomad->lame.trackGain);
+ if (!isnan(nomad->lame.albumGain))
+ d_print("albumGain: %+.1f dB\n", nomad->lame.albumGain);
d_print("encoderDelay: %d, encoderPadding: %d\n", nomad->lame.encoderDelay, nomad->lame.encoderPadding);
#endif

@@ -602,6 +625,7 @@ int nomad_open(struct nomad **nomadp, int fd, int fast)
nomad->cbs.close = default_close;
nomad->start_drop_samples = 0;
nomad->end_drop_samples = 0;
+ nomad->lame.peak = nomad->lame.trackGain = nomad->lame.albumGain = strtof("NAN", NULL);
*nomadp = nomad;
/* on error do_open calls nomad_close */
return do_open(nomad, fast);
@@ -614,6 +638,7 @@ int nomad_open_callbacks(struct nomad **nomadp, void *datasource, int fast, stru
nomad = xnew0(struct nomad, 1);
nomad->datasource = datasource;
nomad->cbs = *cbs;
+ nomad->lame.peak = nomad->lame.trackGain = nomad->lame.albumGain = strtof("NAN", NULL);
*nomadp = nomad;
/* on error do_open calls nomad_close */
return do_open(nomad, fast);
@@ -851,6 +876,15 @@ int nomad_time_seek(struct nomad *nomad, double pos)
return 0;
}

+int nomad_lame_replaygain(struct nomad *nomad, float *peak, float *trackGain)
+{
+ if (isnan(nomad->lame.trackGain))
+ return -1;
+ *peak = nomad->lame.peak;
+ *trackGain = nomad->lame.trackGain;
+ return 0;
+}
+
double nomad_time_tell(struct nomad *nomad)
{
return timer_to_seconds(nomad->timer);
diff --git a/nomad.h b/nomad.h
index de1227b..dff2075 100644
--- a/nomad.h
+++ b/nomad.h
@@ -77,6 +77,7 @@ int nomad_read(struct nomad *nomad, char *buffer, int count);
/* -NOMAD_ERROR_ERRNO */
int nomad_time_seek(struct nomad *nomad, double pos);

+int nomad_lame_replaygain(struct nomad *nomad, float *peak, float *trackGain);
double nomad_time_tell(struct nomad *nomad);
double nomad_time_total(struct nomad *nomad);
--
1.7.4.1
Johannes Weißl
2011-03-30 02:33:06 UTC
Permalink
---
nomad.c | 56 ++++++++++++++++++++++++++++++--------------------------
1 files changed, 30 insertions(+), 26 deletions(-)

diff --git a/nomad.c b/nomad.c
index 1f3367d..1911614 100644
--- a/nomad.c
+++ b/nomad.c
@@ -169,32 +169,36 @@ static int parse_lame(struct nomad *nomad, struct mad_bitptr ptr, int bitlen)

mad_bit_read(&ptr, 16);

- /* The reference volume was changed from the 83dB used in the
- * ReplayGain spec to 89dB in lame 3.95.1. Bump the gain for older
- * versions, since everyone else uses 89dB instead of 83dB.
- * Unfortunately, lame didn't differentiate between 3.95 and 3.95.1, so
- * it's impossible to make the proper adjustment for 3.95.
- * Fortunately, 3.95 was only out for about a day before 3.95.1 was
- * released. -- tmz */
- if (version_major < 3 || (version_major == 3 && version_minor < 95))
- adj = 6;
-
- val = mad_bit_read(&ptr, 32) / (float) (1 << 23);
- /* peak value of 0.0 means lame didn't calculate the peak at all
- * (--replaygain-fast), even silence has a value > 0.0 */
- if (val)
- nomad->lame.peak = val;
- for (i = 0; i < 2; i++) {
- int gain, gain_type;
- gain_type = replaygain_decode(mad_bit_read(&ptr, 16), &gain);
- val = gain / 10.f + adj;
- if (gain_type == 1)
- nomad->lame.trackGain = val;
- /* LAME currently doesn't store any album gain!
- else if (gain_type == 2)
- nomad->lame.albumGain = val;
- */
- }
+ /* ReplayGain in LAME tag was added in 3.94 */
+ if (version_major > 3 || (version_major == 3 && version_minor >= 94)) {
+ /* The reference volume was changed from the 83dB used in the
+ * ReplayGain spec to 89dB in lame 3.95.1. Bump the gain for older
+ * versions, since everyone else uses 89dB instead of 83dB.
+ * Unfortunately, lame didn't differentiate between 3.95 and 3.95.1, so
+ * it's impossible to make the proper adjustment for 3.95.
+ * Fortunately, 3.95 was only out for about a day before 3.95.1 was
+ * released. -- tmz */
+ if (version_major < 3 || (version_major == 3 && version_minor < 95))
+ adj = 6;
+
+ val = mad_bit_read(&ptr, 32) / (float) (1 << 23);
+ /* peak value of 0.0 means lame didn't calculate the peak at all
+ * (--replaygain-fast), even silence has a value > 0.0 */
+ if (val)
+ nomad->lame.peak = val;
+ for (i = 0; i < 2; i++) {
+ int gain, gain_type;
+ gain_type = replaygain_decode(mad_bit_read(&ptr, 16), &gain);
+ val = gain / 10.f + adj;
+ if (gain_type == 1)
+ nomad->lame.trackGain = val;
+ /* LAME currently doesn't store any album gain!
+ else if (gain_type == 2)
+ nomad->lame.albumGain = val;
+ */
+ }
+ } else
+ mad_bit_read(&ptr, 48);

mad_bit_read(&ptr, 16);
--
1.7.4.1
Johannes Weißl
2011-03-30 16:13:29 UTC
Permalink
---
nomad.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/nomad.c b/nomad.c
index 1911614..24a0730 100644
--- a/nomad.c
+++ b/nomad.c
@@ -167,10 +167,10 @@ static int parse_lame(struct nomad *nomad, struct mad_bitptr ptr, int bitlen)
d_print("detected LAME version %s\n", nomad->lame.encoder + 4);
#endif

- mad_bit_read(&ptr, 16);
-
/* ReplayGain in LAME tag was added in 3.94 */
if (version_major > 3 || (version_major == 3 && version_minor >= 94)) {
+ mad_bit_read(&ptr, 16);
+
/* The reference volume was changed from the 83dB used in the
* ReplayGain spec to 89dB in lame 3.95.1. Bump the gain for older
* versions, since everyone else uses 89dB instead of 83dB.
@@ -197,10 +197,10 @@ static int parse_lame(struct nomad *nomad, struct mad_bitptr ptr, int bitlen)
nomad->lame.albumGain = val;
*/
}
- } else
- mad_bit_read(&ptr, 48);

- mad_bit_read(&ptr, 16);
+ mad_bit_read(&ptr, 16);
+ } else
+ mad_bit_read(&ptr, 96);

nomad->lame.encoderDelay = mad_bit_read(&ptr, 12);
nomad->lame.encoderPadding = mad_bit_read(&ptr, 12);
--
1.7.4.1
Gregory Petrosyan
2011-03-30 20:42:44 UTC
Permalink
Merged to -pu, thanks a lot!

Gregory
Gregory Petrosyan
2011-04-05 20:57:04 UTC
Permalink
In master now, thanks!

Gregory

Johannes Weißl
2011-03-30 01:51:54 UTC
Permalink
---
player.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/player.c b/player.c
index be24c70..08a71f8 100644
--- a/player.c
+++ b/player.c
@@ -367,8 +367,8 @@ static void update_rg_scale(void)

scale = pow(10.0, db / 20.0);
replaygain_scale = scale;
+ limit = 1.0 / peak;
if (replaygain_limit && !isnan(peak)) {
- limit = 1.0 / peak;
if (replaygain_scale > limit)
replaygain_scale = limit;
}
--
1.7.4.1
Loading...