<commit_before>/**
 * \file TubeFilter.cpp
 */

#include "TubeFilter.h"

#include <cassert>

#include <ATK/Utility/SimplifiedVectorizedNewtonRaphson.h>
#include <ATK/Utility/VectorizedNewtonRaphson.h>

namespace ATK
{
  template <typename DataType_>
  class TubeFunction
  {
  protected:
    const DataType_ mu;
    const DataType_ K;
    const DataType_ Kp;
    const DataType_ Kvb;
    const DataType_ Kg;
    const DataType_ Ex;

    DataType_ Lb(DataType_ Vbe, DataType_ Vce)
    {
      if(mu * Vbe + Vce > 0)
        return K * std::pow(mu * Vbe + Vce, 1.5);
      return 0;
    }

    DataType_ Lb_Vbe(DataType_ Vbe, DataType_ Vce)
    {
      if (mu * Vbe + Vce > 0)
        return K * mu * 1.5 * std::sqrt(mu * Vbe + Vce);
      return 0;
    }

    DataType_ Lb_Vce(DataType_ Vbe, DataType_ Vce)
    {
      if (mu * Vbe + Vce > 0)
        return K * 1.5 * std::sqrt(mu * Vbe + Vce);;
      return 0;
    }

    DataType_ Lc(DataType_ Vbe, DataType_ Vce)
    {
      if (Vce > 0)
      {
        DataType_ E1 = Vce / Kp * std::log(1 + std::exp(Kp * (1/mu + Vbe / std::sqrt(Kvb + Vce * Vce))));
        return 2 / Kg * std::pow(E1, Ex);
      }
      return 0;
    }

    DataType_ Lc_Vbe(DataType_ Vbe, DataType_ Vce)
    {
      if (Vce > 0)
      {
        DataType_ E2 = 1 + std::exp(Kp * (1 / mu + Vbe / std::sqrt(Kvb + Vce * Vce)));
        DataType_ E1 = Vce / Kp * std::log(E2);
        DataType_ E1p = Vce / Kp / E2 * (E2 - 1) * Kp / std::sqrt(Kvb + Vce * Vce);
        return 2 * Ex / Kg * std::pow(E1, Ex - 1) * E1p;
      }
      return 0;
    }

    DataType_ Lc_Vce(DataType_ Vbe, DataType_ Vce)
    {
      if (Vce > 0)
      {
        DataType_ E2 = 1 + std::exp(Kp * (1 / mu + Vbe / std::sqrt(Kvb + Vce * Vce)));
        DataType_ E1 = Vce / Kp * std::log(E2);
        DataType_ E1p = 1/Kp * std::log(E2) + Vce / Kp / E2 * (E2 - 1) * Kp * Vce / std::pow(Kvb + Vce * Vce, 1.5);
        return 2 * Ex / Kg * std::pow(E1, Ex - 1) * E1p;
      }
      return 0;
    }

    TubeFunction(DataType_ mu, DataType_ K, DataType_ Kp, DataType_ Kvb, DataType_ Kg, DataType_ Ex)
      :mu(mu), K(K), Kp(Kp), Kvb(Kvb), Kg(Kg), Ex(Ex)
    {
    }

  };

  template <typename DataType_>
  class TubeFilter<DataType_>::CommonCathodeTriodeFunction : public TubeFunction<DataType_>
  {
    const DataType_ dt;

    const DataType_ Rp;
    const DataType_ Rg;
    const DataType_ Ro;
    const DataType_ Rk;
    const DataType_ VBias;
    const DataType_ Co;
    const DataType_ Ck;

    using TubeFunction<DataType_>::Lb;
    using TubeFunction<DataType_>::Lb_Vbe;
    using TubeFunction<DataType_>::Lb_Vce;
    using TubeFunction<DataType_>::Lc;
    using TubeFunction<DataType_>::Lc_Vbe;
    using TubeFunction<DataType_>::Lc_Vce;

  public:
    typedef DataType_ DataType;
    typedef Eigen::Matrix<DataType, 4, 1> Vector;
    typedef Eigen::Matrix<DataType, 4, 4> Matrix;

    CommonCathodeTriodeFunction(DataType dt, DataType Rp, DataType Rg, DataType Ro, DataType Rk, DataType VBias, DataType Co, DataType Ck, DataType_ mu, DataType_ K, DataType_ Kp, DataType_ Kvb, DataType_ Kg, DataType_ Ex)
      :TubeFunction<DataType_>(mu, K, Kp, Kvb, Kg, Ex), dt(dt), Rp(Rp), Rg(Rg), Ro(Ro), Rk(Rk), VBias(VBias), Co(Co), Ck(Ck)
    {
    }

    Vector estimate(int64_t i, const DataType* const * ATK_RESTRICT input, DataType* const * ATK_RESTRICT output)
    {
      Vector y0 = Vector::Zero();
      for(int j = 0; j < 4; ++j)
      {
        y0.data()[j] = output[j][i-1];
      }

      return y0;
    }

    std::pair<Vector, Matrix> operator()(int64_t i, const DataType* const * ATK_RESTRICT input, DataType* const * ATK_RESTRICT output, const Vector& y1)
    {
      auto Ib_old = Lb(output[3][i-1] - output[0][i-1], output[2][i-1] - output[0][i-1]);
      auto Ic_old = Lc(output[3][i-1] - output[0][i-1], output[2][i-1] - output[0][i-1]);

      auto Ib = Lb(y1(3) - y1(0), y1(2) - y1(0));
      auto Ic = Lc(y1(3) - y1(0), y1(2) - y1(0));

      auto Ib_Vbe = Lb_Vbe(y1(3) - y1(0), y1(2) - y1(0));
      auto Ib_Vce = Lb_Vce(y1(3) - y1(0), y1(2) - y1(0));

      auto Ic_Vbe = Lc_Vbe(y1(3) - y1(0), y1(2) - y1(0));
      auto Ic_Vce = Lc_Vce(y1(3) - y1(0), y1(2) - y1(0));

      auto f1_old = - output[0][i-1] / (Rk * Ck) + (Ib_old + Ic_old) / Ck;
      auto f2_old = - (output[1][i-1] + output[2][i-1]) / (Ro * Co);

      auto f1 = - y1(0) / (Rk * Ck) + (Ib + Ic) / Ck;
      auto f2 = - (y1(1) + y1(2)) / (Ro * Co);

      auto g1 = y1(2) + Rp * (Ic + (y1(1) + y1(2)) / Ro) - VBias;
      auto g2 = y1(3) - input[0][i] + Rg * Ib;

      Vector F(Vector::Zero());
      F << (dt / 2 * (f1 + f1_old) + output[0][i-1] - y1(0)),
           (dt / 2 * (f2 + f2_old) + output[1][i-1] - y1(1)),
           (g1),
           (g2);

      Matrix M(Matrix::Zero());
      M << (-1 -dt/2/(Rk * Ck)) - dt/2*((Ib_Vbe + Ic_Vbe + Ib_Vce + Ic_Vce)/ Ck), 0, dt/2*(Ib_Vce + Ic_Vce) / Ck, dt/2*(Ib_Vbe + Ic_Vbe) / Ck,
            0, -1 -dt/2*(Ro * Co), -dt/2*(Ro * Co), 0,
            -Rp * (Ic_Vbe + Ic_Vce), Rp / Ro, 1 + Rp / Ro + Rp * Ic_Vce, Rp * Ic_Vbe,
            -Rg * (Ib_Vbe + Ib_Vce), 0, Rg * Ib_Vce, Rg * Ib_Vbe + 1;

      return std::make_pair(F, M);
    }

  };

  template <typename DataType_>
  class CommonCathodeTriodeInitialFunction : public TubeFunction<DataType_>
  {
    const DataType_ Rp;
    const DataType_ Rg;
    const DataType_ Ro;
    const DataType_ Rk;
    const DataType_ VBias;

    using TubeFunction<DataType_>::Lb;
    using TubeFunction<DataType_>::Lb_Vbe;
    using TubeFunction<DataType_>::Lb_Vce;
    using TubeFunction<DataType_>::Lc;
    using TubeFunction<DataType_>::Lc_Vbe;
    using TubeFunction<DataType_>::Lc_Vce;

  public:
    typedef DataType_ DataType;
    typedef Eigen::Matrix<DataType, 3, 1> Vector;
    typedef Eigen::Matrix<DataType, 3, 3> Matrix;

    CommonCathodeTriodeInitialFunction(DataType Rp, DataType Rg, DataType Ro, DataType Rk, DataType VBias, DataType_ mu, DataType_ K, DataType_ Kp, DataType_ Kvb, DataType_ Kg, DataType_ Ex)
      :TubeFunction<DataType_>(mu, K, Kp, Kvb, Kg, Ex), Rp(Rp), Rg(Rg), Ro(Ro), Rk(Rk), VBias(VBias)
    {
    }

    std::pair<Vector, Matrix> operator()(const Vector& y1)
    {
      auto Ib = Lb(y1(0) - y1(1), y1(0) - y1(2));
      auto Ic = Lc(y1(0) - y1(1), y1(0) - y1(2));

      auto Ib_Vbe = Lb_Vbe(y1(0) - y1(1), y1(0) - y1(2));
      auto Ib_Vce = Lb_Vce(y1(0) - y1(1), y1(0) - y1(2));

      auto Ic_Vbe = Lc_Vbe(y1(0) - y1(1), y1(0) - y1(2));
      auto Ic_Vce = Lc_Vce(y1(0) - y1(1), y1(0) - y1(2));

      Vector F(Vector::Zero());
      F << y1(0) - VBias + Ic * Rp,
        Ib * Rg + y1(1),
        y1(2) - (Ib + Ic) * Rk;

      Matrix M(Matrix::Zero());
      M << 1 + Rp * (Ic_Vbe + Ic_Vce), -Rp * Ic_Vbe, -Rp * Ic_Vce,
        (Ib_Vbe + Ib_Vce) * Rg, 1 - Rg * Ib_Vbe, -Rg * Ib_Vce,
        -(Ic_Vbe + Ic_Vce + Ib_Vbe + Ib_Vce) * Rk, (Ic_Vbe + Ib_Vbe) * Rk, 1 + (Ic_Vce + Ib_Vce) * Rk;

      return std::make_pair(F, M);
    }
  };

  template <typename DataType>
  TubeFilter<DataType>::TubeFilter(DataType Rp, DataType Rg, DataType Ro, DataType Rk, DataType VBias, DataType Co, DataType Ck, DataType mu, DataType K, DataType Kp, DataType Kvb, DataType Kg, DataType Ex)
    :Parent(1, 5), Rp(Rp), Rg(Rg), Ro(Ro), Rk(Rk), VBias(VBias), Co(Co), Ck(Ck), mu(mu), K(K), Kp(Kp), Kvb(Kvb), Kg(Kg), Ex(Ex)
  {
    input_delay = output_delay = 1;
  }

  template <typename DataType>
  TubeFilter<DataType>::TubeFilter(TubeFilter&& other)
    :Parent(std::move(other)), Rp(other.Rp), Rg(other.Rg), Ro(other.Ro), Rk(other.Rk), VBias(other.VBias), Co(other.Co), Ck(other.Ck), mu(other.mu), K(other.K), Kp(other.Kp), Kvb(other.Kvb), Kg(other.Kg), Ex(other.Ex)
  {
  }

  template<typename DataType_>
  TubeFilter<DataType_>::~TubeFilter()
  {
  }

  template<typename DataType_>
  void TubeFilter<DataType_>::setup()
  {
    Parent::setup();
    optimizer.reset(new VectorizedNewtonRaphson<CommonCathodeTriodeFunction, 4, 10, true>(CommonCathodeTriodeFunction(static_cast<DataType>(1. / input_sampling_rate),
      Rp, Rg, Ro, Rk, //R
      VBias, // VBias
      Co, Ck, // C
      mu, K, Kp, Kvb, Kg, Ex // tube
      )));
  }

  template<typename DataType_>
  void TubeFilter<DataType_>::full_setup()
  {
    Parent::full_setup();
    // setup default_output

    SimplifiedVectorizedNewtonRaphson<CommonCathodeTriodeInitialFunction<DataType_>, 3, 10> custom(CommonCathodeTriodeInitialFunction<DataType_>(
      Rp, Rg, Ro, Rk, //R
      VBias, // VBias
      mu, K, Kp, Kvb, Kg, Ex // tube
      ));

    auto stable = custom.optimize();

    default_output[0] = 0;
    default_output[1] = stable(2);
    default_output[2] = -stable(0);
    default_output[3] = stable(0);
    default_output[4] = stable(1);
  }

  template<typename DataType_>
  void TubeFilter<DataType_>::process_impl(int64_t size) const
  {
    assert(input_sampling_rate == output_sampling_rate);

    for(int64_t i = 0; i < size; ++i)
    {
      optimizer->optimize(i, converted_inputs.data(), outputs.data() + 1);
      outputs[0][i] = outputs[2][i] + outputs[3][i];
    }
  }

  template<typename DataType_>
  TubeFilter<DataType_> TubeFilter<DataType_>::build_standard_filter()
  {
    return TubeFilter<DataType_>(100e3, 220e3, 22e3, 2.7e3, //R
      400, // VBias
      20e-9, 10e-6, // C
      88.5, 1.73e-6, 600, 300, 1060, 1.4 // transistor
      );
  }

  template class TubeFilter<float>;
  template class TubeFilter<double>;
}
<commit_msg>full_setup properly<commit_after>/**
 * \file TubeFilter.cpp
 */

#include "TubeFilter.h"

#include <cassert>

#include <ATK/Utility/SimplifiedVectorizedNewtonRaphson.h>
#include <ATK/Utility/VectorizedNewtonRaphson.h>

namespace ATK
{
  template <typename DataType_>
  class TubeFunction
  {
  protected:
    const DataType_ mu;
    const DataType_ K;
    const DataType_ Kp;
    const DataType_ Kvb;
    const DataType_ Kg;
    const DataType_ Ex;

    DataType_ Lb(DataType_ Vbe, DataType_ Vce)
    {
      if(mu * Vbe + Vce > 0)
        return K * std::pow(mu * Vbe + Vce, 1.5);
      return 0;
    }

    DataType_ Lb_Vbe(DataType_ Vbe, DataType_ Vce)
    {
      if (mu * Vbe + Vce > 0)
        return K * mu * 1.5 * std::sqrt(mu * Vbe + Vce);
      return 0;
    }

    DataType_ Lb_Vce(DataType_ Vbe, DataType_ Vce)
    {
      if (mu * Vbe + Vce > 0)
        return K * 1.5 * std::sqrt(mu * Vbe + Vce);;
      return 0;
    }

    DataType_ Lc(DataType_ Vbe, DataType_ Vce)
    {
      if (Vce > 0)
      {
        DataType_ E1 = Vce / Kp * std::log(1 + std::exp(Kp * (1/mu + Vbe / std::sqrt(Kvb + Vce * Vce))));
        return 2 / Kg * std::pow(E1, Ex);
      }
      return 0;
    }

    DataType_ Lc_Vbe(DataType_ Vbe, DataType_ Vce)
    {
      if (Vce > 0)
      {
        DataType_ E2 = 1 + std::exp(Kp * (1 / mu + Vbe / std::sqrt(Kvb + Vce * Vce)));
        DataType_ E1 = Vce / Kp * std::log(E2);
        DataType_ E1p = Vce / Kp / E2 * (E2 - 1) * Kp / std::sqrt(Kvb + Vce * Vce);
        return 2 * Ex / Kg * std::pow(E1, Ex - 1) * E1p;
      }
      return 0;
    }

    DataType_ Lc_Vce(DataType_ Vbe, DataType_ Vce)
    {
      if (Vce > 0)
      {
        DataType_ E2 = 1 + std::exp(Kp * (1 / mu + Vbe / std::sqrt(Kvb + Vce * Vce)));
        DataType_ E1 = Vce / Kp * std::log(E2);
        DataType_ E1p = 1/Kp * std::log(E2) + Vce / Kp / E2 * (E2 - 1) * Kp * Vce / std::pow(Kvb + Vce * Vce, 1.5);
        return 2 * Ex / Kg * std::pow(E1, Ex - 1) * E1p;
      }
      return 0;
    }

    TubeFunction(DataType_ mu, DataType_ K, DataType_ Kp, DataType_ Kvb, DataType_ Kg, DataType_ Ex)
      :mu(mu), K(K), Kp(Kp), Kvb(Kvb), Kg(Kg), Ex(Ex)
    {
    }

  };

  template <typename DataType_>
  class TubeFilter<DataType_>::CommonCathodeTriodeFunction : public TubeFunction<DataType_>
  {
    const DataType_ dt;

    const DataType_ Rp;
    const DataType_ Rg;
    const DataType_ Ro;
    const DataType_ Rk;
    const DataType_ VBias;
    const DataType_ Co;
    const DataType_ Ck;

    using TubeFunction<DataType_>::Lb;
    using TubeFunction<DataType_>::Lb_Vbe;
    using TubeFunction<DataType_>::Lb_Vce;
    using TubeFunction<DataType_>::Lc;
    using TubeFunction<DataType_>::Lc_Vbe;
    using TubeFunction<DataType_>::Lc_Vce;

  public:
    typedef DataType_ DataType;
    typedef Eigen::Matrix<DataType, 4, 1> Vector;
    typedef Eigen::Matrix<DataType, 4, 4> Matrix;

    CommonCathodeTriodeFunction(DataType dt, DataType Rp, DataType Rg, DataType Ro, DataType Rk, DataType VBias, DataType Co, DataType Ck, DataType_ mu, DataType_ K, DataType_ Kp, DataType_ Kvb, DataType_ Kg, DataType_ Ex)
      :TubeFunction<DataType_>(mu, K, Kp, Kvb, Kg, Ex), dt(dt), Rp(Rp), Rg(Rg), Ro(Ro), Rk(Rk), VBias(VBias), Co(Co), Ck(Ck)
    {
    }

    Vector estimate(int64_t i, const DataType* const * ATK_RESTRICT input, DataType* const * ATK_RESTRICT output)
    {
      Vector y0 = Vector::Zero();
      for(int j = 0; j < 4; ++j)
      {
        y0.data()[j] = output[j][i-1];
      }

      return y0;
    }

    std::pair<Vector, Matrix> operator()(int64_t i, const DataType* const * ATK_RESTRICT input, DataType* const * ATK_RESTRICT output, const Vector& y1)
    {
      auto Ib_old = Lb(output[3][i-1] - output[0][i-1], output[2][i-1] - output[0][i-1]);
      auto Ic_old = Lc(output[3][i-1] - output[0][i-1], output[2][i-1] - output[0][i-1]);

      auto Ib = Lb(y1(3) - y1(0), y1(2) - y1(0));
      auto Ic = Lc(y1(3) - y1(0), y1(2) - y1(0));

      auto Ib_Vbe = Lb_Vbe(y1(3) - y1(0), y1(2) - y1(0));
      auto Ib_Vce = Lb_Vce(y1(3) - y1(0), y1(2) - y1(0));

      auto Ic_Vbe = Lc_Vbe(y1(3) - y1(0), y1(2) - y1(0));
      auto Ic_Vce = Lc_Vce(y1(3) - y1(0), y1(2) - y1(0));

      auto f1_old = - output[0][i-1] / (Rk * Ck) + (Ib_old + Ic_old) / Ck;
      auto f2_old = - (output[1][i-1] + output[2][i-1]) / (Ro * Co);

      auto f1 = - y1(0) / (Rk * Ck) + (Ib + Ic) / Ck;
      auto f2 = - (y1(1) + y1(2)) / (Ro * Co);

      auto g1 = y1(2) + Rp * (Ic + (y1(1) + y1(2)) / Ro) - VBias;
      auto g2 = y1(3) - input[0][i] + Rg * Ib;

      Vector F(Vector::Zero());
      F << (dt / 2 * (f1 + f1_old) + output[0][i-1] - y1(0)),
           (dt / 2 * (f2 + f2_old) + output[1][i-1] - y1(1)),
           (g1),
           (g2);

      Matrix M(Matrix::Zero());
      M << (-1 -dt/2/(Rk * Ck)) - dt/2*((Ib_Vbe + Ic_Vbe + Ib_Vce + Ic_Vce)/ Ck), 0, dt/2*(Ib_Vce + Ic_Vce) / Ck, dt/2*(Ib_Vbe + Ic_Vbe) / Ck,
            0, -1 -dt/2*(Ro * Co), -dt/2*(Ro * Co), 0,
            -Rp * (Ic_Vbe + Ic_Vce), Rp / Ro, 1 + Rp / Ro + Rp * Ic_Vce, Rp * Ic_Vbe,
            -Rg * (Ib_Vbe + Ib_Vce), 0, Rg * Ib_Vce, Rg * Ib_Vbe + 1;

      return std::make_pair(F, M);
    }

  };

  template <typename DataType_>
  class CommonCathodeTriodeInitialFunction : public TubeFunction<DataType_>
  {
    const DataType_ Rp;
    const DataType_ Rg;
    const DataType_ Ro;
    const DataType_ Rk;
    const DataType_ VBias;

    using TubeFunction<DataType_>::Lb;
    using TubeFunction<DataType_>::Lb_Vbe;
    using TubeFunction<DataType_>::Lb_Vce;
    using TubeFunction<DataType_>::Lc;
    using TubeFunction<DataType_>::Lc_Vbe;
    using TubeFunction<DataType_>::Lc_Vce;

  public:
    typedef DataType_ DataType;
    typedef Eigen::Matrix<DataType, 3, 1> Vector;
    typedef Eigen::Matrix<DataType, 3, 3> Matrix;

    CommonCathodeTriodeInitialFunction(DataType Rp, DataType Rg, DataType Ro, DataType Rk, DataType VBias, DataType_ mu, DataType_ K, DataType_ Kp, DataType_ Kvb, DataType_ Kg, DataType_ Ex)
      :TubeFunction<DataType_>(mu, K, Kp, Kvb, Kg, Ex), Rp(Rp), Rg(Rg), Ro(Ro), Rk(Rk), VBias(VBias)
    {
    }

    std::pair<Vector, Matrix> operator()(const Vector& y1)
    {
      auto Ib = Lb(y1(0) - y1(1), y1(0) - y1(2));
      auto Ic = Lc(y1(0) - y1(1), y1(0) - y1(2));

      auto Ib_Vbe = Lb_Vbe(y1(0) - y1(1), y1(0) - y1(2));
      auto Ib_Vce = Lb_Vce(y1(0) - y1(1), y1(0) - y1(2));

      auto Ic_Vbe = Lc_Vbe(y1(0) - y1(1), y1(0) - y1(2));
      auto Ic_Vce = Lc_Vce(y1(0) - y1(1), y1(0) - y1(2));

      Vector F(Vector::Zero());
      F << y1(0) - VBias + Ic * Rp,
        Ib * Rg + y1(1),
        y1(2) - (Ib + Ic) * Rk;

      Matrix M(Matrix::Zero());
      M << 1 + Rp * (Ic_Vbe + Ic_Vce), -Rp * Ic_Vbe, -Rp * Ic_Vce,
        (Ib_Vbe + Ib_Vce) * Rg, 1 - Rg * Ib_Vbe, -Rg * Ib_Vce,
        -(Ic_Vbe + Ic_Vce + Ib_Vbe + Ib_Vce) * Rk, (Ic_Vbe + Ib_Vbe) * Rk, 1 + (Ic_Vce + Ib_Vce) * Rk;

      return std::make_pair(F, M);
    }
  };

  template <typename DataType>
  TubeFilter<DataType>::TubeFilter(DataType Rp, DataType Rg, DataType Ro, DataType Rk, DataType VBias, DataType Co, DataType Ck, DataType mu, DataType K, DataType Kp, DataType Kvb, DataType Kg, DataType Ex)
    :Parent(1, 5), Rp(Rp), Rg(Rg), Ro(Ro), Rk(Rk), VBias(VBias), Co(Co), Ck(Ck), mu(mu), K(K), Kp(Kp), Kvb(Kvb), Kg(Kg), Ex(Ex)
  {
    input_delay = output_delay = 1;
  }

  template <typename DataType>
  TubeFilter<DataType>::TubeFilter(TubeFilter&& other)
    :Parent(std::move(other)), Rp(other.Rp), Rg(other.Rg), Ro(other.Ro), Rk(other.Rk), VBias(other.VBias), Co(other.Co), Ck(other.Ck), mu(other.mu), K(other.K), Kp(other.Kp), Kvb(other.Kvb), Kg(other.Kg), Ex(other.Ex)
  {
  }

  template<typename DataType_>
  TubeFilter<DataType_>::~TubeFilter()
  {
  }

  template<typename DataType_>
  void TubeFilter<DataType_>::setup()
  {
    Parent::setup();
    optimizer.reset(new VectorizedNewtonRaphson<CommonCathodeTriodeFunction, 4, 10, true>(CommonCathodeTriodeFunction(static_cast<DataType>(1. / input_sampling_rate),
      Rp, Rg, Ro, Rk, //R
      VBias, // VBias
      Co, Ck, // C
      mu, K, Kp, Kvb, Kg, Ex // tube
      )));
  }

  template<typename DataType_>
  void TubeFilter<DataType_>::full_setup()
  {
    // setup default_output
    SimplifiedVectorizedNewtonRaphson<CommonCathodeTriodeInitialFunction<DataType_>, 3, 10> custom(CommonCathodeTriodeInitialFunction<DataType_>(
      Rp, Rg, Ro, Rk, //R
      VBias, // VBias
      mu, K, Kp, Kvb, Kg, Ex // tube
      ));

    auto stable = custom.optimize();

    default_output[0] = 0;
    default_output[1] = stable(2);
    default_output[2] = -stable(0);
    default_output[3] = stable(0);
    default_output[4] = stable(1);

    Parent::full_setup();
  }

  template<typename DataType_>
  void TubeFilter<DataType_>::process_impl(int64_t size) const
  {
    assert(input_sampling_rate == output_sampling_rate);

    for(int64_t i = 0; i < size; ++i)
    {
      optimizer->optimize(i, converted_inputs.data(), outputs.data() + 1);
      outputs[0][i] = outputs[2][i] + outputs[3][i];
    }
  }

  template<typename DataType_>
  TubeFilter<DataType_> TubeFilter<DataType_>::build_standard_filter()
  {
    return TubeFilter<DataType_>(100e3, 220e3, 22e3, 2.7e3, //R
      400, // VBias
      20e-9, 10e-6, // C
      88.5, 1.73e-6, 600, 300, 1060, 1.4 // transistor
      );
  }

  template class TubeFilter<float>;
  template class TubeFilter<double>;
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <iomanip>
#include <iostream>
#include <memory>
#include <vector>
#include "lib/crc_factories.h"
#include "lib/file.h"
#include "lib/util.h"

namespace
{
    class hex
    {
        public:
            hex(CRC::Value hash, int length) : hash(hash), length(length) { }
            friend std::ostream &operator <<(std::ostream &os, const hex &h)
            {
                os << std::hex
                    << std::uppercase
                    << std::setw(h.length)
                    << std::setfill('0')
                    << h.hash;
                return os;
            }
        private:
            CRC::Value hash;
            int length;
    };

    class flag
    {
        public:
            flag(bool on) : on(on) { }
            friend std::ostream &operator <<(std::ostream &os, const flag &h)
            {
                os << (h.on ? "x" : "-");
                return os;
            }
        private:
            bool on;
    };

    void printUsage(std::ostream &s, std::vector<std::shared_ptr<CRC>> crcs)
    {
        s << "CRC manipulator v" << CRCMANIP_VERSION << "\n";
        s << R"(
Freely reverse and change CRC checksums through smart file patching.
Usage: crcmanip p[atch] INFILE OUTFILE CHECKSUM [PATCH_OPTIONS]
   or: crcmanip c[alc]  INFILE [CALC_OPTIONS]
   or: crcmanip h[elp]

Common options:
  INFILE               path to input file
  OUTFILE              path to output file
  CHECKSUM             target checksum; must be a hexadecimal value

PATCH_OPTIONS can be:
  -a, --algorithm ALG  which algorithm to use
  -i, --insert         specifies that patch should be inserted (default)
  -o, --overwrite      specifies that patch should overwrite existing bytes
  -p, --position NUM   position where to append the patch; unless specified,
                       patch will be placed at the end of the input file;
                       if position is negative, patch will be placed at the
                       n-th byte from the end of file

CALC_OPTIONS can be:
  -a, --algorithm ALG  which algorithm to use

Available ALG aglorithms:
)";

        const size_t maxChecksumSize = 8;
        size_t maxNameSize = 0;
        for (auto &crc : crcs)
            if (maxNameSize < crc->getSpecs().name.size())
                maxNameSize = crc->getSpecs().name.size();

        std::ios oldState(nullptr);
        oldState.copyfmt(std::cout);

        std::cout << "  "
            << std::setw(maxNameSize) << std::left << "Name"
            << " | " << std::setw(8) << std::left << "polynom."
            << "  " << std::setw(8) << std::left << "init XOR"
            << "  " << std::setw(8) << std::left << "end XOR"
            << "  flags"
            << "\n";

        bool isDefault = true;
        for (auto &crc : crcs)
        {
            const auto &specs = crc->getSpecs();
            auto fill = std::string(maxChecksumSize - specs.numBytes * 2, ' ');
            std::cout.copyfmt(oldState);
            std::cout
                << "  "
                << std::setw(maxNameSize) << std::left << crc->getSpecs().name
                << " | " << fill << hex(specs.polynomial, specs.numBytes * 2)
                << "  " << fill << hex(specs.initialXOR, specs.numBytes * 2)
                << "  " << fill << hex(specs.finalXOR, specs.numBytes * 2)
                << "  " << flag(isDefault)
                << " " << flag(specs.flags & CRC::Flags::BigEndian)
                << " " << flag(specs.flags & CRC::Flags::UseFileSize)
                << "\n";
            isDefault = false;
        }

        std::cout.copyfmt(oldState);

        s << R"(
Flag legend:
  1. Use by default when no --algorithm supplied?
  2. Uses big endian?
  3. Appends the file size internally?

Examples:
  ./crcmanip p input.txt output.txt 1234abcd
  ./crcmanip patch input.txt output.txt 1234abcd -p -1
  ./crcmanip calc input.txt -a CRC16IBM
)";
    }

    void validateChecksum(CRC &crc, const std::string &str)
    {
        size_t expectedDigits = crc.getSpecs().numBytes * 2;
        if (str.length() > expectedDigits)
        {
            throw std::runtime_error(
                "Error: Specified checksum has more than "
                + std::to_string(expectedDigits)
                + " digits.");
        }

        if (str.length() < expectedDigits)
        {
            std::cerr
                << "Warning: specified checksum has less than "
                << expectedDigits
                << " digits. Resulting checksum will be padded with 0.\n";
        }

        const std::string allowedCharacters = "0123456789abcdefABCDEF";
        for (auto &c : str)
        {
            if (allowedCharacters.find(c) == std::string::npos)
            {
                throw std::runtime_error(
                    "Error: Specified checksum contains invalid characters.\n"
                    "Only hexadecimal values are accepted.\n");
            }
        }
    }

    class Command
    {
        public:
            virtual void parse(std::vector<std::string> args) = 0;
            virtual void run() const = 0;
    };

    class CalculateCommand : public Command
    {
        public:
            CalculateCommand(std::vector<std::shared_ptr<CRC>> crcs);
            virtual void parse(std::vector<std::string> args);
            virtual void run() const;

        private:
            std::shared_ptr<CRC> crc;
            std::unique_ptr<File> inputFile;

            std::vector<std::shared_ptr<CRC>> crcs;
    };

    CalculateCommand::CalculateCommand(std::vector<std::shared_ptr<CRC>> crcs)
        : crcs(crcs)
    {
    }

    void CalculateCommand::parse(std::vector<std::string> args)
    {
        crc = crcs[0];

        if (args.size() < 1)
            throw std::runtime_error("No input file specified.");
        inputFile = File::fromFileName(
            args[0], File::Mode::Read | File::Mode::Binary);

        for (size_t i = 1; i < args.size(); i++)
        {
            auto &arg = args[i];
            if (arg == "-a" || arg == "--alg" || arg == "--algorithm")
            {
                if (i == args.size() - 1)
                    throw std::runtime_error(arg + " needs a parameter.");
                auto algo  = args[++i];
                auto it = std::find_if(
                    crcs.begin(), crcs.end(), [&](std::shared_ptr<CRC> crc)
                    { return crc->getSpecs().name == algo; });
                if (it == crcs.end())
                    throw std::runtime_error("Unknown algorithm: " + algo);
                crc = *it;
            }
        }
    }

    void CalculateCommand::run() const
    {
        Progress dummyProgress;
        auto checksum = crc->computeChecksum(*inputFile, dummyProgress);
        std::cout << hex(checksum, crc->getSpecs().numBytes * 2) << std::endl;
    }

    class PatchCommand : public Command
    {
        public:
            PatchCommand(std::vector<std::shared_ptr<CRC>> crcs);
            virtual void parse(std::vector<std::string> args);
            virtual void run() const;

        private:
            std::shared_ptr<CRC> crc;
            std::unique_ptr<File> inputFile;
            std::unique_ptr<File> outputFile;
            CRC::Value checksum;
            File::OffsetType position;
            bool positionSupplied;
            bool overwrite;

            std::vector<std::shared_ptr<CRC>> crcs;
    };

    PatchCommand::PatchCommand(std::vector<std::shared_ptr<CRC>> crcs)
        : crcs(crcs)
    {
    }

    void PatchCommand::parse(std::vector<std::string> args)
    {
        crc = crcs[0];
        positionSupplied = false;
        position = 0;
        overwrite = false;

        if (args.size() < 1)
            throw std::runtime_error("No input file specified.");
        inputFile = File::fromFileName(
            args[0], File::Mode::Read | File::Mode::Binary);

        if (args.size() < 2)
            throw std::runtime_error("No output file specified.");
        outputFile = File::fromFileName(
            args[1], File::Mode::Write | File::Mode::Binary);

        if (args.size() < 3)
            throw std::runtime_error("No checksum specified.");

        for (size_t i = 3; i < args.size(); i++)
        {
            auto &arg = args[i];
            if (arg == "-i" || arg == "--insert")
                overwrite = false;
            else if (arg == "-o" || arg == "--overwrite")
                overwrite = true;
            else if (arg == "-p" || arg == "--pos" || arg == "--position")
            {
                if (i == args.size() - 1)
                    throw std::runtime_error(arg + " needs a parameter.");
                auto pos = args[++i];
                positionSupplied = true;
                position = std::stoll(pos);
            }
            else if (arg == "-a" || arg == "--alg" || arg == "--algorithm")
            {
                if (i == args.size() - 1)
                    throw std::runtime_error(arg + " needs a parameter.");
                auto algo  = args[++i];
                auto it = std::find_if(
                    crcs.begin(), crcs.end(), [&](std::shared_ptr<CRC> crc)
                    { return crc->getSpecs().name == algo; });
                if (it == crcs.end())
                    throw std::runtime_error("Unknown algorithm: " + algo);
                crc = *it;
            }
        }

        validateChecksum(*crc, args[2]);
        checksum = std::stoull(args[2], nullptr, 16);
    }

    void PatchCommand::run() const
    {
        Progress writeProgress;
        writeProgress.started = []() { std::cout << "Output started\n"; };
        writeProgress.finished = []() { std::cout << "Output finished\n"; };

        Progress crcProgress;
        crcProgress.started = []() { std::cout << "Checksum started\n"; };
        crcProgress.finished = []() { std::cout << "Checksum finished\n"; };

        crcProgress.changed = writeProgress.changed
            = [](double percentage)
                {
                    std::cout
                        << std::setw(5)
                        << std::fixed
                        << std::setprecision(2)
                        << percentage
                        << "% done\r";
                        std::cout.flush();
                };

        auto correctedPosition = positionSupplied
            ? shiftUserPosition(
                position,
                inputFile->getSize(),
                crc->getSpecs().numBytes,
                overwrite)
            : computeAutoPosition(
                inputFile->getSize(),
                crc->getSpecs().numBytes,
                overwrite);

        crc->applyPatch(
            checksum,
            correctedPosition,
            *inputFile,
            *outputFile,
            overwrite,
            writeProgress,
            crcProgress);
    }
}

int main(int argc, char **argv)
{
    std::vector<std::string> args;
    for (int i = 1; i < argc; i++)
        args.push_back(std::string(argv[i]));

    auto crcs = createAllCRC();

    for (auto &arg : args)
    {
        if (arg == "-h" || arg == "--help")
        {
            printUsage(std::cout, crcs);
            return 0;
        }
    }

    std::unique_ptr<Command> command;
    try
    {
        if (args.size() < 1)
            throw std::runtime_error("No command chosen.");

        auto cmdName = args[0];
        args.erase(args.begin());
        cmdName.erase(0, cmdName.find_first_not_of('-'));

        if (cmdName == "p" || cmdName == "patch")
            command.reset(new PatchCommand(crcs));
        else if (cmdName == "c" || cmdName == "calc" || cmdName == "calculate")
            command.reset(new CalculateCommand(crcs));
        else if (cmdName == "h" || cmdName == "help")
        {
            printUsage(std::cout, crcs);
            return 0;
        }
        else
            throw std::invalid_argument("Unknown command: " + cmdName);

        command->parse(args);
    }
    catch (std::exception &e)
    {
        std::cerr << e.what() << "\n";
        printUsage(std::cerr, crcs);
        return 1;
    }

    try
    {
        command->run();
        return 0;
    }
    catch (std::exception &e)
    {
        std::cerr << e.what() << "\n";
        return 1;
    }
}
<commit_msg>Changed usage to be printed only on argument error<commit_after>#include <algorithm>
#include <iomanip>
#include <iostream>
#include <memory>
#include <vector>
#include "lib/crc_factories.h"
#include "lib/file.h"
#include "lib/util.h"

namespace
{
    class arg_error : public std::logic_error
    {
        public:
            arg_error(const std::string &msg) : std::logic_error(msg) { }
    };

    class hex
    {
        public:
            hex(CRC::Value hash, int length) : hash(hash), length(length) { }
            friend std::ostream &operator <<(std::ostream &os, const hex &h)
            {
                os << std::hex
                    << std::uppercase
                    << std::setw(h.length)
                    << std::setfill('0')
                    << h.hash;
                return os;
            }
        private:
            CRC::Value hash;
            int length;
    };

    class flag
    {
        public:
            flag(bool on) : on(on) { }
            friend std::ostream &operator <<(std::ostream &os, const flag &h)
            {
                os << (h.on ? "x" : "-");
                return os;
            }
        private:
            bool on;
    };

    void printUsage(std::ostream &s, std::vector<std::shared_ptr<CRC>> crcs)
    {
        s << "CRC manipulator v" << CRCMANIP_VERSION << "\n";
        s << R"(
Freely reverse and change CRC checksums through smart file patching.
Usage: crcmanip p[atch] INFILE OUTFILE CHECKSUM [PATCH_OPTIONS]
   or: crcmanip c[alc]  INFILE [CALC_OPTIONS]
   or: crcmanip h[elp]

Common options:
  INFILE               path to input file
  OUTFILE              path to output file
  CHECKSUM             target checksum; must be a hexadecimal value

PATCH_OPTIONS can be:
  -a, --algorithm ALG  which algorithm to use
  -i, --insert         specifies that patch should be inserted (default)
  -o, --overwrite      specifies that patch should overwrite existing bytes
  -p, --position NUM   position where to append the patch; unless specified,
                       patch will be placed at the end of the input file;
                       if position is negative, patch will be placed at the
                       n-th byte from the end of file

CALC_OPTIONS can be:
  -a, --algorithm ALG  which algorithm to use

Available ALG aglorithms:
)";

        const size_t maxChecksumSize = 8;
        size_t maxNameSize = 0;
        for (auto &crc : crcs)
            if (maxNameSize < crc->getSpecs().name.size())
                maxNameSize = crc->getSpecs().name.size();

        std::ios oldState(nullptr);
        oldState.copyfmt(std::cout);

        std::cout << "  "
            << std::setw(maxNameSize) << std::left << "Name"
            << " | " << std::setw(8) << std::left << "polynom."
            << "  " << std::setw(8) << std::left << "init XOR"
            << "  " << std::setw(8) << std::left << "end XOR"
            << "  flags"
            << "\n";

        bool isDefault = true;
        for (auto &crc : crcs)
        {
            const auto &specs = crc->getSpecs();
            auto fill = std::string(maxChecksumSize - specs.numBytes * 2, ' ');
            std::cout.copyfmt(oldState);
            std::cout
                << "  "
                << std::setw(maxNameSize) << std::left << crc->getSpecs().name
                << " | " << fill << hex(specs.polynomial, specs.numBytes * 2)
                << "  " << fill << hex(specs.initialXOR, specs.numBytes * 2)
                << "  " << fill << hex(specs.finalXOR, specs.numBytes * 2)
                << "  " << flag(isDefault)
                << " " << flag(specs.flags & CRC::Flags::BigEndian)
                << " " << flag(specs.flags & CRC::Flags::UseFileSize)
                << "\n";
            isDefault = false;
        }

        std::cout.copyfmt(oldState);

        s << R"(
Flag legend:
  1. Use by default when no --algorithm supplied?
  2. Uses big endian?
  3. Appends the file size internally?

Examples:
  ./crcmanip p input.txt output.txt 1234abcd
  ./crcmanip patch input.txt output.txt 1234abcd -p -1
  ./crcmanip calc input.txt -a CRC16IBM
)";
    }

    void validateChecksum(CRC &crc, const std::string &str)
    {
        size_t expectedDigits = crc.getSpecs().numBytes * 2;
        if (str.length() > expectedDigits)
        {
            throw arg_error(
                "Error: Specified checksum has more than "
                + std::to_string(expectedDigits)
                + " digits.");
        }

        if (str.length() < expectedDigits)
        {
            std::cerr
                << "Warning: specified checksum has less than "
                << expectedDigits
                << " digits. Resulting checksum will be padded with 0.\n";
        }

        const std::string allowedCharacters = "0123456789abcdefABCDEF";
        for (auto &c : str)
        {
            if (allowedCharacters.find(c) == std::string::npos)
            {
                throw arg_error(
                    "Error: Specified checksum contains invalid characters.\n"
                    "Only hexadecimal values are accepted.\n");
            }
        }
    }

    class Command
    {
        public:
            virtual void parse(std::vector<std::string> args) = 0;
            virtual void run() const = 0;
    };

    class CalculateCommand : public Command
    {
        public:
            CalculateCommand(std::vector<std::shared_ptr<CRC>> crcs);
            virtual void parse(std::vector<std::string> args);
            virtual void run() const;

        private:
            std::shared_ptr<CRC> crc;
            std::unique_ptr<File> inputFile;

            std::vector<std::shared_ptr<CRC>> crcs;
    };

    CalculateCommand::CalculateCommand(std::vector<std::shared_ptr<CRC>> crcs)
        : crcs(crcs)
    {
    }

    void CalculateCommand::parse(std::vector<std::string> args)
    {
        crc = crcs[0];

        if (args.size() < 1)
            throw arg_error("No input file specified.");
        inputFile = File::fromFileName(
            args[0], File::Mode::Read | File::Mode::Binary);

        for (size_t i = 1; i < args.size(); i++)
        {
            auto &arg = args[i];
            if (arg == "-a" || arg == "--alg" || arg == "--algorithm")
            {
                if (i == args.size() - 1)
                    throw arg_error(arg + " needs a parameter.");
                auto algo  = args[++i];
                auto it = std::find_if(
                    crcs.begin(), crcs.end(), [&](std::shared_ptr<CRC> crc)
                    { return crc->getSpecs().name == algo; });
                if (it == crcs.end())
                    throw arg_error("Unknown algorithm: " + algo);
                crc = *it;
            }
        }
    }

    void CalculateCommand::run() const
    {
        Progress dummyProgress;
        auto checksum = crc->computeChecksum(*inputFile, dummyProgress);
        std::cout << hex(checksum, crc->getSpecs().numBytes * 2) << std::endl;
    }

    class PatchCommand : public Command
    {
        public:
            PatchCommand(std::vector<std::shared_ptr<CRC>> crcs);
            virtual void parse(std::vector<std::string> args);
            virtual void run() const;

        private:
            std::shared_ptr<CRC> crc;
            std::unique_ptr<File> inputFile;
            std::unique_ptr<File> outputFile;
            CRC::Value checksum;
            File::OffsetType position;
            bool positionSupplied;
            bool overwrite;

            std::vector<std::shared_ptr<CRC>> crcs;
    };

    PatchCommand::PatchCommand(std::vector<std::shared_ptr<CRC>> crcs)
        : crcs(crcs)
    {
    }

    void PatchCommand::parse(std::vector<std::string> args)
    {
        crc = crcs[0];
        positionSupplied = false;
        position = 0;
        overwrite = false;

        if (args.size() < 1)
            throw arg_error("No input file specified.");
        inputFile = File::fromFileName(
            args[0], File::Mode::Read | File::Mode::Binary);

        if (args.size() < 2)
            throw arg_error("No output file specified.");
        outputFile = File::fromFileName(
            args[1], File::Mode::Write | File::Mode::Binary);

        if (args.size() < 3)
            throw arg_error("No checksum specified.");

        for (size_t i = 3; i < args.size(); i++)
        {
            auto &arg = args[i];
            if (arg == "-i" || arg == "--insert")
                overwrite = false;
            else if (arg == "-o" || arg == "--overwrite")
                overwrite = true;
            else if (arg == "-p" || arg == "--pos" || arg == "--position")
            {
                if (i == args.size() - 1)
                    throw arg_error(arg + " needs a parameter.");
                auto pos = args[++i];
                positionSupplied = true;
                position = std::stoll(pos);
            }
            else if (arg == "-a" || arg == "--alg" || arg == "--algorithm")
            {
                if (i == args.size() - 1)
                    throw arg_error(arg + " needs a parameter.");
                auto algo  = args[++i];
                auto it = std::find_if(
                    crcs.begin(), crcs.end(), [&](std::shared_ptr<CRC> crc)
                    { return crc->getSpecs().name == algo; });
                if (it == crcs.end())
                    throw arg_error("Unknown algorithm: " + algo);
                crc = *it;
            }
        }

        validateChecksum(*crc, args[2]);
        checksum = std::stoull(args[2], nullptr, 16);
    }

    void PatchCommand::run() const
    {
        Progress writeProgress;
        writeProgress.started = []() { std::cout << "Output started\n"; };
        writeProgress.finished = []() { std::cout << "Output finished\n"; };

        Progress crcProgress;
        crcProgress.started = []() { std::cout << "Checksum started\n"; };
        crcProgress.finished = []() { std::cout << "Checksum finished\n"; };

        crcProgress.changed = writeProgress.changed
            = [](double percentage)
                {
                    std::cout
                        << std::setw(5)
                        << std::fixed
                        << std::setprecision(2)
                        << percentage
                        << "% done\r";
                        std::cout.flush();
                };

        auto correctedPosition = positionSupplied
            ? shiftUserPosition(
                position,
                inputFile->getSize(),
                crc->getSpecs().numBytes,
                overwrite)
            : computeAutoPosition(
                inputFile->getSize(),
                crc->getSpecs().numBytes,
                overwrite);

        crc->applyPatch(
            checksum,
            correctedPosition,
            *inputFile,
            *outputFile,
            overwrite,
            writeProgress,
            crcProgress);
    }
}

int main(int argc, char **argv)
{
    std::vector<std::string> args;
    for (int i = 1; i < argc; i++)
        args.push_back(std::string(argv[i]));

    auto crcs = createAllCRC();

    for (auto &arg : args)
    {
        if (arg == "-h" || arg == "--help")
        {
            printUsage(std::cout, crcs);
            return 0;
        }
    }

    try
    {
        std::unique_ptr<Command> command;
        try
        {
            if (args.size() < 1)
                throw arg_error("No command chosen.");

            auto cmdName = args[0];
            args.erase(args.begin());
            cmdName.erase(0, cmdName.find_first_not_of('-'));

            if (cmdName == "p" || cmdName == "patch")
                command.reset(new PatchCommand(crcs));
            else if (cmdName == "c" || cmdName == "calc"
                || cmdName == "calculate")
            {
                command.reset(new CalculateCommand(crcs));
            }
            else if (cmdName == "h" || cmdName == "help")
            {
                printUsage(std::cout, crcs);
                return 0;
            }
            else
                throw arg_error("Unknown command: " + cmdName);

            command->parse(args);
        }
        catch (arg_error &e)
        {
            std::cerr << e.what() << "\n";
            printUsage(std::cerr, crcs);
            return 1;
        }

        command->run();
        return 0;
    }
    catch (std::exception &e)
    {
        std::cerr << e.what() << "\n";
        return 1;
    }
}
<|endoftext|>


<commit_before>#include <iomanip>
#include <iostream>
#include <memory>
#include <vector>

#ifndef __unix
    #include <sys/fcntl.h> // for setmode
#endif

#include "CRC/CRC.h"
#include "CRC/CRC16CCITT.h"
#include "CRC/CRC16IBM.h"
#include "CRC/CRC32.h"
#include "File/File.h"
#include "util.h"

namespace
{
    std::vector<std::shared_ptr<CRC>> getAllCrcs()
    {
        std::vector<std::shared_ptr<CRC>> crcs;
        crcs.push_back(std::shared_ptr<CRC>(new CRC32));
        crcs.push_back(std::shared_ptr<CRC>(new CRC16CCITT));
        crcs.push_back(std::shared_ptr<CRC>(new CRC16IBM));
        return crcs;
    }

    void printUsage(std::ostream &s, std::vector<std::shared_ptr<CRC>> crcs)
    {
        s << "CRC manipulator v" << CRCMANIP_VERSION << "\n";
        s << R"(
Freely reverse and change CRC checksums through smart file patching.
Usage: crcmanip INFILE OUTFILE CHECKSUM [OPTIONS]

INFILE               input file. if -, standard input will be used.
OUTFILE              output file. if -, standard output will be used.
CHECKSUM             target checksum.

OPTIONS can be:
-h, --help           print this information.
-p, --position=NUM   position where to append the patch. Unless specified,
                     patch will be placed at the end of the input file.
                     If position is negative, patch will be placed at the
                     n-th byte from the end of file.
    --insert         specifies that patch should be inserted (default)
    --overwrite      specifies that patch should overwrite existing bytes
-a, --algorithm=ALG  specifies which algorithm to use.

Available algorithms:
)";

        bool isDefault = true;
        for (auto &crc : crcs)
        {
            std::cout
                << "* "
                << crc->getName()
                << (isDefault ? " (default)" : "")
                << "\n";
            isDefault = false;
        }

        s << R"(
CHECKSUM must be a hexadecimal value.
INFILE must be seekable stream. In other words, it cannot be a pipe
(particularly standard input), fifo etc.

Examples:
./crcmanip input.txt output.txt 1234abcd
./crcmanip input.txt output.txt 1234abcd -p -1
./crcmanip input.txt - 1234abcd >output.txt
./crcmanip - output.txt 1234abcd <input.txt
./crcmanip - - 1234abcd <input.txt >output.txt
)";
        exit(EXIT_FAILURE);
    }

    void validateChecksum(CRC &crc, const std::string &str)
    {
        if (str.length() > crc.getNumBytes() * 2)
        {
            std::cerr
                << "Error: Specified checksum has more than "
                << crc.getNumBytes() * 2
                << " digits.\n";
            exit(EXIT_FAILURE);
        }

        if (str.length() < crc.getNumBytes() * 2)
        {
            std::cerr
                << "Warning: specified checksum has less than "
                << crc.getNumBytes() * 2
                << " digits. Resulting checksum will be padded with 0.\n";
        }

        const std::string allowedCharacters = "0123456789abcdefABCDEF";
        for (size_t i = 0; i < str.length(); i++)
        {
            if (allowedCharacters.find(str[i]) == std::string::npos)
            {
                std::cerr
                    << "Error: Specified checksum contains invalid characters. "
                    << "Only hexadecimal values are accepted.\n";
                exit(EXIT_FAILURE);
            }
        }
    }

    class FacadeArgs
    {
        public:
            std::shared_ptr<CRC> crc;
            CRCType checksum;
            std::string inputPath;
            std::string outputPath;
            File::OffsetType position;
            bool automaticPosition;
            bool overwrite;
    };

    FacadeArgs parseArguments(
        std::vector<std::string> args, std::vector<std::shared_ptr<CRC>> crcs)
    {
        FacadeArgs fa;
        fa.crc = crcs[0];
        fa.automaticPosition = true;
        fa.position = 0;
        fa.overwrite = false;
        fa.inputPath = "";
        fa.outputPath = "";

        for (auto &arg : args)
        {
            if (arg == "-h" || arg == "--help")
            {
                printUsage(std::cout, crcs);
                exit(EXIT_SUCCESS);
            }
        }

        if (args.size() < 1)
        {
            std::cerr << "No input file specified.\n";
            printUsage(std::cerr, crcs);
            exit(EXIT_FAILURE);
        }
        if (args[0] != "")
            fa.inputPath = args[0];

        if (args.size() < 2)
        {
            std::cerr << "No output file specified.\n";
            printUsage(std::cerr, crcs);
            exit(EXIT_FAILURE);
        }
        if (args[1] != "-")
            fa.outputPath = args[1];

        if (args.size() < 3)
        {
            std::cerr << "No checksum specified.\n";
            printUsage(std::cerr, crcs);
            exit(EXIT_FAILURE);
        }

        for (size_t i = 3; i < args.size(); i++)
        {
            auto &arg = args[i];
            if (arg == "--insert")
                fa.overwrite = false;
            else if (arg == "--overwrite")
                fa.overwrite = true;
            else if (arg == "-p" || arg == "--pos" || arg == "--position")
            {
                if (i == args.size() - 1)
                {
                    std::cerr << "--position needs an additional parameter.\n";
                    printUsage(std::cerr, crcs);
                    exit(EXIT_FAILURE);
                }
                arg = args[++i];
                fa.automaticPosition = false;
                fa.position = std::stoll(arg);
            }
            else if (arg == "-a" || arg == "--alg" || arg == "--algorithm")
            {
                if (i == args.size() - 1)
                {
                    std::cerr << "--algorithm needs an additional parameter.\n";
                    printUsage(std::cerr, crcs);
                    exit(EXIT_FAILURE);
                }
                auto algo  = args[++i];
                bool found = false;
                for (auto &crc : crcs)
                {
                    if (crc->getName() == algo)
                    {
                        fa.crc = crc;
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    std::cerr << "Unknown algorithm: " << algo << "\n";
                    printUsage(std::cerr, crcs);
                    exit(EXIT_FAILURE);
                }
            }
        }

        validateChecksum(*fa.crc, args[2]);
        fa.checksum = std::stoull(args[2], nullptr, 16);

        return fa;
    }

    void run(FacadeArgs &fa)
    {
        Progress writeProgress;
        writeProgress.started
            = []() { std::cout << "Output started" << std::endl; };
        writeProgress.finished
            = []() { std::cout << "Output finished" << std::endl; };

        Progress checksumProgress;
        checksumProgress.started
            = []() { std::cout << "Partial checksum started" << std::endl; };
        checksumProgress.finished
            = []() { std::cout << "Partial checksum finished" << std::endl; };

        checksumProgress.changed = writeProgress.changed
            = [](double percentage)
                {
                    std::cout
                        << std::setw(5)
                        << std::fixed
                        << std::setprecision(2)
                        << percentage
                        << "% done\r";
                        std::cout.flush();
                };

        std::unique_ptr<File> inputFile;
        try
        {
            if (fa.inputPath == "")
            {
                #ifndef __unix
                    setmode(fileno(stdin), O_BINARY);
                #endif
                inputFile = File::fromFileHandle(stdin);
            }
            else
            {
                inputFile = File::fromFileName(
                    fa.inputPath, File::Mode::Read | File::Mode::Binary);
            }
        }
        catch (...)
        {
            std::cerr << "Failed to open " << fa.inputPath << " for reading.\n";
            exit(EXIT_FAILURE);
        }

        if (fa.automaticPosition)
        {
            fa.position = computeAutoPosition(
                inputFile->getSize(), fa.crc->getNumBytes(), fa.overwrite);
        }
        else
        {
            fa.position = shiftUserPosition(
                fa.position,
                inputFile->getSize(),
                fa.crc->getNumBytes(),
                fa.overwrite);
        }

        std::unique_ptr<File> outputFile;
        try
        {
            if (fa.outputPath == "")
            {
                #ifndef __unix
                    setmode(fileno(stdout), O_BINARY);
                #endif
                outputFile = File::fromFileHandle(stdout);
            }
            else
            {
                outputFile = File::fromFileName(
                    fa.outputPath, File::Mode::Write | File::Mode::Binary);
            }
        }
        catch (...)
        {
            std::cerr
                << "Failed to open " << fa.outputPath << " for writing.\n";
            exit(EXIT_FAILURE);
        }

        fa.crc->applyPatch(
            fa.checksum,
            fa.position,
            *inputFile,
            *outputFile,
            fa.overwrite,
            writeProgress,
            checksumProgress);

        exit(EXIT_SUCCESS);
    }
}

int main(int argc, char **argv)
{
    std::vector<std::string> args;
    for (int i = 1; i < argc; i++)
        args.push_back(std::string(argv[i]));

    auto crcs = getAllCrcs();
    auto fa = parseArguments(args, crcs);
    run(fa);
}
<commit_msg>Simplified error handling in CLI<commit_after>#include <iomanip>
#include <iostream>
#include <memory>
#include <vector>

#ifndef __unix
    #include <sys/fcntl.h> // for setmode
#endif

#include "CRC/CRC.h"
#include "CRC/CRC16CCITT.h"
#include "CRC/CRC16IBM.h"
#include "CRC/CRC32.h"
#include "File/File.h"
#include "util.h"

namespace
{
    std::vector<std::shared_ptr<CRC>> getAllCrcs()
    {
        std::vector<std::shared_ptr<CRC>> crcs;
        crcs.push_back(std::shared_ptr<CRC>(new CRC32));
        crcs.push_back(std::shared_ptr<CRC>(new CRC16CCITT));
        crcs.push_back(std::shared_ptr<CRC>(new CRC16IBM));
        return crcs;
    }

    void printUsage(std::ostream &s, std::vector<std::shared_ptr<CRC>> crcs)
    {
        s << "CRC manipulator v" << CRCMANIP_VERSION << "\n";
        s << R"(
Freely reverse and change CRC checksums through smart file patching.
Usage: crcmanip INFILE OUTFILE CHECKSUM [OPTIONS]

INFILE               input file. if -, standard input will be used.
OUTFILE              output file. if -, standard output will be used.
CHECKSUM             target checksum.

OPTIONS can be:
-h, --help           print this information.
-p, --position=NUM   position where to append the patch. Unless specified,
                     patch will be placed at the end of the input file.
                     If position is negative, patch will be placed at the
                     n-th byte from the end of file.
    --insert         specifies that patch should be inserted (default)
    --overwrite      specifies that patch should overwrite existing bytes
-a, --algorithm=ALG  specifies which algorithm to use.

Available algorithms:
)";

        bool isDefault = true;
        for (auto &crc : crcs)
        {
            std::cout
                << "* "
                << crc->getName()
                << (isDefault ? " (default)" : "")
                << "\n";
            isDefault = false;
        }

        s << R"(
CHECKSUM must be a hexadecimal value.
INFILE must be seekable stream. In other words, it cannot be a pipe
(particularly standard input), fifo etc.

Examples:
./crcmanip input.txt output.txt 1234abcd
./crcmanip input.txt output.txt 1234abcd -p -1
./crcmanip input.txt - 1234abcd >output.txt
./crcmanip - output.txt 1234abcd <input.txt
./crcmanip - - 1234abcd <input.txt >output.txt
)";
        exit(EXIT_FAILURE);
    }

    void validateChecksum(CRC &crc, const std::string &str)
    {
        if (str.length() > crc.getNumBytes() * 2)
        {
            throw std::runtime_error(
                "Error: Specified checksum has more than "
                + std::to_string(crc.getNumBytes() * 2)
                + " digits.");
        }

        if (str.length() < crc.getNumBytes() * 2)
        {
            std::cerr
                << "Warning: specified checksum has less than "
                << crc.getNumBytes() * 2
                << " digits. Resulting checksum will be padded with 0.\n";
        }

        const std::string allowedCharacters = "0123456789abcdefABCDEF";
        for (auto &c : str)
        {
            if (allowedCharacters.find(c) == std::string::npos)
            {
                throw std::runtime_error(
                    "Error: Specified checksum contains invalid characters.\n"
                    "Only hexadecimal values are accepted.\n");
            }
        }
    }

    class FacadeArgs
    {
        public:
            std::shared_ptr<CRC> crc;
            CRCType checksum;
            std::string inputPath;
            std::string outputPath;
            File::OffsetType position;
            bool automaticPosition;
            bool overwrite;
    };

    FacadeArgs parseArguments(
        std::vector<std::string> args, std::vector<std::shared_ptr<CRC>> crcs)
    {
        FacadeArgs fa;
        fa.crc = crcs[0];
        fa.automaticPosition = true;
        fa.position = 0;
        fa.overwrite = false;
        fa.inputPath = "";
        fa.outputPath = "";

        for (auto &arg : args)
        {
            if (arg == "-h" || arg == "--help")
            {
                printUsage(std::cout, crcs);
                exit(EXIT_SUCCESS);
            }
        }

        try
        {
            if (args.size() < 1)
                throw std::runtime_error("No input file specified.");
            if (args[0] != "-")
                fa.inputPath = args[0];

            if (args.size() < 2)
                throw std::runtime_error("No output file specified.");
            if (args[1] != "-")
                fa.outputPath = args[1];

            if (args.size() < 3)
                throw std::runtime_error("No checksum specified.");

            for (size_t i = 3; i < args.size(); i++)
            {
                auto &arg = args[i];
                if (arg == "--insert")
                    fa.overwrite = false;
                else if (arg == "--overwrite")
                    fa.overwrite = true;
                else if (arg == "-p" || arg == "--pos" || arg == "--position")
                {
                    if (i == args.size() - 1)
                        throw std::runtime_error(arg + " needs a parameter.");
                    auto pos = args[++i];
                    fa.automaticPosition = false;
                    fa.position = std::stoll(pos);
                }
                else if (arg == "-a" || arg == "--alg" || arg == "--algorithm")
                {
                    if (i == args.size() - 1)
                        throw std::runtime_error(arg + " needs a parameter.");
                    auto algo  = args[++i];
                    bool found = false;
                    for (auto &crc : crcs)
                    {
                        if (crc->getName() == algo)
                        {
                            fa.crc = crc;
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                        throw std::runtime_error("Unknown algorithm: " + algo);
                }
            }

            validateChecksum(*fa.crc, args[2]);
            fa.checksum = std::stoull(args[2], nullptr, 16);
        }
        catch (std::exception &e)
        {
            std::cerr << e.what() << "\n";
            printUsage(std::cerr, crcs);
            exit(EXIT_FAILURE);
        }
        return fa;
    }

    void run(FacadeArgs &fa)
    {
        Progress writeProgress;
        writeProgress.started
            = []() { std::cout << "Output started" << std::endl; };
        writeProgress.finished
            = []() { std::cout << "Output finished" << std::endl; };

        Progress checksumProgress;
        checksumProgress.started
            = []() { std::cout << "Partial checksum started" << std::endl; };
        checksumProgress.finished
            = []() { std::cout << "Partial checksum finished" << std::endl; };

        checksumProgress.changed = writeProgress.changed
            = [](double percentage)
                {
                    std::cout
                        << std::setw(5)
                        << std::fixed
                        << std::setprecision(2)
                        << percentage
                        << "% done\r";
                        std::cout.flush();
                };

        std::unique_ptr<File> inputFile;
        try
        {
            if (fa.inputPath == "")
            {
                #ifndef __unix
                    setmode(fileno(stdin), O_BINARY);
                #endif
                inputFile = File::fromFileHandle(stdin);
            }
            else
            {
                inputFile = File::fromFileName(
                    fa.inputPath, File::Mode::Read | File::Mode::Binary);
            }
        }
        catch (...)
        {
            std::cerr << "Failed to open " << fa.inputPath << " for reading.\n";
            exit(EXIT_FAILURE);
        }

        if (fa.automaticPosition)
        {
            fa.position = computeAutoPosition(
                inputFile->getSize(), fa.crc->getNumBytes(), fa.overwrite);
        }
        else
        {
            fa.position = shiftUserPosition(
                fa.position,
                inputFile->getSize(),
                fa.crc->getNumBytes(),
                fa.overwrite);
        }

        std::unique_ptr<File> outputFile;
        try
        {
            if (fa.outputPath == "")
            {
                #ifndef __unix
                    setmode(fileno(stdout), O_BINARY);
                #endif
                outputFile = File::fromFileHandle(stdout);
            }
            else
            {
                outputFile = File::fromFileName(
                    fa.outputPath, File::Mode::Write | File::Mode::Binary);
            }
        }
        catch (...)
        {
            std::cerr
                << "Failed to open " << fa.outputPath << " for writing.\n";
            exit(EXIT_FAILURE);
        }

        fa.crc->applyPatch(
            fa.checksum,
            fa.position,
            *inputFile,
            *outputFile,
            fa.overwrite,
            writeProgress,
            checksumProgress);

        exit(EXIT_SUCCESS);
    }
}

int main(int argc, char **argv)
{
    std::vector<std::string> args;
    for (int i = 1; i < argc; i++)
        args.push_back(std::string(argv[i]));

    auto crcs = getAllCrcs();
    auto fa = parseArguments(args, crcs);
    run(fa);
}
<|endoftext|>


<commit_before>/**
 * L I N E A R   A L G E B R A   O P C O D E S   F O R   C S O U N D
 * Michael Gogins
 *
 * These opcodes implement many linear algebra operations
 * from BLAS and LAPACK, up to and including eigenvalue decompositions.
 * They are designed to facilitate signal processing,
 * and of course other mathematical operations,
 * in the Csound orchestra language.
 *
 * These opcodes work with the following data types (and data type codes):
 * 1. Real scalars, which are Csound i-rate (ir) or k-rate scalars (kr),
 *    where x stands for either i or k (xr).
 * 2. Complex scalars, which are ordered pairs of Csound scalars (xcr, xci).
 * 3. Allocated real vectors (xvr).
 * 4. Allocated complex vectors (xvc).
 * 5. Allocated real matrices (xmr).
 * 6. Allocated complex matrices (xmc).
 * 7. Storage for each allocated array is created using AUXCH,
 *    but it is used as a regular Csound variable,
 *    which is always a pointer to a floating-point number.
 *    The size and type code of the array are found
 *    in the first 8 bytes of storage:
 *    bytes 0 through 4: number of elements in the array.
 *    bytes 5 through 7: type code (e.g. 'imc'), encoding rate, rank, type.
 *    byte  8:           first byte of the first element of the array.
 *
 * The BLAS vector-vector copy functions are overloaded,
 * and can also be used for copying BLAS arrays
 * to and from other Csound data types:
 * 1. Csound a-rate scalars (which are already vectors)
 *    and function tables (i-rate scalars as function table numbers)
 *    can copied to and from real vectors (xvr)
 *    of the same size.
 * 2. Csound fsigs (PVS signals, PVSDAT)
 *    and wsigs (spectral signals, SPECDAT)
 *    can be copied to and from complex vectors (xvc)
 *    of the same size.
 *
 * Opcode names and signatures are determined as follows:
 * 1. All opcode names in this library are prefixed "la_" for "linear algebra".
 * 2. The opcode name is then additionally prefixed with a data type code.
 *    Because Csound variables have a fixed precision
 *    (always single or always double),
 *    Csound data types (r for real, c for complex) are used instead of
 *    BLAS data types (S, D, C, Z).
 * 3. The body of the opcode name is the same as
 *    the body of the BLAS or LAPACK name.
 * 4. The return values and parameters are prefixed
 *    first with the Csound rate, then with v for vector or m for matrix,
 *    then with the data type code, then (if a variable) with an underscore;
 *    as previously noted complex scalars are pairs of real scalars.
 *    Thus, the i-rate BLAS complex scalar a is icr_a, ici_a;
 *    the k-rate BLAS complex vector x is kvc_x; and
 *    the i-rate or k-rate BLAS real matrix A is xvr_A.
 * 5. Because all Csound data types and allocated arrays
 *    know their own size, BLAS and LAPACK size arguments are omitted,
 *    except from creator functions; this is similar to the FORTRAN 95
 *    interface to the BLAS routines.
 * 6. Operations that return scalars usually return i-rate or k-rate values
 *    on the left-hand side of the opcode.
 * 7. Operations that return vectors or matrices always copy the return value
 *    into a preallocated argument on the right-hand side of the opcode.
 * 8. The rate (i-rate versus k-rate or a-rate) of either the return value,
 *    or the first argument if there is no return value, determines
 *    the rate of the operation.  The exact same function is called
 *    for i-rate, k-rate, and a-rate opcodes;
 *    the only difference is that an i-rate opcode is evaluated only in the init pass,
 *    while a k-rate or a-rate opcode is evaluated in each kperiod pass.
 * 9. All arrays are 0-based.
 *10. All matrices are considered to be row-major
 *    (x or i goes along rows, y or j goes along columns).
 *11. All arrays are considered to be general and dense; therefore, the BLAS
 *    banded, Hermitian, symmetric, and sparse routines are not implemented.
 *12. At this time, only the general-purpose 'driver' routines
 *    for LAPACK are implemented.
 *
 * For more complete information on how to use the opcodes,
 * what the arguments are, which arguments are inputs, which arguments are outputs,
 * and so on, consult BLAS and LAPACK documentation,
 * e.g. http://www.intel.com/software/products/mkl/docs/WebHelp/mkl.htm.
 *
 * The operations are:
 *
 * ALLOCATORS
 *
 * Allocate real vector.
 * xvr la_rv ir_size
 *
 * Allocate complex vector.
 * xvc la_cv ir_size
 *
 * Allocate real matrix, with optional diagonal.
 * xmr la_rm ir_rows, ir_columns [, or_diagonal]
 *
 * Allocate complex matrix, with optional diagonal.
 * xmc la_cm irows, icolumns [, or_diagonal, oi_diagonal]
 *
 * LEVEL 1 BLAS -- VECTOR-VECTOR OPERATIONS
 *
 * Vector-vector dot product:
 * Return x * y.
 * xr       la_rdot  xvr_x, xvr_y
 * xcr, xci la_cdotu xvc_x, xvc_y
 *
 * Conjugate vector-vector dot product:
 * Return conjg(x) * y.
 * xcr, xci la_cdotc xvc_x, xvc_y
 *
 * Compute y := a * x + y.
 * la_raxpy xr_a, xvr_x, xvr_y
 * la_caxpy xr_a, xcr_x, xcr_y
 *
 * Givens rotation:
 * Given a point in a, b,
 * compute the Givens plane rotation in a, b, c, s
 * that zeros the y-coordinate of the point.
 * la_rrotg xr_a, xr_b, xr_c, xr_s
 * la_crotg xcr_a, xci_a, xcr_b, xci_b, xcr_c, xci_c, xcr_s, xci_s
 *
 * Rotate a vector x by a vector y:
 * For all i, x[i] = c * x[i] + s * y[i];
 * For all i, y[i] = c * y[i] - s * x[i].
 * la_rrot xvr_x, xvr_y, xr_c, xr_s
 * la_crot xvc_x, xvc_y, xr_c, xr_s
 *
 * Vector copy:
 * Compute y := x.
 * Note that x or y can be a-rate, function table number,
 *
 * la_rcopy xvr_x, xvr_y
 * la_ccopy xcr_x, xvc_y
 *
 * Vector swap:
 * Swap vector x with vector y.
 * la_rswap xvr_x, xvr_y
 * la_cswap xcr_x, xvc_y
 *
 * Vector norm:
 * Return the Euclidean norm of vector x.
 * xr       rnrm2 xvr_x
 * xcr, xci cnrm2 xcr_x
 *
 * Vector absolute value:
 * Return the real sum of the absolute values of the vector elements.
 * xr asum xvr_x
 * xr axum xcr_x
 *
 * Vector scale:
 * Compute x := alpha * x.
 * la_rscal xr_alpha, xvr_x
 * la_cscal xcr_alpha, xci_alpha, xcr_x
 *
 * Vector absolute maximum:
 * Return the index of the maximum absolute value in vector x.
 * xr la_ramax xvr_x
 * xr la_camax xvc_x
 *
 * Vector absolute minimum:
 * Return the index of the minimum absolute value in vector x.
 * xr la_ramin xvr_x
 * xr la_camin xvc_x
 *
 * LEVEL 2 BLAS -- MATRIX-VECTOR OPERATIONS
 *
 * Matrix-vector dot product:
 * Compute y := alpha * A * x + beta * y, if trans is 0.
 * Compute y := alpha * A' * x + beta * y, if trans is 1.
 * Compute y := alpha * conjg(A') * x + beta * y, if trans is 2.
 * la_rgemv xmr_A, xvr_x, xvr_ay [, Pr_alpha][, or_beta][, or_trans]
 * la_cgemv xmc_A, xvc_x, xvc_ay [, Pcr_alpha, oci_alpha][, ocr_beta, oci_beta][, or_trans]
 *
 * Rank-1 update of a matrix:
 * Compute A := alpha * x * y' + A.
 * la_rger xr_alpha, xvr_x, xvr_y, xmr_A
 * la_cger xcr_alpha, xci_alpha, xvc_x, xvc_y, xmc_A
 *
 * Rank-1 update of a conjugated matrix:
 * Compute A := alpha * x * conjg(y') + A
 * la_rgerc xmr_A, xvr_x, xvr_y, [, Pr_alpha]
 * la_cgerc xmc_A, xvc_x, xvc_y, [, Pcr_alpha, oci_alpha]
 *
 * Solve a system of linear equations:
 * Coefficients are in a packed triangular matrix,
 * upper triangular if uplo = 0, lower triangular if uplo = 1.
 * Solve A * x = b for x, if trans = 0.
 * Solve A' * x = b for x, if trans = 1.
 * Solve conjg(A') * x = b for x, if trans = 2.
 * la_rtpsv xmr_A, xvr_x, xvr_b [, or_uplo][, or_trans]
 * la_ctpsv xmc_A, xvc_x, xvc_b [, or_uplo][, or_trans]
 *
 * LEVEL 3 BLAS -- MATRIX-MATRIX OPERATIONS
 *
 * Matrix-matrix dot product:
 * Compute C := alpha * op(A) * op(B) + beta * C,
 * where transa or transb is 0 if op(X) is X, 1 if op(X) is X', or 2 if op(X) is conjg(X);
 * alpha and beta are 1 by default (set beta to 0 if you don't want to zero C first).
 * la_rgemm xmr_A, xmr_B, xmr_C [, or_transa][, or_transb][, Pr_alpha][, Pr_beta]
 * la_cgemm xmc_A, xmc_B, xmc_C [, or_transa][, or_transb][, Pcr_alpha, oci_alpha][, Pcr_beta, oci_beta]
 *
 * Solve a matrix equation:
 * Solve op(A) * X = alpha * B or X * op(A) = alpha * B for X,
 * where transa is 0 if op(X) is X, 1 if op(X) is X', or 2 if op(X) is conjg(X);
 * side is 0 for op(A) on the left, or 1 for op(A) on the right;
 * uplo is 0 for upper triangular A, or 1 for lower triangular A;
 * and diag is 0 for unit triangular A, or 1 for non-unit triangular A.
 * la_rtrsm xmr_A, xmr_B [, or_side][, or_uplo][, or_transa][, or_diag] [, Pr_alpha]
 * la_ctrsm xmc_A, cmc_B [, or_side][, or_uplo][, or_transa][, or_diag] [, Pcr_alpha, oci_alpha]
 *
 * LAPACK -- LINEAR SOLUTIONS
 *
 * Solve a system of linear equations:
 * Solve A * X = B,
 * where A is a square matrix of coefficients,
 * the columns of B are individual right-hand sides,
 * ipiv is a vector for pivot elements,
 * the columns of B are replaced with the corresponding solutions,
 * and info is replaced with 0 for success, -i for a bad value in the ith parameter,
 * or i if U(i, i) is 0, i.e. U is singular.
 * la_rgesv xmr_A, xmr_B [, ovr_ipiv][, or_info]
 * la_cgesv xmc_A, xmc_B [, ovc_ipiv][, or_info]
 *
 * LAPACK -- LINEAR LEAST SQUARES PROBLEMS
 *
 * QR or LQ factorization:
 * Uses QR or LQ factorization to solve an overdetermined or underdetermined
 * linear system with full rank matrix,
 * where A is the m x n matrix to factor;
 * B is an m x number of right-hand sides,
 * containing B as input and solution X as result;
 * if trans = 0, A is normal;
 * if trans = 1, A is transposed (real matrices only);
 * if trans = 2, A is conjugate-transposed (complex matrices only);
 * and info is replaced with 0 for success, -i for a bad value in the ith parameter,
 * or i if U(i, i) is 0, the i-th diagonal element of the triangular factor
 * of A is zero, so that A does not have full rank; the least squares solution could not be computed.
 * la_rgels xmr_A, xmr_B [, or_trans] [, or_info]
 *
 * LAPACK -- SINGULAR VALUE DECOMPOSITION
 *
 * Singular value decomposition of a general rectangular matrix:
 * Singular value decomposition of a general rectangular matrix by divide and conquer:
 *
 * LAPACK -- NONSYMMETRIX EIGENPROBLEMS
 *
 * Computes the eigenvalues and Schur factorization of a general matrix,
 * and orders the factorization so that selected eigenvalues are at the top left of the Schur form:
 * Computes the eigenvalues and left and right eigenvectors of a general matrix:
 *
 * LAPACK -- GENERALIZED NONSYMMETRIC EIGENPROBLEMS
 *
 * Compute the generalized eigenvalues, Schur form,
 * and the left and/or right Schur vectors for a pair of nonsymmetric matrices:
 * Computes the generalized eigenvalues, and the left and/or right generalized eigenvectors
 * for a pair of nonsymmetric matrices:
 *
 */
extern "C"
{
  // a-rate, k-rate, FUNC, SPECDAT
#include <csoundCore.h>
  // PVSDAT
#include <pstream.h>
}

/**
 * Used for all types of arrays
 * (vectors and matrices, real and complex).
 */
struct BLASArray
{
  size_t elements;
  char[4] typecode;
  MYFLT *data;
};

#include <OpcodeBase.hpp>

<commit_msg>no message<commit_after>/**
 * L I N E A R   A L G E B R A   O P C O D E S   F O R   C S O U N D
 * Michael Gogins
 *
 * These opcodes implement many linear algebra operations
 * from BLAS and LAPACK, up to and including eigenvalue decompositions.
 * They are designed to facilitate signal processing,
 * and of course other mathematical operations,
 * in the Csound orchestra language.
 *
 * The opcodes work with the following data types (and data type codes):
 * 1. Real scalars, which are Csound i-rate (ir) or k-rate scalars (kr),
 *    where x stands for either i or k (xr).
 * 2. Complex scalars, which are ordered pairs of Csound scalars (xcr, xci).
 * 3. Allocated real vectors (xvr).
 * 4. Allocated complex vectors (xvc).
 * 5. Allocated real matrices (xmr).
 * 6. Allocated complex matrices (xmc).
 * 7. Storage for each allocated array is created using AUXCH,
 *    but it is used as a regular Csound variable,
 *    which is always a pointer to a floating-point number.
 *    The size and type code of the array are found
 *    in the first 8 bytes of storage:
 *    bytes 0 through 4: number of elements in the array.
 *    bytes 5 through 7: type code (e.g. 'imc'), encoding rate, rank, type.
 *    byte  8:           first byte of the first element of the array.
 *
 * The BLAS vector-vector copy functions are overloaded,
 * and can also be used for copying BLAS arrays
 * to and from other Csound data types:
 * 1. Csound a-rate scalars (which are already vectors)
 *    and function tables (i-rate scalars as function table numbers)
 *    can copied to and from real vectors (xvr)
 *    of the same size.
 * 2. Csound fsigs (PVS signals, PVSDAT)
 *    and wsigs (spectral signals, SPECDAT)
 *    can be copied to and from complex vectors (xvc)
 *    of the same size.
 *
 * Opcode names and signatures are determined as follows:
 * 1. All opcode names in this library are prefixed "la_" for "linear algebra".
 * 2. The opcode name is then additionally prefixed with a data type code.
 *    Because Csound variables have a fixed precision
 *    (always single or always double),
 *    Csound data types (r for real, c for complex) are used instead of
 *    BLAS data types (S, D, C, Z).
 * 3. The body of the opcode name is the same as
 *    the body of the BLAS or LAPACK name.
 * 4. The return values and parameters are prefixed
 *    first with the Csound rate, then with v for vector or m for matrix,
 *    then with the data type code, then (if a variable) with an underscore;
 *    as previously noted complex scalars are pairs of real scalars.
 *    Thus, the i-rate BLAS complex scalar a is icr_a, ici_a;
 *    the k-rate BLAS complex vector x is kvc_x; and
 *    the i-rate or k-rate BLAS real matrix A is xvr_A.
 * 5. Because all Csound data types and allocated arrays
 *    know their own size, BLAS and LAPACK size arguments are omitted,
 *    except from creator functions; this is similar to the FORTRAN 95
 *    interface to the BLAS routines.
 * 6. Operations that return scalars usually return i-rate or k-rate values
 *    on the left-hand side of the opcode.
 * 7. Operations that return vectors or matrices always copy the return value
 *    into a preallocated argument on the right-hand side of the opcode.
 * 8. The rate (i-rate versus k-rate or a-rate) of either the return value,
 *    or the first argument if there is no return value, determines
 *    the rate of the operation.  The exact same function is called
 *    for i-rate, k-rate, and a-rate opcodes;
 *    the only difference is that an i-rate opcode is evaluated only in the init pass,
 *    while a k-rate or a-rate opcode is evaluated in each kperiod pass.
 * 9. All arrays are 0-based.
 *10. All matrices are considered to be row-major
 *    (x or i goes along rows, y or j goes along columns).
 *11. All arrays are considered to be general and dense; therefore, the BLAS
 *    banded, Hermitian, symmetric, and sparse routines are not implemented.
 *12. At this time, only the general-purpose 'driver' routines
 *    for LAPACK are implemented.
 *
 * For more complete information on how to use the opcodes,
 * what the arguments are, which arguments are inputs, which arguments are outputs,
 * and so on, consult BLAS and LAPACK documentation,
 * e.g. http://www.intel.com/software/products/mkl/docs/WebHelp/mkl.htm.
 *
 * The operations are:
 *
 * ALLOCATORS
 *
 * Allocate real vector.
 * xvr la_rv ir_size
 *
 * Allocate complex vector.
 * xvc la_cv ir_size
 *
 * Allocate real matrix, with optional diagonal.
 * xmr la_rm ir_rows, ir_columns [, or_diagonal]
 *
 * Allocate complex matrix, with optional diagonal.
 * xmc la_cm irows, icolumns [, or_diagonal, oi_diagonal]
 *
 * LEVEL 1 BLAS -- VECTOR-VECTOR OPERATIONS
 *
 * Vector-vector dot product:
 * Return x * y.
 * xr       la_rdot  xvr_x, xvr_y
 * xcr, xci la_cdotu xvc_x, xvc_y
 *
 * Conjugate vector-vector dot product:
 * Return conjg(x) * y.
 * xcr, xci la_cdotc xvc_x, xvc_y
 *
 * Compute y := a * x + y.
 * la_raxpy xr_a, xvr_x, xvr_y
 * la_caxpy xr_a, xcr_x, xcr_y
 *
 * Givens rotation:
 * Given a point in a, b,
 * compute the Givens plane rotation in a, b, c, s
 * that zeros the y-coordinate of the point.
 * la_rrotg xr_a, xr_b, xr_c, xr_s
 * la_crotg xcr_a, xci_a, xcr_b, xci_b, xcr_c, xci_c, xcr_s, xci_s
 *
 * Rotate a vector x by a vector y:
 * For all i, x[i] = c * x[i] + s * y[i];
 * For all i, y[i] = c * y[i] - s * x[i].
 * la_rrot xvr_x, xvr_y, xr_c, xr_s
 * la_crot xvc_x, xvc_y, xr_c, xr_s
 *
 * Vector copy:
 * Compute y := x.
 * Note that x or y can be a-rate, function table number,
 *
 * la_rcopy xvr_x, xvr_y
 * la_ccopy xcr_x, xvc_y
 *
 * Vector swap:
 * Swap vector x with vector y.
 * la_rswap xvr_x, xvr_y
 * la_cswap xcr_x, xvc_y
 *
 * Vector norm:
 * Return the Euclidean norm of vector x.
 * xr       rnrm2 xvr_x
 * xcr, xci cnrm2 xcr_x
 *
 * Vector absolute value:
 * Return the real sum of the absolute values of the vector elements.
 * xr asum xvr_x
 * xr axum xcr_x
 *
 * Vector scale:
 * Compute x := alpha * x.
 * la_rscal xr_alpha, xvr_x
 * la_cscal xcr_alpha, xci_alpha, xcr_x
 *
 * Vector absolute maximum:
 * Return the index of the maximum absolute value in vector x.
 * xr la_ramax xvr_x
 * xr la_camax xvc_x
 *
 * Vector absolute minimum:
 * Return the index of the minimum absolute value in vector x.
 * xr la_ramin xvr_x
 * xr la_camin xvc_x
 *
 * LEVEL 2 BLAS -- MATRIX-VECTOR OPERATIONS
 *
 * Matrix-vector dot product:
 * Compute y := alpha * A * x + beta * y, if trans is 0.
 * Compute y := alpha * A' * x + beta * y, if trans is 1.
 * Compute y := alpha * conjg(A') * x + beta * y, if trans is 2.
 * la_rgemv xmr_A, xvr_x, xvr_ay [, Pr_alpha][, or_beta][, or_trans]
 * la_cgemv xmc_A, xvc_x, xvc_ay [, Pcr_alpha, oci_alpha][, ocr_beta, oci_beta][, or_trans]
 *
 * Rank-1 update of a matrix:
 * Compute A := alpha * x * y' + A.
 * la_rger xr_alpha, xvr_x, xvr_y, xmr_A
 * la_cger xcr_alpha, xci_alpha, xvc_x, xvc_y, xmc_A
 *
 * Rank-1 update of a conjugated matrix:
 * Compute A := alpha * x * conjg(y') + A
 * la_rgerc xmr_A, xvr_x, xvr_y, [, Pr_alpha]
 * la_cgerc xmc_A, xvc_x, xvc_y, [, Pcr_alpha, oci_alpha]
 *
 * Solve a system of linear equations:
 * Coefficients are in a packed triangular matrix,
 * upper triangular if uplo = 0, lower triangular if uplo = 1.
 * Solve A * x = b for x, if trans = 0.
 * Solve A' * x = b for x, if trans = 1.
 * Solve conjg(A') * x = b for x, if trans = 2.
 * la_rtpsv xmr_A, xvr_x, xvr_b [, or_uplo][, or_trans]
 * la_ctpsv xmc_A, xvc_x, xvc_b [, or_uplo][, or_trans]
 *
 * LEVEL 3 BLAS -- MATRIX-MATRIX OPERATIONS
 *
 * Matrix-matrix dot product:
 * Compute C := alpha * op(A) * op(B) + beta * C,
 * where transa or transb is 0 if op(X) is X, 1 if op(X) is X', or 2 if op(X) is conjg(X);
 * alpha and beta are 1 by default (set beta to 0 if you don't want to zero C first).
 * la_rgemm xmr_A, xmr_B, xmr_C [, or_transa][, or_transb][, Pr_alpha][, Pr_beta]
 * la_cgemm xmc_A, xmc_B, xmc_C [, or_transa][, or_transb][, Pcr_alpha, oci_alpha][, Pcr_beta, oci_beta]
 *
 * Solve a matrix equation:
 * Solve op(A) * X = alpha * B or X * op(A) = alpha * B for X,
 * where transa is 0 if op(X) is X, 1 if op(X) is X', or 2 if op(X) is conjg(X);
 * side is 0 for op(A) on the left, or 1 for op(A) on the right;
 * uplo is 0 for upper triangular A, or 1 for lower triangular A;
 * and diag is 0 for unit triangular A, or 1 for non-unit triangular A.
 * la_rtrsm xmr_A, xmr_B [, or_side][, or_uplo][, or_transa][, or_diag] [, Pr_alpha]
 * la_ctrsm xmc_A, cmc_B [, or_side][, or_uplo][, or_transa][, or_diag] [, Pcr_alpha, oci_alpha]
 *
 * LAPACK -- LINEAR SOLUTIONS
 *
 * Solve a system of linear equations:
 * Solve A * X = B,
 * where A is a square matrix of coefficients,
 * the columns of B are individual right-hand sides,
 * ipiv is a vector for pivot elements,
 * the columns of B are replaced with the corresponding solutions,
 * and info is replaced with 0 for success, -i for a bad value in the ith parameter,
 * or i if U(i, i) is 0, i.e. U is singular.
 * la_rgesv xmr_A, xmr_B [, ovr_ipiv][, or_info]
 * la_cgesv xmc_A, xmc_B [, ovc_ipiv][, or_info]
 *
 * LAPACK -- LINEAR LEAST SQUARES PROBLEMS
 *
 * QR or LQ factorization:
 * Uses QR or LQ factorization to solve an overdetermined or underdetermined
 * linear system with full rank matrix,
 * where A is the m x n matrix to factor;
 * B is an m x number of right-hand sides,
 * containing B as input and solution X as result;
 * if trans = 0, A is normal;
 * if trans = 1, A is transposed (real matrices only);
 * if trans = 2, A is conjugate-transposed (complex matrices only);
 * and info is replaced with 0 for success, -i for a bad value in the ith parameter,
 * or i if U(i, i) is 0, the i-th diagonal element of the triangular factor
 * of A is zero, so that A does not have full rank; the least squares solution could not be computed.
 * la_rgels xmr_A, xmr_B [, or_trans] [, or_info]
 *
 * LAPACK -- SINGULAR VALUE DECOMPOSITION
 *
 * Singular value decomposition of a general rectangular matrix:
 * Singular value decomposition of a general rectangular matrix by divide and conquer:
 *
 * LAPACK -- NONSYMMETRIX EIGENPROBLEMS
 *
 * Computes the eigenvalues and Schur factorization of a general matrix,
 * and orders the factorization so that selected eigenvalues are at the top left of the Schur form:
 * Computes the eigenvalues and left and right eigenvectors of a general matrix:
 *
 * LAPACK -- GENERALIZED NONSYMMETRIC EIGENPROBLEMS
 *
 * Compute the generalized eigenvalues, Schur form,
 * and the left and/or right Schur vectors for a pair of nonsymmetric matrices:
 * Computes the generalized eigenvalues, and the left and/or right generalized eigenvectors
 * for a pair of nonsymmetric matrices:
 *
 */
extern "C"
{
  // a-rate, k-rate, FUNC, SPECDAT
#include <csoundCore.h>
  // PVSDAT
#include <pstream.h>
}

/**
 * Used for all types of arrays
 * (vectors and matrices, real and complex).
 */
struct BLASArray
{
  size_t elements;
  char[4] typecode;
  MYFLT *data;
};

#include <OpcodeBase.hpp>

<|endoftext|>


<commit_before>#include "glwidget.h"
#include <QFileDialog> //open file dialog

GLWidget::GLWidget(QWidget *parent)
    : QGLWidget(QGLFormat(QGL::SampleBuffers), parent){

    setAutoFillBackground(false);
    setFocusPolicy(Qt::ClickFocus);
    setFocus();

    //Color de fondo de la ventana
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    //inicialización del volumen de vista
    zoom=1; x=0; y=0;

    //crear los objetos de la escena
    selection=0; currentImage=0;
}

GLWidget::~GLWidget(){
    delete selection;
    delete currentImage;
}

void GLWidget::initializeGL(){
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}

void GLWidget::paintGL(){
    glClear(GL_COLOR_BUFFER_BIT);

    if(currentImage)
        currentImage->paint();

    if(selection){
          glColor3f(0,1,1);
          selection->paint();
          //degrees display
          renderText(selection->pib.x, selection->pib.y, 0,
                     QString::number(selection->angle(),0,3)+"º",
                     QFont("Arial", 12, QFont::Bold, false) );
    }

}

void GLWidget::resizeGL(int width, int height){

    //se actualiza puerto de vista
     glViewport(0,0,width,height);

     // se actualiza el volumen de vista
     aplyView();

     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     paintGL();
}

void GLWidget::aplyView(){
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();

     //glOtho2d(a,b,c,d) == glOtrho(a,b,c,d,-1,1)
     glOrtho(x-(width()/2)/zoom, x+(width()/2)/zoom,
             y-(height()/2)/zoom, y+(height()/2)/zoom, -1, 1);
}

void GLWidget::loadImage(){
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"", tr("Images (*.*)"));
    currentImage = new RImage(fileName);
    QWidget* p= ((QWidget*)parent());
    p->setWindowTitle(fileName);
    QMargins m= p->contentsMargins();
    resize(currentImage->size());
    p->resize(width()+m.right()+m.left(),height()+m.bottom()+m.top());
}

void GLWidget::saveImage(){
    QString fileName =QFileDialog::getSaveFileName(this, tr("Save Image"), "", tr("Images (*.png)"));
    //save currentImage to flileName
    if(currentImage->save(fileName)){
        delete currentImage;
        currentImage =0;
        ((QWidget*)parent())->setWindowTitle("Practica 4");
    }
}

void GLWidget::keyPressEvent(QKeyEvent *e){
    int key= e->key();
    switch(key){

            case Qt::Key_Insert :
                        loadImage();
                        break;

            case Qt::Key_S :
                        saveImage();
                        break;

            default:   return;
    }
    repaint();
}

V2d GLWidget::calcle(int X, int Y){
    return V2d( x-( width()/2 -X)/zoom,
                y+(height()/2- Y)/zoom);
}

void GLWidget::mousePressEvent(QMouseEvent * event){
    if(!selection && event->button() == Qt::LeftButton)
            selection= new Selection(calcle(event->x(), event->y()));
}

void GLWidget::mouseMoveEvent(QMouseEvent * event ){
    if(! selection)return;
    if(! event->buttons() & Qt::LeftButton)return;
    selection->setV(calcle(event->x(), event->y()));
    repaint();
}

void GLWidget::mouseReleaseEvent(QMouseEvent * event ){
    if(event->button()!=Qt::LeftButton || ! selection)return;

    if(currentImage){
        currentImage->rotate(selection->angle());
        ((QWidget*)parent())->setWindowTitle(QString::number(currentImage->angle(),0,1)+"º");
    }
    delete selection;
    selection=0;
    repaint();
}
<commit_msg>Minor changes in magins<commit_after>#include "glwidget.h"
#include <QFileDialog> //open file dialog
#include "window.h"

GLWidget::GLWidget(QWidget *parent)
    : QGLWidget(QGLFormat(QGL::SampleBuffers), parent){

    setAutoFillBackground(false);
    setFocusPolicy(Qt::ClickFocus);
    setFocus();

    //Color de fondo de la ventana
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    //inicialización del volumen de vista
    zoom=1; x=0; y=0;

    //crear los objetos de la escena
    selection=0; currentImage=0;
}

GLWidget::~GLWidget(){
    delete selection;
    delete currentImage;
}

void GLWidget::initializeGL(){
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}

void GLWidget::paintGL(){
    glClear(GL_COLOR_BUFFER_BIT);

    if(currentImage)
        currentImage->paint();

    if(selection){
          glColor3f(0,1,1);
          selection->paint();
          //degrees display
          renderText(selection->pib.x, selection->pib.y, 0,
                     QString::number(selection->angle(),0,3)+"º",
                     QFont("Arial", 12, QFont::Bold, false) );
    }

}

void GLWidget::resizeGL(int width, int height){

    //se actualiza puerto de vista
     glViewport(0,0,width,height);

     // se actualiza el volumen de vista
     aplyView();

     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     paintGL();
}

void GLWidget::aplyView(){
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();

     //glOtho2d(a,b,c,d) == glOtrho(a,b,c,d,-1,1)
     glOrtho(x-(width()/2)/zoom, x+(width()/2)/zoom,
             y-(height()/2)/zoom, y+(height()/2)/zoom, -1, 1);
}

void GLWidget::loadImage(){
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"", tr("Images (*.*)"));
    currentImage = new RImage(fileName);
    QWidget* p= ((QWidget*)parent());
    resize(currentImage->size());
    p->setWindowTitle(fileName);
    //TODO automatice margins (currently 25px)
    p->resize(width()+25,height()+25);
}

void GLWidget::saveImage(){
    QString fileName =QFileDialog::getSaveFileName(this, tr("Save Image"), "", tr("Images (*.png)"));
    //save currentImage to flileName
    if(currentImage->save(fileName)){
        delete currentImage;
        currentImage =0;
        ((QWidget*)parent())->setWindowTitle("Practica 4");
    }
}

void GLWidget::keyPressEvent(QKeyEvent *e){
    int key= e->key();
    switch(key){

            case Qt::Key_Insert :
                        loadImage();
                        break;

            case Qt::Key_S :
                        saveImage();
                        break;

            default:   return;
    }
    repaint();
}

V2d GLWidget::calcle(int X, int Y){
    return V2d( x-( width()/2 -X)/zoom,
                y+(height()/2- Y)/zoom);
}

void GLWidget::mousePressEvent(QMouseEvent * event){
    if(!selection && event->button() == Qt::LeftButton)
            selection= new Selection(calcle(event->x(), event->y()));
}

void GLWidget::mouseMoveEvent(QMouseEvent * event ){
    if(! selection)return;
    if(! event->buttons() & Qt::LeftButton)return;
    selection->setV(calcle(event->x(), event->y()));
    repaint();
}

void GLWidget::mouseReleaseEvent(QMouseEvent * event ){
    if(event->button()!=Qt::LeftButton || ! selection)return;

    if(currentImage){
        currentImage->rotate(selection->angle());
        ((QWidget*)parent())->setWindowTitle(QString::number(currentImage->angle(),0,1)+"º");
    }
    delete selection;
    selection=0;
    repaint();
}
<|endoftext|>


<commit_before>/**
 * \file HadamardMixture.cpp
 */

#include "FeedbackDelayNetworkFilter.hxx"
#include "HadamardMixture.h"

#if ATK_EIGEN == 1

#include <complex>

#include <Eigen/Dense>

#include <ATK/Utility/fmath.h>

namespace ATK
{
  template<typename DataType_, unsigned int order>
  class HadamardMixture<DataType_, order>::MixtureImpl
  {
  public:
    typedef Eigen::Matrix<DataType, nb_channels, 1> Vector;
    typedef Eigen::Matrix<DataType, nb_channels, nb_channels> Matrix;

    MixtureImpl()
      :transition(create())
    {
    }

    Vector mix(const Vector& x) const
    {
      return transition * x;
    }

  protected:
    const Matrix transition;

    static Matrix create()
    {
      return (1 / fmath::pow(2, order / 2.)) * recursive_create<order>();
    }

    template<unsigned int recursive_order>
    static typename std::enable_if<recursive_order == 0, Eigen::Matrix<DataType_, 1, 1>>::type recursive_create()
    {
      return Eigen::Matrix<DataType_, 1, 1>::Constant(1);
    }

    template<unsigned int recursive_order>
    static typename std::enable_if<recursive_order != 0, Eigen::Matrix<DataType_, 1<<recursive_order, 1<<recursive_order>>::type recursive_create()
    {
      constexpr auto big_size = 1 << recursive_order;
      constexpr auto small_size = 1 << (recursive_order - 1);
      Eigen::Matrix<DataType_, big_size, big_size> cur_transition;

      auto M_1 = recursive_create<recursive_order - 1>();
      cur_transition.block(0, 0, small_size, small_size) = M_1;
      cur_transition.block(0, small_size, small_size, small_size) = M_1;
      cur_transition.block(small_size, 0, small_size, small_size) = -M_1;
      cur_transition.block(small_size, small_size, small_size, small_size) = M_1;
      return cur_transition;
    }
  };

  template class FeedbackDelayNetworkFilter<HadamardMixture<float, 1>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<double, 1>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<float>, 1>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<double>, 1>>;

  template class FeedbackDelayNetworkFilter<HadamardMixture<float, 2>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<double, 2>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<float>, 2>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<double>, 2>>;

  template class FeedbackDelayNetworkFilter<HadamardMixture<float, 3>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<double, 3>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<float>, 3>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<double>, 3>>;
}

#endif
<commit_msg>Fix compilation on VS 2015??<commit_after>/**
 * \file HadamardMixture.cpp
 */

#include "FeedbackDelayNetworkFilter.hxx"
#include "HadamardMixture.h"

#if ATK_EIGEN == 1

#include <complex>

#include <Eigen/Dense>

#include <ATK/Core/TypeTraits.h>
#include <ATK/Utility/fmath.h>

namespace ATK
{
  template<typename DataType_, unsigned int order>
  class HadamardMixture<DataType_, order>::MixtureImpl
  {
  public:
    typedef Eigen::Matrix<DataType, nb_channels, 1> Vector;
    typedef Eigen::Matrix<DataType, nb_channels, nb_channels> Matrix;

    MixtureImpl()
      :transition(create())
    {
    }

    Vector mix(const Vector& x) const
    {
      return transition * x;
    }

  protected:
    const Matrix transition;

    static Matrix create()
    {
      return ((1 / fmath::pow(2, order / 2.)) * recursive_create<order>()).cast<DataType_>();
    }

    template<unsigned int recursive_order>
    static typename std::enable_if<recursive_order == 0, Eigen::Matrix<typename TypeTraits<DataType_>::Scalar, 1, 1>>::type recursive_create()
    {
      return Eigen::Matrix<typename TypeTraits<DataType_>::Scalar, 1, 1>::Constant(1);
    }

    template<unsigned int recursive_order>
    static typename std::enable_if<recursive_order != 0, Eigen::Matrix<typename TypeTraits<DataType_>::Scalar, 1<<recursive_order, 1<<recursive_order>>::type recursive_create()
    {
      constexpr auto big_size = 1 << recursive_order;
      constexpr auto small_size = 1 << (recursive_order - 1);
      Eigen::Matrix<typename TypeTraits<DataType_>::Scalar, big_size, big_size> cur_transition;

      auto M_1 = recursive_create<recursive_order - 1>();
      cur_transition.block(0, 0, small_size, small_size) = M_1;
      cur_transition.block(0, small_size, small_size, small_size) = M_1;
      cur_transition.block(small_size, 0, small_size, small_size) = -M_1;
      cur_transition.block(small_size, small_size, small_size, small_size) = M_1;
      return cur_transition;
    }
  };

  template class FeedbackDelayNetworkFilter<HadamardMixture<float, 1>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<double, 1>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<float>, 1>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<double>, 1>>;

  template class FeedbackDelayNetworkFilter<HadamardMixture<float, 2>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<double, 2>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<float>, 2>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<double>, 2>>;

  template class FeedbackDelayNetworkFilter<HadamardMixture<float, 3>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<double, 3>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<float>, 3>>;
  template class FeedbackDelayNetworkFilter<HadamardMixture<std::complex<double>, 3>>;
}

#endif
<|endoftext|>