//=========================================================
//  MusE
//  Linux Music Editor
//    $Id: ticksynth.cpp,v 1.8.2.1 2004/11/08 22:55:11 spamatica Exp $
//  (C) Copyright 2004 Werner Schweer (ws@seh.de)
//=========================================================

#include "audio.h"
#include "ticksynth.h"
#include "default_click.h"

SynthI* metronome;

class MetronomeSynth;
static MetronomeSynth* metronomeSynth;

//---------------------------------------------------------
//   MetronomeSynth
//---------------------------------------------------------

class MetronomeSynth : public Synth {
   public:
      MetronomeSynth(const QFileInfo& fi) : Synth(fi) {}
      virtual ~MetronomeSynth() {}
      virtual void incInstances(int) {}
      virtual void* instantiate();
      virtual SynthIF* createSIF() const;
      };

//---------------------------------------------------------
//   instantiate
//---------------------------------------------------------

void* MetronomeSynth::instantiate()
      {
      return 0;
      }

//---------------------------------------------------------
//   MetronomeSynthIF
//---------------------------------------------------------

class MetronomeSynthIF : public SynthIF
      {
      const float* data;
      int pos;
      int len;
      void process(float** buffer, int offset, int n);

   public:
      MetronomeSynthIF() {
            data = 0;
            }
      virtual bool guiVisible() const { return false; }
      virtual void showGui(bool) {}
      virtual bool hasGui() const { return false; }
      virtual void getGeometry(int*, int*, int*, int*) const {}
      virtual void setGeometry(int, int, int, int) {}
      virtual iMPEvent getData(MidiPort*, MPEventList*, iMPEvent, unsigned pos, int ports, unsigned n, float** buffer);
      virtual bool putEvent(const MidiPlayEvent& ev);
      virtual MidiPlayEvent receiveEvent() { return MidiPlayEvent(); }
      virtual int eventsPending() const { return 0; }
      virtual bool init(Synth*) { return true; }
      virtual int channels() const { return 1; }
      virtual void deactivate3() {}
      virtual const char* getPatchName(int, int, int) const { return ""; }
      virtual const char* getPatchName(int, int, MType) { return ""; }
      virtual void populatePatchPopup(QPopupMenu*, int, MType) {};
      virtual void write(int, Xml&) const {}
      virtual void setParameter(int, float) {}
      virtual int getControllerInfo(int, const char**, int*, int*, int*) { return 0; }
      };

//---------------------------------------------------------
//   getData
//---------------------------------------------------------

iMPEvent MetronomeSynthIF::getData(MidiPort*, MPEventList* el, iMPEvent i, unsigned pos, int/*ports*/, unsigned n, float** buffer)
      {
      int curPos      = pos;
      int endPos      = pos + n;
      int off         = pos;
      int frameOffset = audio->getFrameOffset();

      for (; i != el->end(); ++i) {
            int frame = i->time() - frameOffset;
            if (frame >= endPos)
                  break;
            if (frame > curPos) {
                  if (frame < pos)
                        printf("should not happen: missed event %d\n", pos -frame);
                  else
                        process(buffer, curPos-pos, frame - curPos);
                  curPos = frame;
                  }
            putEvent(*i);
            }
      if (endPos - curPos)
            process(buffer, curPos - off, endPos - curPos);
      return el->end();
      }

//---------------------------------------------------------
//   putEvent
//---------------------------------------------------------

bool MetronomeSynthIF::putEvent(const MidiPlayEvent& ev)
      {
      if (ev.dataA() == 0) {
            data = defaultClickEmphasis;
            len  = defaultClickEmphasisLength;
            }
      else {
            data = defaultClick;
            len  = defaultClickLength;
            }
      pos = 0;
      return false;
      }

//---------------------------------------------------------
//   createSIF
//---------------------------------------------------------

SynthIF* MetronomeSynth::createSIF() const
      {
      return new MetronomeSynthIF();
      }

//---------------------------------------------------------
//   process
//    synthesize n samples into buffer+offset
//---------------------------------------------------------

void MetronomeSynthIF::process(float** buffer, int offset, int n)
      {
      if (data == 0)
            return;

      const float* s = data + pos;
      float* d       = *buffer + offset;
      int l          = std::min(n, len);

      for (int i = 0; i < l; ++i)
            *d++ += *s++ * audioClickVolume;
      pos += l;
      len -= l;
      if (len <= 0)
            data = 0;
      }

//---------------------------------------------------------
//   initMetronome
//---------------------------------------------------------

void initMetronome()
      {
      QFileInfo fi;
      metronomeSynth = new MetronomeSynth(fi);
      metronome = new SynthI();
      QString name("metronome");
      metronome->initInstance(metronomeSynth, name);
      }

