Source

jackpipe-dev / src / LinearSineGenerator.h

Full commit
/*
 * Copyright © 2011 Aleksey Kunitskiy <alexey.kv@gmail.com>
 * 
 * This file is part of JackPipe
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */
#ifndef _LinearSineGenerator_H_
#define _LinearSineGenerator_H_

#include <cstdlib>
#include <cmath>
#include <stdexcept>
#include "Vector.h"
#include "SignalGenerator.h"

namespace JackPipe {

template<typename T>
class LinearSineGenerator : public SignalGenerator<T> {

  typedef SignalGenerator<T> sg_t;
  
protected:
  void generateRandPhaseShifts(typename Vector<T>::vec16_t &v);

  T _f1;
  unsigned _uBlockCount;
  unsigned _uFreqCount;
  long _lRandomSeed;

  typename Vector<T>::vec16_t _fvPhaseShifts;

public:
  LinearSineGenerator(const T f0, const T f1,
      const T fSr, const unsigned uB,
      bool bFreqBase2 = false, const long lRs = 0, bool bRoundUp = true)
    throw(std::invalid_argument);
  virtual ~LinearSineGenerator () {};

  virtual void generateSignal(typename Vector<T>::vec16_t &v, bool normalize = false) throw(std::runtime_error);
  virtual void generateSignal(typename Vector<T>::vec16_t &v,
      typename Vector<T>::vec16_t const& amp, bool normalize = false);

  T getf1() const { return _f1; }
  unsigned getBufferSize() const { return sg_t::_uBlockSize * _uBlockCount; }
  unsigned getBlockCount() const { return _uBlockCount; }
  unsigned getFreqCount() const { return _uFreqCount; }

  typename Vector<T>::vec16_t const&
    getPhaseShifts() const { return _fvPhaseShifts; }
};
  
template<typename T>
LinearSineGenerator<T>::LinearSineGenerator(
    const T f0, const T f1,
    const T fSr, const unsigned uB,
    bool bFreqBase2, const long lRs, bool bRoundUp)
  throw(std::invalid_argument)
  : SignalGenerator<T>(f0, fSr,
      bFreqBase2 == true
        ? SignalGenerator<T>::base2Approx
        : SignalGenerator<T>::aligned4Approx,
        bRoundUp)
{
  if (f0 > f1)
    throw (std::invalid_argument("f0 must be less than f1"));
  if ((fSr / static_cast<T>(2.0)) < f1)
    throw (std::invalid_argument("f1 must be less than nyquist frequency"));
  
  _f1 = f1;
  _uBlockCount = uB;
  _lRandomSeed = lRs;

  _uFreqCount = static_cast<unsigned>(_f1 * static_cast<T>(sg_t::_uBlockSize) / sg_t::_fSr);

  generateRandPhaseShifts(_fvPhaseShifts);
}

template<typename T>
void LinearSineGenerator<T>::generateRandPhaseShifts(typename Vector<T>::vec16_t &v)
{
  Vector<T>::resizeIfLess(v, _uFreqCount);

  srand(_lRandomSeed);

  for (unsigned i = 0; i < _uFreqCount; i++)
  {
    T d = 
      static_cast<T>(rand())
      / static_cast<T>(RAND_MAX);
    v[i] = 
      static_cast<T>(2.0)
      * static_cast<T>(M_PI)
      * d;
  }
}

template<typename T>
void LinearSineGenerator<T>::generateSignal(
    typename Vector<T>::vec16_t &v,
    bool normalize )
throw(std::runtime_error)
{
  Vector<T>::resizeIfLess(v, getBufferSize());

  T max = static_cast<T>(0.0);
  T bs = static_cast<T>(sg_t::_uBlockSize);
  for (unsigned i = 0; i < sg_t::_uBlockSize; i++)
  {
    v[i] = static_cast<T>(0.0);
    T ii = static_cast<T>(i) / bs;
    for (unsigned j = 0; j < _uFreqCount; j++)
    {
      v[i] += std::sin(
          static_cast<T>(2.0)
          * static_cast<T>(M_PI)
          * static_cast<T>(j+1)
          * ii
          + _fvPhaseShifts[j] );
    }
    //FIXME: don't compute normalization
    //       constant if normalize == false
    //       probably compiler can optimize this
    //       in compile time, but who knows...
    if (normalize && std::abs(v[i]) > max)
      max = std::abs(v[i]);
  }

  if (normalize)
    Vector<T>::scaleVecDiv(v, max, sg_t::_uBlockSize);

  growVector(v, _uBlockCount);
}

//FIXME: reuse code from generateSignal(std::vector, bool)
template<typename T>
void LinearSineGenerator<T>::generateSignal(typename Vector<T>::vec16_t &v,
      typename Vector<T>::vec16_t const &amp, bool normalize)
{
  Vector<T>::resizeIfLess(v, getBufferSize());

  T max = static_cast<T>(0.0);
  T bs = static_cast<T>(sg_t::_uBlockSize);
  for (unsigned i = 0; i < sg_t::_uBlockSize; i++)
  {
    v[i] = static_cast<T>(0.0);
    T ii = static_cast<T>(i) / bs;
    for (unsigned j = 0; j < _uFreqCount; j++)
    {
      v[i] += amp[j]*std::sin(
          static_cast<T>(2.0)
          * static_cast<T>(M_PI)
          * static_cast<T>(j+1u)
          * ii
          + _fvPhaseShifts[j] );
    }
    //FIXME: don't compute normalization
    //       constant if normalize == false
    //       probably compiler can optimize this
    //       in compile time, but who knows...
    if (normalize && std::abs(v[i]) > max)
      max = std::abs(v[i]);
  }

  if (normalize)
    Vector<T>::scaleVecDiv(v, max, sg_t::_uBlockSize);

  growVector(v, _uBlockCount);
}

} // JackPipe

#endif
//  vim:set ts=2 sw=2 tw=78 et: