wideband VBR seems to (almost) work. Need to adapt it to work on ultra-
[speexdsp.git] / libspeex / nb_celp.c
index d5ae5ef..e3ff6a2 100644 (file)
 #include "misc.h"
 #include "speex_callbacks.h"
 
+#ifdef SLOW_TRIG
+#include "math_approx.h"
+#define cos speex_cos
+#endif
+
 extern int training_weight;
 #ifndef M_PI
 #define M_PI           3.14159265358979323846  /* pi */
@@ -56,10 +61,12 @@ extern int training_weight;
 float exc_gain_quant_scal3[8]={-2.794750, -1.810660, -1.169850, -0.848119, -0.587190, -0.329818, -0.063266, 0.282826};
 
 float exc_gain_quant_scal1[2]={-0.35, 0.05};
-/*float exc_gain_quant_scal1[2]={-0.35, 0.05};*/
 
 #define sqr(x) ((x)*(x))
+
+#ifndef min
 #define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
 
 void *nb_encoder_init(SpeexMode *m)
 {
@@ -67,8 +74,8 @@ void *nb_encoder_init(SpeexMode *m)
    SpeexNBMode *mode;
    int i;
 
-   mode=m->mode;
-   st = speex_alloc(sizeof(EncState));
+   mode=(SpeexNBMode *)m->mode;
+   st = (EncState*)speex_alloc(sizeof(EncState));
    st->mode=m;
    /* Codec parameters, should eventually have several "modes"*/
    st->frameSize = mode->frameSize;
@@ -92,71 +99,71 @@ void *nb_encoder_init(SpeexMode *m)
    st->bounded_pitch = 0;
 
    /* Allocating input buffer */
-   st->inBuf = speex_alloc(st->bufSize*sizeof(float));
+   st->inBuf = (float*)speex_alloc(st->bufSize*sizeof(float));
    st->frame = st->inBuf + st->bufSize - st->windowSize;
    /* Allocating excitation buffer */
-   st->excBuf = speex_alloc(st->bufSize*sizeof(float));
+   st->excBuf = (float*)speex_alloc(st->bufSize*sizeof(float));
    st->exc = st->excBuf + st->bufSize - st->windowSize;
-   st->swBuf = speex_alloc(st->bufSize*sizeof(float));
+   st->swBuf = (float*)speex_alloc(st->bufSize*sizeof(float));
    st->sw = st->swBuf + st->bufSize - st->windowSize;
 
-   st->exc2Buf = speex_alloc(st->bufSize*sizeof(float));
+   st->exc2Buf = (float*)speex_alloc(st->bufSize*sizeof(float));
    st->exc2 = st->exc2Buf + st->bufSize - st->windowSize;
 
-   st->innov = speex_alloc(st->frameSize*sizeof(float));
+   st->innov = (float*)speex_alloc(st->frameSize*sizeof(float));
 
    /* Asymetric "pseudo-Hamming" window */
    {
       int part1, part2;
       part1 = st->subframeSize*7/2;
       part2 = st->subframeSize*5/2;
-      st->window = speex_alloc(st->windowSize*sizeof(float));
+      st->window = (float*)speex_alloc(st->windowSize*sizeof(float));
       for (i=0;i<part1;i++)
          st->window[i]=.54-.46*cos(M_PI*i/part1);
       for (i=0;i<part2;i++)
          st->window[part1+i]=.54+.46*cos(M_PI*i/part2);
    }
    /* Create the window for autocorrelation (lag-windowing) */
-   st->lagWindow = speex_alloc((st->lpcSize+1)*sizeof(float));
+   st->lagWindow = (float*)speex_alloc((st->lpcSize+1)*sizeof(float));
    for (i=0;i<st->lpcSize+1;i++)
       st->lagWindow[i]=exp(-.5*sqr(2*M_PI*st->lag_factor*i));
 
-   st->autocorr = speex_alloc((st->lpcSize+1)*sizeof(float));
+   st->autocorr = (float*)speex_alloc((st->lpcSize+1)*sizeof(float));
 
-   st->stack = speex_alloc(20000*sizeof(float));
+   st->stack = (float*)speex_alloc(20000*sizeof(float));
+
+   st->buf2 = (float*)speex_alloc(st->windowSize*sizeof(float));
 
-   st->buf2 = speex_alloc(st->windowSize*sizeof(float));
-
-   st->lpc = speex_alloc((st->lpcSize+1)*sizeof(float));
-   st->interp_lpc = speex_alloc((st->lpcSize+1)*sizeof(float));
-   st->interp_qlpc = speex_alloc((st->lpcSize+1)*sizeof(float));
-   st->bw_lpc1 = speex_alloc((st->lpcSize+1)*sizeof(float));
-   st->bw_lpc2 = speex_alloc((st->lpcSize+1)*sizeof(float));
-
-   st->lsp = speex_alloc(st->lpcSize*sizeof(float));
-   st->qlsp = speex_alloc(st->lpcSize*sizeof(float));
-   st->old_lsp = speex_alloc(st->lpcSize*sizeof(float));
-   st->old_qlsp = speex_alloc(st->lpcSize*sizeof(float));
-   st->interp_lsp = speex_alloc(st->lpcSize*sizeof(float));
-   st->interp_qlsp = speex_alloc(st->lpcSize*sizeof(float));
-   st->rc = speex_alloc(st->lpcSize*sizeof(float));
+   st->lpc = (float*)speex_alloc((st->lpcSize+1)*sizeof(float));
+   st->interp_lpc = (float*)speex_alloc((st->lpcSize+1)*sizeof(float));
+   st->interp_qlpc = (float*)speex_alloc((st->lpcSize+1)*sizeof(float));
+   st->bw_lpc1 = (float*)speex_alloc((st->lpcSize+1)*sizeof(float));
+   st->bw_lpc2 = (float*)speex_alloc((st->lpcSize+1)*sizeof(float));
+
+   st->lsp = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->qlsp = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->old_lsp = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->old_qlsp = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->interp_lsp = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->interp_qlsp = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->rc = (float*)speex_alloc(st->lpcSize*sizeof(float));
    st->first = 1;
    for (i=0;i<st->lpcSize;i++)
    {
       st->lsp[i]=(M_PI*((float)(i+1)))/(st->lpcSize+1);
    }
 
-   st->mem_sp = speex_alloc(st->lpcSize*sizeof(float));
-   st->mem_sw = speex_alloc(st->lpcSize*sizeof(float));
-   st->mem_sw_whole = speex_alloc(st->lpcSize*sizeof(float));
-   st->mem_exc = speex_alloc(st->lpcSize*sizeof(float));
+   st->mem_sp = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->mem_sw = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->mem_sw_whole = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->mem_exc = (float*)speex_alloc(st->lpcSize*sizeof(float));
 
-   st->pi_gain = speex_alloc(st->nbSubframes*sizeof(float));
+   st->pi_gain = (float*)speex_alloc(st->nbSubframes*sizeof(float));
 
-   st->pitch = speex_alloc(st->nbSubframes*sizeof(int));
+   st->pitch = (int*)speex_alloc(st->nbSubframes*sizeof(int));
 
    if (1) {
-      st->vbr = speex_alloc(sizeof(VBRState));
+      st->vbr = (VBRState*)speex_alloc(sizeof(VBRState));
       vbr_init(st->vbr);
       st->vbr_quality = 8;
       st->vbr_enabled = 0;
@@ -164,20 +171,21 @@ void *nb_encoder_init(SpeexMode *m)
       st->vbr = 0;
    }
    st->complexity=2;
+   st->sampling_rate=8000;
 
    return st;
 }
 
 void nb_encoder_destroy(void *state)
 {
-   EncState *st=state;
+   EncState *st=(EncState *)state;
    /* Free all allocated memory */
    speex_free(st->inBuf);
    speex_free(st->excBuf);
    speex_free(st->swBuf);
    speex_free(st->exc2Buf);
    speex_free(st->innov);
-   speex_free(st->stack);
+   speex_free((float*)st->stack);
 
    speex_free(st->window);
    speex_free(st->buf2);
@@ -208,7 +216,7 @@ void nb_encoder_destroy(void *state)
    speex_free(st->vbr);
 
    /*Free state memory... should be last*/
-   speex_free(st);
+   speex_free((float*)st);
 }
 
 void nb_encode(void *state, float *in, SpeexBits *bits)
@@ -218,12 +226,11 @@ void nb_encode(void *state, float *in, SpeexBits *bits)
    int ol_pitch;
    float ol_pitch_coef;
    float ol_gain;
-   float delta_qual=0;
    float *res, *target, *mem;
-   float *stack;
+   void *stack;
    float *syn_resp;
 
-   st=state;
+   st=(EncState *)state;
    stack=st->stack;
 
    /* Copy new data in input buffer */
@@ -244,7 +251,7 @@ void nb_encode(void *state, float *in, SpeexBits *bits)
       st->buf2[i] = st->frame[i] * st->window[i];
 
    /* Compute auto-correlation */
-   autocorr(st->buf2, st->autocorr, st->lpcSize+1, st->windowSize);
+   _spx_autocorr(st->buf2, st->autocorr, st->lpcSize+1, st->windowSize);
 
    st->autocorr[0] += 10;        /* prevents NANs */
    st->autocorr[0] *= st->lpc_floor; /* Noise floor in auto-correlation domain */
@@ -357,21 +364,34 @@ void nb_encode(void *state, float *in, SpeexBits *bits)
    /*Experimental VBR stuff*/
    if (st->vbr)
    {
-      delta_qual = vbr_analysis(st->vbr, in, st->frameSize, ol_pitch, ol_pitch_coef);
+      st->relative_quality = vbr_analysis(st->vbr, in, st->frameSize, ol_pitch, ol_pitch_coef);
       /*if (delta_qual<0)*/
-         delta_qual*=.1*(3+st->vbr_quality);
+      /*  delta_qual*=.1*(3+st->vbr_quality);*/
       if (st->vbr_enabled) 
       {
-         int qual = (int)floor(st->vbr_quality+delta_qual+.5);
-         if (qual<1 && delta_qual>-3.5)
-            qual=1;
-         if (qual<0)
-            qual=0;
-         if (qual>10)
-            qual=10;
-         if (qual==10 && st->vbr_quality<10)
-            qual=9;
-         speex_encoder_ctl(state, SPEEX_SET_QUALITY, &qual);
+         int mode;
+         mode = 7;
+         while (mode)
+         {
+            int v1;
+            float thresh;
+            v1=(int)floor(st->vbr_quality);
+            if (v1==10)
+               thresh = vbr_nb_thresh[mode][v1];
+            else
+               thresh = (st->vbr_quality-v1)*vbr_nb_thresh[mode][v1+1] + (1+v1-st->vbr_quality)*vbr_nb_thresh[mode][v1];
+            if (st->relative_quality > thresh)
+               break;
+            mode--;
+         }
+         /*fprintf(stderr, "");
+         fprintf (stderr, "encode %f %d\n", st->relative_quality, mode);
+         fprintf(stderr, "encode: %d %d\n",st->submodeID, mode);*/
+
+         speex_encoder_ctl(state, SPEEX_SET_MODE, &mode);
+         /*fprintf(stderr, "encode: %d %d\n",st->submodeID, mode);*/
+      } else {
+         st->relative_quality = -1;
       }
    }
    /*printf ("VBR quality = %f\n", vbr_qual);*/
@@ -394,7 +414,7 @@ void nb_encode(void *state, float *in, SpeexBits *bits)
       st->first=1;
 
       /* Final signal synthesis from excitation */
-      iir_mem2(st->exc, st->interp_qlpc, st->frame, st->subframeSize, st->lpcSize, st->mem_sp);
+      iir_mem2(st->exc, st->interp_qlpc, st->frame, st->frameSize, st->lpcSize, st->mem_sp);
 
       in[0] = st->frame[0] + st->preemph*st->pre_mem2;
       for (i=1;i<st->frameSize;i++)
@@ -451,11 +471,11 @@ void nb_encode(void *state, float *in, SpeexBits *bits)
    }
 
    /* Filter response */
-   res = PUSH(stack, st->subframeSize);
+   res = PUSH(stack, st->subframeSize, float);
    /* Target signal */
-   target = PUSH(stack, st->subframeSize);
-   syn_resp = PUSH(stack, st->subframeSize);
-   mem = PUSH(stack, st->lpcSize);
+   target = PUSH(stack, st->subframeSize, float);
+   syn_resp = PUSH(stack, st->subframeSize, float);
+   mem = PUSH(stack, st->lpcSize, float);
 
    /* Loop on sub-frames */
    for (sub=0;sub<st->nbSubframes;sub++)
@@ -505,7 +525,6 @@ void nb_encode(void *state, float *in, SpeexBits *bits)
          st->pi_gain[sub] += tmp*st->interp_qlpc[i];
          tmp = -tmp;
       }
-     
 
       /* Compute bandwidth-expanded (unquantized) LPCs for perceptual weighting */
       bw_lpc(st->gamma1, st->interp_lpc, st->bw_lpc1, st->lpcSize);
@@ -671,8 +690,8 @@ void nb_encode(void *state, float *in, SpeexBits *bits)
 
          /* In some (rare) modes, we do a second search (more bits) to reduce noise even more */
          if (SUBMODE(double_codebook)) {
-            float *tmp_stack=stack;
-            float *innov2 = PUSH(tmp_stack, st->subframeSize);
+            void *tmp_stack=stack;
+            float *innov2 = PUSH(tmp_stack, st->subframeSize, float);
             for (i=0;i<st->subframeSize;i++)
                innov2[i]=0;
             for (i=0;i<st->subframeSize;i++)
@@ -731,8 +750,8 @@ void *nb_decoder_init(SpeexMode *m)
    SpeexNBMode *mode;
    int i;
 
-   mode=m->mode;
-   st = speex_alloc(sizeof(DecState));
+   mode=(SpeexNBMode*)m->mode;
+   st = (DecState *)speex_alloc(sizeof(DecState));
    st->mode=m;
 
    st->first=1;
@@ -757,26 +776,26 @@ void *nb_decoder_init(SpeexMode *m)
 
    st->stack = speex_alloc(20000*sizeof(float));
 
-   st->inBuf = speex_alloc(st->bufSize*sizeof(float));
+   st->inBuf = (float*)speex_alloc(st->bufSize*sizeof(float));
    st->frame = st->inBuf + st->bufSize - st->windowSize;
-   st->excBuf = speex_alloc(st->bufSize*sizeof(float));
+   st->excBuf = (float*)speex_alloc(st->bufSize*sizeof(float));
    st->exc = st->excBuf + st->bufSize - st->windowSize;
    for (i=0;i<st->bufSize;i++)
       st->inBuf[i]=0;
    for (i=0;i<st->bufSize;i++)
       st->excBuf[i]=0;
-   st->innov = speex_alloc(st->frameSize*sizeof(float));
+   st->innov = (float*)speex_alloc(st->frameSize*sizeof(float));
 
-   st->interp_qlpc = speex_alloc((st->lpcSize+1)*sizeof(float));
-   st->qlsp = speex_alloc(st->lpcSize*sizeof(float));
-   st->old_qlsp = speex_alloc(st->lpcSize*sizeof(float));
-   st->interp_qlsp = speex_alloc(st->lpcSize*sizeof(float));
-   st->mem_sp = speex_alloc(5*st->lpcSize*sizeof(float));
+   st->interp_qlpc = (float*)speex_alloc((st->lpcSize+1)*sizeof(float));
+   st->qlsp = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->old_qlsp = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->interp_qlsp = (float*)speex_alloc(st->lpcSize*sizeof(float));
+   st->mem_sp = (float*)speex_alloc(5*st->lpcSize*sizeof(float));
 
-   st->pi_gain = speex_alloc(st->nbSubframes*sizeof(float));
+   st->pi_gain = (float*)speex_alloc(st->nbSubframes*sizeof(float));
    st->last_pitch = 40;
    st->count_lost=0;
-
+   st->sampling_rate=8000;
 
    st->user_callback.func = &speex_default_user_handler;
    st->user_callback.data = NULL;
@@ -789,7 +808,7 @@ void *nb_decoder_init(SpeexMode *m)
 void nb_decoder_destroy(void *state)
 {
    DecState *st;
-   st=state;
+   st=(DecState*)state;
    speex_free(st->inBuf);
    speex_free(st->excBuf);
    speex_free(st->innov);
@@ -804,7 +823,7 @@ void nb_decoder_destroy(void *state)
    speex_free(state);
 }
 
-static void nb_decode_lost(DecState *st, float *out, float *stack)
+static void nb_decode_lost(DecState *st, float *out, void *stack)
 {
    int i, sub;
    float *awk1, *awk2, *awk3;
@@ -813,9 +832,9 @@ static void nb_decode_lost(DecState *st, float *out, float *stack)
    speex_move(st->inBuf, st->inBuf+st->frameSize, (st->bufSize-st->frameSize)*sizeof(float));
    speex_move(st->excBuf, st->excBuf+st->frameSize, (st->bufSize-st->frameSize)*sizeof(float));
 
-   awk1=PUSH(stack, (st->lpcSize+1));
-   awk2=PUSH(stack, (st->lpcSize+1));
-   awk3=PUSH(stack, (st->lpcSize+1));
+   awk1=PUSH(stack, (st->lpcSize+1), float);
+   awk2=PUSH(stack, (st->lpcSize+1), float);
+   awk3=PUSH(stack, (st->lpcSize+1), float);
 
    for (sub=0;sub<st->nbSubframes;sub++)
    {
@@ -899,9 +918,9 @@ int nb_decode(void *state, SpeexBits *bits, float *out)
    float best_pitch_gain=-1;
    int wideband;
    int m;
-   float *stack;
+   void *stack;
    float *awk1, *awk2, *awk3;
-   st=state;
+   st=(DecState*)state;
    stack=st->stack;
 
    /* If bits is NULL, consider the packet to be lost (what could we do anyway) */
@@ -964,9 +983,9 @@ int nb_decode(void *state, SpeexBits *bits, float *out)
       for (i=0;i<st->frameSize;i++)
          st->exc[i]=0;
       st->first=1;
-      
+
       /* Final signal synthesis from excitation */
-      iir_mem2(st->exc, st->interp_qlpc, st->frame, st->subframeSize, st->lpcSize, st->mem_sp);
+      iir_mem2(st->exc, st->interp_qlpc, st->frame, st->frameSize, st->lpcSize, st->mem_sp);
 
       out[0] = st->frame[0] + st->preemph*st->pre_mem;
       for (i=1;i<st->frameSize;i++)
@@ -1008,9 +1027,9 @@ int nb_decode(void *state, SpeexBits *bits, float *out)
       /*printf ("decode_ol_gain: %f\n", ol_gain);*/
    }
 
-   awk1=PUSH(stack, st->lpcSize+1);
-   awk2=PUSH(stack, st->lpcSize+1);
-   awk3=PUSH(stack, st->lpcSize+1);
+   awk1=PUSH(stack, st->lpcSize+1, float);
+   awk2=PUSH(stack, st->lpcSize+1, float);
+   awk3=PUSH(stack, st->lpcSize+1, float);
 
    /*Loop on subframes */
    for (sub=0;sub<st->nbSubframes;sub++)
@@ -1156,8 +1175,8 @@ int nb_decode(void *state, SpeexBits *bits, float *out)
          /* Decode second codebook (only for some modes) */
          if (SUBMODE(double_codebook))
          {
-            float *tmp_stack=stack;
-            float *innov2 = PUSH(tmp_stack, st->subframeSize);
+            void *tmp_stack=stack;
+            float *innov2 = PUSH(tmp_stack, st->subframeSize, float);
             for (i=0;i<st->subframeSize;i++)
                innov2[i]=0;
             SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, bits, tmp_stack);
@@ -1215,7 +1234,7 @@ int nb_decode(void *state, SpeexBits *bits, float *out)
 void nb_encoder_ctl(void *state, int request, void *ptr)
 {
    EncState *st;
-   st=state;     
+   st=(EncState*)state;     
    switch(request)
    {
    case SPEEX_GET_FRAME_SIZE:
@@ -1236,14 +1255,15 @@ void nb_encoder_ctl(void *state, int request, void *ptr)
       (*(int*)ptr) = st->vbr_enabled;
       break;
    case SPEEX_SET_VBR_QUALITY:
-      st->vbr_quality = (*(int*)ptr);
+      st->vbr_quality = (*(float*)ptr);
       break;
    case SPEEX_GET_VBR_QUALITY:
-      (*(int*)ptr) = st->vbr_quality;
+      (*(float*)ptr) = st->vbr_quality;
       break;
    case SPEEX_SET_QUALITY:
       {
          int quality = (*(int*)ptr);
+         /*
          if (quality<=0)
             st->submodeID = 0;
          else if (quality<=1)
@@ -1261,7 +1281,12 @@ void nb_encoder_ctl(void *state, int request, void *ptr)
          else if (quality<=10)
             st->submodeID = 7;
          else
-            fprintf(stderr, "Unknown nb_ctl quality: %d\n", quality);
+         fprintf(stderr, "Unknown nb_ctl quality: %d\n", quality);*/
+         if (quality < 0)
+            quality = 0;
+         if (quality > 10)
+            quality = 10;
+         st->submodeID = ((SpeexNBMode*)(st->mode->mode))->quality_map[quality];
       }
       break;
    case SPEEX_SET_COMPLEXITY:
@@ -1272,11 +1297,58 @@ void nb_encoder_ctl(void *state, int request, void *ptr)
    case SPEEX_GET_COMPLEXITY:
       (*(int*)ptr) = st->complexity;
       break;
+   case SPEEX_SET_BITRATE:
+      {
+         int i=10, rate, target;
+         target = (*(int*)ptr);
+         while (i>=1)
+         {
+            speex_encoder_ctl(st, SPEEX_SET_QUALITY, &i);
+            speex_encoder_ctl(st, SPEEX_GET_BITRATE, &rate);
+            if (rate <= target)
+               break;
+            i--;
+         }
+      }
+      break;
    case SPEEX_GET_BITRATE:
       if (st->submodes[st->submodeID])
-         (*(int*)ptr) = 50*SUBMODE(bits_per_frame);
+         (*(int*)ptr) = st->sampling_rate*SUBMODE(bits_per_frame)/st->frameSize;
       else
-         (*(int*)ptr) = 50*(NB_SUBMODE_BITS+1);
+         (*(int*)ptr) = st->sampling_rate*(NB_SUBMODE_BITS+1)/st->frameSize;
+      break;
+   case SPEEX_SET_SAMPLING_RATE:
+      st->sampling_rate = (*(int*)ptr);
+      break;
+   case SPEEX_GET_SAMPLING_RATE:
+      (*(int*)ptr)=st->sampling_rate;
+      break;
+   case SPEEX_GET_PI_GAIN:
+      {
+         int i;
+         float *g = (float*)ptr;
+         for (i=0;i<st->nbSubframes;i++)
+            g[i]=st->pi_gain[i];
+      }
+      break;
+   case SPEEX_GET_EXC:
+      {
+         int i;
+         float *e = (float*)ptr;
+         for (i=0;i<st->frameSize;i++)
+            e[i]=st->exc[i];
+      }
+      break;
+   case SPEEX_GET_INNOV:
+      {
+         int i;
+         float *e = (float*)ptr;
+         for (i=0;i<st->frameSize;i++)
+            e[i]=st->innov[i];
+      }
+      break;
+   case SPEEX_GET_RELATIVE_QUALITY:
+      (*(float*)ptr)=st->relative_quality;
       break;
    default:
       fprintf(stderr, "Unknown nb_ctl request: %d\n", request);
@@ -1286,7 +1358,7 @@ void nb_encoder_ctl(void *state, int request, void *ptr)
 void nb_decoder_ctl(void *state, int request, void *ptr)
 {
    DecState *st;
-   st=state;
+   st=(DecState*)state;
    switch(request)
    {
    case SPEEX_SET_ENH:
@@ -1300,13 +1372,19 @@ void nb_decoder_ctl(void *state, int request, void *ptr)
       break;
    case SPEEX_GET_BITRATE:
       if (st->submodes[st->submodeID])
-         (*(int*)ptr) = 50*SUBMODE(bits_per_frame);
+         (*(int*)ptr) = st->sampling_rate*SUBMODE(bits_per_frame)/st->frameSize;
       else
-         (*(int*)ptr) = 50*(NB_SUBMODE_BITS+1);
+         (*(int*)ptr) = st->sampling_rate*(NB_SUBMODE_BITS+1)/st->frameSize;
+      break;
+   case SPEEX_SET_SAMPLING_RATE:
+      st->sampling_rate = (*(int*)ptr);
+      break;
+   case SPEEX_GET_SAMPLING_RATE:
+      (*(int*)ptr)=st->sampling_rate;
       break;
    case SPEEX_SET_HANDLER:
       {
-         SpeexCallback *c = ptr;
+         SpeexCallback *c = (SpeexCallback*)ptr;
          st->speex_callbacks[c->callback_id].func=c->func;
          st->speex_callbacks[c->callback_id].data=c->data;
          st->speex_callbacks[c->callback_id].callback_id=c->callback_id;
@@ -1314,12 +1392,36 @@ void nb_decoder_ctl(void *state, int request, void *ptr)
       break;
    case SPEEX_SET_USER_HANDLER:
       {
-         SpeexCallback *c = ptr;
+         SpeexCallback *c = (SpeexCallback*)ptr;
          st->user_callback.func=c->func;
          st->user_callback.data=c->data;
          st->user_callback.callback_id=c->callback_id;
       }
       break;
+   case SPEEX_GET_PI_GAIN:
+      {
+         int i;
+         float *g = (float*)ptr;
+         for (i=0;i<st->nbSubframes;i++)
+            g[i]=st->pi_gain[i];
+      }
+      break;
+   case SPEEX_GET_EXC:
+      {
+         int i;
+         float *e = (float*)ptr;
+         for (i=0;i<st->frameSize;i++)
+            e[i]=st->exc[i];
+      }
+      break;
+   case SPEEX_GET_INNOV:
+      {
+         int i;
+         float *e = (float*)ptr;
+         for (i=0;i<st->frameSize;i++)
+            e[i]=st->innov[i];
+      }
+      break;
    default:
       fprintf(stderr, "Unknown nb_ctl request: %d\n", request);
    }