Skip to content

Commit

Permalink
implement '--opus-header-gain' option for more control over Opus head…
Browse files Browse the repository at this point in the history
…er gain field
  • Loading branch information
jiixyj committed Dec 24, 2021
1 parent a660cf8 commit 7c77876
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 14 deletions.
30 changes: 22 additions & 8 deletions scanner/scanner-tag/rgtag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@ clamp_gain_data(struct gain_data *gd)

static int
tag_vorbis_comment(char const *filename, char const *extension,
struct gain_data *gd, struct gain_data_strings *gds, bool opus_compat)
struct gain_data *gd, struct gain_data_strings *gds,
OpusTagInfo const *opus_tag_info)
{
std::pair<TagLib::File *, TagLib::Ogg::XiphComment *> p =
get_ogg_file(filename, extension);
Expand All @@ -333,8 +334,19 @@ tag_vorbis_comment(char const *filename, char const *extension,
struct gain_data_strings gds_opus(&gd_opus);

if (is_opus) {
double opus_header_gain = /**/
(gd->album_mode ? gd->album_gain : gd->track_gain) - 5.0;
double opus_header_gain;

if (opus_tag_info->opus_gain_reference ==
OPUS_GAIN_REFERENCE_ABSOLUTE) {
opus_header_gain = opus_tag_info->offset;
} else {
opus_header_gain = /**/
(!opus_tag_info->is_track && gd->album_mode) ?
gd->album_gain :
gd->track_gain;
opus_header_gain -= 5.0;
opus_header_gain += opus_tag_info->offset;
}

int16_t opus_header_gain_int = to_opus_gain(opus_header_gain);

Expand Down Expand Up @@ -373,7 +385,7 @@ tag_vorbis_comment(char const *filename, char const *extension,
gds = &gds_opus;
}

if (is_opus && !opus_compat) {
if (is_opus && !opus_tag_info->vorbisgain_compat) {
p.second->removeFields("REPLAYGAIN_TRACK_GAIN");
p.second->removeFields("REPLAYGAIN_TRACK_PEAK");
p.second->removeFields("REPLAYGAIN_ALBUM_GAIN");
Expand Down Expand Up @@ -590,7 +602,7 @@ has_tag_mp4(char const *filename)

int
set_rg_info(char const *filename, char const *extension, struct gain_data *gd,
int opus_compat)
OpusTagInfo const *opus_tag_info)
{
if (std::strcmp(extension, "opus") != 0) {
/* For opus, we clamp in tag_vorbis_comment(). */
Expand All @@ -608,7 +620,7 @@ set_rg_info(char const *filename, char const *extension, struct gain_data *gd,
!std::strcmp(extension, "ogg") || /**/
!std::strcmp(extension, "oga")) {
return tag_vorbis_comment(filename, extension, gd, &gds,
!!opus_compat);
opus_tag_info);
}

if (!std::strcmp(extension, "mpc") || !std::strcmp(extension, "wv")) {
Expand All @@ -623,7 +635,8 @@ set_rg_info(char const *filename, char const *extension, struct gain_data *gd,
}

bool
has_rg_info(char const *filename, char const *extension, int opus_compat)
has_rg_info(char const *filename, char const *extension,
OpusTagInfo const *opus_tag_info)
{
if (!std::strcmp(extension, "mp3") || !std::strcmp(extension, "mp2")) {
return has_tag_id3v2(filename);
Expand All @@ -633,7 +646,8 @@ has_rg_info(char const *filename, char const *extension, int opus_compat)
!std::strcmp(extension, "opus") || /**/
!std::strcmp(extension, "ogg") || /**/
!std::strcmp(extension, "oga")) {
return has_vorbis_comment(filename, extension, !!opus_compat);
return has_vorbis_comment(filename, extension,
opus_tag_info->vorbisgain_compat);
}

// TODO: implement "0.0 workaround" for ape
Expand Down
17 changes: 15 additions & 2 deletions scanner/scanner-tag/rgtag.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,26 @@ struct gain_data {
double album_peak;
};

typedef enum {
OPUS_GAIN_REFERENCE_ABSOLUTE,
OPUS_GAIN_REFERENCE_R128,
} OpusGainReference;

typedef struct {
bool vorbisgain_compat;
OpusGainReference opus_gain_reference;
double offset;
bool is_track;
} OpusTagInfo;

double clamp_rg(double x);
void clamp_gain_data(struct gain_data *gd);

int set_rg_info(char const *filename, char const *extension,
struct gain_data *gd, int opus_compat);
struct gain_data *gd, OpusTagInfo const *opus_tag_info);

bool has_rg_info(char const *filename, char const *extension, int opus_compat);
bool has_rg_info(char const *filename, char const *extension,
OpusTagInfo const *opus_tag_info);

#ifdef __cplusplus
}
Expand Down
102 changes: 98 additions & 4 deletions scanner/scanner-tag/scanner-tag.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "scanner-tag.h"

#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

Expand All @@ -14,13 +16,101 @@ static struct file_data empty;

extern gboolean verbose;
extern gboolean histogram;

static gboolean track = FALSE;
static gboolean dry_run = FALSE;
static gboolean incremental_tagging = FALSE;
static gboolean force_as_album = FALSE;

static gboolean opus_vorbisgain_compat = FALSE;
static OpusTagInfo opus_tag_info = {
.opus_gain_reference = OPUS_GAIN_REFERENCE_R128,
};

extern gchar *decode_to_file;

static gboolean
parse_opus_header_gain(gchar const *option_name, gchar const *value,
gpointer data, GError **error)
{
gboolean rc = FALSE;

(void)option_name;
(void)data;
(void)error;

gchar **elements = g_strsplit(value, ",", -1);
if (elements[0] == NULL) {
goto out;
}

bool is_rg;
if (strcmp(elements[0], "r128") == 0) {
opus_tag_info.opus_gain_reference = OPUS_GAIN_REFERENCE_R128;
is_rg = false;
} else if (strcmp(elements[0], "rg") == 0) {
opus_tag_info.opus_gain_reference = OPUS_GAIN_REFERENCE_R128;
is_rg = true;
} else {
gchar *endptr;
gdouble offset = g_ascii_strtod(elements[0], &endptr);
if (endptr == elements[0] || *endptr != '\0' || errno != 0 ||
!isfinite(offset)) {
goto out;
}
opus_tag_info.opus_gain_reference =
OPUS_GAIN_REFERENCE_ABSOLUTE;
opus_tag_info.offset = offset;
}

bool got_track = false;
bool got_offset = false;
for (gchar **it = elements + 1; *it != NULL; ++it) {
if (opus_tag_info.opus_gain_reference ==
OPUS_GAIN_REFERENCE_ABSOLUTE) {
goto out;
}

if (strcmp(*it, "track") == 0) {
if (got_track) {
goto out;
}
got_track = true;

opus_tag_info.is_track = true;

} else if (strncmp(*it, "offset=", 7) == 0) {
if (got_offset) {
goto out;
}
got_offset = true;

gchar *startptr = *it + 7;
gchar *endptr;
gdouble offset = g_ascii_strtod(startptr, &endptr);
if (endptr == startptr || *endptr != '\0' ||
errno != 0 || !isfinite(offset)) {
goto out;
}
opus_tag_info.offset = offset;

} else {
goto out;
}
}

if (opus_tag_info.opus_gain_reference == OPUS_GAIN_REFERENCE_R128 &&
is_rg) {
opus_tag_info.offset += 5.0;
}

rc = TRUE;

out:
g_strfreev(elements);
return rc;
}

static GOptionEntry entries[] = {
{ "track", 't', 0, G_OPTION_ARG_NONE, /**/
&track, NULL, NULL },
Expand All @@ -32,6 +122,8 @@ static GOptionEntry entries[] = {
&force_as_album, NULL, NULL },
{ "opus-vorbisgain-compat", 0, 0, G_OPTION_ARG_NONE, /**/
&opus_vorbisgain_compat, NULL, NULL },
{ "opus-header-gain", 0, 0, G_OPTION_ARG_CALLBACK, /**/
parse_opus_header_gain, NULL, NULL },
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, 0 },
};

Expand Down Expand Up @@ -178,8 +270,7 @@ tag_file(struct filename_list_node *fln, int *ret)
get_filename_and_extension(fln, &basename, &extension,
&filename);

error = set_rg_info(filename, extension, &gd,
opus_vorbisgain_compat);
error = set_rg_info(filename, extension, &gd, &opus_tag_info);
if (error) {
if (tag_output_state == 0) {
fflush(stderr);
Expand Down Expand Up @@ -242,7 +333,7 @@ tag_files(GSList *files)

fprintf(stderr, "Tagging");
g_slist_foreach(files, (GFunc)tag_file, &ret);
if (!ret) {
if (ret == 0) {
fprintf(stderr, " Success!");
}
fputc('\n', stderr);
Expand All @@ -258,7 +349,7 @@ append_to_untagged_list(struct filename_list_node *fln, GSList **ret)
char *filename;
get_filename_and_extension(fln, &basename, &extension, &filename);

if (!has_rg_info(filename, extension, opus_vorbisgain_compat)) {
if (!has_rg_info(filename, extension, &opus_tag_info)) {
*ret = g_slist_prepend(*ret, fln);
}

Expand Down Expand Up @@ -294,5 +385,8 @@ loudness_tag_parse(int *argc, char **argv[])
}
return FALSE;
}

opus_tag_info.vorbisgain_compat = opus_vorbisgain_compat != FALSE;

return TRUE;
}

0 comments on commit 7c77876

Please sign in to comment.