/*
 *
 *    soniK digital audio editor
 *    Copyright (C) 2003-2006  Robert Walker <rob@tenfoot.org.uk>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program 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 General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
#ifndef SONIK_SIGPROC_H
#define SONIK_SIGPROC_H

#include "sonik_types.h"
#include "sonik_complex.h"

#include <qstring.h>

#include <cmath>

namespace Sonik
{
  // Common abs interface
  inline int    abs(int i)    { return std::abs(i); }
  inline float  abs(float f)  { return std::fabs(f); }
  inline double abs(double d) { return std::fabs(d); }

  //
  //
  // Simple statistics
  //
  //

  /**
   * find the position and value of the minimum value in buf
   */
  template <typename T>
  void min(const T* buf, size_t len, size_t& pos, T& val);
  template <typename T>
  void min(const auto_buffer<T>& buf, size_t& pos, T& val);
  template <typename T>
  void min(const auto_buffer<const T>& buf, size_t& pos, T& val);

  /**
   * find the position and value of the maximum value in buf
   */
  template <typename T>
  void max(const T* buf, size_t len, size_t& pos, T& val);
  template <typename T>
  void max(const auto_buffer<T>& buf, size_t& pos, T& val);
  template <typename T>
  void max(const auto_buffer<const T>& buf, size_t& pos, T& val);

  /**
   * find the position and value of the minimum and maximum values in buf
   */
  template <typename T>
  void minmax(const T* buf, size_t len,
              size_t& minPos, T& minVal, size_t& maxPos, T& maxVal);
  template <typename T>
  void minmax(const auto_buffer<T>& buf,
              size_t& minPos, T& minVal, size_t& maxPos, T& maxVal);
  template <typename T>
  void minmax(const auto_buffer<const T>& buf,
              size_t& minPos, T& minVal, size_t& maxPos, T& maxVal);

  /**
   * find the position and value of the minimum absolute value in buf
   */
  template <typename T>
  void absMin(const T* buf, size_t len, size_t& pos, T& val);
  template <typename T>
  void absMin(const auto_buffer<T>& buf, size_t& pos, T& val);
  template <typename T>
  void absMin(const auto_buffer<const T>& buf, size_t& pos, T& val);

  /**
   * find the position and value of the maximum absolute value in buf
   */
  template <typename T>
  void absMax(const T* buf, size_t len, size_t& pos, T& val);
  template <typename T>
  void absMax(const auto_buffer<T>& buf, size_t& pos, T& val);
  template <typename T>
  void absMax(const auto_buffer<const T>& buf, size_t& pos, T& val);

  /**
   * find the position and value of the minimum and maximum absolute
   * values in buf
   */
  template <typename T>
  void absMinmax(const T* buf, size_t len,
                 size_t& minPos, T& minVal, size_t& maxPos, T& maxVal);
  template <typename T>
  void absMinmax(const auto_buffer<T>& buf,
                 size_t& minPos, T& minVal, size_t& maxPos, T& maxVal);
  template <typename T>
  void absMinmax(const auto_buffer<const T>& buf,
                 size_t& minPos, T& minVal, size_t& maxPos, T& maxVal);

  /**
   * calculate the mean value of buf
   */
  template <typename T>
  double mean(const T* buf, size_t len);
  template <typename T>
  double mean(const auto_buffer<T>& buf);
  template <typename T>
  double mean(const auto_buffer<const T>& buf);

  /**
   * calculate the mean absolute value of buf
   */
  template <typename T>
  double absMean(const T* buf, size_t len);
  template <typename T>
  double absMean(const auto_buffer<T>& buf);
  template <typename T>
  double absMean(const auto_buffer<const T>& buf);

  /**
   * calculate the rms value of buf
   */
  template <typename T>
  double rms(const T* buf, size_t len);
  template <typename T>
  double rms(const auto_buffer<T>& buf);
  template <typename T>
  double rms(const auto_buffer<const T>& buf);

  //
  //
  // Manipulation
  //
  //

  /**
   * fill buf with constant
   */
  template <typename T>
  void fill(T* buf, size_t len, const T& v = SampleTraits<T>::zero());
  template <typename T>
  void fill(auto_buffer<T>& buf, const T& v = SampleTraits<T>::zero());

  /**
   * add constant to each sample in buf
   */
  template <typename T>
  void offset(T* buf, size_t len, T d);
  template <typename T>
  void offset(auto_buffer<T>& buf, T d);

  /**
   * multiply each sample in buf by constant
   */
  template <typename T>
  void scale(T* buf, size_t len, float s);
  template <typename T>
  void scale(auto_buffer<T>& buf, float s);

  /**
   * log10 of each sample in buf
   */
  template <typename T>
  void log10(T* buf, size_t len);
  template <typename T>
  void log10(auto_buffer<T>& buf);

  /**
   * add corresponing samples in two buffers (a = a + b)
   */
  template <typename T>
  void add(T* a, T* b, size_t len);
  template <typename T>
  void add(auto_buffer<T>& a, auto_buffer<T>& b);

  /**
   * subtract corresponing samples in two buffers (a = a - b)
   */
  template <typename T>
  void sub(T* a, T* b, size_t len);
  template <typename T>
  void sub(auto_buffer<T>& a, auto_buffer<T>& b);

  /**
   * multiply corresponing samples in two buffers (a = a * b)
   */
  template <typename T>
  void mul(T* a, T* b, size_t len);
  template <typename T>
  void mul(auto_buffer<T>& a, auto_buffer<T>& b);

  /**
   * reverse buffer
   */
  template <typename T>
  void reverse(T* buf, size_t len);
  template <typename T>
  void reverse(auto_buffer<T>& buf);

  //
  //
  // Windowing
  //
  //

  /**
   * Types of window functions
   */
  enum WindowFunction { RECTANGULAR, TRIANGULAR,
                        BARTLETT, BLACKMAN, CHEBYSHEV, HAMMING, HANN, KAISER,
                        UNKNOWN = -1 };

  /**
   * Get name of window function
   */
  QString windowToString(WindowFunction f);

  /**
   * Get window function from name
   */
  WindowFunction stringToWindow(const QString& s);

  /**
   * Generate a window function
   */
  void makeWindow(Sample* buf, size_t len, WindowFunction f);
  void makeWindow(auto_buffer<Sample>& buf, WindowFunction f);

  /**
   * Generate a triangular window function
   */
  void makeWindowRectangular(Sample* buf, size_t len);

  /**
   * Generate a triangular window function
   */
  void makeWindowTriangular(Sample* buf, size_t len);

  /**
   * Generate a bartlett window function
   */
  void makeWindowBartlett(Sample* buf, size_t len);

  /**
   * Generate a blackman window function
   */
  void makeWindowBlackman(Sample* buf, size_t len);

  /**
   * Generate a chebyshev window function
   */
  void makeWindowChebyshev(Sample* buf, size_t len, double ripple=100.0);

  /**
   * Generate a hamming window function
   */
  void makeWindowHamming(Sample* buf, size_t len);

  /**
   * Generate a hann window function to
   */
  void makeWindowHann(Sample* buf, size_t len);

  /**
   * Generate a kaiser window function
   */
  void makeWindowKaiser(Sample* buf, size_t len, double beta=0.5);

  //
  //
  // Fourier transforms
  //
  //

  struct FFTParms
  {
    virtual ~FFTParms() = 0;
  };

  FFTParms* createFFTParms(size_t len);

  /**
   * Calculate fast fourier transform of buf
   */
  void fft(const Sample* buf,
           ComplexSample* out,
           size_t len,
           FFTParms* parms = 0);
}

#include "sonik_sigproc.tcc"

#endif // SONIK_SIGPROC_H
