static int update_filter()

in subprojects/speex/resample.c [605:792]


static int update_filter(SpeexResamplerState *st)
{
   spx_uint32_t old_length = st->filt_len;
   spx_uint32_t old_alloc_size = st->mem_alloc_size;
   int use_direct;
   spx_uint32_t min_sinc_table_length;
   spx_uint32_t min_alloc_size;

   st->int_advance = st->num_rate/st->den_rate;
   st->frac_advance = st->num_rate%st->den_rate;
   st->oversample = quality_map[st->quality].oversample;
   st->filt_len = quality_map[st->quality].base_length;

   if (st->num_rate > st->den_rate)
   {
      /* down-sampling */
      st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate;
      if (_muldiv(&st->filt_len,st->filt_len,st->num_rate,st->den_rate) != RESAMPLER_ERR_SUCCESS)
         goto fail;
      /* Round up to make sure we have a multiple of 8 for SSE */
      st->filt_len = ((st->filt_len-1)&(~0x7))+8;
      if (2*st->den_rate < st->num_rate)
         st->oversample >>= 1;
      if (4*st->den_rate < st->num_rate)
         st->oversample >>= 1;
      if (8*st->den_rate < st->num_rate)
         st->oversample >>= 1;
      if (16*st->den_rate < st->num_rate)
         st->oversample >>= 1;
      if (st->oversample < 1)
         st->oversample = 1;
   } else {
      /* up-sampling */
      st->cutoff = quality_map[st->quality].upsample_bandwidth;
   }

   /* Choose the resampling type that requires the least amount of memory */
#ifdef RESAMPLE_FULL_SINC_TABLE
   use_direct = 1;
   if (INT_MAX/sizeof(spx_word16_t)/st->den_rate < st->filt_len)
      goto fail;
#else
   use_direct = st->filt_len*st->den_rate <= st->filt_len*st->oversample+8
                && INT_MAX/sizeof(spx_word16_t)/st->den_rate >= st->filt_len;
#endif
   if (use_direct)
   {
      min_sinc_table_length = st->filt_len*st->den_rate;
   } else {
      if ((INT_MAX/sizeof(spx_word16_t)-8)/st->oversample < st->filt_len)
         goto fail;

      min_sinc_table_length = st->filt_len*st->oversample+8;
   }
   if (st->sinc_table_length < min_sinc_table_length)
   {
      spx_word16_t *sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,min_sinc_table_length*sizeof(spx_word16_t));
      if (!sinc_table)
         goto fail;

      st->sinc_table = sinc_table;
      st->sinc_table_length = min_sinc_table_length;
   }
   if (use_direct)
   {
      spx_uint32_t i;
      for (i=0;i<st->den_rate;i++)
      {
         spx_int32_t j;
         for (j=0;j<st->filt_len;j++)
         {
            st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func);
         }
      }
#ifdef FIXED_POINT
      st->resampler_ptr = resampler_basic_direct_single;
#else
      if (st->quality>8)
         st->resampler_ptr = resampler_basic_direct_double;
      else
         st->resampler_ptr = resampler_basic_direct_single;
#endif
      /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
   } else {
      spx_int32_t i;
      for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++)
         st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func);
#ifdef FIXED_POINT
      st->resampler_ptr = resampler_basic_interpolate_single;
#else
      if (st->quality>8)
         st->resampler_ptr = resampler_basic_interpolate_double;
      else
         st->resampler_ptr = resampler_basic_interpolate_single;
#endif
      /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
   }

   /* Here's the place where we update the filter memory to take into account
      the change in filter length. It's probably the messiest part of the code
      due to handling of lots of corner cases. */

   /* Adding buffer_size to filt_len won't overflow here because filt_len
      could be multiplied by sizeof(spx_word16_t) above. */
   min_alloc_size = st->filt_len-1 + st->buffer_size;
   if (min_alloc_size > st->mem_alloc_size)
   {
      spx_word16_t *mem;
      if (INT_MAX/sizeof(spx_word16_t)/st->nb_channels < min_alloc_size)
          goto fail;
      else if (!(mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*min_alloc_size * sizeof(*mem))))
          goto fail;

      st->mem = mem;
      st->mem_alloc_size = min_alloc_size;
   }
   if (!st->started)
   {
      spx_uint32_t i;
      for (i=0;i<st->nb_channels*st->mem_alloc_size;i++)
         st->mem[i] = 0;
      /*speex_warning("reinit filter");*/
   } else if (st->filt_len > old_length)
   {
      spx_uint32_t i;
      /* Increase the filter length */
      /*speex_warning("increase filter size");*/
      for (i=st->nb_channels;i--;)
      {
         spx_uint32_t j;
         spx_uint32_t olen = old_length;
         /*if (st->magic_samples[i])*/
         {
            /* Try and remove the magic samples as if nothing had happened */

            /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */
            olen = old_length + 2*st->magic_samples[i];
            for (j=old_length-1+st->magic_samples[i];j--;)
               st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j];
            for (j=0;j<st->magic_samples[i];j++)
               st->mem[i*st->mem_alloc_size+j] = 0;
            st->magic_samples[i] = 0;
         }
         if (st->filt_len > olen)
         {
            /* If the new filter length is still bigger than the "augmented" length */
            /* Copy data going backward */
            for (j=0;j<olen-1;j++)
               st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)];
            /* Then put zeros for lack of anything better */
            for (;j<st->filt_len-1;j++)
               st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0;
            /* Adjust last_sample */
            st->last_sample[i] += (st->filt_len - olen)/2;
         } else {
            /* Put back some of the magic! */
            st->magic_samples[i] = (olen - st->filt_len)/2;
            for (j=0;j<st->filt_len-1+st->magic_samples[i];j++)
               st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
         }
      }
   } else if (st->filt_len < old_length)
   {
      spx_uint32_t i;
      /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic"
         samples so they can be used directly as input the next time(s) */
      for (i=0;i<st->nb_channels;i++)
      {
         spx_uint32_t j;
         spx_uint32_t old_magic = st->magic_samples[i];
         st->magic_samples[i] = (old_length - st->filt_len)/2;
         /* We must copy some of the memory that's no longer used */
         /* Copy data going backward */
         for (j=0;j<st->filt_len-1+st->magic_samples[i]+old_magic;j++)
            st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
         st->magic_samples[i] += old_magic;
      }
   }
   return RESAMPLER_ERR_SUCCESS;

fail:
   st->resampler_ptr = resampler_basic_zero;
   /* st->mem may still contain consumed input samples for the filter.
      Restore filt_len so that filt_len - 1 still points to the position after
      the last of these samples. */
   st->filt_len = old_length;
   return RESAMPLER_ERR_ALLOC_FAILED;
}