Skip to content

Commit

Permalink
Preserving 24-bit accuracy for fixed-point encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
jmvalin committed Sep 27, 2024
1 parent b7f3d5c commit 7abe7f0
Show file tree
Hide file tree
Showing 13 changed files with 239 additions and 140 deletions.
14 changes: 14 additions & 0 deletions celt/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ typedef opus_val32 opus_res;
#define RES2FLOAT(a) ((1.f/32768.f/256.)*(a))
#define INT16TORES(a) SHL32(EXTEND32(a), RES_SHIFT)
#define ADD_RES(a, b) ADD32(a, b)
#define FLOAT2RES(a) float2int(32768.f*256.f*(a))
#define RES2SIG(a) SHL32((a), SIG_SHIFT-RES_SHIFT)
#define MULT16_RES_Q15(a,b) MULT16_32_Q15(a,b)
#else
typedef opus_val16 opus_res;
#define RES_SHIFT 0
Expand All @@ -153,8 +156,13 @@ typedef opus_val16 opus_res;
#define RES2FLOAT(a) ((1.f/32768.f)*(a))
#define INT16TORES(a) (a)
#define ADD_RES(a, b) SAT16(ADD32((a), (b)));
#define FLOAT2RES(a) FLOAT2INT16(a)
#define RES2SIG(a) SHL32(EXTEND32(a), SIG_SHIFT)
#define MULT16_RES_Q15(a,b) MULT16_16_Q15(a,b)
#endif

#define RES2VAL16(a) RES2INT16(a)

#define celt_isnan(x) 0

#define Q15ONE 32767
Expand Down Expand Up @@ -313,6 +321,12 @@ static OPUS_INLINE int celt_isnan(float x)
#define RES2FLOAT(a) (a)
#define INT16TORES(a) ((a)*(1/CELT_SIG_SCALE))
#define ADD_RES(a, b) ADD32(a, b)
#define FLOAT2RES(a) (a)
#define RES2SIG(a) (CELT_SIG_SCALE*(a))
#define MULT16_RES_Q15(a,b) MULT16_16_Q15(a,b)

#define RES2VAL16(a) (a)


#endif /* !FIXED_POINT */

Expand Down
4 changes: 2 additions & 2 deletions celt/celt.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ typedef struct {

int celt_encoder_get_size(int channels);

int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_res * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);

int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels,
int arch);
Expand Down Expand Up @@ -229,7 +229,7 @@ void validate_celt_decoder(CELTDecoder *st);

int resampling_factor(opus_int32 rate);

void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
void celt_preemphasis(const opus_res * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip);

void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
Expand Down
63 changes: 45 additions & 18 deletions celt/celt_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * OPUS
}


void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
void celt_preemphasis(const opus_res * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip)
{
int i;
Expand All @@ -529,11 +529,11 @@ void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RES
{
for (i=0;i<N;i++)
{
opus_val16 x;
x = SCALEIN(pcmp[CC*i]);
celt_sig x;
x = RES2SIG(pcmp[CC*i]);
/* Apply pre-emphasis */
inp[i] = SHL32(x, SIG_SHIFT) - m;
m = SHR32(MULT16_16(coef0, x), 15-SIG_SHIFT);
inp[i] = x - m;
m = MULT16_32_Q15(coef0, x);
}
*mem = m;
return;
Expand All @@ -545,7 +545,7 @@ void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RES
OPUS_CLEAR(inp, N);
}
for (i=0;i<Nu;i++)
inp[i*upsample] = SCALEIN(pcmp[CC*i]);
inp[i*upsample] = RES2SIG(pcmp[CC*i]);

#ifndef FIXED_POINT
if (clip)
Expand All @@ -567,7 +567,7 @@ void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RES
celt_sig x, tmp;
x = inp[i];
/* Apply pre-emphasis */
tmp = MULT16_16(coef2, x);
tmp = SHL32(MULT16_32_Q15(coef2, x), 15-SIG_SHIFT);
inp[i] = tmp + m;
m = MULT16_32_Q15(coef1, inp[i]) - MULT16_32_Q15(coef0, tmp);
}
Expand All @@ -576,11 +576,11 @@ void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RES
{
for (i=0;i<N;i++)
{
opus_val16 x;
celt_sig x;
x = inp[i];
/* Apply pre-emphasis */
inp[i] = SHL32(x, SIG_SHIFT) - m;
m = SHR32(MULT16_16(coef0, x), 15-SIG_SHIFT);
inp[i] = x - m;
m = MULT16_32_Q15(coef0, x);
}
}
*mem = m;
Expand Down Expand Up @@ -1596,7 +1596,7 @@ static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32
return target;
}

int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_res * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
{
int i, c, N;
opus_int32 bits;
Expand Down Expand Up @@ -1812,8 +1812,8 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,

ALLOC(in, CC*(N+overlap), celt_sig);

sample_max=MAX32(st->overlap_max, celt_maxabs16(pcm, C*(N-overlap)/st->upsample));
st->overlap_max=celt_maxabs16(pcm+C*(N-overlap)/st->upsample, C*overlap/st->upsample);
sample_max=MAX32(st->overlap_max, celt_maxabs_res(pcm, C*(N-overlap)/st->upsample));
st->overlap_max=celt_maxabs_res(pcm+C*(N-overlap)/st->upsample, C*overlap/st->upsample);
sample_max=MAX32(sample_max, st->overlap_max);
#ifdef FIXED_POINT
silence = (sample_max==0);
Expand Down Expand Up @@ -2472,7 +2472,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
} while (++c<CC);

/* We reuse freq[] as scratch space for the de-emphasis */
deemphasis(out_mem, (opus_val16*)pcm, N, CC, st->upsample, mode->preemph, st->preemph_memD, 0);
deemphasis(out_mem, (opus_res*)pcm, N, CC, st->upsample, mode->preemph, st->preemph_memD, 0);
st->prefilter_period_old = st->prefilter_period;
st->prefilter_gain_old = st->prefilter_gain;
st->prefilter_tapset_old = st->prefilter_tapset;
Expand Down Expand Up @@ -2544,32 +2544,59 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
#ifdef CUSTOM_MODES

#ifdef FIXED_POINT
#ifdef ENABLE_RES24
int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
{
int j, ret, C, N;
VARDECL(opus_res, in);
ALLOC_STACK;

if (pcm==NULL)
return OPUS_BAD_ARG;

C = st->channels;
N = frame_size;
ALLOC(in, C*N, opus_res);

for (j=0;j<C*N;j++)
in[j] = INT16TORES(pcm[j]);

ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
#ifdef RESYNTH
for (j=0;j<C*N;j++)
((float*)pcm)[j]=RES2INT16(in[j]);
#endif
RESTORE_STACK;
return ret;
}
#else
int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
{
return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
}
#endif

#ifndef DISABLE_FLOAT_API
int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
{
int j, ret, C, N;
VARDECL(opus_int16, in);
VARDECL(opus_res, in);
ALLOC_STACK;

if (pcm==NULL)
return OPUS_BAD_ARG;

C = st->channels;
N = frame_size;
ALLOC(in, C*N, opus_int16);
ALLOC(in, C*N, opus_res);

for (j=0;j<C*N;j++)
in[j] = FLOAT2INT16(pcm[j]);
in[j] = FLOAT2RES(pcm[j]);

ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
#ifdef RESYNTH
for (j=0;j<C*N;j++)
((float*)pcm)[j]=in[j]*(1.f/32768.f);
((float*)pcm)[j]=RES2FLOAT(in[j]);
#endif
RESTORE_STACK;
return ret;
Expand Down
18 changes: 18 additions & 0 deletions celt/mathops.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,24 @@ static OPUS_INLINE opus_val32 celt_maxabs16(const opus_val16 *x, int len)
}
#endif

#ifdef ENABLE_RES24
static OPUS_INLINE opus_res celt_maxabs_res(const opus_res *x, int len)
{
int i;
opus_res maxval = 0;
opus_res minval = 0;
for (i=0;i<len;i++)
{
maxval = MAX32(maxval, x[i]);
minval = MIN32(minval, x[i]);
}
return MAX32(maxval,-minval);
}
#else
#define celt_maxabs_res celt_maxabs16
#endif


#ifndef OVERRIDE_CELT_MAXABS32
#ifdef FIXED_POINT
static OPUS_INLINE opus_val32 celt_maxabs32(const opus_val32 *x, int len)
Expand Down
2 changes: 1 addition & 1 deletion silk/API.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ opus_int silk_InitEncoder( /* O Returns error co
opus_int silk_Encode( /* O Returns error code */
void *encState, /* I/O State */
silk_EncControlStruct *encControl, /* I Control status */
const opus_int16 *samplesIn, /* I Speech sample input vector */
const opus_res *samplesIn, /* I Speech sample input vector */
opus_int nSamplesIn, /* I Number of samples in input vector */
ec_enc *psRangeEnc, /* I/O Compressor data structure */
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
Expand Down
12 changes: 7 additions & 5 deletions silk/enc_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ static opus_int silk_QueryEncoder( /* O Returns error co
opus_int silk_Encode( /* O Returns error code */
void *encState, /* I/O State */
silk_EncControlStruct *encControl, /* I Control status */
const opus_int16 *samplesIn, /* I Speech sample input vector */
const opus_res *samplesIn, /* I Speech sample input vector */
opus_int nSamplesIn, /* I Number of samples in input vector */
ec_enc *psRangeEnc, /* I/O Compressor data structure */
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
Expand Down Expand Up @@ -282,7 +282,7 @@ opus_int silk_Encode( /* O Returns error co
if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) {
opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
for( n = 0; n < nSamplesFromInput; n++ ) {
buf[ n ] = samplesIn[ 2 * n ];
buf[ n ] = RES2INT16(samplesIn[ 2 * n ]);
}
/* Making sure to start both resamplers from the same state when switching from mono to stereo */
if( psEnc->nPrevChannelsInternal == 1 && id==0 ) {
Expand All @@ -296,7 +296,7 @@ opus_int silk_Encode( /* O Returns error co
nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx;
nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
for( n = 0; n < nSamplesFromInput; n++ ) {
buf[ n ] = samplesIn[ 2 * n + 1 ];
buf[ n ] = RES2INT16(samplesIn[ 2 * n + 1 ]);
}
ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
&psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
Expand All @@ -305,7 +305,7 @@ opus_int silk_Encode( /* O Returns error co
} else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) {
/* Combine left and right channels before resampling */
for( n = 0; n < nSamplesFromInput; n++ ) {
sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ];
sum = RES2INT16(samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ]);
buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 );
}
ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
Expand All @@ -323,7 +323,9 @@ opus_int silk_Encode( /* O Returns error co
psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
} else {
celt_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 );
silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16));
for( n = 0; n < nSamplesFromInput; n++ ) {
buf[n] = RES2INT16(samplesIn[n]);
}
ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
&psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
Expand Down
12 changes: 4 additions & 8 deletions src/mapping_matrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void mapping_matrix_multiply_channel_in_float(
const MappingMatrix *matrix,
const float *input,
int input_rows,
opus_val16 *output,
opus_res *output,
int output_row,
int output_rows,
int frame_size)
Expand All @@ -108,11 +108,7 @@ void mapping_matrix_multiply_channel_in_float(
matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] *
input[MATRIX_INDEX(input_rows, col, i)];
}
#if defined(FIXED_POINT)
output[output_rows * i] = FLOAT2INT16((1/32768.f)*tmp);
#else
output[output_rows * i] = (1/32768.f)*tmp;
#endif
output[output_rows * i] = FLOAT2RES((1/32768.f)*tmp);
}
}

Expand Down Expand Up @@ -153,7 +149,7 @@ void mapping_matrix_multiply_channel_in_short(
const MappingMatrix *matrix,
const opus_int16 *input,
int input_rows,
opus_val16 *output,
opus_res *output,
int output_row,
int output_rows,
int frame_size)
Expand Down Expand Up @@ -182,7 +178,7 @@ void mapping_matrix_multiply_channel_in_short(
#endif
}
#if defined(FIXED_POINT)
output[output_rows * i] = (opus_int16)((tmp + 64) >> 7);
output[output_rows * i] = INT16TORES((tmp + 64) >> 7);
#else
output[output_rows * i] = (1/(32768.f*32768.f))*tmp;
#endif
Expand Down
4 changes: 2 additions & 2 deletions src/mapping_matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void mapping_matrix_multiply_channel_in_float(
const MappingMatrix *matrix,
const float *input,
int input_rows,
opus_val16 *output,
opus_res *output,
int output_row,
int output_rows,
int frame_size
Expand All @@ -87,7 +87,7 @@ void mapping_matrix_multiply_channel_in_short(
const MappingMatrix *matrix,
const opus_int16 *input,
int input_rows,
opus_val16 *output,
opus_res *output,
int output_row,
int output_rows,
int frame_size
Expand Down
Loading

0 comments on commit 7abe7f0

Please sign in to comment.