/* BseResampler - FPU and SSE optimized FIR Resampling code
 * Copyright (C) 2006 Stefan Westerfeld
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#include "bseresampler.hh"
#include "bseresampler.tcc"
#include "bseblockutils.hh"

namespace Bse
{

namespace Resampler
{

/*---- Resampler2 methods ----*/

Resampler2::~Resampler2()
{
}

/*---- Resampler2FactoryFPU implementation ----*/

class Resampler2FactoryFPU : public Resampler2Factory {
public:
  Resampler2*
  create_impl (Mode      mode,
	       Precision precision)
  {
    /* keep in sync with Resampler2FactorySSE */
    /* alternatively, we could make this a template */
    if (mode == MODE_UPSAMPLE)
      {
	switch (precision)
	  {
	  case PREC_48DB: return create_impl_with_coeffs <Upsampler2<16, false> > (halfband_fir_48db_coeffs, 16, 2.0);
	  case PREC_96DB: return create_impl_with_coeffs <Upsampler2<32, false> > (halfband_fir_96db_coeffs, 32, 2.0);
	  }
      }
    else if (mode == MODE_DOWNSAMPLE)
      {
	switch (precision)
	  {
	  case PREC_48DB: return create_impl_with_coeffs <Downsampler2<16, false> > (halfband_fir_48db_coeffs, 16, 1.0);
	  case PREC_96DB: return create_impl_with_coeffs <Downsampler2<32, false> > (halfband_fir_96db_coeffs, 32, 1.0);
	  }
      }
    return 0;
  }
} resampler2_factory_fpu;

/*---- Resampler2Factory methods ----*/

Resampler2*
Resampler2Factory::create (Mode      mode,
                           Precision precision)
{
  return Block::resampler2_factory()->create_impl (mode, precision);
}

Resampler2Factory*
Resampler2Factory::default_factory()
{
  return &resampler2_factory_fpu;
}

/*---- coefficient sets for Resampler2Factory ----*/
/* 
 * halfband FIR filter for factor 2 resampling, created with octave
 *
 * design method: windowed sinc,  using ultraspherical window
 *
 *   coefficients = 32
 *             x0 = 1.01065
 *          alpha = 0.75
 *
 * design criteria (44100 Hz => 88200 Hz):
 * 
 *       passband = [     0, 18000 ]  1 - 2^-16 <= H(z) <= 1+2^-16
 *     transition = [ 18000, 26100 ]
 *       stopband = [ 26100, 44100 ]  | H(z) | <= -96 dB
 *
 * and for 48 kHz => 96 kHz:
 *
 *       passband = [     0, 19589 ]  1 - 2^-16 <= H(z) <= 1+2^-16
 *     transition = [ 19588, 29386 ]
 *       stopband = [ 29386, 48000 ]  | H(z) | <= -96 dB
 *
 * in order to keep the coefficient number down to 32, the filter
 * does only "almost" fulfill the spec, but its really really close
 * (no stopband ripple > -95 dB)
 */

const double Resampler2Factory::halfband_fir_96db_coeffs[32] =
{
  -3.48616530828033e-05,
   0.000112877490936198,
  -0.000278961878372482,
   0.000590495306376081,
  -0.00112566995029848,
   0.00198635062559427,
  -0.00330178798332932,
   0.00523534239035401,
  -0.00799905465189065,
   0.0118867161189188,
  -0.0173508611368417,
   0.0251928452706978,
  -0.0370909694665106,
   0.057408291607388,
  -0.102239638342325,
   0.317002929635456,
   /* here, a 0.5 coefficient will be used */
   0.317002929635456,
  -0.102239638342325,
   0.0574082916073878,
  -0.0370909694665105,
   0.0251928452706976,
  -0.0173508611368415,
   0.0118867161189186,
  -0.00799905465189052,
   0.0052353423903539,
  -0.00330178798332923,
   0.00198635062559419,
  -0.00112566995029842,
   0.000590495306376034,
  -0.00027896187837245,
   0.000112877490936177,
  -3.48616530827983e-05
};

/*
 *   coefficients = 16
 *             x0 = 1.013
 *          alpha = 0.2
 */
const double Resampler2Factory::halfband_fir_48db_coeffs[16] =
{
  -0.00270578824181636,
   0.00566964586625895,
  -0.0106460585587187,
   0.0185209590435965,
  -0.0310433957594089,
   0.0525722488176905,
  -0.0991138314110143,
   0.315921760444802,
   /* here, a 0.5 coefficient will be used */
   0.315921760444802,
  -0.0991138314110145,
   0.0525722488176907,
  -0.031043395759409,
   0.0185209590435966,
  -0.0106460585587187,
   0.00566964586625899,
  -0.00270578824181638
};

} /* namespace Resampler */

} /* namespace Bse */

/*---- Resampler2 C API ----*/

BseResampler2*
bse_resampler2_create (BseResampler2Mode      mode,
                       BseResampler2Precision precision)
{
  return Bse::Resampler::Resampler2Factory::create (static_cast<Bse::Resampler::Resampler2Factory::Mode> (mode),
                                                    static_cast<Bse::Resampler::Resampler2Factory::Precision> (precision));
}

void
bse_resampler2_destroy (BseResampler2 *resampler)
{
  delete reinterpret_cast<Bse::Resampler::Resampler2 *> (resampler);
}

void
bse_resampler2_process_block (BseResampler2 *resampler,
                              const float   *input,
                              unsigned int   n_input_samples,
			      float         *output)
{
  reinterpret_cast<Bse::Resampler::Resampler2 *> (resampler)->process_block (input, n_input_samples, output);
}

guint
bse_resampler2_order (BseResampler2 *resampler)
{
  return reinterpret_cast<Bse::Resampler::Resampler2 *> (resampler)->order();
}
