switch to using FLAC__stream_encoder_set_compression_level()
authorJosh Coalson <jcoalson@users.sourceforce.net>
Fri, 3 Nov 2006 16:16:32 +0000 (16:16 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Fri, 3 Nov 2006 16:16:32 +0000 (16:16 +0000)
src/flac/encode.c
src/flac/encode.h
src/flac/main.c

index 2e046fc..2de8ca4 100644 (file)
@@ -75,7 +75,6 @@ typedef struct {
        FLAC__uint64 total_samples_to_encode;
        FLAC__uint64 bytes_written;
        FLAC__uint64 samples_written;
-       unsigned blocksize;
        unsigned stats_mask;
 
        FLAC__StreamEncoder *encoder;
@@ -1531,7 +1530,6 @@ FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg, FLAC_
        e->total_samples_to_encode = 0;
        e->bytes_written = 0;
        e->samples_written = 0;
-       e->blocksize = 0;
        e->stats_mask = 0;
 
        e->encoder = 0;
@@ -1629,6 +1627,7 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
        FLAC__StreamMetadata **metadata = static_metadata;
        FLAC__StreamEncoderInitStatus init_status;
        const FLAC__bool is_cdda = (channels == 1 || channels == 2) && (bps == 16) && (sample_rate == 44100);
+       char apodizations[2000];
 
        FLAC__ASSERT(sizeof(options.pictures)/sizeof(options.pictures[0]) <= 64);
 
@@ -1637,6 +1636,8 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
        e->bits_per_sample = bps;
        e->sample_rate = sample_rate;
 
+       apodizations[0] = '\0';
+
        if(e->replay_gain) {
                if(channels != 1 && channels != 2) {
                        flac__utils_printf(stderr, 1, "%s: ERROR, number of channels (%u) must be 1 or 2 for --replay-gain\n", e->inbasefilename, channels);
@@ -1654,9 +1655,6 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
                }
        }
 
-       if(channels != 2)
-               options.do_mid_side = options.loose_mid_side = false;
-
        if(!parse_cuesheet(&cuesheet, options.cuesheet_filename, e->inbasefilename, is_cdda, e->total_samples_to_encode))
                return false;
 
@@ -1891,26 +1889,66 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
                return false;
        }
 
-       e->blocksize = options.blocksize;
-       e->stats_mask = (options.do_exhaustive_model_search || options.do_qlp_coeff_prec_search)? 0x0f : 0x3f;
-
        FLAC__stream_encoder_set_verify(e->encoder, options.verify);
        FLAC__stream_encoder_set_streamable_subset(e->encoder, !options.lax);
-       FLAC__stream_encoder_set_do_mid_side_stereo(e->encoder, options.do_mid_side);
-       FLAC__stream_encoder_set_loose_mid_side_stereo(e->encoder, options.loose_mid_side);
        FLAC__stream_encoder_set_channels(e->encoder, channels);
        FLAC__stream_encoder_set_bits_per_sample(e->encoder, bps);
        FLAC__stream_encoder_set_sample_rate(e->encoder, sample_rate);
-       FLAC__stream_encoder_set_blocksize(e->encoder, options.blocksize);
-       FLAC__stream_encoder_set_apodization(e->encoder, options.apodizations);
-       FLAC__stream_encoder_set_max_lpc_order(e->encoder, options.max_lpc_order);
-       FLAC__stream_encoder_set_qlp_coeff_precision(e->encoder, options.qlp_coeff_precision);
-       FLAC__stream_encoder_set_do_qlp_coeff_prec_search(e->encoder, options.do_qlp_coeff_prec_search);
-       FLAC__stream_encoder_set_do_escape_coding(e->encoder, options.do_escape_coding);
-       FLAC__stream_encoder_set_do_exhaustive_model_search(e->encoder, options.do_exhaustive_model_search);
-       FLAC__stream_encoder_set_min_residual_partition_order(e->encoder, options.min_residual_partition_order);
-       FLAC__stream_encoder_set_max_residual_partition_order(e->encoder, options.max_residual_partition_order);
-       FLAC__stream_encoder_set_rice_parameter_search_dist(e->encoder, options.rice_parameter_search_dist);
+       for(i = 0; i < options.num_compression_settings; i++) {
+               switch(options.compression_settings[i].type) {
+                       case CST_BLOCKSIZE:
+                               FLAC__stream_encoder_set_blocksize(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+                       case CST_COMPRESSION_LEVEL:
+                               FLAC__stream_encoder_set_compression_level(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               apodizations[0] = '\0';
+                               break;
+                       case CST_DO_MID_SIDE:
+                               FLAC__stream_encoder_set_do_mid_side_stereo(e->encoder, options.compression_settings[i].value.t_bool);
+                               break;
+                       case CST_LOOSE_MID_SIDE:
+                               FLAC__stream_encoder_set_loose_mid_side_stereo(e->encoder, options.compression_settings[i].value.t_bool);
+                               break;
+                       case CST_APODIZATION:
+                               if(strlen(apodizations)+strlen(options.compression_settings[i].value.t_string)+2 >= sizeof(apodizations)) {
+                                       flac__utils_printf(stderr, 1, "%s: ERROR: too many apodization functions requested\n", e->inbasefilename);
+                                       if(0 != cuesheet)
+                                               FLAC__metadata_object_delete(cuesheet);
+                                       return false;
+                               }
+                               else {
+                                       strcat(apodizations, options.compression_settings[i].value.t_string);
+                                       strcat(apodizations, ";");
+                               }
+                               break;
+                       case CST_MAX_LPC_ORDER:
+                               FLAC__stream_encoder_set_max_lpc_order(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+                       case CST_QLP_COEFF_PRECISION:
+                               FLAC__stream_encoder_set_qlp_coeff_precision(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+                       case CST_DO_QLP_COEFF_PREC_SEARCH:
+                               FLAC__stream_encoder_set_do_qlp_coeff_prec_search(e->encoder, options.compression_settings[i].value.t_bool);
+                               break;
+                       case CST_DO_ESCAPE_CODING:
+                               FLAC__stream_encoder_set_do_escape_coding(e->encoder, options.compression_settings[i].value.t_bool);
+                               break;
+                       case CST_DO_EXHAUSTIVE_MODEL_SEARCH:
+                               FLAC__stream_encoder_set_do_exhaustive_model_search(e->encoder, options.compression_settings[i].value.t_bool);
+                               break;
+                       case CST_MIN_RESIDUAL_PARTITION_ORDER:
+                               FLAC__stream_encoder_set_min_residual_partition_order(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+                       case CST_MAX_RESIDUAL_PARTITION_ORDER:
+                               FLAC__stream_encoder_set_max_residual_partition_order(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+                       case CST_RICE_PARAMETER_SEARCH_DIST:
+                               FLAC__stream_encoder_set_rice_parameter_search_dist(e->encoder, options.compression_settings[i].value.t_unsigned);
+                               break;
+               }
+       }
+       if(*apodizations)
+               FLAC__stream_encoder_set_apodization(e->encoder, apodizations);
        FLAC__stream_encoder_set_total_samples_estimate(e->encoder, e->total_samples_to_encode);
        FLAC__stream_encoder_set_metadata(e->encoder, (num_metadata > 0)? metadata : 0, num_metadata);
 
@@ -1941,6 +1979,8 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
        else
                e->outputfile_opened = true;
 
+       e->stats_mask = (FLAC__stream_encoder_get_do_exhaustive_model_search(e->encoder) || FLAC__stream_encoder_get_do_qlp_coeff_prec_search(e->encoder))? 0x0f : 0x3f;
+
        if(0 != cuesheet)
                FLAC__metadata_object_delete(cuesheet);
 
index 1450253..9aed30a 100644 (file)
 
 extern const int FLAC_ENCODE__DEFAULT_PADDING;
 
+typedef enum {
+       CST_BLOCKSIZE,
+       CST_COMPRESSION_LEVEL,
+       CST_DO_MID_SIDE,
+       CST_LOOSE_MID_SIDE,
+       CST_APODIZATION,
+       CST_MAX_LPC_ORDER,
+       CST_QLP_COEFF_PRECISION,
+       CST_DO_QLP_COEFF_PREC_SEARCH,
+       CST_DO_ESCAPE_CODING,
+       CST_DO_EXHAUSTIVE_MODEL_SEARCH,
+       CST_MIN_RESIDUAL_PARTITION_ORDER,
+       CST_MAX_RESIDUAL_PARTITION_ORDER,
+       CST_RICE_PARAMETER_SEARCH_DIST
+} compression_setting_type_t;
+
+typedef struct {
+       compression_setting_type_t type;
+       union {
+               FLAC__bool t_bool;
+               unsigned t_unsigned;
+               const char *t_string;
+       } value;
+} compression_setting_t;
+
 typedef struct {
        utils__SkipUntilSpecification skip_specification;
        utils__SkipUntilSpecification until_specification;
@@ -42,19 +67,9 @@ typedef struct {
        long serial_number;
 #endif
        FLAC__bool lax;
-       FLAC__bool do_mid_side;
-       FLAC__bool loose_mid_side;
-       FLAC__bool do_exhaustive_model_search;
-       FLAC__bool do_escape_coding;
-       FLAC__bool do_qlp_coeff_prec_search;
-       unsigned min_residual_partition_order;
-       unsigned max_residual_partition_order;
-       unsigned rice_parameter_search_dist;
-       char *apodizations;
-       unsigned max_lpc_order;
-       unsigned blocksize;
-       unsigned qlp_coeff_precision;
        int padding;
+       size_t num_compression_settings;
+       compression_setting_t compression_settings[64];
        char *requested_seek_points;
        int num_requested_seek_points;
        const char *cuesheet_filename;
index 83aa1a7..4b0a2cd 100644 (file)
@@ -64,6 +64,9 @@ static FLAC__bool init_options();
 static int parse_options(int argc, char *argv[]);
 static int parse_option(int short_option, const char *long_option, const char *option_argument);
 static void free_options();
+static void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool value);
+static void add_compression_setting_string(compression_setting_type_t type, const char *value);
+static void add_compression_setting_unsigned(compression_setting_type_t type, unsigned value);
 
 static int usage_error(const char *message, ...);
 static void short_usage();
@@ -221,11 +224,6 @@ static struct {
        FLAC__bool use_ogg;
        FLAC__bool has_serial_number; /* true iff --serial-number was used */
        long serial_number; /* this is the Ogg serial number and is unused for native FLAC */
-       FLAC__bool do_mid_side;
-       FLAC__bool loose_mid_side;
-       FLAC__bool do_exhaustive_model_search;
-       FLAC__bool do_escape_coding;
-       FLAC__bool do_qlp_coeff_prec_search;
        FLAC__bool force_to_stdout;
        FLAC__bool force_aiff_format;
        FLAC__bool force_raw_format;
@@ -236,9 +234,8 @@ static struct {
        const char *output_prefix;
        analysis_options aopts;
        int padding; /* -1 => no -P options were given, 0 => -P- was given, else -P value */
-       char apodizations[1000]; /* bad MAGIC NUMBER but buffer overflow is checked */
-       unsigned max_lpc_order;
-       unsigned qlp_coeff_precision;
+       size_t num_compression_settings;
+       compression_setting_t compression_settings[64]; /* bad MAGIC NUMBER but buffer overflow is checked */
        const char *skip_specification;
        const char *until_specification;
        const char *cue_specification;
@@ -248,10 +245,6 @@ static struct {
        int format_bps;
        int format_sample_rate;
        off_t format_input_size;
-       int blocksize;
-       int min_residual_partition_order;
-       int max_residual_partition_order;
-       int rice_parameter_search_dist;
        char requested_seek_points[5000]; /* bad MAGIC NUMBER but buffer overflow is checked */
        int num_requested_seek_points; /* -1 => no -S options were given, 0 => -S- was given */
        const char *cuesheet_filename;
@@ -334,26 +327,6 @@ int do_it()
                 * tweak options; validate the values
                 */
                if(!option_values.mode_decode) {
-                       if(option_values.blocksize < 0) {
-                               if(option_values.max_lpc_order == 0)
-                                       option_values.blocksize = 1152;
-                               else
-                                       option_values.blocksize = 4608;
-                       }
-                       if(option_values.max_residual_partition_order < 0) {
-                               if(option_values.blocksize <= 1152)
-                                       option_values.max_residual_partition_order = 2;
-                               else if(option_values.blocksize <= 2304)
-                                       option_values.max_residual_partition_order = 3;
-                               else if(option_values.blocksize <= 4608)
-                                       option_values.max_residual_partition_order = 3;
-                               else
-                                       option_values.max_residual_partition_order = 4;
-                               option_values.min_residual_partition_order = option_values.max_residual_partition_order;
-                       }
-                       if(option_values.rice_parameter_search_dist < 0) {
-                               option_values.rice_parameter_search_dist = 0;
-                       }
                        if(0 != option_values.cue_specification)
                                return usage_error("ERROR: --cue is not allowed in test mode\n");
                }
@@ -373,8 +346,6 @@ int do_it()
                if(0 != option_values.cue_specification && (0 != option_values.skip_specification || 0 != option_values.until_specification))
                        return usage_error("ERROR: --cue may not be combined with --skip or --until\n");
 
-               FLAC__ASSERT(option_values.blocksize >= 0 || option_values.mode_decode);
-
                if(option_values.format_channels >= 0) {
                        if(option_values.format_channels == 0 || (unsigned)option_values.format_channels > FLAC__MAX_CHANNELS)
                                return usage_error("ERROR: invalid number of channels '%u', must be > 0 and <= %u\n", option_values.format_channels, FLAC__MAX_CHANNELS);
@@ -403,12 +374,6 @@ int do_it()
                        if(option_values.format_sample_rate >= 0)
                                return usage_error("ERROR: --sample-rate not allowed with --decode\n");
                }
-               if(!option_values.mode_decode && ((unsigned)option_values.blocksize < FLAC__MIN_BLOCK_SIZE || (unsigned)option_values.blocksize > FLAC__MAX_BLOCK_SIZE)) {
-                       return usage_error("ERROR: invalid blocksize '%u', must be >= %u and <= %u\n", (unsigned)option_values.blocksize, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
-               }
-               if(option_values.qlp_coeff_precision > 0 && option_values.qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION) {
-                       return usage_error("ERROR: invalid value '%u' for qlp coeff precision, must be 0 or >= %u\n", option_values.qlp_coeff_precision, FLAC__MIN_QLP_COEFF_PRECISION);
-               }
 
                if(option_values.sector_align) {
                        if(option_values.mode_decode)
@@ -464,32 +429,6 @@ int do_it()
        flac__utils_printf(stderr, 2, "flac comes with ABSOLUTELY NO WARRANTY.  This is free software, and you are\n");
        flac__utils_printf(stderr, 2, "welcome to redistribute it under certain conditions.  Type `flac' for details.\n\n");
 
-       if(!option_values.mode_decode) {
-               char padopt[16];
-               if(option_values.padding == 0)
-                       strcpy(padopt, "-");
-               else
-                       sprintf(padopt, " %d", option_values.padding > 0? option_values.padding : FLAC_ENCODE__DEFAULT_PADDING);
-               flac__utils_printf(stderr, 2,
-                       "options:%s%s%s%s -P%s -b %u%s -l %u%s%s%s -q %u -r %u,%u%s\n",
-                       option_values.delete_input?" --delete-input-file":"",
-                       option_values.sector_align?" --sector-align":"",
-                       option_values.use_ogg?" --ogg":"",
-                       option_values.lax?" --lax":"",
-                       padopt,
-                       (unsigned)option_values.blocksize,
-                       option_values.loose_mid_side?" -M":option_values.do_mid_side?" -m":"",
-                       option_values.max_lpc_order,
-                       option_values.do_exhaustive_model_search?" -e":"",
-                       option_values.do_escape_coding?" -E":"",
-                       option_values.do_qlp_coeff_prec_search?" -p":"",
-                       option_values.qlp_coeff_precision,
-                       (unsigned)option_values.min_residual_partition_order,
-                       (unsigned)option_values.max_residual_partition_order,
-                       option_values.verify? " -V":""
-               );
-       }
-
        if(option_values.mode_decode) {
                FLAC__bool first = true;
 
@@ -570,11 +509,6 @@ FLAC__bool init_options()
        option_values.use_ogg = false;
        option_values.has_serial_number = false;
        option_values.serial_number = 0;
-       option_values.do_mid_side = true;
-       option_values.loose_mid_side = false;
-       option_values.do_exhaustive_model_search = false;
-       option_values.do_escape_coding = false;
-       option_values.do_qlp_coeff_prec_search = false;
        option_values.force_to_stdout = false;
        option_values.force_aiff_format = false;
        option_values.force_raw_format = false;
@@ -586,9 +520,7 @@ FLAC__bool init_options()
        option_values.aopts.do_residual_text = false;
        option_values.aopts.do_residual_gnuplot = false;
        option_values.padding = -1;
-       option_values.apodizations[0] = '\0';
-       option_values.max_lpc_order = 8;
-       option_values.qlp_coeff_precision = 0;
+       option_values.num_compression_settings = 0;
        option_values.skip_specification = 0;
        option_values.until_specification = 0;
        option_values.cue_specification = 0;
@@ -598,10 +530,6 @@ FLAC__bool init_options()
        option_values.format_bps = -1;
        option_values.format_sample_rate = -1;
        option_values.format_input_size = (off_t)(-1);
-       option_values.blocksize = -1;
-       option_values.min_residual_partition_order = -1;
-       option_values.max_residual_partition_order = -1;
-       option_values.rice_parameter_search_dist = -1;
        option_values.requested_seek_points[0] = '\0';
        option_values.num_requested_seek_points = -1;
        option_values.cuesheet_filename = 0;
@@ -667,6 +595,7 @@ int parse_option(int short_option, const char *long_option, const char *option_a
 {
        const char *violation;
        char *p;
+       int i;
 
        if(short_option == 0) {
                FLAC__ASSERT(0 != long_option);
@@ -857,16 +786,18 @@ int parse_option(int short_option, const char *long_option, const char *option_a
                }
 #endif
                else if(0 == strcmp(long_option, "no-exhaustive-model-search")) {
-                       option_values.do_exhaustive_model_search = false;
+                       add_compression_setting_bool(CST_DO_EXHAUSTIVE_MODEL_SEARCH, false);
                }
                else if(0 == strcmp(long_option, "no-mid-side")) {
-                       option_values.do_mid_side = option_values.loose_mid_side = false;
+                       add_compression_setting_bool(CST_DO_MID_SIDE, false);
+                       add_compression_setting_bool(CST_LOOSE_MID_SIDE, false);
                }
                else if(0 == strcmp(long_option, "no-adaptive-mid-side")) {
-                       option_values.loose_mid_side = option_values.do_mid_side = false;
+                       add_compression_setting_bool(CST_DO_MID_SIDE, false);
+                       add_compression_setting_bool(CST_LOOSE_MID_SIDE, false);
                }
                else if(0 == strcmp(long_option, "no-qlp-coeff-prec-search")) {
-                       option_values.do_qlp_coeff_prec_search = false;
+                       add_compression_setting_bool(CST_DO_QLP_COEFF_PREC_SEARCH, false);
                }
                else if(0 == strcmp(long_option, "no-padding")) {
                        option_values.padding = 0;
@@ -934,98 +865,15 @@ int parse_option(int short_option, const char *long_option, const char *option_a
                                        return usage_error("ERROR: (-T/--tag) %s\n", violation);
                                break;
                        case '0':
-                               option_values.do_exhaustive_model_search = false;
-                               option_values.do_escape_coding = false;
-                               option_values.do_mid_side = false;
-                               option_values.loose_mid_side = false;
-                               option_values.qlp_coeff_precision = 0;
-                               option_values.min_residual_partition_order = option_values.max_residual_partition_order = 2;
-                               option_values.rice_parameter_search_dist = 0;
-                               option_values.max_lpc_order = 0;
-                               break;
                        case '1':
-                               option_values.do_exhaustive_model_search = false;
-                               option_values.do_escape_coding = false;
-                               option_values.do_mid_side = true;
-                               option_values.loose_mid_side = true;
-                               option_values.qlp_coeff_precision = 0;
-                               option_values.min_residual_partition_order = option_values.max_residual_partition_order = 2;
-                               option_values.rice_parameter_search_dist = 0;
-                               option_values.max_lpc_order = 0;
-                               break;
                        case '2':
-                               option_values.do_exhaustive_model_search = false;
-                               option_values.do_escape_coding = false;
-                               option_values.do_mid_side = true;
-                               option_values.loose_mid_side = false;
-                               option_values.qlp_coeff_precision = 0;
-                               option_values.min_residual_partition_order = 0;
-                               option_values.max_residual_partition_order = 3;
-                               option_values.rice_parameter_search_dist = 0;
-                               option_values.max_lpc_order = 0;
-                               break;
                        case '3':
-                               option_values.do_exhaustive_model_search = false;
-                               option_values.do_escape_coding = false;
-                               option_values.do_mid_side = false;
-                               option_values.loose_mid_side = false;
-                               option_values.qlp_coeff_precision = 0;
-                               option_values.min_residual_partition_order = option_values.max_residual_partition_order = 3;
-                               option_values.rice_parameter_search_dist = 0;
-                               option_values.max_lpc_order = 6;
-                               break;
                        case '4':
-                               option_values.do_exhaustive_model_search = false;
-                               option_values.do_escape_coding = false;
-                               option_values.do_mid_side = true;
-                               option_values.loose_mid_side = true;
-                               option_values.qlp_coeff_precision = 0;
-                               option_values.min_residual_partition_order = option_values.max_residual_partition_order = 3;
-                               option_values.rice_parameter_search_dist = 0;
-                               option_values.max_lpc_order = 8;
-                               break;
                        case '5':
-                               option_values.do_exhaustive_model_search = false;
-                               option_values.do_escape_coding = false;
-                               option_values.do_mid_side = true;
-                               option_values.loose_mid_side = false;
-                               option_values.qlp_coeff_precision = 0;
-                               option_values.min_residual_partition_order = option_values.max_residual_partition_order = 3;
-                               option_values.rice_parameter_search_dist = 0;
-                               option_values.max_lpc_order = 8;
-                               break;
                        case '6':
-                               option_values.do_exhaustive_model_search = false;
-                               option_values.do_escape_coding = false;
-                               option_values.do_mid_side = true;
-                               option_values.loose_mid_side = false;
-                               option_values.qlp_coeff_precision = 0;
-                               option_values.min_residual_partition_order = 0;
-                               option_values.max_residual_partition_order = 4;
-                               option_values.rice_parameter_search_dist = 0;
-                               option_values.max_lpc_order = 8;
-                               break;
                        case '7':
-                               option_values.do_exhaustive_model_search = true;
-                               option_values.do_escape_coding = false;
-                               option_values.do_mid_side = true;
-                               option_values.loose_mid_side = false;
-                               option_values.qlp_coeff_precision = 0;
-                               option_values.min_residual_partition_order = 0;
-                               option_values.max_residual_partition_order = 6;
-                               option_values.rice_parameter_search_dist = 0;
-                               option_values.max_lpc_order = 8;
-                               break;
                        case '8':
-                               option_values.do_exhaustive_model_search = true;
-                               option_values.do_escape_coding = false;
-                               option_values.do_mid_side = true;
-                               option_values.loose_mid_side = false;
-                               option_values.qlp_coeff_precision = 0;
-                               option_values.min_residual_partition_order = 0;
-                               option_values.max_residual_partition_order = 6;
-                               option_values.rice_parameter_search_dist = 0;
-                               option_values.max_lpc_order = 12;
+                               add_compression_setting_unsigned(CST_COMPRESSION_LEVEL, short_option-'0');
                                break;
                        case '9':
                                return usage_error("ERROR: compression level '9' is reserved\n");
@@ -1055,61 +903,76 @@ int parse_option(int short_option, const char *long_option, const char *option_a
                                FLAC__ASSERT(0 != option_argument);
                                option_values.padding = atoi(option_argument);
                                if(option_values.padding < 0)
-                                       return usage_error("ERROR: argument to -P must be >= 0; for no padding use -P-\n");
+                                       return usage_error("ERROR: argument to -%c must be >= 0; for no padding use -%c-\n", short_option, short_option);
                                break;
                        case 'b':
                                FLAC__ASSERT(0 != option_argument);
-                               option_values.blocksize = atoi(option_argument);
+                               i = atoi(option_argument);
+                               if((i < (int)FLAC__MIN_BLOCK_SIZE || i > (int)FLAC__MAX_BLOCK_SIZE))
+                                       return usage_error("ERROR: invalid blocksize (-%c) '%d', must be >= %u and <= %u\n", short_option, i, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
+                               add_compression_setting_unsigned(CST_BLOCKSIZE, (unsigned)i);
                                break;
                        case 'e':
-                               option_values.do_exhaustive_model_search = true;
+                               add_compression_setting_bool(CST_DO_EXHAUSTIVE_MODEL_SEARCH, true);
                                break;
                        case 'E':
-                               option_values.do_escape_coding = true;
+                               add_compression_setting_bool(CST_DO_ESCAPE_CODING, true);
                                break;
                        case 'l':
                                FLAC__ASSERT(0 != option_argument);
-                               option_values.max_lpc_order = atoi(option_argument);
+                               i = atoi(option_argument);
+                               if((i < 0 || i > (int)FLAC__MAX_LPC_ORDER))
+                                       return usage_error("ERROR: invalid LPC order (-%c) '%d', must be >= %u and <= %u\n", short_option, i, 0, FLAC__MAX_LPC_ORDER);
+                               add_compression_setting_unsigned(CST_MAX_LPC_ORDER, (unsigned)i);
                                break;
                        case 'A':
                                FLAC__ASSERT(0 != option_argument);
-                               if(strlen(option_values.apodizations)+strlen(option_argument)+2 >= sizeof(option_values.apodizations)) {
-                                       return usage_error("ERROR: too many apodization functions requested\n");
-                               }
-                               else {
-                                       strcat(option_values.apodizations, option_argument);
-                                       strcat(option_values.apodizations, ";");
-                               }
+                               add_compression_setting_string(CST_APODIZATION, option_argument);
                                break;
                        case 'm':
-                               option_values.do_mid_side = true;
-                               option_values.loose_mid_side = false;
+                               add_compression_setting_bool(CST_DO_MID_SIDE, true);
+                               add_compression_setting_bool(CST_LOOSE_MID_SIDE, false);
                                break;
                        case 'M':
-                               option_values.loose_mid_side = option_values.do_mid_side = true;
+                               add_compression_setting_bool(CST_DO_MID_SIDE, true);
+                               add_compression_setting_bool(CST_LOOSE_MID_SIDE, true);
                                break;
                        case 'p':
-                               option_values.do_qlp_coeff_prec_search = true;
+                               add_compression_setting_bool(CST_DO_QLP_COEFF_PREC_SEARCH, true);
                                break;
                        case 'q':
                                FLAC__ASSERT(0 != option_argument);
-                               option_values.qlp_coeff_precision = atoi(option_argument);
+                               i = atoi(option_argument);
+                               if(i < 0 || (i > 0 && (i < (int)FLAC__MIN_QLP_COEFF_PRECISION || i > (int)FLAC__MAX_QLP_COEFF_PRECISION)))
+                                       return usage_error("ERROR: invalid value '%d' for qlp coeff precision (-%c), must be 0 or between %u and %u, inclusive\n", i, short_option, FLAC__MIN_QLP_COEFF_PRECISION, FLAC__MAX_QLP_COEFF_PRECISION);
+                               add_compression_setting_unsigned(CST_QLP_COEFF_PRECISION, (unsigned)i);
                                break;
                        case 'r':
                                FLAC__ASSERT(0 != option_argument);
                                p = strchr(option_argument, ',');
                                if(0 == p) {
-                                       option_values.min_residual_partition_order = 0;
-                                       option_values.max_residual_partition_order = atoi(option_argument);
+                                       add_compression_setting_unsigned(CST_MIN_RESIDUAL_PARTITION_ORDER, 0);
+                                       i = atoi(option_argument);
+                                       if(i < 0)
+                                               return usage_error("ERROR: invalid value '%d' for residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER);
+                                       add_compression_setting_unsigned(CST_MAX_RESIDUAL_PARTITION_ORDER, (unsigned)i);
                                }
                                else {
-                                       option_values.min_residual_partition_order = atoi(option_argument);
-                                       option_values.max_residual_partition_order = atoi(++p);
+                                       i = atoi(option_argument);
+                                       if(i < 0)
+                                               return usage_error("ERROR: invalid value '%d' for min residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER);
+                                       add_compression_setting_unsigned(CST_MIN_RESIDUAL_PARTITION_ORDER, (unsigned)i);
+                                       i = atoi(++p);
+                                       if(i < 0)
+                                               return usage_error("ERROR: invalid value '%d' for max residual partition order (-%c), must be between 0 and %u, inclusive\n", i, short_option, FLAC__MAX_RICE_PARTITION_ORDER);
+                                       add_compression_setting_unsigned(CST_MAX_RESIDUAL_PARTITION_ORDER, (unsigned)i);
                                }
                                break;
                        case 'R':
-                               FLAC__ASSERT(0 != option_argument);
-                               option_values.rice_parameter_search_dist = atoi(option_argument);
+                               i = atoi(option_argument);
+                               if(i < 0)
+                                       return usage_error("ERROR: invalid value '%d' for Rice parameter search distance (-%c), must be >= 0\n", i, short_option);
+                               add_compression_setting_unsigned(CST_RICE_PARAMETER_SEARCH_DIST, (unsigned)i);
                                break;
                        default:
                                FLAC__ASSERT(0);
@@ -1135,6 +998,33 @@ void free_options()
                FLAC__metadata_object_delete(option_values.pictures[i]);
 }
 
+void add_compression_setting_bool(compression_setting_type_t type, FLAC__bool value)
+{
+       if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0]))
+               die("too many compression settings");
+       option_values.compression_settings[option_values.num_compression_settings].type = type;
+       option_values.compression_settings[option_values.num_compression_settings].value.t_bool = value;
+       option_values.num_compression_settings++;
+}
+
+void add_compression_setting_string(compression_setting_type_t type, const char *value)
+{
+       if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0]))
+               die("too many compression settings");
+       option_values.compression_settings[option_values.num_compression_settings].type = type;
+       option_values.compression_settings[option_values.num_compression_settings].value.t_string = value;
+       option_values.num_compression_settings++;
+}
+
+void add_compression_setting_unsigned(compression_setting_type_t type, unsigned value)
+{
+       if(option_values.num_compression_settings >= sizeof(option_values.compression_settings)/sizeof(option_values.compression_settings[0]))
+               die("too many compression settings");
+       option_values.compression_settings[option_values.num_compression_settings].type = type;
+       option_values.compression_settings[option_values.num_compression_settings].value.t_unsigned = value;
+       option_values.num_compression_settings++;
+}
+
 int usage_error(const char *message, ...)
 {
        if(flac__utils_verbosity_ >= 1) {
@@ -1745,19 +1635,10 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_
        common_options.serial_number = option_values.serial_number++;
 #endif
        common_options.lax = option_values.lax;
-       common_options.do_mid_side = option_values.do_mid_side;
-       common_options.loose_mid_side = option_values.loose_mid_side;
-       common_options.do_exhaustive_model_search = option_values.do_exhaustive_model_search;
-       common_options.do_escape_coding = option_values.do_escape_coding;
-       common_options.do_qlp_coeff_prec_search = option_values.do_qlp_coeff_prec_search;
-       common_options.min_residual_partition_order = option_values.min_residual_partition_order;
-       common_options.max_residual_partition_order = option_values.max_residual_partition_order;
-       common_options.rice_parameter_search_dist = option_values.rice_parameter_search_dist;
-       common_options.apodizations = option_values.apodizations;
-       common_options.max_lpc_order = option_values.max_lpc_order;
-       common_options.blocksize = (unsigned)option_values.blocksize;
-       common_options.qlp_coeff_precision = option_values.qlp_coeff_precision;
        common_options.padding = option_values.padding;
+       common_options.num_compression_settings = option_values.num_compression_settings;
+       FLAC__ASSERT(sizeof(common_options.compression_settings) >= sizeof(option_values.compression_settings));
+       memcpy(common_options.compression_settings, option_values.compression_settings, sizeof(option_values.compression_settings));
        common_options.requested_seek_points = option_values.requested_seek_points;
        common_options.num_requested_seek_points = option_values.num_requested_seek_points;
        common_options.cuesheet_filename = option_values.cuesheet_filename;