#include "pch.h"
//#include "xbyak\xbyak.h"
#include "WaveTableSynth.h"

namespace stps = std::placeholders;

namespace sf {

  std::vector<Synthesizer::WaveTable> Synthesizer::WaveTable::WaveTables;

  void makeWaveFormat(WAVEFORMATEXTENSIBLE& format,
    int sample_rate = 44100,int channels = 2,int bits_per_sample = 32,int valid_bits_per_sample = 32,
    uint32_t type = WAVE_FORMAT_EXTENSIBLE,
    const GUID& sub_type = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
  {
    ZeroMemory(&format,sizeof(WAVEFORMATEXTENSIBLE));
    format.Format.wFormatTag = type;
    format.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
    format.SubFormat = sub_type;
    format.Format.nSamplesPerSec = sample_rate;
    format.Format.nChannels = channels;
    format.Format.wBitsPerSample = bits_per_sample;
    format.Format.nBlockAlign = (format.Format.wBitsPerSample / 8) * format.Format.nChannels;
    format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec  * format.Format.nBlockAlign;
    format.Samples.wValidBitsPerSample = valid_bits_per_sample;
    format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
  }

  void makeWaveFormat(WAVEFORMATEX& format,int sample_rate = 44100,int channels = 2,int bits = 16,uint32_t type = WAVE_FORMAT_PCM)
  {
    ZeroMemory(&format,sizeof(WAVEFORMATEX));
    format.wFormatTag = type;
    format.nSamplesPerSec = sample_rate;
    format.nChannels = channels;
    format.wBitsPerSample = bits;
    format.nBlockAlign = (format.wBitsPerSample / 8) * format.nChannels;
    format.nAvgBytesPerSec = format.nSamplesPerSec  * format.nBlockAlign;
  };

  void Synthesizer::WaveTableOscillator::WaveTable(Synthesizer::WaveTable *p) 
  {
    waveTable_ = p;
    if(waveTable_->stereo)
    {
      processor_ = std::bind(&sf::Synthesizer::WaveTableOscillator::ProcessStereo,this,stps::_1,stps::_2,stps::_3);
    } else {
      processor_ = std::bind(&sf::Synthesizer::WaveTableOscillator::ProcessMono,this,stps::_1,stps::_2,stps::_3);
    }

  }

  struct Synthesizer::impl {

    impl(){};
    explicit impl(WAVEFORMATEXTENSIBLE& format,int channel) : format_(format) ,isEnable_(false)
    {
 
      // Voiceのセットアップ
      //Voice v((float)format.Format.nSamplesPerSec);
      //v.SetProgram(0,programs_[0]);
      //Voice v1((float)format.Format.nSamplesPerSec);
      //v1.SetProgram(0,programs_[0]);
      //Voice v4 = v;
      //Voice v5 = v;
      //Voice v2 = std::move(v);
      //Voice v3(std::move(v1));

      for(int i = 0; i < channel;++i)
      {
        voices_.push_back(Voice((float)format.Format.nSamplesPerSec));
      }

    };

    ~impl(){};

    void Restart(){};

    void Process(float *buffer)
    {
      for(int j = 0;j < voices_.size();++j)
      {
        voices_[j].Process(buffer);
        //*buffer +=  buffer[0]; 
        //*(buffer+ 1) += buffer[1]; 
      }
    }
    //void ProcessBuffer(boost::shared_array<float> arr,int bufferSize)
    //{
    //  // 今のところ出力はステレオ前提
    //  float *ptr = arr.get();
    //  float buffer[2];
    //  for(int i = 0;i < bufferSize;++i)
    //  {
    //    for(int j = 0;j < voices_.size();++j)
    //    {
    //      voices_[j].Process(buffer);
    //      *ptr +=  buffer[0]; 
    //      *(ptr + 1) += buffer[1]; 
    //    }
    //    ptr += 2;
    //  }

    //  //static float sampleIncrement = (440.0f /* Hz */ * (M_PI * 2.0f)) / (float)format_.Format.nSamplesPerSec;
    //  //static float theta = 0.0f;

    //  //for (size_t i = 0 ; i < bufferSize ; ++i)
    //  //{
    //  //  float sinValue = sinf( theta );
    //  //  int offset = i * format_.Format.nChannels;
    //  //  for(size_t j = 0 ;j < format_.Format.nChannels; j++)
    //  //  {
    //  //    arr[offset + j] = sinValue;
    //  //  }
    //  //  theta += sampleIncrement;
    //  //}
    //}


    enum struct EnvelopeStatus
    {
      None,Attack,Decay,Sustain,Release,End
    };

    struct EnvelopeController
    {
      EnvelopeController() : envelope_(nullptr),stepTime_(1.0f / 44100.0f)
      {
      }
      EnvelopeController(const EnvelopeController& src) :
        envelope_(src.envelope_),
        status_(src.status_),
        delta_(src.delta_),
        counter_(src.counter_),
        stepTime_(src.stepTime_),
        time_(src.time_),
        value_(src.value_)
      {}

      EnvelopeController(EnvelopeController&& src) :
        envelope_(std::move( src.envelope_)),
        status_(std::move(src.status_)),
        delta_(std::move(src.delta_)),
        counter_(std::move(src.counter_)),
        stepTime_(std::move(src.stepTime_)),
        time_(std::move(src.time_)),
        value_(std::move(src.value_))
      {}

      EnvelopeController& operator= (const EnvelopeController& src)
      {
        if(this != &src)
        {
          envelope_ = src.envelope_;
          status_ = src.status_;
          delta_ = src.delta_;
          counter_ = src.counter_;
          stepTime_ = src.stepTime_;
          time_ = src.time_;
          value_ = src.value_;
        }
        return *this;
      }

      EnvelopeController& operator= (EnvelopeController&& src)
      {
        if(this != &src)
        {
          envelope_ = std::move(src.envelope_);
          status_ = std::move(src.status_);
          delta_ = std::move(src.delta_);
          counter_ = std::move(src.counter_);
          stepTime_ = std::move(src.stepTime_);
          time_ = std::move(src.time_);
          value_ = std::move(src.value_);
        }
        return *this;
      }

      void Reset()
      {
        status_ = EnvelopeStatus::None;
      }

      void Init(Envelope * env,float sampleRate) 
      {
        envelope_ = env;
        stepTime_ = 1.0f / sampleRate;
      }

      void Attack()
      {
        counter_ = 0.0f;
        if(envelope_->attackTime == 0.0f)
        {
          value_ = 1.0f;
          return Decay();
        }
        status_ = EnvelopeStatus::Attack;
        delta_ = stepTime_ /  envelope_->attackTime; 
        value_ = 0.0f;

      }

      void Decay()
      {
        if(envelope_->sustainLevel == 1.0f)
        {
          Sustain();
        }
        delta_ = (1.0f - envelope_->sustainLevel) * stepTime_ / (envelope_->decayTime); 
        status_ = EnvelopeStatus::Decay;
      }

      void Sustain()
      {

        if(envelope_->sustainLevel == 0.0f)
        {
          status_ = EnvelopeStatus::End;
        }

        status_ = EnvelopeStatus::Sustain;
      }

      void Release()
      {
        if(envelope_->releaseNoteOff){
          delta_ = value_ * stepTime_ / (envelope_->releaseTime ); 
          status_ = EnvelopeStatus::Release;
        }
      }

      float Process()
      {
        if(!IsEnable())
        {
          return 1.0f;
        }

        if(envelope_->gain == 0.0f)
        {
          return 0.0f;
        }
        counter_ += stepTime_;
        switch (status_)
        {
        case EnvelopeStatus::Attack:
          value_ += delta_;
          if(value_ >= 1.0f)
          {
            value_ = 1.0f;
            Decay();
          }
          break;
        case EnvelopeStatus::Decay:
          value_ -= delta_;
          if(value_ <= envelope_->sustainLevel)
          {
            value_ = envelope_->sustainLevel;
            Sustain();
          }
          break;
        case EnvelopeStatus::Sustain:
          {
            value_ =  envelope_->sustainLevel;
          }
          break;
        case EnvelopeStatus::Release:
          {
            value_ -= delta_;
            if(value_ <= 0.0f)
            {
              value_ = 0.0f;
              status_ = EnvelopeStatus::End;
            }
          }
          break;
        }
        return value_ * envelope_->gain;
      }

      EnvelopeStatus GetStatus()
      {
        return status_;
      }

      bool IsEnable() const {return envelope_ != nullptr && envelope_->enable;}

    private:
      Envelope* envelope_;
      EnvelopeStatus status_;
      float delta_;
      float counter_;
      float stepTime_;
      float time_;
      float value_;
    };

    struct LFOController
    {
      LFOController() : lfo_(nullptr),value_(0.0f),stepTime_(0.0f)
      {
      };

      LFOController(const LFOController& src) :
        lfo_(src.lfo_),
        osc_(src.osc_),
        envelopeController_(src.envelopeController_),
        sampleRate_(src.sampleRate_),
        value_(src.value_),
        stepTime_(src.stepTime_),
        pitchDelta_(src.pitchDelta_),
        stepDelta_(src.stepDelta_)
      {

      }

      LFOController(LFOController&& src) :
        lfo_(std::move(src.lfo_)),
        osc_(std::move(src.osc_)),
        envelopeController_(std::move(src.envelopeController_)),
        sampleRate_(std::move(src.sampleRate_)),
        value_(std::move(src.value_)),
        stepTime_(std::move(src.stepTime_)),
        pitchDelta_(std::move(src.pitchDelta_)),
        stepDelta_(std::move(src.stepDelta_))
      {

      }

      LFOController& operator= (const LFOController& src)
      {
        if(this != & src)
        {
          lfo_ = src.lfo_;
          osc_ = src.osc_;
          envelopeController_ = src.envelopeController_;
          sampleRate_ = src.sampleRate_;
          value_ = src.value_;
          stepTime_ = src.stepTime_;
          pitchDelta_ = src.pitchDelta_;
          stepDelta_ = src.stepDelta_;
        }
        return *this;
      }

      LFOController& operator= (LFOController&& src)
      {
        if(this != & src)
        {
          lfo_ = std::move(src.lfo_);
          osc_ = std::move(src.osc_);
          envelopeController_ = std::move(src.envelopeController_);
          sampleRate_ = std::move(src.sampleRate_);
          value_ = std::move(src.value_);
          stepTime_ = std::move(src.stepTime_);
          pitchDelta_ = std::move(src.pitchDelta_);
          stepDelta_ = std::move(src.stepDelta_);
        }
        return *this;
      }

      void LFOController::LFO(sf::Synthesizer::LFO *lfo)
      {
        lfo_ = lfo;
      }

      sf::Synthesizer::LFO& LFOController::LFO()
      {
        return *lfo_;
      }

      void Init(float sampleRate)
      {
        // assert(lfo_ != nullptr);
        osc_.WaveTable(lfo_->waveForm);
        sampleRate_ = sampleRate;
        stepDelta_ = 1.0f / sampleRate_;
        pitchDelta_ = lfo_->freq  * ((float)osc_.WaveTable().waveData.size()) /  ( sampleRate_ );
        envelopeController_.Init(&lfo_->envelope,sampleRate);
      };

      void Attack()
      {
        envelopeController_.Attack();
      }

      void Release()
      {
        envelopeController_.Release();
      }

      void Reset()
      {
        assert(lfo_ != nullptr);
      }

      float Process()
      {
        float buffer[2];
        osc_.Process(buffer,pitchDelta_,1.0f);
        float value = buffer[0];
        value = value * envelopeController_.Process() * lfo_->gain;
        return value;
      };

      void PreProcess()
      {
        float buffer[2];
        osc_.Process(buffer,pitchDelta_,0.0f);
        envelopeController_.Process();
      }

      float SampleRate() const {return sampleRate_;}
      void SampleRate(float v) 
      {
        sampleRate_ = v;
      }

      //      Synthesizer::impl::Envelope& Envelope() {return envelope_;}


    private:
      sf::Synthesizer::LFO * lfo_;
      WaveTableOscillator osc_;
      //      Synthesizer::impl::Envelope envelope_;
      EnvelopeController envelopeController_;
      float sampleRate_;
      float value_;
      float stepTime_;
      float pitchDelta_;
      float stepDelta_;
    };

    struct FilterController
    {
      //sampleRate_,
      //  filter_,
      //  y1_,
      //  y2_,
      //  y3_,
      //  y4_,
      //  oldx_,
      //  oldy1_,
      //  oldy2_,
      //  oldy3_,
      //  x_,
      //  r_,
      //  p_,
      //  k_

      FilterController() :
        cutoff_(0.0f),
        sampleRate_(44100.0f),
        filter_(nullptr),
        y1_(0.0f),
        y2_(0.0f),
        y3_(0.0f),
        y4_(0.0f),
        oldx_(0.0f),
        oldy1_(0.0f),
        oldy2_(0.0f),
        oldy3_(0.0f),
        x_(0.0f),
        r_(0.0f),
        p_(0.0f),
        k_(0.0f)
      {
        //        Init();
      }

      FilterController(const FilterController& src) :
        cutoff_(src.cutoff_),
        sampleRate_(src.sampleRate_),
        filter_(src.filter_),
        y1_(src.y1_),
        y2_(src.y2_),
        y3_(src.y3_),
        y4_(src.y4_),
        oldx_(src.oldx_),
        oldy1_(src.oldy1_),
        oldy2_(src.oldy2_),
        oldy3_(src.oldy3_),
        x_(src.x_),
        r_(src.r_),
        p_(src.p_),
        k_(src.k_)
      {

      }

      FilterController(FilterController&& src) :
        cutoff_(std::move(src.cutoff_)),
        sampleRate_(std::move(src.sampleRate_)),
        filter_(std::move(src.filter_)),
        y1_(std::move(src.y1_)),
        y2_(std::move(src.y2_)),
        y3_(std::move(src.y3_)),
        y4_(std::move(src.y4_)),
        oldx_(std::move(src.oldx_)),
        oldy1_(std::move(src.oldy1_)),
        oldy2_(std::move(src.oldy2_)),
        oldy3_(std::move(src.oldy3_)),
        x_(std::move(src.x_)),
        r_(std::move(src.r_)),
        p_(std::move(src.p_)),
        k_(std::move(src.k_))
      {

      }

      FilterController& operator= (const FilterController& src)
      {
        if(this != &src)
        {
          cutoff_ = src.cutoff_;
          sampleRate_ = src.sampleRate_;
          filter_ = src.filter_;
          y1_ = src.y1_;
          y2_ = src.y2_;
          y3_ = src.y3_;
          y4_ = src.y4_;
          oldx_ = src.oldx_;
          oldy1_ = src.oldy1_;
          oldy2_ = src.oldy2_;
          oldy3_ = src.oldy3_;
          x_ = src.x_;
          r_ = src.r_;
          p_ = src.p_;
          k_ = src.k_;
        }
        return *this;
      }

      FilterController& operator= (FilterController&& src)
      {
        if(this != &src)
        {
          cutoff_ = std::move(src.cutoff_);
          sampleRate_ = std::move(src.sampleRate_);
          filter_ = std::move(src.filter_);
          y1_ = std::move(src.y1_);
          y2_ = std::move(src.y2_);
          y3_ = std::move(src.y3_);
          y4_ = std::move(src.y4_);
          oldx_ = std::move(src.oldx_);
          oldy1_ = std::move(src.oldy1_);
          oldy2_ = std::move(src.oldy2_);
          oldy3_ = std::move(src.oldy3_);
          x_ = std::move(src.x_);
          r_ = std::move(src.r_);
          p_ = std::move(src.p_);
          k_ = std::move(src.k_);
        }
        return *this;
      }

      ~FilterController(){}

      void Init(Synthesizer::Filter* filter,float sampleRate)
      {
        filter_ = filter;
        cutoff_ = filter->cutoff;
        sampleRate_ = sampleRate;
        assert(filter_ != nullptr);

        y1_ = y2_ = y3_ = y4_ = oldx_ = oldy1_ = oldy2_ = oldy3_ = 0.0f;
        Calc();
      }

      void Calc()
      {
        float f = (cutoff_ + cutoff_) / sampleRate_;
        p_ = f * (1.8f - 0.8f * f);
        k_ = p_+ p_ - 1.0f;

        float t = (1.0f - p_) * 1.386249f;
        float t2 = 12.0f + t*t;
        r_ = filter_->resonance * (t2 + 6.0f * t) / (t2 - 6.0f * t);
      }

      float Process(float input)
      {
        x_ = input - r_ * y4_;

        y1_ = x_ * p_ +  oldx_ * p_ -  k_ * y1_;
        y2_ = y1_ * p_ + oldy1_ * p_ - k_ * y2_;
        y3_ = y2_ * p_ + oldy2_ * p_ - k_ * y3_;
        y4_ = y3_ * p_ + oldy3_ * p_ - k_ * y4_;

        y4_ -= (y4_ * y4_ * y4_) / 6.0f;

        oldx_ = x_; oldy1_ = y1_; oldy2_ = y2_; oldy3_ = y3_;
        return y4_;
      }

      Synthesizer::Filter* FilterController::Filter()
      {
        return filter_;
      }

      void FilterController::Filter(Synthesizer::Filter* filter)
      {
        Init(filter,sampleRate_);
      }

      void Start()
      {
        y1_ = y2_ = y3_ = y4_ = oldx_ = oldy1_ = oldy2_ = oldy3_ = 0.0f;
        Calc();
      }

      void CutOff(float v ) {cutoff_ = v;Calc();}
      float CutOff() const {return cutoff_;}

    private:
      float cutoff_;
      float sampleRate_;
      Synthesizer::Filter *filter_;
      float fs_;
      float y1_,y2_,y3_,y4_;
      float oldx_;
      float oldy1_,oldy2_,oldy3_;
      float x_;
      float r_;
      float p_;
      float k_;

    };



    struct Voice 
    {

      explicit Voice(float sampleRate)  
        : 
      programNo_(0),
        noteOn_(false),
        isFree_(true),
        pitchOffset_(0.0f),
        volumeOffset_(1.0f),
        stepTime_(0.0f),
        currentTime_(0.0f),
        curentIndex_(0),
        pan_(0.5f),
        sampleRate_(sampleRate),
        pitchDelta_(0.0f),
        pitchCounter_(0.0f),
        waveSize_(0)
      {};

      Voice(const Voice& src) 
        : 
        timber_(src.timber_),
        programNo_(src.programNo_),
        noteOn_(src.noteOn_),
        isFree_(src.isFree_),
        pitchOffset_(src.pitchOffset_),
        volumeOffset_(src.volumeOffset_),
        stepTime_(src.stepTime_),
        currentTime_(src.currentTime_),
        curentIndex_(src.curentIndex_),
        pan_(src.pan_),
        sampleRate_(src.sampleRate_),
        pitchDelta_(src.pitchDelta_),
        pitchCounter_(src.pitchCounter_),
        waveSize_(src.waveSize_),
        ampEnv_(src.ampEnv_),
        ampLFO_(src.ampLFO_),
        filterEnv_(src.filterEnv_),
        filterLFO_(src.filterLFO_),
        filterL_(src.filterL_),
        filterR_(src.filterR_),
        pitchEnv_(src.pitchEnv_),
        pitchLFO_(src.pitchLFO_),
        panEnv_(src.panEnv_),
        panLFO_(src.panLFO_)
      {
        //        osc_ = std::move(osc_->Clone());
      }

      Voice(Voice&& src) 
        : 
        timber_(std::move(src.timber_)),
        programNo_(std::move(src.programNo_)),
        noteOn_(std::move(src.noteOn_)),
        isFree_(std::move(src.isFree_)),
        pitchOffset_(std::move(src.pitchOffset_)),
        volumeOffset_(std::move(src.volumeOffset_)),
        stepTime_(std::move(src.stepTime_)),
        currentTime_(std::move(src.currentTime_)),
        curentIndex_(std::move(src.curentIndex_)),
        pan_(std::move(src.pan_)),
        sampleRate_(std::move(src.sampleRate_)),
        pitchDelta_(std::move(src.pitchDelta_)),
        pitchCounter_(std::move(src.pitchCounter_)),
        waveSize_(std::move(src.waveSize_)),
        //        osc_(std::move(src.osc_)),
        ampEnv_(std::move(src.ampEnv_)),
        ampLFO_(std::move(src.ampLFO_)),
        filterEnv_(std::move(src.filterEnv_)),
        filterLFO_(std::move(src.filterLFO_)),
        filterL_(std::move(src.filterL_)),
        filterR_(std::move(src.filterR_)),
        pitchEnv_(std::move(src.pitchEnv_)),
        pitchLFO_(std::move(src.pitchLFO_)),
        panEnv_(std::move(src.panEnv_)),
        panLFO_(std::move(src.panLFO_))
      {
        //       osc_.reset(src.osc_.release());
        //       *this = std::move(src);
      }

      Voice& operator= (const Voice& src)
      {
        if(this != &src)
        {
          timber_ = src.timber_;
          programNo_ = src.programNo_;
          noteOn_ = src.noteOn_;
          isFree_ = src.isFree_;
          pitchOffset_ = src.pitchOffset_;
          volumeOffset_ = src.volumeOffset_;
          stepTime_ = src.stepTime_;
          currentTime_ = src.currentTime_;
          curentIndex_ = src.curentIndex_;
          pan_ = src.pan_;
          sampleRate_ = src.sampleRate_;
          pitchDelta_ = src.pitchDelta_;
          pitchCounter_ = src.pitchCounter_;
          waveSize_ = src.waveSize_;
          //        osc_ = src.osc_->Clone();
          ampEnv_ = src.ampEnv_;
          ampLFO_ = src.ampLFO_;
          filterEnv_ = src.filterEnv_;
          filterLFO_ = src.filterLFO_;
          filterL_ = src.filterL_;
          filterR_ = src.filterR_;
          pitchEnv_ = src.pitchEnv_;
          pitchLFO_ = src.pitchLFO_;
          panEnv_ = src.panEnv_;
          panLFO_ = src.panLFO_;          
        }
        return *this;
      }

      Voice& operator= (Voice&& src)
      {
        if(this != &src)
        {
          timber_ = std::move(src.timber_);
          programNo_ = std::move(src.programNo_);
          noteOn_ = std::move(src.noteOn_);
          isFree_ = std::move(src.isFree_);
          pitchOffset_ = std::move(src.pitchOffset_);
          volumeOffset_ = std::move(src.volumeOffset_);
          stepTime_ = std::move(src.stepTime_);
          currentTime_ = std::move(src.currentTime_);
          curentIndex_ = std::move(src.curentIndex_);
          pan_ = std::move(src.pan_);
          sampleRate_ = std::move(src.sampleRate_);
          pitchDelta_ = std::move(src.pitchDelta_);
          pitchCounter_ = std::move(src.pitchCounter_);
          waveSize_ = std::move(src.waveSize_);
          //        osc_.reset(src.osc_.release());
          ampEnv_ = std::move(src.ampEnv_);
          ampLFO_ = std::move(src.ampLFO_);
          filterEnv_ = std::move(src.filterEnv_);
          filterLFO_ = std::move(src.filterLFO_);
          filterL_ = std::move(src.filterL_);
          filterR_ = std::move(src.filterR_);
          pitchEnv_ = std::move(src.pitchEnv_);
          pitchLFO_ = std::move(src.pitchLFO_);
          panEnv_ = std::move(src.panEnv_);
          panLFO_ = std::move(src.panLFO_);        
        }
        return *this;
      }

      void SetSampleRate(float sampleRate)
      {
        sampleRate_ = sampleRate;
      }

      void SetProgram(int programNo,Program& program)
      {
        timber_ = program.timber;
        programNo_ = programNo;
        Init();
        //        osc_->Init(timber_);
      }

      void Init()
      {
        ampEnv_.Init(&(timber_.amplitude.envelope),sampleRate_);
        filterEnv_.Init(&(timber_.filter.envelope),sampleRate_);
        pitchEnv_.Init(&(timber_.pitch.envelope),sampleRate_);
        panEnv_.Init(&(timber_.pan.envelope),sampleRate_);
        filterL_.Init(&(timber_.filter),sampleRate_);
        filterR_.Init(&(timber_.filter),sampleRate_);

        ampLFO_.LFO(&timber_.amplitude.lfo);
        pitchLFO_.LFO(&timber_.pitch.lfo);
        panLFO_.LFO(&timber_.pan.lfo);
        filterLFO_.LFO(&timber_.filter.lfo);

        ampLFO_.Init(sampleRate_);
        pitchLFO_.Init(sampleRate_);
        panLFO_.Init(sampleRate_);
        filterLFO_.Init(sampleRate_);
      }

      void Process(float* buffer) // 1サンプル分の処理を行う
      {
        if(!isFree_){

          //if(pitchCounter_ >= (waveSize_ - 1.0f))
          //{
          //  pitchCounter_ -= (waveSize_ - 1.0f);
          //}

          // Waveの生成

          float waveData[2];

          timber_.oscillator->Process(
            waveData,
            pitchDelta_, 
            pitchOffset_
            + pitchLFO_.Process() 
            + pitchEnv_.Process() 
            + timber_.pitch.pitch );

          // フィルター処理

          float cutoff = timber_.filter.cutoff + filterEnv_.Process() + filterLFO_.Process();
          filterL_.CutOff(cutoff);
          filterR_.CutOff(cutoff);

          waveData[0] = filterL_.Process(waveData[0]);
          waveData[1] = filterR_.Process(waveData[1]);


          float volume = ampEnv_.Process() + ampLFO_.Process();
          if(volume > 1.0f) 
          {
            volume = 1.0f;
          }




          // クリッピング

          //if(waveData > 1.0f) waveData = 1.0f;
          //if(waveData < 1.0f) waveData = -1.0f;

          float pan =  (pan_ + panLFO_.Process());
          if(pan > 1.0f) pan = 1.0f;
          if(pan < -1.0f) pan = -1.0f;

          float rvolume;
          float lvolume;


          if(pan > 0.0f)
          {
            rvolume = volume * volumeOffset_;
            lvolume = rvolume * (1.0f - pan);
          } else {
            lvolume = volume * volumeOffset_;
            rvolume = lvolume * (1.0f + pan);
          }

          waveData[0] = waveData[0] * lvolume;
          waveData[1] = waveData[1] * rvolume;

          buffer[0] += waveData[0]; 
          buffer[1] += waveData[1];

          if(!noteOn_ && ampEnv_.GetStatus() == EnvelopeStatus::End)
          {
            isFree_ = true;
          }
        }
      }

      bool isFree() {return isFree_;}

      void NoteOn(float pitch,float volume) 
      { 
        if(!noteOn_){
          isFree_ = false;
          noteOn_ = true;
          pitchOffset_ = pitch;
          volumeOffset_ = volume;
          stepTime_ = 1.0f / sampleRate_;
          pitchDelta_ = timber_.oscillator->CalcPitchDelta(sampleRate_);
          //          waveSize_ = (float)osc_->waveData.size();
          currentTime_ = 0.0f;
          curentIndex_ = 0;
          pan_ = timber_.pan.pan;
          pitchCounter_ = 0.0f;
          ampEnv_.Attack();
          filterEnv_.Attack();
          pitchEnv_.Attack();
          panEnv_.Attack();

          ampLFO_.Attack();
          filterLFO_.Attack();
          pitchLFO_.Attack();
          panLFO_.Attack();

          filterL_.Start();
          filterR_.Start();
        }
      }

      void NoteOff()
      {
        if(noteOn_)
        {
          noteOn_ = false;
          ampEnv_.Release();
          filterEnv_.Release();
          pitchEnv_.Release();
          panEnv_.Release();

          ampLFO_.Release();
          filterLFO_.Release();
          pitchLFO_.Release();
          panLFO_.Release();

        }
      }

      int CurrentProgramNo() const {return programNo_;}

    private:
      Timber timber_;
      int programNo_;
      bool noteOn_;
      bool isFree_;
      float pitchOffset_;
      float volumeOffset_;
      float stepTime_;
      float currentTime_;
      int curentIndex_;
      float pan_;
      float sampleRate_;
      float pitchDelta_;
      float pitchCounter_;
      float waveSize_;
      // std::unique_ptr<Oscillator> osc_;
      EnvelopeController ampEnv_;
      LFOController ampLFO_;
      EnvelopeController filterEnv_;
      LFOController filterLFO_;
      FilterController filterL_;
      FilterController filterR_;
      EnvelopeController pitchEnv_;
      LFOController pitchLFO_;
      EnvelopeController panEnv_;
      LFOController panLFO_;
    };

    typedef std::vector<Voice> VoicesType; 
    typedef std::vector<Timber> TimbersType; 
    typedef std::vector<Program> ProgramsType; 

    void NoteOn(int index,float pitch,float velocity)
    {
      voices_[index].NoteOn(pitch,velocity);
    };

    void NoteOff(int index)
    {
      voices_[index].NoteOff();
    };

    void AddProgram(Program&& program)
    {
      programs_.push_back(program);
    }

    Program& GetProgram(int index)
    {
      return programs_.at(index);
    }

    void UpdateProgram(int index,Program&& program)
    {
      programs_[index] = std::move(program);
    }

    size_t ProgramsSize()
    {
      return programs_.size();
    }

    void AssignProgramToVoice(int programNo,int voiceChannelNo)
    {
      assert(programNo < programs_.size() && voiceChannelNo < voices_.size());
      voices_.at(voiceChannelNo).SetProgram(programNo,programs_.at(programNo));
    }

    size_t Voices() const {return voices_.size();};

    bool isEnable() const {return isEnable_;}
    void isEnable(bool v) {isEnable_ = v;}

    void Clear()
    {
      WaveTable::WaveTables.clear();
      programs_.clear();
    }

  private:
    bool isEnable_; 
    WAVEFORMATEXTENSIBLE format_;
    ProgramsType programs_;// プリセット
    VoicesType voices_; // Max 64 Voices
    //    WaveTablesType waveTables_;
  };

  Synthesizer::Synthesizer() : impl_(new Synthesizer::impl()){};

  Synthesizer::Synthesizer(WAVEFORMATEXTENSIBLE& format,int channel ) : impl_(new Synthesizer::impl(format,channel))
  {
  }

  Synthesizer::~Synthesizer()
  {

  }

  //void Synthesizer::ProcessBuffer(boost::shared_array<float> arr,int bufferSize)
  //{
  //  impl_->ProcessBuffer(arr,bufferSize);
  //}

  void Synthesizer::Process(float* buffer)
  {
    impl_->Process(buffer);
  }


  void Synthesizer::Restart()
  {
    impl_->Restart();
  }

  void Synthesizer::NoteOn(int index,float pitch,float velocity)
  {
    impl_->NoteOn(index,pitch,velocity);
  };
  void Synthesizer::NoteOff(int index)
  {
    impl_->NoteOff(index);
  };

  size_t Synthesizer::Voices() const 
  {
    return impl_->Voices();
  }

  void Synthesizer::AddProgram(Program&& program)
  {
    impl_->AddProgram(std::move(program));
  }

  Synthesizer::Program& Synthesizer::GetProgram(int index)
  {
    return impl_->GetProgram(index);
  };

  void Synthesizer::UpdateProgram(int index,Program&& program)
  {
    impl_->UpdateProgram(index,std::move(program));
  }
  size_t Synthesizer::ProgramsSize()
  {
    return impl_->ProgramsSize();
  }

  void Synthesizer::AssignProgramToVoice(int programNo,int voiceChannelNo)
  {
    impl_->AssignProgramToVoice(programNo,voiceChannelNo);
  }

  Synthesizer::WaveTablesType& Synthesizer::WaveTables()
  {
    return WaveTable::WaveTables;
  }

  bool Synthesizer::isEnable() const 
  {
    return impl_->isEnable();

  }
  void Synthesizer::isEnable(bool v)
  {
    impl_->isEnable(v);
  }

  void Synthesizer::Clear()
  {
    impl_->Clear();
  }

}
