mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-10-10 08:03:04 -04:00
opus: fixed-phase SILK resampler interpolation
The 8, 12 and 16 kHz to 48 kHz steps visit only two or three FIR phases in a fixed cycle, so each set of input samples is read once and reused across outputs. Bit-exact; OPUS_NO_SILK_FIXED_PHASE disables it. Measured with silk_5.opus (WB SILK): e200v1: 36.31 -> 33.38 MHz, -8.1% Clip+: 21.66 -> 20.93 MHz, -3.4% Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Change-Id: Icb0f8ded62739dfee1f574e4888a54c778aa3d53
This commit is contained in:
parent
67ba9c3121
commit
b6b2d95309
2 changed files with 92 additions and 0 deletions
|
|
@ -18,6 +18,10 @@ Celt:
|
|||
silk, since config.h defines exactly one of them per core
|
||||
* add #define ABS(a)(((a) < 0) ? - (a) :(a)) to mathops.h
|
||||
|
||||
Silk:
|
||||
* added fixed-phase interpolation paths for the 8, 12 and 16 kHz to 48 kHz
|
||||
steps in resampler_private_IIR_FIR.c (disable with OPUS_NO_SILK_FIXED_PHASE)
|
||||
|
||||
Opus-tools:
|
||||
* copied src/opus_header.h and src/opus_header.c to lib/rbcodec/codecs/libopus
|
||||
* changed #include <ogg/ogg.h> to #include "ogg/ogg.h" in opus_header.h
|
||||
|
|
|
|||
|
|
@ -33,6 +33,83 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "resampler_private.h"
|
||||
#include "stack_alloc.h"
|
||||
|
||||
#ifndef OPUS_NO_SILK_FIXED_PHASE
|
||||
/* One output at phase p from eight consecutive samples: the same sum as the
|
||||
generic loop below, but as plain 16x16 C multiplies the compiler can
|
||||
schedule, where silk_SMLABB is inline asm on ARMv5E. */
|
||||
static OPUS_INLINE opus_int16 silk_IIR_FIR_tap8(
|
||||
opus_int16 x0, opus_int16 x1, opus_int16 x2, opus_int16 x3,
|
||||
opus_int16 x4, opus_int16 x5, opus_int16 x6, opus_int16 x7,
|
||||
opus_int p
|
||||
)
|
||||
{
|
||||
const opus_int16 *a = silk_resampler_frac_FIR_12[ p ];
|
||||
const opus_int16 *b = silk_resampler_frac_FIR_12[ 11 - p ];
|
||||
opus_int32 res_Q15;
|
||||
|
||||
res_Q15 = (opus_int32)x0 * a[ 0 ];
|
||||
res_Q15 += (opus_int32)x1 * a[ 1 ];
|
||||
res_Q15 += (opus_int32)x2 * a[ 2 ];
|
||||
res_Q15 += (opus_int32)x3 * a[ 3 ];
|
||||
res_Q15 += (opus_int32)x4 * b[ 3 ];
|
||||
res_Q15 += (opus_int32)x5 * b[ 2 ];
|
||||
res_Q15 += (opus_int32)x6 * b[ 1 ];
|
||||
res_Q15 += (opus_int32)x7 * b[ 0 ];
|
||||
return (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) );
|
||||
}
|
||||
|
||||
/* The steps silk_resampler_init produces for 16 and 8 kHz to 48 kHz visit
|
||||
only three phases, in a fixed cycle, for any batch up to
|
||||
RESAMPLER_MAX_BATCH_SIZE_IN: the rounding in the step never drifts across
|
||||
a phase boundary before the index restarts. Checked exhaustively over
|
||||
every batch length. The third output's window starts off2 samples later,
|
||||
and each cycle advances adv samples. */
|
||||
static OPUS_INLINE opus_int16 *silk_IIR_FIR_cycle3(
|
||||
opus_int16 *out, const opus_int16 *buf, opus_int32 max_index_Q16,
|
||||
opus_int32 inc, opus_int p0, opus_int p1, opus_int p2, opus_int off2,
|
||||
opus_int adv
|
||||
)
|
||||
{
|
||||
opus_int32 index_Q16 = 0;
|
||||
|
||||
while( index_Q16 < max_index_Q16 ) {
|
||||
opus_int16 x0 = buf[ 0 ], x1 = buf[ 1 ], x2 = buf[ 2 ], x3 = buf[ 3 ];
|
||||
opus_int16 x4 = buf[ 4 ], x5 = buf[ 5 ], x6 = buf[ 6 ], x7 = buf[ 7 ];
|
||||
*out++ = silk_IIR_FIR_tap8( x0, x1, x2, x3, x4, x5, x6, x7, p0 );
|
||||
if( ( index_Q16 += inc ) >= max_index_Q16 ) break;
|
||||
*out++ = silk_IIR_FIR_tap8( x0, x1, x2, x3, x4, x5, x6, x7, p1 );
|
||||
if( ( index_Q16 += inc ) >= max_index_Q16 ) break;
|
||||
if( off2 ) {
|
||||
*out++ = silk_IIR_FIR_tap8( x1, x2, x3, x4, x5, x6, x7, buf[ 8 ], p2 );
|
||||
} else {
|
||||
*out++ = silk_IIR_FIR_tap8( x0, x1, x2, x3, x4, x5, x6, x7, p2 );
|
||||
}
|
||||
index_Q16 += inc;
|
||||
buf += adv;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* 12 kHz to 48 kHz steps by exactly half a sample: phases 0 and 6. */
|
||||
static OPUS_INLINE opus_int16 *silk_IIR_FIR_cycle2(
|
||||
opus_int16 *out, const opus_int16 *buf, opus_int32 max_index_Q16
|
||||
)
|
||||
{
|
||||
opus_int32 index_Q16 = 0;
|
||||
|
||||
while( index_Q16 < max_index_Q16 ) {
|
||||
opus_int16 x0 = buf[ 0 ], x1 = buf[ 1 ], x2 = buf[ 2 ], x3 = buf[ 3 ];
|
||||
opus_int16 x4 = buf[ 4 ], x5 = buf[ 5 ], x6 = buf[ 6 ], x7 = buf[ 7 ];
|
||||
*out++ = silk_IIR_FIR_tap8( x0, x1, x2, x3, x4, x5, x6, x7, 0 );
|
||||
if( ( index_Q16 += 32768 ) >= max_index_Q16 ) break;
|
||||
*out++ = silk_IIR_FIR_tap8( x0, x1, x2, x3, x4, x5, x6, x7, 6 );
|
||||
index_Q16 += 32768;
|
||||
buf += 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
static OPUS_INLINE opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL(
|
||||
opus_int16 *out,
|
||||
opus_int16 *buf,
|
||||
|
|
@ -44,6 +121,17 @@ static OPUS_INLINE opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL(
|
|||
opus_int16 *buf_ptr;
|
||||
opus_int32 table_index;
|
||||
|
||||
#ifndef OPUS_NO_SILK_FIXED_PHASE
|
||||
switch( index_increment_Q16 ) {
|
||||
case 43691: /* 16 kHz */
|
||||
return silk_IIR_FIR_cycle3( out, buf, max_index_Q16, 43691, 0, 8, 4, 1, 2 );
|
||||
case 21846: /* 8 kHz */
|
||||
return silk_IIR_FIR_cycle3( out, buf, max_index_Q16, 21846, 0, 4, 8, 0, 1 );
|
||||
case 32768: /* 12 kHz */
|
||||
return silk_IIR_FIR_cycle2( out, buf, max_index_Q16 );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Interpolate upsampled signal and store in output array */
|
||||
for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
|
||||
table_index = silk_SMULWB( index_Q16 & 0xFFFF, 12 );
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue