class HiHat {
  public:
    float frequency;
    float base_frequency;
    float frequency_range;
    float wavetable_start = 0;
    int wavetable_window_size = 1048;
    EnvelopeSimpleLog volume_envelope;
    HPF hpf;
    float gain = 1.0;
    void setup();
    void update();
    void reset();
    void trigger();
    float render();
    void advanceOscillator();
    void setVolumeDecay(float speed);
    void setFrequency(float frequency);
    void setWavetableStart(float start);
    void setHpfFrequency(float frequency);

  private:
    
    // Generate the wavetable using the python script. Make sure the lenght is updated wherever it occures in this script
    #include "HihatWavetable.h"

    float wavetable_progress = 0.0;
};

void HiHat::setup() {
  // Set some parameters
  this->volume_envelope.amount = 1.0;
  this->hpf.setFrequency(700.0);
  this->volume_envelope.setSnap(0.0005);

}

void HiHat::update() {
  this->volume_envelope.update();
}

void HiHat::reset() {
  this->volume_envelope.reset();
}

void HiHat::trigger() {
  this->reset();
  this->setWavetableStart(random(this->wavetable_start-0.2, this->wavetable_start+0.2));
}

float HiHat::render() {
  float orig_sample = this->volume_envelope.value * this->wavetable[min(104728-1, max(0, (int)this->wavetable_progress))];
  float filtered_sample = hpf.render(orig_sample);
  float sample = (orig_sample/8 + filtered_sample/2) * this->gain;
  return sample / 2 + 511;
}

void HiHat::advanceOscillator() {
  this->wavetable_progress += this->frequency;

  // Ensure the wavetable progress is within bounds
  if (this->wavetable_progress > 104728-1) {
    this->wavetable_progress = this->wavetable_start;
  }

  // Restart the wavetable if we are at the end of the table
  if (this->wavetable_progress > (this->wavetable_start + this->wavetable_window_size)) {
    this->wavetable_progress = this->wavetable_start;
    this->setWavetableStart(random(this->wavetable_start-0.2, this->wavetable_start+0.2));
  }
}

void HiHat::setVolumeDecay(float speed) {
  // Speed defines the decrement with which the envelope counter falls each update
  // the incoming variable is assumed to be in the range 0.0 to 1.0
  speed = 0.0001 + speed/200.0;
  this->volume_envelope.setSpeed(speed);
}
void HiHat::setFrequency(float frequency) {
  this->frequency = this->base_frequency + frequency * this->frequency_range;
}

void HiHat::setWavetableStart(float start) {
  // Set start to be somewhere within the sample (start is assumed to have a value from 0.0 to 1.0)
  start = start * (104728 - this->wavetable_window_size);
  this->wavetable_start = max(0.0, min(104728-1-this->wavetable_window_size, start));
  // Figure out the previous offset so we can keep the relative phase within the window
  float previous_offset = this->wavetable_progress - this->wavetable_start;
  this->wavetable_progress = this->wavetable_start + previous_offset;
}

void HiHat::setHpfFrequency(float frequency) {
  frequency = 350.0 + frequency * 4000.0;
  this->hpf.setFrequency(frequency);
}