/*
   MicroMDAEPiano

   MicroMDAEPiano is a port of the MDA-EPiano sound engine
   (https://sourceforge.net/projects/mda-vst/) for the Teensy-3.5/3.6 with audio shield.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

#ifndef __mdaEPiano__
#define __mdaEPiano__

#include <Audio.h>
#include <Arduino.h>
#include <string.h>
#include "config.h"

#define NPARAMS 12       //number of parameters
#define NPROGS   1       //number of programs
#define NOUTS    2       //number of outputs
#define SUSTAIN 128
#define SILENCE 0.0001f  //voice choking
#define WAVELEN 422414   //wave data bytes

// MDAEPiano parameter mapping
#define MDA_EP_DECAY 0
#define MDA_EP_RELEASE 1
#define MDA_EP_HARDNESS 2
#define MDA_EP_TREBLE 3
#define MDA_EP_PAN_TREM 4
#define MDA_EP_LFO_RATE 5
#define MDA_EP_VELOCITY_SENSE 6
#define MDA_EP_STEREO 7
#define MDA_EP_MAX_POLY 8
#define MDA_EP_TUNE 9
#define MDA_EP_DETUNE 10
#define MDA_EP_OVERDRIVE 11

class mdaEPianoProgram
{
    friend class mdaEPiano;
  private:
    float param[NPARAMS];
};

struct VOICE  //voice state
{
  int32_t  delta;  //sample playback
  int32_t  frac;
  int32_t  pos;
  int32_t  end;
  int32_t  loop;

  float env;  //envelope
  float dec;

  float f0;   //first-order LPF
  float f1;
  float ff;

  float outl;
  float outr;
  int32_t  note; //remember what note triggered this
};


struct KGRP  //keygroup
{
  int32_t  root;  //MIDI root note
  int32_t  high;  //highest note
  int32_t  pos;
  int32_t  end;
  int32_t  loop;
};

class mdaEPiano
{
  public:
    mdaEPiano();
    ~mdaEPiano();

    virtual void process(int16_t *outputs_r, int16_t *outputs_l);
    void noteOn(int32_t note, int32_t velocity);
    virtual bool processMidiController(uint8_t data1, uint8_t data2);
    //virtual void setProgram(int32_t program);
    //virtual float getParameter(int32_t index);
    virtual void resume();
    void reset_voices(void);
    void reset_controllers(void);
    void stop_voices(void);
    void setDecay(float value);
    void setRelease(float value);
    void setHardness(float value);
    void setTreble(float value);
    void setPanTremolo(float value);
    void setPanLFO(float value);
    void setVelocitySense(float value);
    void setStereo(float value);
    void setMaxPolyphony(uint8_t value);
    void setTune(float value);
    void setDetune(float value);
    void setOverdrive(float value);
    void setLoudness(float value);
    int32_t getActiveVoices(void);

  private:
    void update();  //my parameter update
    void fillpatch(int32_t p, char *name, float p0, float p1, float p2, float p3, float p4,
                   float p5, float p6, float p7, float p8, float p9, float p10, float p11);
    void setParameter(int32_t index, float value);

    mdaEPianoProgram* programs;
    float Fs, iFs;

    ///global internal variables
    uint8_t max_polyphony;
    KGRP  kgrp[34];
    VOICE voice[NVOICES];
    int32_t activevoices;
    short *waves;
    float width;
    int32_t  size, sustain;
    float lfo0, lfo1, dlfo, lmod, rmod;
    float treb, tfrq, tl, tr;
    float tune, fine, random, stretch, overdrive;
    float muff, muffvel, sizevel, velsens, modwhl;
    float volume;
    float vol;
    //uint8_t curProgram;
};

#endif
