ref: a88a90f9ab476d2629ec5999a34ce5eb76a73a61
parent: 49233ebf56be60e811cd30913eb75edc7762af0a
author: Timothy B. Terriberry <tterribe@xiph.org>
date: Wed Aug 28 20:09:44 EDT 2013
Avoid clipping in short->float stereo downmixing. Previously I'd said this would require a large stack buffer, which was true if you simply wanted to re-use the existing op_short2float_filter() and floating-point op_stereo_filter(). But the latter is not normally compiled for fixed-point anyway, so we can instead write new code that doesn't need the stack buffer without harming anything.
--- a/src/opusfile.c
+++ b/src/opusfile.c
@@ -2765,12 +2765,47 @@
return ret;
}
-#if defined(OP_FIXED_POINT)
+#if !defined(OP_FIXED_POINT)||!defined(OP_DISABLE_FLOAT_API)
-int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){- return op_read_native(_of,_pcm,_buf_size,_li);
-}
+/*Matrices for downmixing from the supported channel counts to stereo.
+ The matrices with 5 or more channels are normalized to a total volume of 2.0,
+ since most mixes sound too quiet if normalized to 1.0 (as there is generally
+ little volume in the side/rear channels).*/
+static const float OP_STEREO_DOWNMIX[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={+ /*3.0*/
+ {+ {0.5858F,0.0F},{0.4142F,0.4142F},{0.0F,0.5858F}+ },
+ /*quadrophonic*/
+ {+ {0.4226F,0.0F},{0.0F,0.4226F},{0.366F,0.2114F},{0.2114F,0.336F}+ },
+ /*5.0*/
+ {+ {0.651F,0.0F},{0.46F,0.46F},{0.0F,0.651F},{0.5636F,0.3254F},+ {0.3254F,0.5636F}+ },
+ /*5.1*/
+ {+ {0.529F,0.0F},{0.3741F,0.3741F},{0.0F,0.529F},{0.4582F,0.2645F},+ {0.2645F,0.4582F},{0.3741F,0.3741F}+ },
+ /*6.1*/
+ {+ {0.4553F,0.0F},{0.322F,0.322F},{0.0F,0.4553F},{0.3943F,0.2277F},+ {0.2277F,0.3943F},{0.2788F,0.2788F},{0.322F,0.322F}+ },
+ /*7.1*/
+ {+ {0.3886F,0.0F},{0.2748F,0.2748F},{0.0F,0.3886F},{0.3366F,0.1943F},+ {0.1943F,0.3366F},{0.3366F,0.1943F},{0.1943F,0.3366F},{0.2748F,0.2748F}+ }
+};
+#endif
+
+#if defined(OP_FIXED_POINT)
+
/*Matrices for downmixing from the supported channel counts to stereo.
The matrices with 5 or more channels are normalized to a total volume of 2.0,
since most mixes sound too quiet if normalized to 1.0 (as there is generally
@@ -2807,6 +2842,10 @@
}
};
+int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){+ return op_read_native(_of,_pcm,_buf_size,_li);
+}
+
static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
op_sample *_src,int _nsamples,int _nchannels){(void)_of;
@@ -2831,6 +2870,7 @@
l+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][0]*s;
r+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][1]*s;
}
+ /*TODO: For 5 or more channels, we should do soft clipping here.*/
dst[2*i+0]=(opus_int16)OP_CLAMP(-32768,l+8192>>14,32767);
dst[2*i+1]=(opus_int16)OP_CLAMP(-32768,r+8192>>14,32767);
}
@@ -2864,23 +2904,41 @@
static int op_short2float_stereo_filter(OggOpusFile *_of,
void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){float *dst;
+ int i;
dst=(float *)_dst;
_nsamples=OP_MIN(_nsamples,_dst_sz>>1);
if(_nchannels==1){- int i;
_nsamples=op_short2float_filter(_of,dst,_nsamples,_src,_nsamples,1);
for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i];
- return _nsamples;
}
- /*It would be better to convert to floats and then downmix (so that we don't
- risk clipping with more than 5 channels), but that would require a large
- stack buffer, which is probably not a good idea if you're using the
- fixed-point build.*/
- if(_nchannels>2){- _nsamples=op_stereo_filter(_of,_src,_nsamples*2,
- _src,_nsamples,_nchannels);
+ else if(_nchannels<5){+ /*For 3 or 4 channels, we can downmix in fixed point without risk of
+ clipping.*/
+ if(_nchannels>2){+ _nsamples=op_stereo_filter(_of,_src,_nsamples*2,
+ _src,_nsamples,_nchannels);
+ }
+ return op_short2float_filter(_of,dst,_dst_sz,_src,_nsamples,2);
}
- return op_short2float_filter(_of,dst,_dst_sz,_src,_nsamples,2);
+ else{+ /*For 5 or more channels, we convert to floats and then downmix (so that we
+ don't risk clipping).*/
+ for(i=0;i<_nsamples;i++){+ float l;
+ float r;
+ int ci;
+ l=r=0;
+ for(ci=0;ci<_nchannels;ci++){+ float s;
+ s=(1.0F/32768)*_src[_nchannels*i+ci];
+ l+=OP_STEREO_DOWNMIX[_nchannels-3][ci][0]*s;
+ r+=OP_STEREO_DOWNMIX[_nchannels-3][ci][1]*s;
+ }
+ dst[2*i+0]=l;
+ dst[2*i+1]=r;
+ }
+ }
+ return _nsamples;
}
int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){@@ -3025,41 +3083,6 @@
_of->state_channel_count=0;
return op_read_native(_of,_pcm,_buf_size,_li);
}
-
-/*Matrices for downmixing from the supported channel counts to stereo.
- The matrices with 5 or more channels are normalized to a total volume of 2.0,
- since most mixes sound too quiet if normalized to 1.0 (as there is generally
- little volume in the side/rear channels).*/
-static const float OP_STEREO_DOWNMIX[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={- /*3.0*/
- {- {0.5858F,0.0F},{0.4142F,0.4142F},{0.0F,0.5858F}- },
- /*quadrophonic*/
- {- {0.4226F,0.0F},{0.0F,0.4226F},{0.366F,0.2114F},{0.2114F,0.336F}- },
- /*5.0*/
- {- {0.651F,0.0F},{0.46F,0.46F},{0.0F,0.651F},{0.5636F,0.3254F},- {0.3254F,0.5636F}- },
- /*5.1*/
- {- {0.529F,0.0F},{0.3741F,0.3741F},{0.0F,0.529F},{0.4582F,0.2645F},- {0.2645F,0.4582F},{0.3741F,0.3741F}- },
- /*6.1*/
- {- {0.4553F,0.0F},{0.322F,0.322F},{0.0F,0.4553F},{0.3943F,0.2277F},- {0.2277F,0.3943F},{0.2788F,0.2788F},{0.322F,0.322F}- },
- /*7.1*/
- {- {0.3886F,0.0F},{0.2748F,0.2748F},{0.0F,0.3886F},{0.3366F,0.1943F},- {0.1943F,0.3366F},{0.3366F,0.1943F},{0.1943F,0.3366F},{0.2748F,0.2748F}- }
-};
static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
op_sample *_src,int _nsamples,int _nchannels){--
⑨