/*
* fft.cc
* DIN Is Noise is copyright (c) 2006-2022 Jagannathan Sampath
* DIN Is Noise is released under GNU Public License 2.0
* For more information, please visit https://dinisnoise.org/
*/


#include "fft.h"
#include "multi_curve.h"
#include "solver.h"
#include <math.h>
#include "viewwin.h"
#include "widget.h"
#include <algorithm>
#include <fstream>

using namespace std;

extern ofstream dlog;
extern viewport view;

fft::fft () : lev ("fft_levels") {
  dx = 1. / NUM_SAMPLES ;
  x = 0;
  cfg = kiss_fft_alloc (NUM_SAMPLES, 0, 0, 0);
  dlog << "+++ FFT setup complete +++ " << endl;
}

void fft::setup () {

  widget* ctrls [] = {&ab_fold, &lev, &l_title};
  widget_load ("d_fft", ctrls, 3);

  ab_fold.set_dir (arrow_button::down);
  ab_fold.set_listener (this);

  l_title.set_text ("FFT");
  l_title.add_child (&ab_fold);
  l_title.add_child (&lev);
	l_title.set_moveable (1);

}

void fft::update () {
  l_title.update ();
  ab_fold.update ();
}

int fft::handle_input () {
  int r = ab_fold.handle_input ();
  if (r) return r;
  r = l_title.handle_input ();
  if (r) return r;
  if (lev.visible) r = lev.handle_input ();
  return r;
}

void fft::draw () {
  widget* ctrls [] = {&ab_fold, &lev, &l_title};
  for (int i = 0; i < 3; ++i) {
    widget* ctrl = ctrls[i];
    if (ctrl->visible) ctrl->draw ();
  }
}

fft::~fft () {
  kiss_fft_free (cfg);
  widget* ctrls [] = {&ab_fold, &lev, &l_title};
  widget_save ("d_fft", ctrls, 3);
  dlog << "--- destroyed fft ---" << endl;
}

void fft::go (multi_curve* crv) {

  // do fft on a bezier multi curve

  solver s (crv);

  x = 0;
  s (x, dx, NUM_SAMPLES, in);

  for (int i = 0; i < NUM_SAMPLES; ++i) {
    cx_in[i].r = in[i];
    cx_in[i].i = 0;
  }

  kiss_fft (cfg, cx_in, cx_out);

  harms.clear ();
  for (int i = 1; i < NUM_SAMPLES; ++i) {
    float x = cx_out[i].r;
    float y = cx_out[i].i;
    float x2 = x*x;
    float y2 = y*y;
    harms.push_back (sqrt (x2 + y2));
  }

  float m0 = *min_element (harms.begin(), harms.end());
  float m1 = *max_element (harms.begin(), harms.end());
  float mm = m1 - m0;
  if (m1 == m0) return;

  lev.clear_hgt_val ();
  for (int i = 0, j = harms.size(); i < j; ++i) {
    float dm = harms[i] - m0;
    float y = dm / mm;
    lev.set_only (i, y);
  }
}
