Use clipping prevention on 16-bit decode paths.
authorTimothy B. Terriberry <tterribe@xiph.org>
Mon, 25 Mar 2013 19:16:47 +0000 (12:16 -0700)
committerTimothy B. Terriberry <tterribe@xiph.org>
Mon, 25 Mar 2013 19:16:47 +0000 (12:16 -0700)
When we decode using libopus's fixed-point APIs, libopus internally
 applies soft clipping prevention.
When we decode using libopus's floating-point APIs, this behavior
 is disabled.
If we're ultimately planning to output the data to the user in
 fixed-point, we need to apply the clipping prevention ourselves.

src/internal.h
src/opusfile.c

index 5416b2e..b3c9691 100644 (file)
@@ -38,6 +38,13 @@ typedef opus_int16 op_sample;
 typedef float      op_sample;
 # endif
 
+/*We're using this define to test for libopus 1.1 or later until libopus
+   provides a better mechanism.*/
+# if defined(OPUS_GET_EXPERT_FRAME_DURATION_REQUEST)
+/*Enable soft clipping prevention in 16-bit decodes.*/
+#  define OP_SOFT_CLIP (1)
+# endif
+
 # if OP_GNUC_PREREQ(4,2)
 /*Disable excessive warnings about the order of operations.*/
 #  pragma GCC diagnostic ignored "-Wparentheses"
@@ -203,8 +210,11 @@ struct OggOpusFile{
   int                od_buffer_pos;
   /*The number of valid samples in the decoded buffer.*/
   int                od_buffer_size;
-  /*Internal state for dithering float->short output.*/
+  /*Internal state for soft clipping and dithering float->short output.*/
 #if !defined(OP_FIXED_POINT)
+# if defined(OP_SOFT_CLIP)
+  float              clip_state[OP_NCHANNELS_MAX];
+# endif
   float              dither_a[OP_NCHANNELS_MAX*4];
   float              dither_b[OP_NCHANNELS_MAX*4];
   int                dither_mute;
index 610b790..a684609 100644 (file)
@@ -2898,19 +2898,27 @@ static const float OP_FCOEF_A[4]={
 };
 
 static void op_shaped_dither16(OggOpusFile *_of,opus_int16 *_dst,
const float *_src,int _nsamples,int _nchannels){
+ float *_src,int _nsamples,int _nchannels){
   opus_uint32 seed;
   int         mute;
+  int         ci;
   int         i;
   mute=_of->dither_mute;
   seed=_of->dither_seed;
-  if(_of->state_channel_count!=_nchannels)mute=65;
+  if(_of->state_channel_count!=_nchannels){
+    mute=65;
+# if defined(OP_SOFT_CLIP)
+    for(ci=0;ci<_nchannels;ci++)_of->clip_state[ci]=0;
+# endif
+  }
+# if defined(OP_SOFT_CLIP)
+  opus_pcm_soft_clip(_src,_nsamples,_nchannels,_of->clip_state);
+# endif
   /*In order to avoid replacing digital silence with quiet dither noise, we
      mute if the output has been silent for a while.*/
   if(mute>64)memset(_of->dither_a,0,sizeof(*_of->dither_a)*4*_nchannels);
   for(i=0;i<_nsamples;i++){
     int silent;
-    int ci;
     silent=1;
     for(ci=0;ci<_nchannels;ci++){
       float r;