ref: 606250ab7f002e287ec5153b69d11a262f3a265f
parent: 0e0b94a877557be6172e482e8911a55039f91ad9
author: Jean-Marc Valin <[email protected]>
date: Tue Feb 15 09:31:21 EST 2011
Improved transitions between the different modes Uses the PLC to prevent glitches
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -78,7 +78,10 @@
SKP_SILK_SDK_DecControlStruct DecControl;
SKP_int32 silk_frame_size;
short pcm_celt[960*2];
+ short pcm_transition[960*2];
int audiosize;
+ int mode;
+ int transition=0;
/* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
if (len<=2)
@@ -89,7 +92,7 @@
/* Decoding mode/bandwidth/framesize from first byte */
if (data[0]&0x80)
{
- st->mode = MODE_CELT_ONLY;
+ mode = MODE_CELT_ONLY;
st->bandwidth = BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3);
if (st->bandwidth == BANDWIDTH_MEDIUMBAND)
st->bandwidth = BANDWIDTH_NARROWBAND;
@@ -97,12 +100,12 @@
audiosize = (st->Fs<<audiosize)/400;
} else if ((data[0]&0x60) == 0x60)
{
- st->mode = MODE_HYBRID;
+ mode = MODE_HYBRID;
st->bandwidth = (data[0]&0x10) ? BANDWIDTH_FULLBAND : BANDWIDTH_SUPERWIDEBAND;
audiosize = (data[0]&0x08) ? st->Fs/50 : st->Fs/100;
} else {
- st->mode = MODE_SILK_ONLY;
+ mode = MODE_SILK_ONLY;
st->bandwidth = BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3);
audiosize = ((data[0]>>3)&0x3);
if (audiosize == 3)
@@ -118,8 +121,16 @@
ec_dec_init(&dec,(unsigned char*)data,len);
} else {
audiosize = frame_size;
+ mode = st->prev_mode;
}
+ if (mode != st->prev_mode
+ && !(mode == MODE_SILK_ONLY && st->prev_mode == MODE_HYBRID)
+ && !(mode == MODE_HYBRID && st->prev_mode == MODE_SILK_ONLY))
+ {
+ transition = 1;
+ opus_decode(st, NULL, 0, pcm_transition, audiosize, 0);
+ }
if (audiosize > frame_size)
{
fprintf(stderr, "PCM buffer too small");
@@ -129,13 +140,17 @@
}
/* SILK processing */
- if (st->mode != MODE_CELT_ONLY)
+ if (mode != MODE_CELT_ONLY)
{
int lost_flag, decoded_samples;
SKP_int16 *pcm_ptr = pcm;
+
+ if (st->prev_mode==MODE_CELT_ONLY)
+ SKP_Silk_SDK_InitDecoder( st->silk_dec );
+
DecControl.API_sampleRate = st->Fs;
DecControl.payloadSize_ms = 1000 * audiosize / st->Fs;
- if( st->mode == MODE_SILK_ONLY ) {
+ if( mode == MODE_SILK_ONLY ) {
if( st->bandwidth == BANDWIDTH_NARROWBAND ) {
DecControl.internalSampleRate = 8000;
} else if( st->bandwidth == BANDWIDTH_MEDIUMBAND ) {
@@ -169,7 +184,7 @@
pcm[i] = 0;
}
- if (st->mode == MODE_HYBRID)
+ if (mode == MODE_HYBRID)
{
/* This should be adjusted based on the SILK bandwidth */
celt_decoder_ctl(st->celt_dec, CELT_SET_START_BAND(17));
@@ -177,7 +192,7 @@
celt_decoder_ctl(st->celt_dec, CELT_SET_START_BAND(0));
}
- if (st->mode != MODE_SILK_ONLY)
+ if (mode != MODE_SILK_ONLY)
{
int endband;
@@ -199,6 +214,8 @@
celt_decoder_ctl(st->celt_dec, CELT_SET_END_BAND(endband));
celt_decoder_ctl(st->celt_dec, CELT_SET_CHANNELS(st->stream_channels));
+ if (st->prev_mode == MODE_SILK_ONLY)
+ celt_decoder_ctl(st->celt_dec, CELT_RESET_STATE);
/* Decode CELT */
celt_ret = celt_decode_with_ec(st->celt_dec, decode_fec?NULL:data, len, pcm_celt, frame_size, &dec);
for (i=0;i<frame_size*st->channels;i++)
@@ -205,10 +222,23 @@
pcm[i] = ADD_SAT16(pcm[i], pcm_celt[i]);
}
+ if (transition)
+ {
+ int tlength;
+ if (mode == MODE_CELT_ONLY)
+ tlength = IMIN(audiosize, 10+st->Fs/200);
+ else
+ tlength = IMIN(audiosize, 10+st->Fs/400);
+ for (i=0;i<audiosize;i++)
+ {
+ pcm[i] = (i*pcm[i] + (audiosize-i)*pcm_transition[i])/audiosize;
+ }
+ }
#if OPUS_TEST_RANGE_CODER_STATE
st->rangeFinal = dec.rng;
#endif
+ st->prev_mode = mode;
return celt_ret<0 ? celt_ret : audiosize;
}
@@ -221,16 +251,10 @@
switch (request)
{
- case OPUS_SET_MODE_REQUEST:
- {
- int value = va_arg(ap, int);
- st->mode = value;
- }
- break;
case OPUS_GET_MODE_REQUEST:
{
int *value = va_arg(ap, int*);
- *value = st->mode;
+ *value = st->prev_mode;
}
break;
case OPUS_SET_BANDWIDTH_REQUEST:
--- a/src/opus_decoder.h
+++ b/src/opus_decoder.h
@@ -37,10 +37,10 @@
int channels;
int stream_channels;
- int mode;
int bandwidth;
/* Sampling rate (at the API level) */
int Fs;
+ int prev_mode;
#ifdef OPUS_TEST_RANGE_CODER_STATE
int rangeFinal;
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -98,10 +98,17 @@
bytes_target = st->bitrate_bps * frame_size / (st->Fs * 8) - 1;
data += 1;
+ if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY)
+ {
+ SKP_SILK_SDK_EncControlStruct dummy;
+ SKP_Silk_SDK_InitEncoder( st->silk_enc, &dummy);
+ }
+
ec_enc_init(&enc, data, max_data_bytes-1);
/* SILK processing */
- if (st->mode != MODE_CELT_ONLY) {
+ if (st->mode != MODE_CELT_ONLY)
+ {
st->silk_mode.bitRate = st->bitrate_bps - 8*st->Fs/frame_size;
if( st->mode == MODE_HYBRID ) {
if( st->bandwidth == BANDWIDTH_SUPERWIDEBAND ) {
@@ -185,6 +192,13 @@
celt_encoder_ctl(st->celt_enc, CELT_SET_VBR(0));
celt_encoder_ctl(st->celt_enc, CELT_SET_BITRATE(510000));
+ if (st->prev_mode == MODE_SILK_ONLY)
+ {
+ celt_encoder_ctl(st->celt_enc, CELT_RESET_STATE);
+ celt_encoder_ctl(st->celt_enc, CELT_SET_PREDICTION(0));
+ } else {
+ celt_encoder_ctl(st->celt_enc, CELT_SET_PREDICTION(2));
+ }
if (st->mode == MODE_HYBRID)
{
int len;
@@ -268,7 +282,7 @@
#if OPUS_TEST_RANGE_CODER_STATE
st->rangeFinal = enc.rng;
#endif
-
+ st->prev_mode = st->mode;
return ret+1;
}
--- a/src/opus_encoder.h
+++ b/src/opus_encoder.h
@@ -43,6 +43,7 @@
int stream_channels;
int mode;
+ int prev_mode;
int bandwidth;
/* Sampling rate (at the API level) */
int Fs;