2001-02-08 00:38:41 +00:00
/* libFLAC - Free Lossless Audio Codec library
2001-01-16 20:17:53 +00:00
* Copyright ( C ) 2000 , 2001 Josh Coalson
2000-12-10 04:09:52 +00:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation ; either
* version 2 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the
* Free Software Foundation , Inc . , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*/
# include <math.h>
# include <stdio.h>
2001-05-31 20:11:02 +00:00
# include "FLAC/assert.h"
2000-12-10 04:09:52 +00:00
# include "FLAC/format.h"
# include "private/lpc.h"
# ifndef M_LN2
/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
# define M_LN2 0.69314718055994530942
# endif
2001-05-16 19:23:35 +00:00
# define LOCAL_FABS(x) ((x)<0.0? -(x):(x))
2001-05-14 21:25:34 +00:00
2001-06-23 03:03:24 +00:00
void FLAC__lpc_compute_autocorrelation ( const FLAC__real data [ ] , unsigned data_len , unsigned lag , FLAC__real autoc [ ] )
2000-12-10 04:09:52 +00:00
{
2001-05-10 19:29:41 +00:00
/* a readable, but slower, version */
#if 0
2001-06-23 03:03:24 +00:00
FLAC__real d ;
2000-12-10 04:09:52 +00:00
unsigned i ;
2001-05-31 20:11:02 +00:00
FLAC__ASSERT ( lag > 0 ) ;
FLAC__ASSERT ( lag < = data_len ) ;
2000-12-10 04:09:52 +00:00
while ( lag - - ) {
for ( i = lag , d = 0.0 ; i < data_len ; i + + )
d + = data [ i ] * data [ i - lag ] ;
autoc [ lag ] = d ;
}
2001-05-10 19:29:41 +00:00
# endif
/*
* this version tends to run faster because of better data locality
* ( ' data_len ' is usually much larger than ' lag ' )
*/
2001-06-23 03:03:24 +00:00
FLAC__real d ;
2001-05-10 19:29:41 +00:00
unsigned sample , coeff ;
const unsigned limit = data_len - lag ;
2001-05-31 20:11:02 +00:00
FLAC__ASSERT ( lag > 0 ) ;
FLAC__ASSERT ( lag < = data_len ) ;
2001-05-10 19:29:41 +00:00
for ( coeff = 0 ; coeff < lag ; coeff + + )
autoc [ coeff ] = 0.0 ;
2001-05-16 19:23:35 +00:00
for ( sample = 0 ; sample < = limit ; sample + + ) {
2001-05-10 19:29:41 +00:00
d = data [ sample ] ;
for ( coeff = 0 ; coeff < lag ; coeff + + )
autoc [ coeff ] + = d * data [ sample + coeff ] ;
}
2001-05-16 19:23:35 +00:00
for ( ; sample < data_len ; sample + + ) {
2001-05-10 19:29:41 +00:00
d = data [ sample ] ;
for ( coeff = 0 ; coeff < data_len - sample ; coeff + + )
autoc [ coeff ] + = d * data [ sample + coeff ] ;
}
2000-12-10 04:09:52 +00:00
}
2001-06-23 03:03:24 +00:00
void FLAC__lpc_compute_lp_coefficients ( const FLAC__real autoc [ ] , unsigned max_order , FLAC__real lp_coeff [ ] [ FLAC__MAX_LPC_ORDER ] , FLAC__real error [ ] )
2000-12-10 04:09:52 +00:00
{
unsigned i , j ;
2001-07-03 04:37:18 +00:00
double r , err , ref [ FLAC__MAX_LPC_ORDER ] , lpc [ FLAC__MAX_LPC_ORDER ] ;
2000-12-10 04:09:52 +00:00
2001-05-31 20:11:02 +00:00
FLAC__ASSERT ( 0 < max_order ) ;
FLAC__ASSERT ( max_order < = FLAC__MAX_LPC_ORDER ) ;
FLAC__ASSERT ( autoc [ 0 ] ! = 0.0 ) ;
2000-12-10 04:09:52 +00:00
err = autoc [ 0 ] ;
for ( i = 0 ; i < max_order ; i + + ) {
/* Sum up this iteration's reflection coefficient. */
2001-05-24 19:27:08 +00:00
r = - autoc [ i + 1 ] ;
2000-12-10 04:09:52 +00:00
for ( j = 0 ; j < i ; j + + )
r - = lpc [ j ] * autoc [ i - j ] ;
ref [ i ] = ( r / = err ) ;
/* Update LPC coefficients and total error. */
lpc [ i ] = r ;
for ( j = 0 ; j < ( i > > 1 ) ; j + + ) {
2001-07-03 04:37:18 +00:00
double tmp = lpc [ j ] ;
2000-12-10 04:09:52 +00:00
lpc [ j ] + = r * lpc [ i - 1 - j ] ;
lpc [ i - 1 - j ] + = r * tmp ;
}
if ( i & 1 )
lpc [ j ] + = lpc [ j ] * r ;
err * = ( 1.0 - r * r ) ;
/* save this order */
for ( j = 0 ; j < = i ; j + + )
2001-07-03 04:37:18 +00:00
lp_coeff [ i ] [ j ] = ( FLAC__real ) ( - lpc [ j ] ) ; /* negate FIR filter coeff to get predictor coeff */
error [ i ] = ( FLAC__real ) err ;
2000-12-10 04:09:52 +00:00
}
}
2001-06-23 03:03:24 +00:00
int FLAC__lpc_quantize_coefficients ( const FLAC__real lp_coeff [ ] , unsigned order , unsigned precision , unsigned bits_per_sample , FLAC__int32 qlp_coeff [ ] , int * shift )
2000-12-10 04:09:52 +00:00
{
unsigned i ;
2001-07-03 04:37:18 +00:00
double d , cmax = - 1e32 ;
2001-07-03 04:10:21 +00:00
FLAC__int32 qmax , qmin ;
const int max_shiftlimit = ( 1 < < ( FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN - 1 ) ) - 1 ;
const int min_shiftlimit = - max_shiftlimit - 1 ;
2001-02-28 23:56:03 +00:00
2001-05-31 20:11:02 +00:00
FLAC__ASSERT ( bits_per_sample > 0 ) ;
2001-06-23 03:03:24 +00:00
FLAC__ASSERT ( bits_per_sample < = sizeof ( FLAC__int32 ) * 8 ) ;
2001-05-31 20:11:02 +00:00
FLAC__ASSERT ( precision > 0 ) ;
FLAC__ASSERT ( precision > = FLAC__MIN_QLP_COEFF_PRECISION ) ;
2001-06-23 03:03:24 +00:00
FLAC__ASSERT ( precision + bits_per_sample < sizeof ( FLAC__int32 ) * 8 ) ;
2001-02-28 23:56:03 +00:00
# ifdef NDEBUG
( void ) bits_per_sample ; /* silence compiler warning about unused parameter */
# endif
/* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
precision - - ;
2001-07-03 04:10:21 +00:00
qmax = 1 < < precision ;
qmin = - qmax ;
qmax - - ;
2001-02-28 23:56:03 +00:00
for ( i = 0 ; i < order ; i + + ) {
if ( lp_coeff [ i ] = = 0.0 )
continue ;
2001-05-14 21:25:34 +00:00
d = LOCAL_FABS ( lp_coeff [ i ] ) ;
2001-02-28 23:56:03 +00:00
if ( d > cmax )
cmax = d ;
}
2001-07-03 04:10:21 +00:00
redo_it :
2001-03-01 19:14:05 +00:00
if ( cmax < 0.0 ) {
/* => coefficients are all 0, which means our constant-detect didn't work */
2001-02-28 23:56:03 +00:00
return 2 ;
}
else {
2001-07-03 04:10:21 +00:00
const int log2cmax = ( int ) floor ( log ( cmax ) / M_LN2 ) ; /* this is a good estimate but may not be precise enough, so we have to check for corner cases later when shifting */
const int maxshift = ( int ) precision - log2cmax - 1 ;
2001-02-28 23:56:03 +00:00
* shift = maxshift ;
if ( * shift < min_shiftlimit | | * shift > max_shiftlimit ) {
return 1 ;
}
}
2001-07-06 00:37:57 +00:00
if ( * shift > = 0 ) {
for ( i = 0 ; i < order ; i + + ) {
qlp_coeff [ i ] = ( FLAC__int32 ) floor ( ( double ) lp_coeff [ i ] * ( double ) ( 1 < < * shift ) ) ;
2001-07-03 04:10:21 +00:00
2001-07-06 00:37:57 +00:00
/* check for corner cases mentioned in the comment for log2cmax above */
if ( qlp_coeff [ i ] > qmax | | qlp_coeff [ i ] < qmin ) {
2001-07-03 04:10:21 +00:00
# ifdef FLAC__OVERFLOW_DETECT
2001-07-06 00:37:57 +00:00
fprintf ( stderr , " FLAC__lpc_quantize_coefficients: compensating for overflow, qlp_coeff[%u]=%d, lp_coeff[%u]=%f, cmax=%f, precision=%u, shift=%d, q=%f, f(q)=%f \n " , i , qlp_coeff [ i ] , i , lp_coeff [ i ] , cmax , precision , * shift , ( double ) lp_coeff [ i ] * ( double ) ( 1 < < * shift ) , floor ( ( double ) lp_coeff [ i ] * ( double ) ( 1 < < * shift ) ) ) ;
2001-07-03 04:10:21 +00:00
# endif
2001-07-06 00:37:57 +00:00
cmax * = 2.0 ;
goto redo_it ;
2001-07-03 04:10:21 +00:00
}
}
2001-07-06 00:37:57 +00:00
}
else { /* (*shift < 0) */
const int nshift = - ( * shift ) ;
2001-07-12 21:27:40 +00:00
# ifdef DEBUG
2001-07-06 00:37:57 +00:00
fprintf ( stderr , " FLAC__lpc_quantize_coefficients: negative shift = %d \n " , * shift ) ;
2001-07-12 21:27:40 +00:00
# endif
2001-07-06 00:37:57 +00:00
for ( i = 0 ; i < order ; i + + ) {
qlp_coeff [ i ] = ( FLAC__int32 ) floor ( ( double ) lp_coeff [ i ] / ( double ) ( 1 < < nshift ) ) ;
/* check for corner cases mentioned in the comment for log2cmax above */
if ( qlp_coeff [ i ] > qmax | | qlp_coeff [ i ] < qmin ) {
2001-07-03 04:10:21 +00:00
# ifdef FLAC__OVERFLOW_DETECT
2001-07-06 00:37:57 +00:00
fprintf ( stderr , " FLAC__lpc_quantize_coefficients: compensating for overflow, qlp_coeff[%u]=%d, lp_coeff[%u]=%f, cmax=%f, precision=%u, shift=%d, q=%f, f(q)=%f \n " , i , qlp_coeff [ i ] , i , lp_coeff [ i ] , cmax , precision , * shift , ( double ) lp_coeff [ i ] / ( double ) ( 1 < < nshift ) , floor ( ( double ) lp_coeff [ i ] / ( double ) ( 1 < < nshift ) ) ) ;
2001-07-03 04:10:21 +00:00
# endif
2001-07-06 00:37:57 +00:00
cmax * = 2.0 ;
goto redo_it ;
2001-07-03 04:10:21 +00:00
}
}
2000-12-10 04:09:52 +00:00
}
2001-07-06 00:37:57 +00:00
2000-12-10 04:09:52 +00:00
return 0 ;
}
2001-06-23 03:03:24 +00:00
void FLAC__lpc_compute_residual_from_qlp_coefficients ( const FLAC__int32 data [ ] , unsigned data_len , const FLAC__int32 qlp_coeff [ ] , unsigned order , int lp_quantization , FLAC__int32 residual [ ] )
2000-12-10 04:09:52 +00:00
{
2001-04-24 22:54:07 +00:00
# ifdef FLAC__OVERFLOW_DETECT
2001-06-23 03:03:24 +00:00
FLAC__int64 sumo ;
2000-12-10 04:09:52 +00:00
# endif
unsigned i , j ;
2001-06-23 03:03:24 +00:00
FLAC__int32 sum ;
const FLAC__int32 * history ;
2000-12-10 04:09:52 +00:00
2001-04-24 22:54:07 +00:00
# ifdef FLAC__OVERFLOW_DETECT_VERBOSE
2000-12-10 04:09:52 +00:00
fprintf ( stderr , " FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d " , data_len , order , lp_quantization ) ;
for ( i = 0 ; i < order ; i + + )
fprintf ( stderr , " , q[%u]=%d " , i , qlp_coeff [ i ] ) ;
fprintf ( stderr , " \n " ) ;
# endif
2001-05-31 20:11:02 +00:00
FLAC__ASSERT ( order > 0 ) ;
2000-12-10 04:09:52 +00:00
for ( i = 0 ; i < data_len ; i + + ) {
2001-04-24 22:54:07 +00:00
# ifdef FLAC__OVERFLOW_DETECT
2000-12-10 04:09:52 +00:00
sumo = 0 ;
# endif
sum = 0 ;
history = data ;
for ( j = 0 ; j < order ; j + + ) {
sum + = qlp_coeff [ j ] * ( * ( - - history ) ) ;
2001-04-24 22:54:07 +00:00
# ifdef FLAC__OVERFLOW_DETECT
2001-06-23 03:03:24 +00:00
sumo + = ( FLAC__int64 ) qlp_coeff [ j ] * ( FLAC__int64 ) ( * history ) ;
2001-07-09 18:22:46 +00:00
# ifdef _MSC_VER /* don't know how to do 64-bit literals in VC++ */
if ( sumo < 0 ) sumo = - sumo ;
if ( sumo > 2147483647 )
# else
if ( sumo > 2147483647ll | | sumo < - 2147483648ll )
# endif
{
2001-07-03 04:37:18 +00:00
fprintf ( stderr , " FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld \n " , i , j , qlp_coeff [ j ] , * history , sumo ) ;
2001-02-08 00:26:45 +00:00
}
2000-12-10 04:09:52 +00:00
# endif
}
* ( residual + + ) = * ( data + + ) - ( sum > > lp_quantization ) ;
}
2001-02-08 00:26:45 +00:00
/* Here's a slower but clearer version:
2000-12-10 04:09:52 +00:00
for ( i = 0 ; i < data_len ; i + + ) {
sum = 0 ;
for ( j = 0 ; j < order ; j + + )
2001-02-08 00:26:45 +00:00
sum + = qlp_coeff [ j ] * data [ i - j - 1 ] ;
2000-12-10 04:09:52 +00:00
residual [ i ] = data [ i ] - ( sum > > lp_quantization ) ;
}
*/
}
2001-06-23 03:03:24 +00:00
void FLAC__lpc_restore_signal ( const FLAC__int32 residual [ ] , unsigned data_len , const FLAC__int32 qlp_coeff [ ] , unsigned order , int lp_quantization , FLAC__int32 data [ ] )
2000-12-10 04:09:52 +00:00
{
2001-04-24 22:54:07 +00:00
# ifdef FLAC__OVERFLOW_DETECT
2001-06-23 03:03:24 +00:00
FLAC__int64 sumo ;
2000-12-10 04:09:52 +00:00
# endif
unsigned i , j ;
2001-06-23 03:03:24 +00:00
FLAC__int32 sum ;
const FLAC__int32 * history ;
2000-12-10 04:09:52 +00:00
2001-04-24 22:54:07 +00:00
# ifdef FLAC__OVERFLOW_DETECT_VERBOSE
2000-12-10 04:09:52 +00:00
fprintf ( stderr , " FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d " , data_len , order , lp_quantization ) ;
for ( i = 0 ; i < order ; i + + )
fprintf ( stderr , " , q[%u]=%d " , i , qlp_coeff [ i ] ) ;
fprintf ( stderr , " \n " ) ;
# endif
2001-05-31 20:11:02 +00:00
FLAC__ASSERT ( order > 0 ) ;
2000-12-10 04:09:52 +00:00
for ( i = 0 ; i < data_len ; i + + ) {
2001-04-24 22:54:07 +00:00
# ifdef FLAC__OVERFLOW_DETECT
2000-12-10 04:09:52 +00:00
sumo = 0 ;
# endif
sum = 0 ;
2001-02-08 00:26:45 +00:00
history = data ;
2000-12-10 04:09:52 +00:00
for ( j = 0 ; j < order ; j + + ) {
sum + = qlp_coeff [ j ] * ( * ( - - history ) ) ;
2001-04-24 22:54:07 +00:00
# ifdef FLAC__OVERFLOW_DETECT
2001-06-23 03:03:24 +00:00
sumo + = ( FLAC__int64 ) qlp_coeff [ j ] * ( FLAC__int64 ) ( * history ) ;
2001-07-09 18:22:46 +00:00
# ifdef _MSC_VER /* don't know how to do 64-bit literals in VC++ */
if ( sumo < 0 ) sumo = - sumo ;
if ( sumo > 2147483647 )
# else
if ( sumo > 2147483647ll | | sumo < - 2147483648ll )
# endif
{
2001-07-03 04:37:18 +00:00
fprintf ( stderr , " FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld \n " , i , j , qlp_coeff [ j ] , * history , sumo ) ;
2001-02-08 00:26:45 +00:00
}
2000-12-10 04:09:52 +00:00
# endif
}
2001-02-08 00:26:45 +00:00
* ( data + + ) = * ( residual + + ) + ( sum > > lp_quantization ) ;
}
/* Here's a slower but clearer version:
for ( i = 0 ; i < data_len ; i + + ) {
sum = 0 ;
for ( j = 0 ; j < order ; j + + )
sum + = qlp_coeff [ j ] * data [ i - j - 1 ] ;
2000-12-10 04:09:52 +00:00
data [ i ] = residual [ i ] + ( sum > > lp_quantization ) ;
}
2001-02-08 00:26:45 +00:00
*/
2000-12-10 04:09:52 +00:00
}
2001-06-23 03:03:24 +00:00
FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample ( FLAC__real lpc_error , unsigned total_samples )
2000-12-10 04:09:52 +00:00
{
2001-07-03 04:37:18 +00:00
double error_scale ;
2000-12-10 04:09:52 +00:00
2001-05-31 20:11:02 +00:00
FLAC__ASSERT ( total_samples > 0 ) ;
2000-12-10 04:09:52 +00:00
2001-06-23 03:03:24 +00:00
error_scale = 0.5 * M_LN2 * M_LN2 / ( FLAC__real ) total_samples ;
2000-12-10 04:09:52 +00:00
2001-02-08 00:26:45 +00:00
if ( lpc_error > 0.0 ) {
2001-07-03 04:37:18 +00:00
FLAC__real bps = ( FLAC__real ) ( ( double ) 0.5 * log ( error_scale * lpc_error ) / M_LN2 ) ;
2001-02-08 00:26:45 +00:00
if ( bps > = 0.0 )
return bps ;
else
return 0.0 ;
}
2001-05-24 19:27:08 +00:00
else if ( lpc_error < 0.0 ) { /* error should not be negative but can happen due to inadequate float resolution */
2001-07-03 04:37:18 +00:00
return ( FLAC__real ) 1e32 ;
2001-05-24 19:27:08 +00:00
}
else {
return 0.0 ;
}
}
2001-07-03 04:37:18 +00:00
FLAC__real FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale ( FLAC__real lpc_error , double error_scale )
2001-05-24 19:27:08 +00:00
{
if ( lpc_error > 0.0 ) {
2001-07-03 04:37:18 +00:00
FLAC__real bps = ( FLAC__real ) ( ( double ) 0.5 * log ( error_scale * lpc_error ) / M_LN2 ) ;
2001-05-24 19:27:08 +00:00
if ( bps > = 0.0 )
return bps ;
else
return 0.0 ;
}
else if ( lpc_error < 0.0 ) { /* error should not be negative but can happen due to inadequate float resolution */
2001-07-03 04:37:18 +00:00
return ( FLAC__real ) 1e32 ;
2001-05-24 19:27:08 +00:00
}
2001-02-08 00:26:45 +00:00
else {
2000-12-10 04:09:52 +00:00
return 0.0 ;
2001-02-08 00:26:45 +00:00
}
2000-12-10 04:09:52 +00:00
}
2001-06-23 03:03:24 +00:00
unsigned FLAC__lpc_compute_best_order ( const FLAC__real lpc_error [ ] , unsigned max_order , unsigned total_samples , unsigned bits_per_signal_sample )
2000-12-10 04:09:52 +00:00
{
unsigned order , best_order ;
2001-07-03 04:37:18 +00:00
FLAC__real best_bits , tmp_bits ;
double error_scale ;
2000-12-10 04:09:52 +00:00
2001-05-31 20:11:02 +00:00
FLAC__ASSERT ( max_order > 0 ) ;
FLAC__ASSERT ( total_samples > 0 ) ;
2001-05-24 19:27:08 +00:00
2001-06-23 03:03:24 +00:00
error_scale = 0.5 * M_LN2 * M_LN2 / ( FLAC__real ) total_samples ;
2000-12-10 04:09:52 +00:00
best_order = 0 ;
2001-06-23 03:03:24 +00:00
best_bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale ( lpc_error [ 0 ] , error_scale ) * ( FLAC__real ) total_samples ;
2000-12-10 04:09:52 +00:00
for ( order = 1 ; order < max_order ; order + + ) {
2001-06-23 03:03:24 +00:00
tmp_bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale ( lpc_error [ order ] , error_scale ) * ( FLAC__real ) ( total_samples - order ) + ( FLAC__real ) ( order * bits_per_signal_sample ) ;
2000-12-10 04:09:52 +00:00
if ( tmp_bits < best_bits ) {
best_order = order ;
best_bits = tmp_bits ;
}
}
return best_order + 1 ; /* +1 since index of lpc_error[] is order-1 */
}