Index: src/opus.c |
diff --git a/src/opus.c b/src/opus.c |
index d6ae7bab24e688901361e9681386d99492fb067f..170bc4b6e5040bbeee2ded6673a4fb500fc77c12 100644 |
--- a/src/opus.c |
+++ b/src/opus.c |
@@ -32,6 +32,105 @@ |
#include "opus.h" |
#include "opus_private.h" |
+#ifndef DISABLE_FLOAT_API |
+OPUS_EXPORT void opus_pcm_soft_clip(float *_x, int N, int C, float *declip_mem) |
+{ |
+ int c; |
+ int i; |
+ float *x; |
+ |
+ /* First thing: saturate everything to +/- 2 which is the highest level our |
+ non-linearity can handle. At the point where the signal reaches +/-2, |
+ the derivative will be zero anyway, so this doesn't introduce any |
+ discontinuity in the derivative. */ |
+ for (i=0;i<N*C;i++) |
+ _x[i] = MAX16(-2.f, MIN16(2.f, _x[i])); |
+ for (c=0;c<C;c++) |
+ { |
+ float a; |
+ float x0; |
+ int curr; |
+ |
+ x = _x+c; |
+ a = declip_mem[c]; |
+ /* Continue applying the non-linearity from the previous frame to avoid |
+ any discontinuity. */ |
+ for (i=0;i<N;i++) |
+ { |
+ if (x[i*C]*a>=0) |
+ break; |
+ x[i*C] = x[i*C]+a*x[i*C]*x[i*C]; |
+ } |
+ |
+ curr=0; |
+ x0 = x[0]; |
+ while(1) |
+ { |
+ int start, end; |
+ float maxval; |
+ int special=0; |
+ int peak_pos; |
+ for (i=curr;i<N;i++) |
+ { |
+ if (x[i*C]>1 || x[i*C]<-1) |
+ break; |
+ } |
+ if (i==N) |
+ { |
+ a=0; |
+ break; |
+ } |
+ peak_pos = i; |
+ start=end=i; |
+ maxval=ABS16(x[i*C]); |
+ /* Look for first zero crossing before clipping */ |
+ while (start>0 && x[i*C]*x[(start-1)*C]>=0) |
+ start--; |
+ /* Look for first zero crossing after clipping */ |
+ while (end<N && x[i*C]*x[end*C]>=0) |
+ { |
+ /* Look for other peaks until the next zero-crossing. */ |
+ if (ABS16(x[end*C])>maxval) |
+ { |
+ maxval = ABS16(x[end*C]); |
+ peak_pos = end; |
+ } |
+ end++; |
+ } |
+ /* Detect the special case where we clip before the first zero crossing */ |
+ special = (start==0 && x[i*C]*x[0]>=0); |
+ |
+ /* Compute a such that maxval + a*maxval^2 = 1 */ |
+ a=(maxval-1)/(maxval*maxval); |
+ if (x[i*C]>0) |
+ a = -a; |
+ /* Apply soft clipping */ |
+ for (i=start;i<end;i++) |
+ x[i*C] = x[i*C]+a*x[i*C]*x[i*C]; |
+ |
+ if (special && peak_pos>=2) |
+ { |
+ /* Add a linear ramp from the first sample to the signal peak. |
+ This avoids a discontinuity at the beginning of the frame. */ |
+ float delta; |
+ float offset = x0-x[0]; |
+ delta = offset / peak_pos; |
+ for (i=curr;i<peak_pos;i++) |
+ { |
+ offset -= delta; |
+ x[i*C] += offset; |
+ x[i*C] = MAX16(-1.f, MIN16(1.f, x[i*C])); |
+ } |
+ } |
+ curr = end; |
+ if (curr==N) |
+ break; |
+ } |
+ declip_mem[c] = a; |
+ } |
+} |
+#endif |
+ |
int encode_size(int size, unsigned char *data) |
{ |
if (size < 252) |