Source

jackpipe-dev / src / SignalGenerator.h

Full commit
/*
 * Copyright © 2010 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 _SignalGenerator_H_
#define _SignalGenerator_H_

#include <algorithm>
#include <cmath>
#include "Misc.h"
#include "Vector.h"

#include <iostream>

namespace JackPipe {

template<typename T>
class SignalGenerator {
  IsSubsetOf<T, float, double, long double> __isFloatingPointCheck;

  template<typename W>
  static unsigned
  f0Base2BufferApprox(const W f0, const W fSr, const bool floor) {
    W tmp;
    floor == true
      ? tmp = std::floor(std::log10(fSr/f0)
              / std::log10(static_cast<T>(2.0) ))
      : tmp = std::ceil(std::log10(fSr/f0)
              / std::log10(static_cast<T>(2.0) ));
    return static_cast<unsigned>(std::pow(static_cast<T>(2.0), tmp));
  }

  template<typename W>
  static unsigned
  f0AlignedBufferApprox(const W f0, const W fSr, const bool floor) {
    T k = fSr / f0;
    return floor == true
      ? static_cast<unsigned>(std::floor(k))
      : static_cast<unsigned>(std::ceil(k));
  }

  template<typename W>
  static unsigned
  f0AlignedBufferApprox(const W f0, const W fSr, const unsigned N, const bool floor) {
    unsigned tmp = f0AlignedBufferApprox<W>(f0, fSr, floor);
    return floor == true
      ? (tmp % N) > 0 ? (tmp + (N-(tmp%N))): tmp
      : (tmp % N) > 0 ? (tmp - (tmp%N)): tmp;
  }

public:
  enum {
    base2Approx,
    alignedApprox,
    aligned4Approx,
    aligned2Approx,
    noApprox
  };

  SignalGenerator(T f0, T fSr, const int approx, const bool floor = true) : _fSr(fSr) {
    switch(approx) {
      case base2Approx:
        _uBlockSize = f0Base2BufferApprox<T>(f0, _fSr, floor);
        _f0 = _fSr / static_cast<T>(_uBlockSize);
        break;
      case alignedApprox:
        _uBlockSize = f0AlignedBufferApprox<T>(f0, _fSr, floor);
        _f0 = _fSr / static_cast<T>(_uBlockSize);
        break;
      case aligned4Approx:
        _uBlockSize = f0AlignedBufferApprox<T>(f0, _fSr, 4u, floor);
        _f0 = _fSr / static_cast<T>(_uBlockSize);
        break;
      case aligned2Approx:
        _uBlockSize = f0AlignedBufferApprox<T>(f0, _fSr, 2u, floor);
        _f0 = _fSr / static_cast<T>(_uBlockSize);
        break;
      default: _f0 = f0;
    }
  }

  virtual ~SignalGenerator () {};

  virtual void generateSignal(typename Vector<T>::vec16_t &v, bool normalize = false) = 0;
  virtual void generateSignal(typename Vector<T>::vec16_t &v,
      typename Vector<T>::vec16_t const& amp, bool normalize = false) {};
  
  virtual typename Vector<T>::vec16_t&
  operator()(typename Vector<T>::vec16_t &v, const bool normalize = false)
  { generateSignal(v, normalize); return v; }

  virtual typename Vector<T>::vec16_t&
  operator[](typename Vector<T>::vec16_t &v)
  { generateSignal(v, true); return v; }

  T getf0() const { return _f0; }
  T getfSr() const { return _fSr; }
  unsigned getBlockSize() const { return _uBlockSize; }

protected:
  //FIXME: due to rounding error _f0 value
  // isn't exact base frequency.
  // Exact frequency can be obtained as _fSr / getBufferSize()
  T _f0;
  T _fSr;

  unsigned _uBlockSize;

  void growVector(typename Vector<T>::vec16_t &v, unsigned n) {
    typename Vector<T>::vec16_t::iterator
      insertMarker = v.begin() + getBlockSize();
    for (unsigned i = 1u; i < n; i++) {
      insertMarker = std::copy(v.begin(),
          v.begin() + getBlockSize(),
          insertMarker );
    }
  }

  void growVector(typename Vector<T>::vec16_t const& src,
      typename Vector<T>::vec16_t &dest,
      unsigned n)
  {
    typename Vector<T>::vec16_t::iterator insertMarker = dest.begin();
    for (unsigned i = 0; i < n; i++) {
      insertMarker = std::copy(src.begin(), src.end(), insertMarker);
    }
  }

}; // SignalGenerator

} // JackPipe

#endif // _SignalGenerator_H_

// vim:set ts=2 sw=2 expandtab tw=78: