#include "pch.h"
#include "Sequencer.h"

namespace sf {

  struct Sequencer::impl 
  {
    impl(Synthesizer& synth,WAVEFORMATEXTENSIBLE& format) 
      : synth_(synth), format_(format) ,tempo_(120.0f),timebase_(480.0f),meter_(4.0f),meterDiv_(4.0f),
      currentTime_(0),status_(Status::Stop)
    {
      Update();
      for(int i = 0,end = synth_.Voices();i < end;++i)
      {
        gateBuffer_.push_back(0);
        currentIndexs_.push_back(0);
        SequenceTracks_.push_back(SequenceDatasType());
      }
    }

    void Reset()
    {
      for(int i = 0,end = synth_.Voices();i < end;++i)
      {
        gateBuffer_.at(i) = 0;
        currentIndexs_.at(i) = 0;
      }
    }
    void Update()
    {
      // stepDeltaTime_ = (int64_t)((((double)meter_ * (double)tempo_ * (double)format_.Format.nSamplesPerSec) / ((double)meterDiv_ * 60.0 * (double)timebase_ )) * (double)(0x100000000));
      stepDeltaTime_ = (int64_t)((  ((double)tempo_ * (double)timebase_ ) / (60.0  * (double)format_.Format.nSamplesPerSec)) * (double)(0x100000000));
    }



    void Process()
    {
      if(status_ == Status::Play){
        currentTime_ += stepDeltaTime_;
        int currentTime = currentTime_ >> 32;
        for(int i  = 0,end = SequenceTracks_.size();i < end;++i)
        {
          SequenceDatasType& track(SequenceTracks_[i]);
          if(!track.empty() && track.size() > currentIndexs_[i]) {
            if(currentTime >= track[currentIndexs_[i]].step) 
            {
              do
              { 
                SequenceData& d(SequenceTracks_[i][currentIndexs_[i]]);
                synth_.NoteOn(i,d.pitch,d.velocity);
                gateBuffer_[i] = (int64_t)d.gateTime << 32;
                currentIndexs_[i] = currentIndexs_[i] + 1;
                if(currentIndexs_[i] >= track.size())
                {
                  break;
                }
              } while(currentTime >= SequenceTracks_[i][currentIndexs_[i]].step);
            }
          }
          // ゲートタイムの処理
          if(gateBuffer_[i] > 0)
          {
            gateBuffer_[i] -= stepDeltaTime_;
            if(gateBuffer_[i] <= 0)
            {
              gateBuffer_[i] = 0;
              synth_.NoteOff(i);
            }
          }
        }
      }
    }

    float TimeBase() const {return timebase_;}
    void TimeBase(float v) {timebase_ = v;Update();}

    float Tempo() const {return tempo_;}
    void Tempo(float v) {tempo_ = v;Update();}

    std::vector<SequenceDatasType>& SequenceTracks() {return SequenceTracks_;}

    void Play()
    {
      status_ = Status::Play;
    }

    void Pause()
    {
      status_ = Status::Pause;
    }

    void Stop()
    {
      status_ = Status::Stop;
      Reset();
    }

  private:

    WAVEFORMATEXTENSIBLE& format_;
    float tempo_;
    float timebase_;
    int meter_;
    int meterDiv_;
    int64_t stepDeltaTime_;
    int64_t currentTime_;
    std::vector<int> currentIndexs_;
    std::vector<int64_t> gateBuffer_;
    SequenceTracksType SequenceTracks_;
    Synthesizer& synth_;
    Status status_;
  };

  Sequencer::Sequencer(Synthesizer& synth,WAVEFORMATEXTENSIBLE& format) : impl_(new impl(synth,format))
  {

  }

  Sequencer::~Sequencer()
  {

  }

  float Sequencer::TimeBase() const {return impl_->TimeBase();}
  void Sequencer::TimeBase(float v) {impl_->TimeBase(v);}

  float Sequencer::Tempo() const {return impl_->Tempo();}
  void Sequencer::Tempo(float v) {impl_->Tempo(v);}

  void Sequencer::Process() {impl_->Process();}
  void Sequencer::Play()
  {
    impl_->Play();
  }

  void Sequencer::Pause()
  {
    impl_->Pause();
  }

  void Sequencer::Stop()
  {
    impl_->Stop();
  }

  SequenceTracksType& Sequencer::SequenceTracks() {return impl_->SequenceTracks();}



}
