From bf0f52c21e439aefdbcf71551621023b0bc9cef0 Mon Sep 17 00:00:00 2001 From: Josh Coalson Date: Tue, 25 Apr 2006 06:38:43 +0000 Subject: [PATCH] add support for specifying which apodization functions to use to window data before lpc analysis --- doc/html/changelog.html | 2 + include/FLAC/file_encoder.h | 15 + include/FLAC/format.h | 4 + include/FLAC/seekable_stream_encoder.h | 15 + include/FLAC/stream_encoder.h | 46 +++ include/OggFLAC/file_encoder.h | 14 + include/OggFLAC/seekable_stream_encoder.h | 13 + include/OggFLAC/stream_encoder.h | 13 + src/flac/encode.c | 6 +- src/flac/encode.h | 1 + src/flac/main.c | 29 +- src/libFLAC/Makefile.lite | 3 +- src/libFLAC/file_encoder.c | 11 + src/libFLAC/format.c | 5 +- src/libFLAC/include/private/lpc.h | 13 + .../include/protected/stream_encoder.h | 42 ++ src/libFLAC/lpc.c | 7 + src/libFLAC/seekable_stream_encoder.c | 11 + src/libFLAC/stream_encoder.c | 381 +++++++++++++++--- src/libOggFLAC/file_encoder.c | 11 + src/libOggFLAC/seekable_stream_encoder.c | 11 + src/libOggFLAC/stream_encoder.c | 11 + 22 files changed, 599 insertions(+), 65 deletions(-) diff --git a/doc/html/changelog.html b/doc/html/changelog.html index 99283d47..4c6af3e9 100644 --- a/doc/html/changelog.html +++ b/doc/html/changelog.html @@ -127,6 +127,7 @@
  • libFLAC: @@ -134,6 +135,7 @@
  • libFLAC++: diff --git a/include/FLAC/file_encoder.h b/include/FLAC/file_encoder.h index fbbfadb3..9b07f54c 100644 --- a/include/FLAC/file_encoder.h +++ b/include/FLAC/file_encoder.h @@ -314,6 +314,21 @@ FLAC_API FLAC__bool FLAC__file_encoder_set_sample_rate(FLAC__FileEncoder *encode */ FLAC_API FLAC__bool FLAC__file_encoder_set_blocksize(FLAC__FileEncoder *encoder, unsigned value); +/** This is inherited from FLAC__SeekableStreamEncoder; see + * FLAC__seekable_stream_encoder_set_apodization(). + * + * \default \c 0 + * \param encoder An encoder instance to set. + * \param specification See above. + * \assert + * \code encoder != NULL \endcode + * \code specification != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +/* @@@@add to unit tests*/ +FLAC_API FLAC__bool FLAC__file_encoder_set_apodization(FLAC__FileEncoder *encoder, const char *specification); + /** This is inherited from FLAC__SeekableStreamEncoder; see * FLAC__seekable_stream_encoder_set_max_lpc_order(). * diff --git a/include/FLAC/format.h b/include/FLAC/format.h index 934586d8..d1c8a875 100644 --- a/include/FLAC/format.h +++ b/include/FLAC/format.h @@ -315,6 +315,10 @@ typedef struct { const FLAC__int32 *residual; /**< The residual signal, length == (blocksize minus order) samples. */ + +#ifdef WINDOW_DEBUG_OUTPUT + char window_type[64]; //@@@@@@ +#endif } FLAC__Subframe_LPC; extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */ diff --git a/include/FLAC/seekable_stream_encoder.h b/include/FLAC/seekable_stream_encoder.h index 4efeb427..f59e924f 100644 --- a/include/FLAC/seekable_stream_encoder.h +++ b/include/FLAC/seekable_stream_encoder.h @@ -416,6 +416,21 @@ FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_sample_rate(FLAC__Seekable */ FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_blocksize(FLAC__SeekableStreamEncoder *encoder, unsigned value); +/** This is inherited from FLAC__StreamEncoder; see + * FLAC__stream_encoder_set_apodization(). + * + * \default \c 0 + * \param encoder An encoder instance to set. + * \param specification See above. + * \assert + * \code encoder != NULL \endcode + * \code specification != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +/* @@@@add to unit tests*/ +FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_apodization(FLAC__SeekableStreamEncoder *encoder, const char *specification); + /** This is inherited from FLAC__StreamEncoder; see * FLAC__stream_encoder_set_max_lpc_order(). * diff --git a/include/FLAC/stream_encoder.h b/include/FLAC/stream_encoder.h index 0ac18a36..4f82fda7 100644 --- a/include/FLAC/stream_encoder.h +++ b/include/FLAC/stream_encoder.h @@ -498,6 +498,52 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *en */ FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value); +/** Sets the apodization function(s) the encoder will use when windowing + * audio data for LPC analysis. + * + * The \a specification is a plain ASCII string which specifies exactly + * which functions to use. There may be more than one (up to 32), + * separated by \c ';' characters. Some functions take one or more + * comma-separated arguments in parentheses. + * + * The available functions are \c bartlett, \c bartlett_hann, + * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop, + * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall, + * \c rectangle, \c triangle, \c tukey(P), \c welch. + * + * For \c gauss(STDDEV), STDDEV specifies the standard deviation + * (0encoder.ogg.stream, bps); OggFLAC__stream_encoder_set_sample_rate(e->encoder.ogg.stream, sample_rate); OggFLAC__stream_encoder_set_blocksize(e->encoder.ogg.stream, options.blocksize); + OggFLAC__stream_encoder_set_apodization(e->encoder.ogg.stream, options.apodizations); OggFLAC__stream_encoder_set_max_lpc_order(e->encoder.ogg.stream, options.max_lpc_order); OggFLAC__stream_encoder_set_qlp_coeff_precision(e->encoder.ogg.stream, options.qlp_coeff_precision); OggFLAC__stream_encoder_set_do_qlp_coeff_prec_search(e->encoder.ogg.stream, options.do_qlp_coeff_prec_search); @@ -1463,6 +1464,7 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio OggFLAC__file_encoder_set_bits_per_sample(e->encoder.ogg.file, bps); OggFLAC__file_encoder_set_sample_rate(e->encoder.ogg.file, sample_rate); OggFLAC__file_encoder_set_blocksize(e->encoder.ogg.file, options.blocksize); + OggFLAC__file_encoder_set_apodization(e->encoder.ogg.file, options.apodizations); OggFLAC__file_encoder_set_max_lpc_order(e->encoder.ogg.file, options.max_lpc_order); OggFLAC__file_encoder_set_qlp_coeff_precision(e->encoder.ogg.file, options.qlp_coeff_precision); OggFLAC__file_encoder_set_do_qlp_coeff_prec_search(e->encoder.ogg.file, options.do_qlp_coeff_prec_search); @@ -1499,6 +1501,7 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio FLAC__stream_encoder_set_bits_per_sample(e->encoder.flac.stream, bps); FLAC__stream_encoder_set_sample_rate(e->encoder.flac.stream, sample_rate); FLAC__stream_encoder_set_blocksize(e->encoder.flac.stream, options.blocksize); + FLAC__stream_encoder_set_apodization(e->encoder.flac.stream, options.apodizations); FLAC__stream_encoder_set_max_lpc_order(e->encoder.flac.stream, options.max_lpc_order); FLAC__stream_encoder_set_qlp_coeff_precision(e->encoder.flac.stream, options.qlp_coeff_precision); FLAC__stream_encoder_set_do_qlp_coeff_prec_search(e->encoder.flac.stream, options.do_qlp_coeff_prec_search); @@ -1534,6 +1537,7 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio FLAC__file_encoder_set_bits_per_sample(e->encoder.flac.file, bps); FLAC__file_encoder_set_sample_rate(e->encoder.flac.file, sample_rate); FLAC__file_encoder_set_blocksize(e->encoder.flac.file, options.blocksize); + FLAC__file_encoder_set_apodization(e->encoder.flac.file, options.apodizations); FLAC__file_encoder_set_max_lpc_order(e->encoder.flac.file, options.max_lpc_order); FLAC__file_encoder_set_qlp_coeff_precision(e->encoder.flac.file, options.qlp_coeff_precision); FLAC__file_encoder_set_do_qlp_coeff_prec_search(e->encoder.flac.file, options.do_qlp_coeff_prec_search); @@ -2141,7 +2145,7 @@ FLAC__bool fskip_ahead(FILE *f, FLAC__uint64 offset) long need = (long)min(offset, LONG_MAX); if(fseek(f, need, SEEK_CUR) < 0) { need = (long)min(offset, sizeof(dump)); - if(fread(dump, 1, need, f) < need) + if((long)fread(dump, 1, need, f) < need) return false; } offset -= need; diff --git a/src/flac/encode.h b/src/flac/encode.h index 773a154f..4dad1c92 100644 --- a/src/flac/encode.h +++ b/src/flac/encode.h @@ -43,6 +43,7 @@ typedef struct { 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; diff --git a/src/flac/main.c b/src/flac/main.c index a1e4338d..e84d32a6 100644 --- a/src/flac/main.c +++ b/src/flac/main.c @@ -147,6 +147,7 @@ static struct share__option long_options_[] = { { "blocksize" , share__required_argument, 0, 'b' }, { "exhaustive-model-search" , share__no_argument, 0, 'e' }, { "max-lpc-order" , share__required_argument, 0, 'l' }, + { "apodization" , share__required_argument, 0, 'A' }, { "mid-side" , share__no_argument, 0, 'm' }, { "adaptive-mid-side" , share__no_argument, 0, 'M' }, { "qlp-coeff-precision-search", share__no_argument, 0, 'p' }, @@ -232,6 +233,7 @@ static struct { const char *output_prefix; analysis_options aopts; int padding; + char apodizations[1000]; /* bad MAGIC NUMBER but buffer overflow is checked */ unsigned max_lpc_order; unsigned qlp_coeff_precision; const char *skip_specification; @@ -247,7 +249,7 @@ static struct { int min_residual_partition_order; int max_residual_partition_order; int rice_parameter_search_dist; - char requested_seek_points[50000]; /* bad MAGIC NUMBER but buffer overflow is checked */ + 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; FLAC__bool cued_seekpoints; @@ -577,6 +579,7 @@ FLAC__bool init_options() option_values.aopts.do_residual_text = false; option_values.aopts.do_residual_gnuplot = false; option_values.padding = 4096; + option_values.apodizations[0] = '\0'; option_values.max_lpc_order = 8; option_values.qlp_coeff_precision = 0; option_values.skip_specification = 0; @@ -615,7 +618,7 @@ int parse_options(int argc, char *argv[]) int short_option; int option_index = 1; FLAC__bool had_error = false; - const char *short_opts = "0123456789ab:cdefFhHl:mMo:pP:q:r:sS:tT:vV"; + const char *short_opts = "0123456789aA:b:cdefFhHl:mMo:pP:q:r:sS:tT:vV"; while ((short_option = share__getopt_long(argc, argv, short_opts, long_options_, &option_index)) != -1) { switch (short_option) { @@ -1030,6 +1033,16 @@ int parse_option(int short_option, const char *long_option, const char *option_a FLAC__ASSERT(0 != option_argument); option_values.max_lpc_order = atoi(option_argument); 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, ";"); + } + break; case 'm': option_values.do_mid_side = true; option_values.loose_mid_side = false; @@ -1210,6 +1223,7 @@ void show_help() printf(" -m, --mid-side Try mid-side coding for each frame\n"); printf(" -M, --adaptive-mid-side Adaptive mid-side coding for all frames\n"); printf(" -e, --exhaustive-model-search Do exhaustive model search (expensive!)\n"); + printf(" -A, --apodization=\"function\" Window audio data with given the function\n"); printf(" -l, --max-lpc-order=# Max LPC order; 0 => only fixed predictors\n"); printf(" -p, --qlp-coeff-precision-search Exhaustively search LP coeff quantization\n"); printf(" -q, --qlp-coeff-precision=# Specify precision in bits\n"); @@ -1422,6 +1436,16 @@ void show_explain() printf(" -M, --adaptive-mid-side Adaptive mid-side coding for all frames\n"); printf(" (stereo only)\n"); printf(" -e, --exhaustive-model-search Do exhaustive model search (expensive!)\n"); + printf(" -A, --apodization=\"function\" Window audio data with given the function.\n"); + printf(" The functions are: bartlett, bartlett_hann,\n"); + printf(" blackman, blackman_harris_4term_92db,\n"); + printf(" connes, flattop, gauss(STDDEV), hamming,\n"); + printf(" hann, kaiser_bessel, nuttall, rectangle,\n"); + printf(" triangle, tukey(P), welch. More than one\n"); + printf(" may be specified but encoding time is a\n"); + printf(" multiple of the number of functions since\n"); + printf(" they are each tried in turn. The default\n"); + printf(" is \"hann\". \n"); printf(" -l, --max-lpc-order=# Max LPC order; 0 => only fixed predictors\n"); printf(" -p, --qlp-coeff-precision-search Do exhaustive search of LP coefficient\n"); printf(" quantization (expensive!); overrides -q;\n"); @@ -1606,6 +1630,7 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ 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; diff --git a/src/libFLAC/Makefile.lite b/src/libFLAC/Makefile.lite index 38da8f39..ac03c3c3 100644 --- a/src/libFLAC/Makefile.lite +++ b/src/libFLAC/Makefile.lite @@ -79,7 +79,8 @@ SRCS_C = \ seekable_stream_encoder.c \ stream_decoder.c \ stream_encoder.c \ - stream_encoder_framing.c + stream_encoder_framing.c \ + window.c include $(topdir)/build/lib.mk diff --git a/src/libFLAC/file_encoder.c b/src/libFLAC/file_encoder.c index db4c421f..8f196937 100644 --- a/src/libFLAC/file_encoder.c +++ b/src/libFLAC/file_encoder.c @@ -314,6 +314,17 @@ FLAC_API FLAC__bool FLAC__file_encoder_set_blocksize(FLAC__FileEncoder *encoder, return FLAC__seekable_stream_encoder_set_blocksize(encoder->private_->seekable_stream_encoder, value); } +FLAC_API FLAC__bool FLAC__file_encoder_set_apodization(FLAC__FileEncoder *encoder, const char *specification) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); + if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED) + return false; + return FLAC__seekable_stream_encoder_set_apodization(encoder->private_->seekable_stream_encoder, specification); +} + FLAC_API FLAC__bool FLAC__file_encoder_set_max_lpc_order(FLAC__FileEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); diff --git a/src/libFLAC/format.c b/src/libFLAC/format.c index 8052b0f4..503a8a8f 100644 --- a/src/libFLAC/format.c +++ b/src/libFLAC/format.c @@ -56,9 +56,10 @@ FLAC_API const char *FLAC__VERSION_STRING = VERSION; #if defined _MSC_VER || defined __MINW32__ /* yet one more hack because of MSVC6: */ -FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.1.2 20050205"; +/*@@@@@@WAS:FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.1.2 20050205";*/ +FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC CVS 20060425"; #else -FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20050205"; +FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20060425"; #endif FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' }; diff --git a/src/libFLAC/include/private/lpc.h b/src/libFLAC/include/private/lpc.h index 37286f51..26f060b7 100644 --- a/src/libFLAC/include/private/lpc.h +++ b/src/libFLAC/include/private/lpc.h @@ -41,6 +41,19 @@ #ifndef FLAC__INTEGER_ONLY_LIBRARY +/* + * FLAC__lpc_window_data() + * -------------------------------------------------------------------- + * Applies the given window to the data. + * @@@@@@ asm optimize + * + * IN in[0,data_len-1] + * IN window[0,data_len-1] + * OUT out[0,lag-1] + * IN data_len + */ +void FLAC__lpc_window_data(const FLAC__real in[], const FLAC__real window[], FLAC__real out[], unsigned data_len); + /* * FLAC__lpc_compute_autocorrelation() * -------------------------------------------------------------------- diff --git a/src/libFLAC/include/protected/stream_encoder.h b/src/libFLAC/include/protected/stream_encoder.h index 86495cc9..d2410be0 100644 --- a/src/libFLAC/include/protected/stream_encoder.h +++ b/src/libFLAC/include/protected/stream_encoder.h @@ -34,6 +34,44 @@ #include "FLAC/stream_encoder.h" +#ifndef FLAC__INTEGER_ONLY_LIBRARY + +#include "private/float.h" + +#define FLAC__MAX_APODIZATION_FUNCTIONS 32 + +typedef enum { + FLAC__APODIZATION_BARTLETT, + FLAC__APODIZATION_BARTLETT_HANN, + FLAC__APODIZATION_BLACKMAN, + FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE, + FLAC__APODIZATION_CONNES, + FLAC__APODIZATION_FLATTOP, + FLAC__APODIZATION_GAUSS, + FLAC__APODIZATION_HAMMING, + FLAC__APODIZATION_HANN, + FLAC__APODIZATION_KAISER_BESSEL, + FLAC__APODIZATION_NUTTALL, + FLAC__APODIZATION_RECTANGLE, + FLAC__APODIZATION_TRIANGLE, + FLAC__APODIZATION_TUKEY, + FLAC__APODIZATION_WELCH +} FLAC__ApodizationFunction; + +typedef struct { + FLAC__ApodizationFunction type; + union { + struct { + FLAC__real stddev; + } gauss; + struct { + FLAC__real p; + } tukey; + } parameters; +} FLAC__ApodizationSpecification; + +#endif // #ifndef FLAC__INTEGER_ONLY_LIBRARY + typedef struct FLAC__StreamEncoderProtected { FLAC__StreamEncoderState state; FLAC__bool verify; @@ -44,6 +82,10 @@ typedef struct FLAC__StreamEncoderProtected { unsigned bits_per_sample; unsigned sample_rate; unsigned blocksize; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + unsigned num_apodizations; + FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS]; +#endif unsigned max_lpc_order; unsigned qlp_coeff_precision; FLAC__bool do_qlp_coeff_prec_search; diff --git a/src/libFLAC/lpc.c b/src/libFLAC/lpc.c index b846db5c..78843831 100644 --- a/src/libFLAC/lpc.c +++ b/src/libFLAC/lpc.c @@ -45,6 +45,13 @@ #define M_LN2 0.69314718055994530942 #endif +void FLAC__lpc_window_data(const FLAC__real in[], const FLAC__real window[], FLAC__real out[], unsigned data_len) +{ + unsigned i; + for(i = 0; i < data_len; i++) + out[i] = in[i] * window[i]; +} + void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]) { /* a readable, but slower, version */ diff --git a/src/libFLAC/seekable_stream_encoder.c b/src/libFLAC/seekable_stream_encoder.c index 18291a80..9fe15c4f 100644 --- a/src/libFLAC/seekable_stream_encoder.c +++ b/src/libFLAC/seekable_stream_encoder.c @@ -318,6 +318,17 @@ FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_blocksize(FLAC__SeekableSt return FLAC__stream_encoder_set_blocksize(encoder->private_->stream_encoder, value); } +FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_apodization(FLAC__SeekableStreamEncoder *encoder, const char *specification) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_apodization(encoder->private_->stream_encoder, specification); +} + FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_max_lpc_order(FLAC__SeekableStreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); diff --git a/src/libFLAC/stream_encoder.c b/src/libFLAC/stream_encoder.c index 8ae4ba42..cee1e10e 100644 --- a/src/libFLAC/stream_encoder.c +++ b/src/libFLAC/stream_encoder.c @@ -29,6 +29,9 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/*@@@@@@*/ +#define WINDOW_DEBUG_OUTPUT + #include #include #include /* for malloc() */ @@ -46,6 +49,7 @@ #include "private/md5.h" #include "private/memory.h" #include "private/stream_encoder_framing.h" +#include "private/window.h" #ifdef HAVE_CONFIG_H #include @@ -108,6 +112,9 @@ static FLAC__bool process_subframe_( FLAC__int32 *residual[2], unsigned *best_subframe, unsigned *best_bits +#ifdef WINDOW_DEBUG_OUTPUT + ,unsigned subframe_number +#endif ); static FLAC__bool add_subframe_( @@ -116,6 +123,9 @@ static FLAC__bool add_subframe_( unsigned subframe_bps, const FLAC__Subframe *subframe, FLAC__BitBuffer *frame +#ifdef WINDOW_DEBUG_OUTPUT +,unsigned subframe_bits +#endif ); static unsigned evaluate_constant_subframe_( @@ -165,6 +175,11 @@ static unsigned evaluate_lpc_subframe_( unsigned rice_parameter_search_dist, FLAC__Subframe *subframe, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents +#ifdef WINDOW_DEBUG_OUTPUT + ,unsigned frame_number + ,unsigned subframe_number + ,FLAC__ApodizationSpecification aspec +#endif ); #endif @@ -308,6 +323,25 @@ static void verify_error_callback_( void *client_data ); +#ifdef WINDOW_DEBUG_OUTPUT +static const char * const winstr[] = { + "bartlett", + "bartlett_hann", + "blackman", + "blackman_harris_4term_92db_sidelobe", + "connes", + "flattop", + "gauss", + "hamming", + "hann", + "kaiser_bessel", + "nuttall", + "rectangular", + "triangle", + "tukey", + "welch" +}; +#endif /*********************************************************************** * @@ -322,6 +356,8 @@ typedef struct FLAC__StreamEncoderPrivate { #ifndef FLAC__INTEGER_ONLY_LIBRARY FLAC__real *real_signal[FLAC__MAX_CHANNELS]; /* the floating-point version of the input signal */ FLAC__real *real_signal_mid_side[2]; /* the floating-point version of the mid-side input signal (stereo only) */ + FLAC__real *window[FLAC__MAX_APODIZATION_FUNCTIONS]; /* the pre-computed floating-point window for each apodization function */ + FLAC__real *windowed_signal; /* the real_signal[] * current window[] */ #endif unsigned subframe_bps[FLAC__MAX_CHANNELS]; /* the effective bits per sample of the input signal (stream bps - wasted bits) */ unsigned subframe_bps_mid_side[2]; /* the effective bits per sample of the mid-side input signal (stream bps - wasted bits + 0/1) */ @@ -378,6 +414,8 @@ typedef struct FLAC__StreamEncoderPrivate { #ifndef FLAC__INTEGER_ONLY_LIBRARY FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS]; FLAC__real *real_signal_mid_side_unaligned[2]; + FLAC__real *window_unaligned[FLAC__MAX_APODIZATION_FUNCTIONS]; + FLAC__real *windowed_signal_unaligned; #endif FLAC__int32 *residual_workspace_unaligned[FLAC__MAX_CHANNELS][2]; FLAC__int32 *residual_workspace_mid_side_unaligned[2][2]; @@ -723,6 +761,11 @@ FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_init(FLAC__StreamEncoder encoder->private_->real_signal_mid_side_unaligned[i] = encoder->private_->real_signal_mid_side[i] = 0; #endif } +#ifndef FLAC__INTEGER_ONLY_LIBRARY + for(i = 0; i < encoder->protected_->num_apodizations; i++) + encoder->private_->window_unaligned[i] = encoder->private_->window[i] = 0; + encoder->private_->windowed_signal_unaligned = encoder->private_->windowed_signal = 0; +#endif for(i = 0; i < encoder->protected_->channels; i++) { encoder->private_->residual_workspace_unaligned[i][0] = encoder->private_->residual_workspace[i][0] = 0; encoder->private_->residual_workspace_unaligned[i][1] = encoder->private_->residual_workspace[i][1] = 0; @@ -1063,6 +1106,77 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *enco return true; } +FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != specification); + if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED) + return false; +#ifdef FLAC__INTEGER_ONLY_LIBRARY + (void)specification; /* silently ignore since we haven't integerized; will always use a rectangular window */ +#else + encoder->protected_->num_apodizations = 0; + while(1) { + const char *s = strchr(specification, ';'); + const size_t n = s? (size_t)(s - specification) : strlen(specification); + if (n==8 && 0 == strncmp("bartlett" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT; + else if(n==13 && 0 == strncmp("bartlett_hann", specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT_HANN; + else if(n==8 && 0 == strncmp("blackman" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN; + else if(n==26 && 0 == strncmp("blackman_harris_4term_92db", specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE; + else if(n==6 && 0 == strncmp("connes" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_CONNES; + else if(n==7 && 0 == strncmp("flattop" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_FLATTOP; + else if(n>7 && 0 == strncmp("gauss(" , specification, 6)) { + FLAC__real stddev = (FLAC__real)strtod(specification+6, 0); + if (stddev > 0.0 && stddev <= 0.5) { + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.gauss.stddev = stddev; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_GAUSS; + } + } + else if(n==7 && 0 == strncmp("hamming" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HAMMING; + else if(n==4 && 0 == strncmp("hann" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HANN; + else if(n==13 && 0 == strncmp("kaiser_bessel", specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_KAISER_BESSEL; + else if(n==7 && 0 == strncmp("nuttall" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_NUTTALL; + else if(n==9 && 0 == strncmp("rectangle" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_RECTANGLE; + else if(n==8 && 0 == strncmp("triangle" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TRIANGLE; + else if(n>7 && 0 == strncmp("tukey(" , specification, 6)) { + FLAC__real p = (FLAC__real)strtod(specification+6, 0); + if (p >= 0.0 && p <= 1.0) { + encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = p; + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY; + } + } + else if(n==5 && 0 == strncmp("welch" , specification, n)) + encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_WELCH; + if (encoder->protected_->num_apodizations == 32) + break; + if (s) + specification = s+1; + else + break; + } + if(encoder->protected_->num_apodizations == 0) { + encoder->protected_->num_apodizations = 1; + encoder->protected_->apodizations[0].type = FLAC__APODIZATION_HANN; + } +#ifdef WINDOW_DEBUG_OUTPUT +{unsigned n;for(n=0;nprotected_->num_apodizations;n++)fprintf(stderr,"@@@@@@ parsed apodization[%zu]: %s\n",n,winstr[encoder->protected_->apodizations[n].type]);} +#endif +#endif + return true; +} + FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); @@ -1648,6 +1762,10 @@ void set_defaults_(FLAC__StreamEncoder *encoder) encoder->protected_->bits_per_sample = 16; encoder->protected_->sample_rate = 44100; encoder->protected_->blocksize = 1152; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + encoder->protected_->num_apodizations = 1; + encoder->protected_->apodizations[0].type = FLAC__APODIZATION_HANN; +#endif encoder->protected_->max_lpc_order = 0; encoder->protected_->qlp_coeff_precision = 0; encoder->protected_->do_qlp_coeff_prec_search = false; @@ -1697,6 +1815,18 @@ void free_(FLAC__StreamEncoder *encoder) } #endif } +#ifndef FLAC__INTEGER_ONLY_LIBRARY + for(i = 0; i < encoder->protected_->num_apodizations; i++) { + if(0 != encoder->private_->window_unaligned[i]) { + free(encoder->private_->window_unaligned[i]); + encoder->private_->window_unaligned[i] = 0; + } + } + if(0 != encoder->private_->windowed_signal_unaligned) { + free(encoder->private_->windowed_signal_unaligned); + encoder->private_->windowed_signal_unaligned = 0; + } +#endif for(channel = 0; channel < encoder->protected_->channels; channel++) { for(i = 0; i < 2; i++) { if(0 != encoder->private_->residual_workspace_unaligned[channel][i]) { @@ -1775,6 +1905,13 @@ FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_size) memset(encoder->private_->integer_signal_mid_side[i], 0, sizeof(FLAC__int32)*4); encoder->private_->integer_signal_mid_side[i] += 4; } +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(ok && encoder->protected_->max_lpc_order > 0) { + for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) + ok = ok && FLAC__memory_alloc_aligned_real_array(new_size, &encoder->private_->window_unaligned[i], &encoder->private_->window[i]); + ok = ok && FLAC__memory_alloc_aligned_real_array(new_size, &encoder->private_->windowed_signal_unaligned, &encoder->private_->windowed_signal); + } +#endif for(channel = 0; ok && channel < encoder->protected_->channels; channel++) { for(i = 0; ok && i < 2; i++) { ok = ok && FLAC__memory_alloc_aligned_int32_array(new_size, &encoder->private_->residual_workspace_unaligned[channel][i], &encoder->private_->residual_workspace[channel][i]); @@ -1796,6 +1933,65 @@ FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_size) else encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR; +#ifndef FLAC__INTEGER_ONLY_LIBRARY + if(ok && encoder->protected_->max_lpc_order > 0) { + for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) { + switch(encoder->protected_->apodizations[i].type) { + case FLAC__APODIZATION_BARTLETT: + FLAC__window_bartlett(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_BARTLETT_HANN: + FLAC__window_bartlett_hann(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_BLACKMAN: + FLAC__window_blackman(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE: + FLAC__window_blackman_harris_4term_92db_sidelobe(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_CONNES: + FLAC__window_connes(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_FLATTOP: + FLAC__window_flattop(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_GAUSS: + FLAC__window_gauss(encoder->private_->window[i], new_size, encoder->protected_->apodizations[i].parameters.gauss.stddev); + break; + case FLAC__APODIZATION_HAMMING: + FLAC__window_hamming(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_HANN: + FLAC__window_hann(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_KAISER_BESSEL: + FLAC__window_kaiser_bessel(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_NUTTALL: + FLAC__window_nuttall(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_RECTANGLE: + FLAC__window_rectangle(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_TRIANGLE: + FLAC__window_triangle(encoder->private_->window[i], new_size); + break; + case FLAC__APODIZATION_TUKEY: + FLAC__window_tukey(encoder->private_->window[i], new_size, encoder->protected_->apodizations[i].parameters.tukey.p); + break; + case FLAC__APODIZATION_WELCH: + FLAC__window_welch(encoder->private_->window[i], new_size); + break; + default: + FLAC__ASSERT(0); + /* double protection */ + FLAC__window_rectangle(encoder->private_->window[i], new_size); + break; + } + } + } +#endif + return ok; } @@ -1994,6 +2190,9 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f encoder->private_->residual_workspace[channel], encoder->private_->best_subframe+channel, encoder->private_->best_subframe_bits+channel +#ifdef WINDOW_DEBUG_OUTPUT + ,channel +#endif ) ) return false; @@ -2024,6 +2223,9 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f encoder->private_->residual_workspace_mid_side[channel], encoder->private_->best_subframe_mid_side+channel, encoder->private_->best_subframe_bits_mid_side+channel +#ifdef WINDOW_DEBUG_OUTPUT + ,channel +#endif ) ) return false; @@ -2037,6 +2239,9 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f unsigned left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */ FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */ FLAC__ChannelAssignment channel_assignment; +#ifdef WINDOW_DEBUG_OUTPUT + unsigned left_bits = 0, right_bits = 0; +#endif FLAC__ASSERT(encoder->protected_->channels == 2); @@ -2075,18 +2280,34 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]]; right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]]; +#ifdef WINDOW_DEBUG_OUTPUT + left_bits = encoder->private_->best_subframe_bits [0]; + right_bits = encoder->private_->best_subframe_bits [1]; +#endif break; case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]]; right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; +#ifdef WINDOW_DEBUG_OUTPUT + left_bits = encoder->private_->best_subframe_bits [0]; + right_bits = encoder->private_->best_subframe_bits_mid_side [1]; +#endif break; case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: left_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]]; +#ifdef WINDOW_DEBUG_OUTPUT + left_bits = encoder->private_->best_subframe_bits_mid_side [1]; + right_bits = encoder->private_->best_subframe_bits [1]; +#endif break; case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: left_subframe = &encoder->private_->subframe_workspace_mid_side[0][encoder->private_->best_subframe_mid_side[0]]; right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]]; +#ifdef WINDOW_DEBUG_OUTPUT + left_bits = encoder->private_->best_subframe_bits_mid_side [0]; + right_bits = encoder->private_->best_subframe_bits_mid_side [1]; +#endif break; default: FLAC__ASSERT(0); @@ -2114,10 +2335,17 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f } /* note that encoder_add_subframe_ sets the state for us in case of an error */ +#ifdef WINDOW_DEBUG_OUTPUT + if(!add_subframe_(encoder, &frame_header, left_bps , left_subframe , encoder->private_->frame, left_bits)) + return false; + if(!add_subframe_(encoder, &frame_header, right_bps, right_subframe, encoder->private_->frame, right_bits)) + return false; +#else if(!add_subframe_(encoder, &frame_header, left_bps , left_subframe , encoder->private_->frame)) return false; if(!add_subframe_(encoder, &frame_header, right_bps, right_subframe, encoder->private_->frame)) return false; +#endif } else { if(!FLAC__frame_add_header(&frame_header, encoder->protected_->streamable_subset, encoder->private_->frame)) { @@ -2126,7 +2354,7 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_last_f } for(channel = 0; channel < encoder->protected_->channels; channel++) { - if(!add_subframe_(encoder, &frame_header, encoder->private_->subframe_bps[channel], &encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]], encoder->private_->frame)) { + if(!add_subframe_(encoder, &frame_header, encoder->private_->subframe_bps[channel], &encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]], encoder->private_->frame, encoder->private_->best_subframe_bits[channel])) { /* the above function sets the state for us in case of an error */ return false; } @@ -2160,6 +2388,9 @@ FLAC__bool process_subframe_( FLAC__int32 *residual[2], unsigned *best_subframe, unsigned *best_bits +#ifdef WINDOW_DEBUG_OUTPUT + ,unsigned subframe_number +#endif ) { #ifndef FLAC__INTEGER_ONLY_LIBRARY @@ -2277,67 +2508,76 @@ FLAC__bool process_subframe_( else max_lpc_order = encoder->protected_->max_lpc_order; if(max_lpc_order > 0) { - encoder->private_->local_lpc_compute_autocorrelation(real_signal, frame_header->blocksize, max_lpc_order+1, autoc); - /* if autoc[0] == 0.0, the signal is constant and we usually won't get here, but it can happen */ - if(autoc[0] != 0.0) { - FLAC__lpc_compute_lp_coefficients(autoc, max_lpc_order, encoder->private_->lp_coeff, lpc_error); - if(encoder->protected_->do_exhaustive_model_search) { - min_lpc_order = 1; - } - else { - unsigned guess_lpc_order = FLAC__lpc_compute_best_order(lpc_error, max_lpc_order, frame_header->blocksize, subframe_bps); - min_lpc_order = max_lpc_order = guess_lpc_order; - } - for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order; lpc_order++) { - lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize-lpc_order); - if(lpc_residual_bits_per_sample >= (FLAC__double)subframe_bps) - continue; /* don't even try */ - rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (unsigned)(lpc_residual_bits_per_sample+0.5) : 0; /* 0.5 is for rounding */ - rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */ - if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { -#ifdef DEBUG_VERBOSE - fprintf(stderr, "clipping rice_parameter (%u -> %u) @1\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); -#endif - rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1; - } - if(encoder->protected_->do_qlp_coeff_prec_search) { - min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION; - /* ensure a 32-bit datapath throughout for 16bps or less */ - if(subframe_bps <= 16) - max_qlp_coeff_precision = min(32 - subframe_bps - lpc_order, FLAC__MAX_QLP_COEFF_PRECISION); - else - max_qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION; + unsigned a; + for (a = 0; a < encoder->protected_->num_apodizations; a++) { + FLAC__lpc_apply_apodization(real_signal, encoder->private_->window[a], encoder->private_->windowed_signal, frame_header->blocksize); + encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_signal, frame_header->blocksize, max_lpc_order+1, autoc); + /* if autoc[0] == 0.0, the signal is constant and we usually won't get here, but it can happen */ + if(autoc[0] != 0.0) { + FLAC__lpc_compute_lp_coefficients(autoc, max_lpc_order, encoder->private_->lp_coeff, lpc_error); + if(encoder->protected_->do_exhaustive_model_search) { + min_lpc_order = 1; } else { - min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->protected_->qlp_coeff_precision; + unsigned guess_lpc_order = FLAC__lpc_compute_best_order(lpc_error, max_lpc_order, frame_header->blocksize, subframe_bps); + min_lpc_order = max_lpc_order = guess_lpc_order; } - for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) { - _candidate_bits = - evaluate_lpc_subframe_( - encoder, - integer_signal, - residual[!_best_subframe], - encoder->private_->abs_residual, - encoder->private_->abs_residual_partition_sums, - encoder->private_->raw_bits_per_partition, - encoder->private_->lp_coeff[lpc_order-1], - frame_header->blocksize, - subframe_bps, - lpc_order, - qlp_coeff_precision, - rice_parameter, - min_partition_order, - max_partition_order, - precompute_partition_sums, - encoder->protected_->do_escape_coding, - encoder->protected_->rice_parameter_search_dist, - subframe[!_best_subframe], - partitioned_rice_contents[!_best_subframe] - ); - if(_candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */ - if(_candidate_bits < _best_bits) { - _best_subframe = !_best_subframe; - _best_bits = _candidate_bits; + for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order; lpc_order++) { + lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize-lpc_order); + if(lpc_residual_bits_per_sample >= (FLAC__double)subframe_bps) + continue; /* don't even try */ + rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (unsigned)(lpc_residual_bits_per_sample+0.5) : 0; /* 0.5 is for rounding */ + rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */ + if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) { + #ifdef DEBUG_VERBOSE + fprintf(stderr, "clipping rice_parameter (%u -> %u) @1\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1); + #endif + rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1; + } + if(encoder->protected_->do_qlp_coeff_prec_search) { + min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION; + /* ensure a 32-bit datapath throughout for 16bps or less */ + if(subframe_bps <= 16) + max_qlp_coeff_precision = min(32 - subframe_bps - lpc_order, FLAC__MAX_QLP_COEFF_PRECISION); + else + max_qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION; + } + else { + min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->protected_->qlp_coeff_precision; + } + for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) { + _candidate_bits = + evaluate_lpc_subframe_( + encoder, + integer_signal, + residual[!_best_subframe], + encoder->private_->abs_residual, + encoder->private_->abs_residual_partition_sums, + encoder->private_->raw_bits_per_partition, + encoder->private_->lp_coeff[lpc_order-1], + frame_header->blocksize, + subframe_bps, + lpc_order, + qlp_coeff_precision, + rice_parameter, + min_partition_order, + max_partition_order, + precompute_partition_sums, + encoder->protected_->do_escape_coding, + encoder->protected_->rice_parameter_search_dist, + subframe[!_best_subframe], + partitioned_rice_contents[!_best_subframe] +#ifdef WINDOW_DEBUG_OUTPUT + ,frame_header->number.frame_number + ,subframe_number + ,encoder->protected_->apodizations[a] +#endif + ); + if(_candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */ + if(_candidate_bits < _best_bits) { + _best_subframe = !_best_subframe; + _best_bits = _candidate_bits; + } } } } @@ -2367,6 +2607,9 @@ FLAC__bool add_subframe_( unsigned subframe_bps, const FLAC__Subframe *subframe, FLAC__BitBuffer *frame +#ifdef WINDOW_DEBUG_OUTPUT +,unsigned subframe_bits +#endif ) { switch(subframe->type) { @@ -2383,6 +2626,9 @@ FLAC__bool add_subframe_( } break; case FLAC__SUBFRAME_TYPE_LPC: +#ifdef WINDOW_DEBUG_OUTPUT + fprintf(stderr, "WIN:\tframe=%u\tsubframe=?\torder=%u\twindow=%s\tbits=%u\n", frame_header->number.frame_number, subframe->data.lpc.order, subframe->data.lpc.window_type, subframe_bits); +#endif if(!FLAC__subframe_add_lpc(&(subframe->data.lpc), frame_header->blocksize - subframe->data.lpc.order, subframe_bps, subframe->wasted_bits, frame)) { encoder->protected_->state = FLAC__STREAM_ENCODER_FATAL_ERROR_WHILE_ENCODING; return false; @@ -2490,6 +2736,11 @@ unsigned evaluate_lpc_subframe_( unsigned rice_parameter_search_dist, FLAC__Subframe *subframe, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents +#ifdef WINDOW_DEBUG_OUTPUT + ,unsigned frame_number + ,unsigned subframe_number + ,FLAC__ApodizationSpecification aspec +#endif ) { FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; @@ -2504,6 +2755,15 @@ unsigned evaluate_lpc_subframe_( qlp_coeff_precision = min(qlp_coeff_precision, 32 - subframe_bps - FLAC__bitmath_ilog2(order)); } +#ifdef WINDOW_DEBUG_OUTPUT + if (aspec.type == FLAC__APODIZATION_GAUSS) + snprintf(subframe->data.lpc.window_type, sizeof subframe->data.lpc.window_type, "%s(%0.5f)", winstr[aspec.type], aspec.parameters.gauss.stddev); + else if (aspec.type == FLAC__APODIZATION_TUKEY) + snprintf(subframe->data.lpc.window_type, sizeof subframe->data.lpc.window_type, "%s(%0.5f)", winstr[aspec.type], aspec.parameters.tukey.p); + else + strncpy(subframe->data.lpc.window_type, winstr[aspec.type], sizeof subframe->data.lpc.window_type); +#endif + ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, qlp_coeff, &quantization); if(ret != 0) return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */ @@ -2547,6 +2807,9 @@ unsigned evaluate_lpc_subframe_( for(i = 0; i < order; i++) subframe->data.lpc.warmup[i] = signal[i]; +#ifdef WINDOW_DEBUG_OUTPUT + fprintf(stderr, "SWIN:\tframe=%u\tsubframe=%u\torder=%u\twindow=%s\tbits=%u\n", frame_number, subframe_number, order, subframe->data.lpc.window_type, FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)) + residual_bits); +#endif return FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)) + residual_bits; } #endif diff --git a/src/libOggFLAC/file_encoder.c b/src/libOggFLAC/file_encoder.c index 4567685b..f32003b1 100644 --- a/src/libOggFLAC/file_encoder.c +++ b/src/libOggFLAC/file_encoder.c @@ -328,6 +328,17 @@ OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_blocksize(OggFLAC__FileEncoder return OggFLAC__seekable_stream_encoder_set_blocksize(encoder->private_->seekable_stream_encoder, value); } +OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_apodization(OggFLAC__FileEncoder *encoder, const char *specification) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder); + if(encoder->protected_->state != OggFLAC__FILE_ENCODER_UNINITIALIZED) + return false; + return OggFLAC__seekable_stream_encoder_set_apodization(encoder->private_->seekable_stream_encoder, specification); +} + OggFLAC_API FLAC__bool OggFLAC__file_encoder_set_max_lpc_order(OggFLAC__FileEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); diff --git a/src/libOggFLAC/seekable_stream_encoder.c b/src/libOggFLAC/seekable_stream_encoder.c index 0aa6e72f..341b0681 100644 --- a/src/libOggFLAC/seekable_stream_encoder.c +++ b/src/libOggFLAC/seekable_stream_encoder.c @@ -335,6 +335,17 @@ OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_blocksize(OggFLAC__S return FLAC__stream_encoder_set_blocksize(encoder->private_->FLAC_stream_encoder, value); } +OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_apodization(OggFLAC__SeekableStreamEncoder *encoder, const char *specification) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_apodization(encoder->private_->FLAC_stream_encoder, specification); +} + OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_max_lpc_order(OggFLAC__SeekableStreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder); diff --git a/src/libOggFLAC/stream_encoder.c b/src/libOggFLAC/stream_encoder.c index 2552101a..33b1e930 100644 --- a/src/libOggFLAC/stream_encoder.c +++ b/src/libOggFLAC/stream_encoder.c @@ -290,6 +290,17 @@ OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_blocksize(OggFLAC__StreamEnco return FLAC__stream_encoder_set_blocksize(encoder->private_->FLAC_stream_encoder, value); } +OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_apodization(OggFLAC__StreamEncoder *encoder, const char *specification) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder); + if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_apodization(encoder->private_->FLAC_stream_encoder, specification); +} + OggFLAC_API FLAC__bool OggFLAC__stream_encoder_set_max_lpc_order(OggFLAC__StreamEncoder *encoder, unsigned value) { FLAC__ASSERT(0 != encoder);