infrastructure changes for upcoming stereo improvements
[opus.git] / libcelt / modes.c
index 496f242..89ba428 100644 (file)
@@ -1,4 +1,4 @@
-/* (C) 2007 Jean-Marc Valin, CSIRO
+/* (C) 2007-2008 Jean-Marc Valin, CSIRO
 */
 /*
    Redistribution and use in source and binary forms, with or without
 #include "modes.h"
 #include "rate.h"
 #include "os_support.h"
+#include "stack_alloc.h"
+#include "quant_bands.h"
 
-int celt_mode_info(const CELTMode *mode, int request, celt_int32_t *value)
+#ifdef STATIC_MODES
+#include "static_modes.c"
+#endif
+
+#define MODEVALID 0xa110ca7e
+#define MODEFREED 0xb10cf8ee
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+
+int EXPORT celt_mode_info(const CELTMode *mode, int request, celt_int32_t *value)
 {
    switch (request)
    {
@@ -51,14 +65,25 @@ int celt_mode_info(const CELTMode *mode, int request, celt_int32_t *value)
       case CELT_GET_NB_CHANNELS:
          *value = mode->nbChannels;
          break;
+      case CELT_GET_BITSTREAM_VERSION:
+         *value = CELT_BITSTREAM_VERSION;
+         break;
       default:
          return CELT_BAD_ARG;
    }
    return CELT_OK;
 }
 
+#ifndef STATIC_MODES
+
 #define PBANDS 8
-#define MIN_BINS 4
+
+#ifdef STDIN_TUNING
+int MIN_BINS;
+#else
+#define MIN_BINS 3
+#endif
+
 /* Defining 25 critical bands for the full 0-20 kHz audio bandwidth
    Taken from http://ccrma.stanford.edu/~jos/bbt/Bark_Frequency_Scale.html */
 #define BARK_BANDS 25
@@ -74,24 +99,29 @@ static const celt_int16_t pitch_freq[PBANDS+1] ={0, 345, 689, 1034, 1378, 2067,
 
 /* This allocation table is per critical band. When creating a mode, the bits get added together 
    into the codec bands, which are sometimes larger than one critical band at low frequency */
+
+#ifdef STDIN_TUNING
+int BITALLOC_SIZE;
+int *band_allocation;
+#else
 #define BITALLOC_SIZE 10
 static const int band_allocation[BARK_BANDS*BITALLOC_SIZE] = 
    {  2,  2,  1,  1,  2,  2,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-      2,  2,  2,  1,  2,  2,  2,  2,  2,  1,  2,  2,  5,  5,  7,  7,  7,  5,  4,  0,  0,  0,  0,  0,  0,
-      2,  2,  2,  2,  3,  2,  2,  2,  2,  2,  3,  2,  6,  6,  8,  8,  8,  6,  5,  4,  0,  0,  0,  0,  0,
-      3,  2,  2,  2,  3,  3,  2,  3,  2,  2,  4,  3,  7,  7,  9,  9,  9,  7,  6,  5,  5,  5,  0,  0,  0,
-      3,  3,  2,  2,  3,  3,  3,  3,  3,  2,  4,  4,  9,  9, 10, 10, 10,  9,  6,  5,  5,  5,  5,  0,  0,
-      3,  3,  2,  2,  3,  3,  3,  3,  3,  3,  4,  4, 10, 10, 12, 12, 12, 10, 10, 10, 11, 10, 10,  5,  5,
-      4,  4,  4,  4,  5,  5,  5,  5,  5,  4,  7,  7, 14, 13, 13, 13, 13, 13, 15, 16, 17, 18, 20, 18, 11,
-      7,  7,  6,  6,  9,  8,  8,  8,  8,  8, 11, 11, 20, 18, 19, 19, 25, 22, 25, 30, 30, 35, 35, 35, 35,
-      8,  8,  8,  8, 10, 10, 10, 10,  9,  9, 19, 18, 25, 24, 23, 21, 29, 27, 35, 40, 42, 50, 59, 54, 51,
-     11, 11, 10, 10, 14, 13, 13, 13, 13, 12, 19, 18, 35, 34, 33, 31, 39, 37, 45, 50, 52, 60, 60, 60, 60,
-   };
-
+      2,  2,  2,  1,  2,  2,  2,  2,  2,  1,  2,  2,  4,  5,  7,  7,  7,  5,  4,  0,  0,  0,  0,  0,  0,
+      2,  2,  2,  2,  3,  2,  2,  2,  2,  2,  3,  3,  5,  6,  8,  8,  8,  6,  5,  4,  0,  0,  0,  0,  0,
+      3,  2,  2,  2,  3,  3,  2,  3,  2,  3,  4,  4,  6,  7,  9,  9,  9,  7,  6,  5,  5,  5,  0,  0,  0,
+      3,  3,  2,  2,  3,  3,  3,  3,  3,  4,  4,  5,  7,  9, 10, 10, 10,  9,  6,  5,  5,  5,  5,  1,  0,
+      4,  3,  3,  3,  3,  3,  3,  3,  4,  4,  6,  7,  7,  9, 11, 10, 10,  9,  9,  8, 11, 10, 10,  1,  1,
+      5,  5,  4,  4,  5,  5,  5,  5,  6,  6,  8,  8, 10, 12, 15, 15, 13, 12, 12, 12, 18, 18, 16, 10,  1,
+      6,  6,  6,  6,  6,  6,  7,  7,  9,  9, 11, 12, 13, 18, 22, 23, 24, 25, 28, 30, 35, 35, 35, 35, 15,
+      7,  7,  7,  7,  7,  7, 10, 10, 10, 13, 14, 18, 20, 24, 28, 32, 32, 35, 38, 38, 42, 50, 59, 54, 31,
+      8,  8,  8,  8,  8,  9, 10, 12, 14, 20, 22, 25, 28, 30, 35, 42, 46, 50, 55, 60, 62, 62, 62, 62, 62,
+};
+#endif
 
-static int *compute_ebands(int Fs, int frame_size, int *nbEBands)
+static celt_int16_t *compute_ebands(celt_int32_t Fs, int frame_size, int *nbEBands)
 {
-   int *eBands;
+   celt_int16_t *eBands;
    int i, res, min_width, lin, low, high;
    res = (Fs+frame_size)/(2*frame_size);
    min_width = MIN_BINS*res;
@@ -106,7 +136,7 @@ static int *compute_ebands(int Fs, int frame_size, int *nbEBands)
    low = ((bark_freq[lin]/res)+(MIN_BINS-1))/MIN_BINS;
    high = BARK_BANDS-lin;
    *nbEBands = low+high;
-   eBands = celt_alloc(sizeof(int)*(*nbEBands+2));
+   eBands = celt_alloc(sizeof(celt_int16_t)*(*nbEBands+2));
    
    /* Linear spacing (min_width) */
    for (i=0;i<low;i++)
@@ -133,8 +163,8 @@ static int *compute_ebands(int Fs, int frame_size, int *nbEBands)
 static void compute_pbands(CELTMode *mode, int res)
 {
    int i;
-   int *pBands;
-   pBands=celt_alloc(sizeof(int)*(PBANDS+2));
+   celt_int16_t *pBands;
+   pBands=celt_alloc(sizeof(celt_int16_t)*(PBANDS+2));
    mode->nbPBands = PBANDS;
    for (i=0;i<PBANDS+1;i++)
    {
@@ -169,10 +199,10 @@ static void compute_pbands(CELTMode *mode, int res)
 static void compute_allocation_table(CELTMode *mode, int res)
 {
    int i, j, eband;
-   int *allocVectors;
+   celt_int16_t *allocVectors;
    
    mode->nbAllocVectors = BITALLOC_SIZE;
-   allocVectors = celt_alloc(sizeof(int)*(BITALLOC_SIZE*mode->nbEBands));
+   allocVectors = celt_alloc(sizeof(celt_int16_t)*(BITALLOC_SIZE*mode->nbEBands));
    for (i=0;i<BITALLOC_SIZE;i++)
    {
       eband = 0;
@@ -203,13 +233,82 @@ static void compute_allocation_table(CELTMode *mode, int res)
    mode->allocVectors = allocVectors;
 }
 
+#endif /* STATIC_MODES */
 
+static void compute_energy_allocation_table(CELTMode *mode)
+{
+   int i, j;
+   celt_int16_t *alloc;
+   
+   alloc = celt_alloc(sizeof(celt_int16_t)*(mode->nbAllocVectors*(mode->nbEBands+1)));
+   for (i=0;i<mode->nbAllocVectors;i++)
+   {
+      int sum = 0;
+      int min_bits = 1;
+      if (mode->allocVectors[i*mode->nbEBands]>12)
+         min_bits = 2;
+      if (mode->allocVectors[i*mode->nbEBands]>24)
+         min_bits = 3;
+      for (j=0;j<mode->nbEBands;j++)
+      {
+         alloc[i*(mode->nbEBands+1)+j] = mode->allocVectors[i*mode->nbEBands+j]
+                                         / (mode->eBands[j+1]-mode->eBands[j]-1);
+         if (alloc[i*(mode->nbEBands+1)+j]<min_bits)
+            alloc[i*(mode->nbEBands+1)+j] = min_bits;
+         if (alloc[i*(mode->nbEBands+1)+j]>7)
+            alloc[i*(mode->nbEBands+1)+j] = 7;
+         sum += alloc[i*(mode->nbEBands+1)+j];
+         /*printf ("%d ", alloc[i*(mode->nbEBands+1)+j]);*/
+         /*printf ("%f ", mode->allocVectors[i*mode->nbEBands+j]*1.f/(mode->eBands[j+1]-mode->eBands[j]-1));*/
+      }
+      alloc[i*(mode->nbEBands+1)+mode->nbEBands] = sum;
+      /*printf ("\n");*/
+   }
+   mode->energy_alloc = alloc;
+}
 
-CELTMode *celt_mode_create(int Fs, int channels, int frame_size, int lookahead, int *error)
+CELTMode EXPORT *celt_mode_create(celt_int32_t Fs, int channels, int frame_size, int lookahead, int *error)
 {
+   int i;
+#ifdef STDIN_TUNING
+   scanf("%d ", &MIN_BINS);
+   scanf("%d ", &BITALLOC_SIZE);
+   band_allocation = celt_alloc(sizeof(int)*BARK_BANDS*BITALLOC_SIZE);
+   for (i=0;i<BARK_BANDS*BITALLOC_SIZE;i++)
+   {
+      scanf("%d ", band_allocation+i);
+   }
+#endif
+#ifdef STATIC_MODES
+   const CELTMode *m = NULL;
+   CELTMode *mode=NULL;
+   ALLOC_STACK;
+   for (i=0;i<TOTAL_MODES;i++)
+   {
+      if (Fs == static_mode_list[i]->Fs &&
+          channels == static_mode_list[i]->nbChannels &&
+          frame_size == static_mode_list[i]->mdctSize &&
+          lookahead == static_mode_list[i]->overlap)
+      {
+         m = static_mode_list[i];
+         break;
+      }
+   }
+   if (m == NULL)
+   {
+      celt_warning("Mode not included as part of the static modes");
+      if (error)
+         *error = CELT_BAD_ARG;
+      return NULL;
+   }
+   mode = (CELTMode*)celt_alloc(sizeof(CELTMode));
+   CELT_COPY(mode, m, 1);
+#else
    int res;
    CELTMode *mode;
-   
+   celt_word16_t *window;
+   ALLOC_STACK;
+
    /* The good thing here is that permutation of the arguments will automatically be invalid */
    
    if (Fs < 32000 || Fs > 64000)
@@ -243,28 +342,53 @@ CELTMode *celt_mode_create(int Fs, int channels, int frame_size, int lookahead,
    res = (Fs+frame_size)/(2*frame_size);
    
    mode = celt_alloc(sizeof(CELTMode));
+   mode->Fs = Fs;
    mode->overlap = lookahead;
    mode->mdctSize = frame_size;
-   mode->nbMdctBlocks = 1;
    mode->nbChannels = channels;
    mode->eBands = compute_ebands(Fs, frame_size, &mode->nbEBands);
    compute_pbands(mode, res);
-   mode->ePredCoef = .8;
+   mode->ePredCoef = QCONST16(.8f,15);
    
    compute_allocation_table(mode, res);
-   compute_alloc_cache(mode);
    /*printf ("%d bands\n", mode->nbEBands);*/
+   
+   window = (celt_word16_t*)celt_alloc(mode->overlap*sizeof(celt_word16_t));
+
+#ifndef FIXED_POINT
+   for (i=0;i<mode->overlap;i++)
+      window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap));
+#else
+   for (i=0;i<mode->overlap;i++)
+      window[i] = MIN32(32767,32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)));
+#endif
+   mode->window = window;
+
+   mode->bits = (const celt_int16_t **)compute_alloc_cache(mode, mode->nbChannels);
+
+#ifndef SHORTCUTS
+   psydecay_init(&mode->psy, MAX_PERIOD/2, mode->Fs);
+#endif
+   
+   mode->marker_start = MODEVALID;
+   mode->marker_end = MODEVALID;
+#endif /* !STATIC_MODES */
+   mdct_init(&mode->mdct, 2*mode->mdctSize);
+   mode->fft = pitch_state_alloc(MAX_PERIOD);
+
+   mode->prob = quant_prob_alloc(mode);
+   compute_energy_allocation_table(mode);
+   
+   if (error)
+      *error = CELT_OK;
    return mode;
 }
 
-void celt_mode_destroy(CELTMode *mode)
+void EXPORT celt_mode_destroy(CELTMode *mode)
 {
+#ifndef STATIC_MODES
    int i;
-   const int *prevPtr = NULL;
-   celt_free((int*)mode->eBands);
-   celt_free((int*)mode->pBands);
-   celt_free((int*)mode->allocVectors);
-   
+   const celt_int16_t *prevPtr = NULL;
    for (i=0;i<mode->nbEBands;i++)
    {
       if (mode->bits[i] != prevPtr)
@@ -274,7 +398,34 @@ void celt_mode_destroy(CELTMode *mode)
       }
    }
    celt_free((int**)mode->bits);
+   if (check_mode(mode) != CELT_OK)
+      return;
+   celt_free((int*)mode->eBands);
+   celt_free((int*)mode->pBands);
+   celt_free((int*)mode->allocVectors);
+   
+   celt_free((celt_word16_t*)mode->window);
 
+   mode->marker_start = MODEFREED;
+   mode->marker_end = MODEFREED;
+#ifndef SHORTCUTS
+   psydecay_clear(&mode->psy);
+#endif
+#endif
+   mdct_clear(&mode->mdct);
+   pitch_state_free(mode->fft);
+   quant_prob_free(mode->prob);
+   celt_free((celt_int16_t *)mode->energy_alloc);
    celt_free((CELTMode *)mode);
+}
 
+int check_mode(const CELTMode *mode)
+{
+   if (mode->marker_start == MODEVALID && mode->marker_end == MODEVALID)
+      return CELT_OK;
+   if (mode->marker_start == MODEFREED || mode->marker_end == MODEFREED)
+      celt_warning("Using a mode that has already been freed");
+   else
+      celt_warning("This is not a valid CELT mode");
+   return CELT_INVALID_MODE;
 }