/*
* triggered_note.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 "triggered_note.h"
#include "chrono.h"
#include "main.h"
#include "utils.h"
#include "color.h"
#include <cmath>

extern int SAMPLE_RATE;
extern float SAMPLE_DURATION;
extern float MIN_TIME;

triggered_note::triggered_note (const note& n, float vmax, float xx, float yy, int _what, int k, int pmx) {

  tn = n;
  start_hz = tn.hz; 

	volume.now = 0;
	volume.max = vmax;

	state = ATTACK;
	abs_attack = 0;

	decay_time = 0;
	decay_start_volume = 0;
	abs_decay = 0;

	x = xx; y = yy;

  key = k;

  prev_mousex = pmx;
	bend = 1;
  bend_x = 0;

	what = _what;
	if (what == NOISE) {
		nsr.set_samples (SAMPLE_RATE / tn.hz);
		nsr.set_spread (volume.max);
		volume.mult = volume.max;
		r = 1.0f; g = r; b = g;
	} else {
		volume.mult = 1.0f;
		set_rnd_color (r, g, b);
	}

}

void triggered_note::setup (multi_curve* wav, multi_curve* atk, multi_curve* dk) {
  sol (wav);
	float y; sol.mcrv->get_vertex (sol.mcrv->last_vertex, decay_lastx, y);
	player.fill_pitch (tn.step);
	player.set_wave (&sol);
  attack (atk);
  decay (dk);
  startt = ui_clk ();
}

void triggered_note::eval (float* L, float* R, float* wav, float* vol, int n, float attack_time, float decay_time, gotog& __gotog ) {


	float& vn_1 = vol[n-1];

  switch (state) {

    case ATTACK:

			if (equals (attack_time, 0.0f)) attack_time = MIN_TIME;
      delta_attack = SAMPLE_DURATION * 1.0f / attack_time;
      attack (abs_attack, delta_attack, n, vol, _atmin, __gotog); // solve attack curve to get bunch of volumes (range 0 to 1)

			if (what == NOTE) {
				for (int i = 0; i < n; ++i) vol[i] *= volume.max; // scale volume
				player.master (L, R, wav, n, vol);
				volume.now = vn_1;
			} else {
				nsr (L, R, n, vol); 
				volume.now = vn_1 * volume.max;
			}

			decay_start_volume = vn_1;

      break;

    case DECAY:

			if (equals (decay_time, 0.0f)) decay_time = MIN_TIME;
			decay_time = fabs (decay_start_volume) * volume.mult / volume.max * decay_time;
			delta_decay = SAMPLE_DURATION * 1.0f / decay_time;
			decay (abs_decay, delta_decay, n, vol, _atmin, _atmax);
			for (int i = 0; i < n; ++i) vol[i] *= decay_start_volume;
			if (what == NOTE) {
				player.master (L, R, wav, n, vol); 
				volume.now = vn_1;
			} else {
				nsr (L, R, n, vol);
				volume.now = vn_1 * volume.max;
			}
			float x, y; decay.mcrv->get_vertex (decay.mcrv->last_vertex, x, y);
			if (abs_decay >= x) state = FINISHED;
      break;

  }

}

void triggered_note::eval (float attack_time) {
  if (state == ATTACK) {
    float now = ui_clk ();
    float dt = now - startt;
    if (dt >= attack_time) start_decay ();
  }
}

void triggered_note::start_decay () {
  if (state == ATTACK) {
    state = DECAY;
		if (equals (volume.max, 0.0f) || equals (decay_start_volume, 0.0f))
			state = FINISHED; 
		else 
			abs_decay = 0;
  }
}

void triggered_note::set_freq (float f) {
	if (what == NOTE) {
  	tn.set_freq (f);
		player.set_interpolated_pitch (tn.step);
	} else
		nsr.set_samples (SAMPLE_RATE / f);
}

int triggered_note::update_solver (multi_curve& crv, const string& nam) {
	sol.update ();
	if (crv.num_vertices) player.set_mix (crv, nam);
	return player.mixer.active;
}

void update_triggered_notes (std::list<triggered_note>& tl) {
	for (note_iterator i = tl.begin (), j = tl.end (); i != j; ++i) {
		triggered_note& ti = *i;
		ti.player.realloc ();
	}
}

void update_triggered_noises (std::list<triggered_note>& tl) {
	for (note_iterator i = tl.begin (), j = tl.end (); i != j; ++i) {
		triggered_note& ti = *i;
		ti.nsr.warp (&noiser::interp);
	}
}
