ref: bf06c4f2ede23e23ff92ee9fb0fbedd84e69fb01
parent: f8222c997a25aa32d9a7929b59988745ca6b2023
author: Timothy B. Terriberry <tterribe@xiph.org>
date: Mon Mar 25 08:16:47 EDT 2013
Use clipping prevention on 16-bit decode paths. 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.
--- a/src/internal.h
+++ b/src/internal.h
@@ -38,6 +38,13 @@
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 @@
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;
--- a/src/opusfile.c
+++ b/src/opusfile.c
@@ -2898,19 +2898,27 @@
};
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;