#include "tone.h"

/**
 * Přidán attack - zmizí rušivé lupání, prodlouží se obsluha tónu.
 * */

extern "C" const        short onePeriod[];
extern "C" const unsigned int midiTones[];
extern "C" const unsigned int attackTable[];

static constexpr unsigned defFall   = 16u;
static constexpr unsigned maxAttack = 127u;

Tone::Tone() noexcept {
  ampl = 0; freq = 0; base = 0; atck = 0;
  fall = defFall;
}

void Tone::setAmpl (unsigned int a) {
  ampl = a;
}

void Tone::setFreq (unsigned int f) {
  freq = f;
}

void Tone::setMidiOn (unsigned int m) {
  freq = midiTones [m & 0x7F];
  if (freq) atck = maxAttack;
  fall = 1;
}

void Tone::setMidiOff (void) {
  fall = defFall;
  /*
  base = 0;
  freq = 0;
  */
}

void Tone::setFall (unsigned int f) {
  fall = f;
}

int Tone::step (void) {
  unsigned int k,t;
  int y;
  // Spočteme index x pro přístup do tabulky
  const unsigned x  = (base >> 16) & 0xFF;
  y  = onePeriod [x];     // vzorek vezmeme z tabulky
  
  // k je horní půlka amplitudy
  k  = ampl >> 16;
  y  *= k;                // vzorek násobíme amplitudou (tedy tím vrškem)
  y >>= 12;               // a vezmeme jen to, co potřebuje DAC
  k  *= fall;             // Konstanta fall určuje rychlost poklesu amplitudy,
  // čím více, tím je rychlejší. Pokud by bylo 1, pokles je 2^16 vzorků, což už je pomalé.
  base += freq;           // časová základna pro další vzorek

  if (atck) {                   // přidán attack = náběh amplitudy
    t = attackTable [atck];     // z tabulky
    if (t > ampl) ampl = t;     // prevence lupání - nemí být skok amplitudy
    atck -= 1;                  // dočasovat k nule
  } else
    ampl -= k;           // exponenciální pokles amplitudy
  // a je to
  
  return y;
}