diff options
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/audioop.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/Modules/audioop.c b/Modules/audioop.c index 1dd2da0..c3176f9 100644 --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -130,6 +130,9 @@ int sample; } /* End of code taken from sox */ +/* ADPCM step variation table */ +static float newstep[5] = { 0.8, 0.9, 1.0, 1.75, 1.75 }; + #define CHARP(cp, i) ((signed char *)(cp+i)) #define SHORTP(cp, i) ((short *)(cp+i)) #define LONGP(cp, i) ((long *)(cp+i)) @@ -546,6 +549,136 @@ audioop_ulaw2lin(self, args) return rv; } +static object * +audioop_lin2adpcm(self, args) + object *self; + object *args; +{ + signed char *cp; + signed char *ncp; + int len, size, val, step, valprev, delta; + object *rv, *state, *str; + int i; + + if ( !getargs(args, "(s#iO)", + &cp, &len, &size, &state) ) + return 0; + + + if ( size != 1 && size != 2 && size != 4) { + err_setstr(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + str = newsizedstringobject(NULL, len/size); + if ( str == 0 ) + return 0; + ncp = (signed char *)getstringvalue(str); + + /* Decode state, should have (value, step) */ + if ( state == None ) { + /* First time, it seems. Set defaults */ + valprev = 0; + step = 4; /* The '4' is magic. Dunno it's significance */ + } else if ( !getargs(state, "(ii)", &valprev, &step) ) + return 0; + + for ( i=0; i < len; i += size ) { + if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8; + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16; + + /* Step 1 - compute difference with previous value */ + delta = (val - valprev)/step; + + /* Step 2 - Clamp */ + if ( delta < -4 ) + delta = -4; + else if ( delta > 3 ) + delta = 3; + + /* Step 3 - Update previous value */ + valprev += delta*step; + + /* Step 4 - Clamp previous value to 16 bits */ + if ( valprev > 32767 ) + valprev = 32767; + else if ( valprev < -32768 ) + valprev = -32768; + + /* Step 5 - Update step value */ + step = step * newstep[abs(delta)]; + step++; /* Don't understand this. */ + + /* Step 6 - Output value (as a whole byte, currently) */ + *ncp++ = delta; + } + rv = mkvalue("(O(ii))", str, valprev, step); + DECREF(str); + return rv; +} + +static object * +audioop_adpcm2lin(self, args) + object *self; + object *args; +{ + signed char *cp; + signed char *ncp; + int len, size, val, valprev, step, delta; + object *rv, *str, *state; + int i; + + if ( !getargs(args, "(s#iO)", + &cp, &len, &size, &state) ) + return 0; + + if ( size != 1 && size != 2 && size != 4) { + err_setstr(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + /* Decode state, should have (value, step) */ + if ( state == None ) { + /* First time, it seems. Set defaults */ + valprev = 0; + step = 4; /* The '4' is magic. Dunno it's significance */ + } else if ( !getargs(state, "(ii)", &valprev, &step) ) + return 0; + + str = newsizedstringobject(NULL, len*size); + if ( str == 0 ) + return 0; + ncp = (signed char *)getstringvalue(str); + + for ( i=0; i < len*size; i += size ) { + /* Step 1 - get the delta value */ + delta = *cp++; + + /* Step 2 - update output value */ + valprev = valprev + delta*step; + + /* Step 3 - clamp output value */ + if ( valprev > 32767 ) + valprev = 32767; + else if ( valprev < -32768 ) + valprev = -32768; + + /* Step 4 - Update step value */ + step = step * newstep[abs(delta)]; + step++; + + /* Step 5 - Output value */ + if ( size == 1 ) *CHARP(ncp, i) = (signed char)(valprev >> 8); + else if ( size == 2 ) *SHORTP(ncp, i) = (short)(valprev); + else if ( size == 4 ) *LONGP(ncp, i) = (long)(valprev<<16); + } + + rv = mkvalue("(O(ii))", str, valprev, step); + DECREF(str); + return rv; +} + static struct methodlist audioop_methods[] = { { "max", audioop_max }, { "avg", audioop_avg }, @@ -555,6 +688,8 @@ static struct methodlist audioop_methods[] = { { "bias", audioop_bias }, { "ulaw2lin", audioop_ulaw2lin }, { "lin2ulaw", audioop_lin2ulaw }, + { "adpcm2lin", audioop_adpcm2lin }, + { "lin2adpcm", audioop_lin2adpcm }, { "tomono", audioop_tomono }, { "tostereo", audioop_tostereo }, { "getsample", audioop_getsample }, |