shithub: opus

Download patch

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;