Fixed various bugs in the adpcm routines

This commit is contained in:
Jack Jansen 1993-01-08 14:40:53 +00:00
parent ed59d205a9
commit d513f0bcb6

View File

@ -847,7 +847,7 @@ audioop_lin2adpcm(self, args)
{ {
signed char *cp; signed char *cp;
signed char *ncp; signed char *ncp;
int len, size, val, step, valprev, delta, index, sign; int len, size, val, step, valpred, delta, index, sign, vpdiff, diff;
object *rv, *state, *str; object *rv, *state, *str;
int i, outputbuffer, bufferstep; int i, outputbuffer, bufferstep;
@ -869,10 +869,10 @@ audioop_lin2adpcm(self, args)
/* Decode state, should have (value, step) */ /* Decode state, should have (value, step) */
if ( state == None ) { if ( state == None ) {
/* First time, it seems. Set defaults */ /* First time, it seems. Set defaults */
valprev = 0; valpred = 0;
step = 7; step = 7;
index = 0; index = 0;
} else if ( !getargs(state, "(iii)", &valprev, &step, &index) ) } else if ( !getargs(state, "(iii)", &valpred, &step, &index) )
return 0; return 0;
bufferstep = 1; bufferstep = 1;
@ -883,29 +883,50 @@ audioop_lin2adpcm(self, args)
else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16; else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16;
/* Step 1 - compute difference with previous value */ /* Step 1 - compute difference with previous value */
delta = val - valprev; diff = val - valpred;
sign = (delta < 0) ? 8 : 0; sign = (diff < 0) ? 8 : 0;
if ( sign ) delta = (-delta); if ( sign ) diff = (-diff);
/* Step 2 - Divide and clamp */ /* Step 2 - Divide and clamp */
#ifdef NODIVIDE /* Note:
Program using shifts and subtracts; ** This code *approximately* computes:
#else ** delta = diff*4/step;
delta = (delta<<2) / step; ** vpdiff = (delta+0.5)*step/4;
if ( delta > 7 ) delta = 7; ** but in shift step bits are dropped. The net result of this is
#endif ** that even if you have fast mul/div hardware you cannot put it to
** good use since the fixup would be too expensive.
*/
delta = 0;
vpdiff = (step >> 3);
if ( diff >= step ) {
delta = 4;
diff -= step;
vpdiff += step;
}
step >>= 1;
if ( diff >= step ) {
delta |= 2;
diff -= step;
vpdiff += step;
}
step >>= 1;
if ( diff >= step ) {
delta |= 1;
vpdiff += step;
}
/* Step 3 - Update previous value */ /* Step 3 - Update previous value */
if ( sign ) if ( sign )
valprev -= (delta*step)>>2; valpred -= vpdiff;
else else
valprev += (delta*step)>>2; valpred += vpdiff;
/* Step 4 - Clamp previous value to 16 bits */ /* Step 4 - Clamp previous value to 16 bits */
if ( valprev > 32767 ) if ( valpred > 32767 )
valprev = 32767; valpred = 32767;
else if ( valprev < -32768 ) else if ( valpred < -32768 )
valprev = -32768; valpred = -32768;
/* Step 5 - Assemble value, update index and step values */ /* Step 5 - Assemble value, update index and step values */
delta |= sign; delta |= sign;
@ -915,15 +936,15 @@ audioop_lin2adpcm(self, args)
if ( index > 88 ) index = 88; if ( index > 88 ) index = 88;
step = stepsizeTable[index]; step = stepsizeTable[index];
/* Step 6 - Output value (as a whole byte, currently) */ /* Step 6 - Output value */
if ( bufferstep ) { if ( bufferstep ) {
outputbuffer = (delta << 4); outputbuffer = (delta << 4) & 0xf0;
} else { } else {
*ncp++ = delta | outputbuffer; *ncp++ = (delta & 0x0f) | outputbuffer;
} }
bufferstep = !bufferstep; bufferstep = !bufferstep;
} }
rv = mkvalue("(O(iii))", str, valprev, step, index); rv = mkvalue("(O(iii))", str, valpred, step, index);
DECREF(str); DECREF(str);
return rv; return rv;
} }
@ -935,7 +956,7 @@ audioop_adpcm2lin(self, args)
{ {
signed char *cp; signed char *cp;
signed char *ncp; signed char *ncp;
int len, size, val, valprev, step, delta, index, sign; int len, size, val, valpred, step, delta, index, sign, vpdiff;
object *rv, *str, *state; object *rv, *str, *state;
int i, inputbuffer, bufferstep; int i, inputbuffer, bufferstep;
@ -951,10 +972,10 @@ audioop_adpcm2lin(self, args)
/* Decode state, should have (value, step) */ /* Decode state, should have (value, step) */
if ( state == None ) { if ( state == None ) {
/* First time, it seems. Set defaults */ /* First time, it seems. Set defaults */
valprev = 0; valpred = 0;
step = 7; step = 7;
index = 0; index = 0;
} else if ( !getargs(state, "(iii)", &valprev, &step, &index) ) } else if ( !getargs(state, "(iii)", &valpred, &step, &index) )
return 0; return 0;
str = newsizedstringobject(NULL, len*size*2); str = newsizedstringobject(NULL, len*size*2);
@ -975,36 +996,46 @@ audioop_adpcm2lin(self, args)
bufferstep = !bufferstep; bufferstep = !bufferstep;
/* Step 2 - Find new index value (for later) */
index += indexTable[delta]; index += indexTable[delta];
if ( index < 0 ) index = 0; if ( index < 0 ) index = 0;
if ( index > 88 ) index = 88; if ( index > 88 ) index = 88;
/* Step 2 - Separate sign and magnitude */ /* Step 3 - Separate sign and magnitude */
sign = delta & 8; sign = delta & 8;
delta = delta & 7; delta = delta & 7;
/* Step 3 - update output value */ /* Step 4 - Compute difference and new predicted value */
/*
** Computes 'vpdiff = (delta+0.5)*step/4', but see comment
** in adpcm_coder.
*/
vpdiff = step >> 3;
if ( delta & 4 ) vpdiff += step;
if ( delta & 2 ) vpdiff += step>>1;
if ( delta & 1 ) vpdiff += step>>2;
if ( sign ) if ( sign )
valprev -= (delta*step) >> 2; valpred -= vpdiff;
else else
valprev += (delta*step) >> 2; valpred += vpdiff;
/* Step 4 - clamp output value */ /* Step 5 - clamp output value */
if ( valprev > 32767 ) if ( valpred > 32767 )
valprev = 32767; valpred = 32767;
else if ( valprev < -32768 ) else if ( valpred < -32768 )
valprev = -32768; valpred = -32768;
/* Step 5 - Update step value */ /* Step 6 - Update step value */
step = stepsizeTable[index]; step = stepsizeTable[index];
/* Step 6 - Output value */ /* Step 6 - Output value */
if ( size == 1 ) *CHARP(ncp, i) = (signed char)(valprev >> 8); if ( size == 1 ) *CHARP(ncp, i) = (signed char)(valpred >> 8);
else if ( size == 2 ) *SHORTP(ncp, i) = (short)(valprev); else if ( size == 2 ) *SHORTP(ncp, i) = (short)(valpred);
else if ( size == 4 ) *LONGP(ncp, i) = (long)(valprev<<16); else if ( size == 4 ) *LONGP(ncp, i) = (long)(valpred<<16);
} }
rv = mkvalue("(O(iii))", str, valprev, step, index); rv = mkvalue("(O(iii))", str, valpred, step, index);
DECREF(str); DECREF(str);
return rv; return rv;
} }