#include "organ.h"

#include <math.h>
#include <assert.h>

void organ_init(struct organ* restrict o, float samplerate, float* restrict freqtable) {

  float reedfactor = 0;
  float reflectionfactor = 0.5;
  float airfactor = 6;
  float finetune = 0;


  float finetune_factor = pow(2.0,finetune/1200.0);
  for(int i=0;i<128;i++) {
    float frequency = freqtable[i]*finetune_factor;
    pipe_init(&o->pipe[i],samplerate,frequency, reedfactor, reflectionfactor, airfactor);
  }
  o->dckillerstate = 1.0e-9;
  o->dckillercoeff = 6.28*30/samplerate;
}
  
void organ_finalize(struct organ* restrict o) {
  for(int i=0;i<128;i++) {
    pipe_finalize(&o->pipe[i]);
  }
}

void organ_keydown(struct organ* restrict o, int key, float velocity) {
  assert(0 <= key);
  assert(key < 128);
  pipe_keydown(&o->pipe[key]);
}

void organ_keyup(struct organ* restrict o, int key) {
  assert(0 <= key);
  assert(key < 128);
  pipe_keyup(&o->pipe[key]);
}

void organ_process(struct organ* restrict o, int length, float const * const restrict * restrict in, float * const restrict * restrict out) {
  float* outleft = out[0];
  float* outright = out[1];
  for (int i=0;i<length;i++) {
    double organout = 1.0e-5;
    for(int j=0;j<128;j++) {
      struct pipe* restrict p = &o->pipe[j];
      if (pipe_isactive(p)) {
        organout += pipe_tick(p);
      }
    }
    organout -= (o->dckillerstate += (organout - o->dckillerstate)*o->dckillercoeff);
    organout *= 0.10;
    outleft[i] = organout;
    outright[i] = organout;
  }
}

struct synthdesc organdesc = {
  .size = sizeof(struct organ),
  .init = &organ_init,
  .finalize = &organ_finalize,
  .process = &organ_process,
  .keydown = &organ_keydown,
  .keyup = &organ_keyup,
  .commands = NULL,
  .retune = NULL,
};
