beginnings of --replay-gain support

This commit is contained in:
Josh Coalson
2002-10-29 05:47:10 +00:00
parent c955d2ca6e
commit df250077a9
3 changed files with 87 additions and 9 deletions

View File

@@ -29,6 +29,7 @@
#include <stdlib.h> /* for malloc */
#include <string.h> /* for strcmp() */
#include "FLAC/all.h"
#include "share/replaygain.h"
#include "encode.h"
#include "file.h"
@@ -58,6 +59,10 @@ typedef struct {
const char *inbasefilename;
const char *outfilename;
FLAC__bool replay_gain;
unsigned channels;
unsigned bits_per_sample;
unsigned sample_rate;
FLAC__uint64 unencoded_size;
FLAC__uint64 total_samples_to_encode;
FLAC__uint64 bytes_written;
@@ -783,6 +788,9 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
FLAC__ASSERT(!options.common.sector_align || options.bps == 16);
FLAC__ASSERT(!options.common.sector_align || options.sample_rate == 44100);
FLAC__ASSERT(!options.common.sector_align || infilesize >= 0);
FLAC__ASSERT(!options.common.replay_gain || options.common.skip == 0);
FLAC__ASSERT(!options.common.replay_gain || options.channels <= 2);
FLAC__ASSERT(!options.common.replay_gain || FLAC__replaygain_is_valid_sample_frequency(options.sample_rate));
if(!
EncoderSession_construct(
@@ -1174,6 +1182,22 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
FLAC__StreamMetadata padding;
FLAC__StreamMetadata *metadata[3];
e->replay_gain = option.common.replay_gain;
e->channels = channels;
e->bits_per_sample = bps;
e->sample_rate = sample_rate;
if(e->replay_gain) {
if(channels != 1 && channels != 2) {
fprintf(stderr, "%s: ERROR, number of channels (%u) must be 1 or 2 for --replay-gain\n", e->inbasefilename, channels);
return false;
}
if(!FLAC__replaygain_is_valid_sample_frequency(sample_rate)) {
fprintf(stderr, "%s: ERROR, invalid sample rate (%u) for --replay-gain\n", e->inbasefilename, sample_rate);
return false;
}
}
if(channels != 2)
options.do_mid_side = options.loose_mid_side = false;
@@ -1304,6 +1328,11 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], unsigned samples)
{
if(e->replay_gain) {
if(!FLAC__replaygain_analyze(buffer, e->channels==2, e->bits_per_sample, samples))
fprintf(stderr, "%s: WARNING, error while calculating ReplayGain\n", e->inbasefilename);
}
#ifdef FLAC__HAS_OGG
if(e->use_ogg) {
return OggFLAC__stream_encoder_process(e->encoder.ogg.stream, buffer, samples);

View File

@@ -50,10 +50,12 @@ typedef struct {
char *requested_seek_points;
int num_requested_seek_points;
/* options related to --sector-align */
/* options related to --replay-gain and --sector-align */
FLAC__bool is_first_file;
FLAC__bool is_last_file;
FLAC__int32 **align_reservoir;
unsigned *align_reservoir_samples;
FLAC__bool replay_gain;
FLAC__bool sector_align;
FLAC__StreamMetadata *vorbis_comment;

View File

@@ -34,6 +34,7 @@
#define strcasecmp stricmp
#endif
#include "FLAC/all.h"
#include "share/replaygain.h"
#include "analyze.h"
#include "decode.h"
#include "encode.h"
@@ -64,7 +65,7 @@ static void show_help();
static void show_explain();
static void format_mistake(const char *infilename, const char *wrong, const char *right);
static int encode_file(const char *infilename, const char *forced_outfilename, FLAC__bool is_last_file);
static int encode_file(const char *infilename, const char *forced_outfilename, FLAC__bool is_first_file, FLAC__bool is_last_file);
static int decode_file(const char *infilename, const char *forced_outfilename);
static void die(const char *message);
@@ -117,6 +118,7 @@ static struct FLAC__share__option long_options_[] = {
{ "verify", 0, 0, 'V' },
{ "force-raw-format", 0, 0, 0 },
{ "lax", 0, 0, 0 },
{ "replay-gain", 0, 0, 0 },
{ "sector-align", 0, 0, 0 },
{ "seekpoint", 1, 0, 'S' },
{ "padding", 1, 0, 'P' },
@@ -159,6 +161,7 @@ static struct FLAC__share__option long_options_[] = {
{ "no-silent", 0, 0, 0 },
{ "no-seektable", 0, 0, 0 },
{ "no-delete-input-file", 0, 0, 0 },
{ "no-replay-gain", 0, 0, 0 },
{ "no-sector-align", 0, 0, 0 },
{ "no-lax", 0, 0, 0 },
#ifdef FLAC__HAS_OGG
@@ -213,6 +216,7 @@ static struct {
FLAC__bool force_to_stdout;
FLAC__bool force_raw_format;
FLAC__bool delete_input;
FLAC__bool replay_gain;
FLAC__bool sector_align;
const char *cmdline_forced_outfilename;
const char *output_prefix;
@@ -368,15 +372,27 @@ int do_it()
if(option_values.sector_align) {
if(option_values.mode_decode)
return usage_error("ERROR: --sector-align only allowed for encoding\n");
else if(option_values.skip > 0)
if(option_values.skip > 0)
return usage_error("ERROR: --sector-align not allowed with --skip\n");
else if(option_values.format_channels >= 0 && option_values.format_channels != 2)
if(option_values.format_channels >= 0 && option_values.format_channels != 2)
return usage_error("ERROR: --sector-align can only be done with stereo input\n");
else if(option_values.format_bps >= 0 && option_values.format_bps != 16)
if(option_values.format_bps >= 0 && option_values.format_bps != 16)
return usage_error("ERROR: --sector-align can only be done with 16-bit samples\n");
else if(option_values.format_sample_rate >= 0 && option_values.format_sample_rate != 44100)
if(option_values.format_sample_rate >= 0 && option_values.format_sample_rate != 44100)
return usage_error("ERROR: --sector-align can only be done with a sample rate of 44100\n");
}
if(option_values.replay_gain) {
if(option_values.mode_decode)
return usage_error("ERROR: --replay-gain only allowed for encoding\n");
if(option_values.skip > 0)
return usage_error("ERROR: --replay-gain not allowed with --skip\n");
if(option_values.format_channels > 2)
return usage_error("ERROR: --replay-gain can only be done with mono/stereo input\n");
if(option_values.format_sample_rate >= 0 && !FLAC__replaygain_is_valid_sample_frequency(option_values.format_sample_rate))
return usage_error("ERROR: invalid sample rate used with --replay-gain\n");
if(option_values.padding < 0)
fprintf(stderr, "WARNING: --replay-gain may leave a small PADDING block even with --no-padding\n");
}
if(option_values.num_files > 1 && option_values.cmdline_forced_outfilename) {
return usage_error("ERROR: -o/--output-name cannot be used with multiple files\n");
}
@@ -439,7 +455,7 @@ int do_it()
FLAC__bool first = true;
if(option_values.num_files == 0) {
retval = encode_file("-", 0, true);
retval = encode_file("-", 0, first, true);
}
else {
unsigned i;
@@ -448,7 +464,7 @@ int do_it()
for(i = 0, retval = 0; i < option_values.num_files; i++) {
if(0 == strcmp(option_values.filenames[i], "-") && !first)
continue;
retval |= encode_file(option_values.filenames[i], 0, i == (option_values.num_files-1));
retval |= encode_file(option_values.filenames[i], 0, first, i == (option_values.num_files-1));
first = false;
}
}
@@ -479,6 +495,7 @@ FLAC__bool init_options()
option_values.force_to_stdout = false;
option_values.force_raw_format = false;
option_values.delete_input = false;
option_values.replay_gain = false;
option_values.sector_align = false;
option_values.cmdline_forced_outfilename = 0;
option_values.output_prefix = 0;
@@ -589,6 +606,21 @@ int parse_option(int short_option, const char *long_option, const char *option_a
else if(0 == strcmp(long_option, "lax")) {
option_values.lax = true;
}
else if(0 == strcmp(long_option, "replay-gain")) {
option_values.replay_gain = true;
/*
* We want to reserve space in the Vorbis comments
* for the ReplayGain tags that we will set later.
* Why do we store 100000.0 for the gain numbers
* initially? The gain field is variable length, so
* if the real number causes the tag size to shrink,
* we want it to shrink by at least 4 bytes so we can
* backfill with PADDING to avoid rewriting the whole
* file.
*/
if(0 != (violation = FLAC__replaygain_store_to_vorbiscomment(option_values.vorbis_comment, 100000.0, 0.0, 100000.0, 0.0)))
return usage_error("ERROR: (--replay-gain) %s\n", violation);
}
else if(0 == strcmp(long_option, "sector-align")) {
option_values.sector_align = true;
}
@@ -653,6 +685,9 @@ int parse_option(int short_option, const char *long_option, const char *option_a
else if(0 == strcmp(long_option, "no-delete-input-file")) {
option_values.delete_input = false;
}
else if(0 == strcmp(long_option, "no-replay-gain")) {
option_values.replay_gain = false;
}
else if(0 == strcmp(long_option, "no-sector-align")) {
option_values.sector_align = false;
}
@@ -1022,6 +1057,7 @@ void show_help()
#endif
printf(" --lax Allow encoder to generate non-Subset files\n");
printf(" --sector-align Align multiple files on sector boundaries\n");
printf(" --replay-gain Calculate ReplayGain & store in Vorbis comments\n");
printf(" -S, --seekpoint={#|X|#x} Add seek point(s)\n");
printf(" -P, --padding=# Write a PADDING block of length #\n");
printf(" -T, --tag=FIELD=VALUE Add a Vorbis comment; may appear multiple times\n");
@@ -1073,6 +1109,7 @@ void show_help()
#endif
printf(" --no-padding\n");
printf(" --no-qlp-coeff-prec-search\n");
printf(" --no-replay-gain\n");
printf(" --no-residual-gnuplot\n");
printf(" --no-residual-text\n");
printf(" --no-sector-align\n");
@@ -1165,6 +1202,14 @@ void show_explain()
printf(" --lax Allow encoder to generate non-Subset files\n");
printf(" --sector-align Align encoding of multiple CD format WAVE files\n");
printf(" on sector boundaries.\n");
printf(" --replay-gain Calculate ReplayGain values and store in Vorbis\n");
printf(" comments. Title gains/peaks will be computed\n");
printf(" for each file, and an album gain/peak will be\n");
printf(" computed for all files. All input files must\n");
printf(" have the same resolution, sample rate, and\n");
printf(" number of channels. The sample rate must be\n");
printf(" one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1,\n");
printf(" or 48 kHz.\n");
printf(" -S, --seekpoint={#|X|#x} Include a point or points in a SEEKTABLE\n");
printf(" # : a specific sample number for a seek point\n");
printf(" X : a placeholder point (always goes at the end of the SEEKTABLE)\n");
@@ -1277,7 +1322,7 @@ format_mistake(const char *infilename, const char *wrong, const char *right)
fprintf(stderr, "WARNING: %s is not a %s file; treating as a %s file\n", infilename, wrong, right);
}
int encode_file(const char *infilename, const char *forced_outfilename, FLAC__bool is_last_file)
int encode_file(const char *infilename, const char *forced_outfilename, FLAC__bool is_first_file, FLAC__bool is_last_file)
{
FILE *encode_infile;
char outfilename[4096]; /* @@@ bad MAGIC NUMBER */
@@ -1384,9 +1429,11 @@ int encode_file(const char *infilename, const char *forced_outfilename, FLAC__bo
common_options.padding = option_values.padding;
common_options.requested_seek_points = option_values.requested_seek_points;
common_options.num_requested_seek_points = option_values.num_requested_seek_points;
common_options.is_first_file = is_first_file;
common_options.is_last_file = is_last_file;
common_options.align_reservoir = align_reservoir;
common_options.align_reservoir_samples = &align_reservoir_samples;
common_options.replay_gain = option_values.replay_gain;
common_options.sector_align = option_values.sector_align;
common_options.vorbis_comment = option_values.vorbis_comment;
common_options.debug.disable_constant_subframes = option_values.debug.disable_constant_subframes;