//=========================================================
//  MusE
//  Linux Music Editor
//    $Id: mess.h,v 1.1.1.1 2003/10/29 10:05:10 wschweer Exp $
//  (C) Copyright 2001 Werner Schweer (ws@seh.de)
//=========================================================

#ifndef __MESS_H__
#define __MESS_H__

#include <sys/types.h>
#include <config.h>

#include <list>

#include <alsa/asoundlib.h>
#include "globaldefs.h"

//---------------------------------------------------------
//   MidiPatch
//---------------------------------------------------------

struct MidiPatch {
      signed char typ;                     // 1 - GM  2 - GS  4 - XG
      signed char hbank, lbank, prog;
      const char* name;
      };

//---------------------------------------------------------
//   RawMidiEvent
//    midi event
//---------------------------------------------------------

class RawMidiEvent {
      int _type;           // alsa event type
      signed char _chan;
      int _dataA;
      int _dataB;
      unsigned char* _data;
      int _dataLen;

   public:
      RawMidiEvent() {
            _data = 0;
            }
      ~RawMidiEvent() {
            if (_data)
                  delete _data;
            }
      int type() const              { return _type; }
      void setType(int t)           { _type = t; }
      int chan() const              { return _chan; }
      void setChan(int a)           { _chan = a; }
      int dataA() const             { return _dataA; }
      void setDataA(int a)          { _dataA = a;    }
      int dataB() const             { return _dataB; }
      void setDataB(int a)          { _dataB = a;    }
      unsigned char* data() const   { return _data; }
      void setData(unsigned char* p) { _data = p; }
      int dataLen() const           { return _dataLen; }
      void setDataLen(int l)        { _dataLen = l; }
      };

//---------------------------------------------------------
//   MEvent
//    time stamped midi event
//---------------------------------------------------------

class MEvent : public RawMidiEvent {
      int _samplePos;                // time stamp

   public:
      MEvent() : RawMidiEvent() {}
      ~MEvent() {}
      int samplePos() const         { return _samplePos; }
      void setSamplePos(int val)    { _samplePos = val; }
      void adjustSamplePos(int bs)  { _samplePos %= bs; }
      };

class MEventQueue : public std::list<MEvent* > {
      };

typedef MEventQueue::iterator iMEvent;

//---------------------------------------------------------
//  Mess
//    MusE experimental software synth
//    LADSPA instance
//---------------------------------------------------------

class Mess {
      int _sampleRate;
      struct Verweis { Verweis* next; };
      enum {nelem = 64};
      struct Chunk {
            Chunk* next;
            char mem[nelem * sizeof(MEvent)];
            };
      Chunk* chunks;
      Verweis* head;
      void grow();

   protected:
      const char* _className;       // synth plugin name
      char* _name;                  // instance name
      snd_seq_t* alsaSeq;
      snd_seq_addr_t _alsaPort;     // registered alsa midi port
      snd_seq_addr_t _musePort;
      struct pollfd* pfd;           // poll file descriptors for midi
      int npfd;
      double startFrame;
      pthread_mutex_t lock;
      pthread_mutex_t messLock;
      pthread_cond_t messReady;
      MEventQueue events;

      void sendSysex(const unsigned char* p, int n);
      virtual void processEvent(MEvent* ev) = 0;
      virtual void write(int /*n*/, float** /*buffer*/, int /*offset*/) {}
      float** outputPorts;
      int _channels;           // 1 - mono,  2 - stereo

   public:
      int realTimePriority;
      uid_t euid, ruid;
      Mess(const char* instName, int channels);
      virtual ~Mess();
      void registerAlsa();

      MEvent* allocMEvent();
      void freeMEvent(MEvent*);

      virtual bool init()            { return false; }
      void setPort(int n, float* p)  { outputPorts[n] = p; }
      void midiRun();
      pthread_t midiThread;
      int channels() const           { return _channels; }
      int sampleRate() const         { return _sampleRate; }
      void setSampleRate(int r)      { _sampleRate = r; }

      int alsaClient() const         { return _alsaPort.client; }
      int alsaPort() const           { return _alsaPort.port; }
//      void setName(const char* s);
      const char* name() const       { return _name; }
      const char* className() const  { return _className; }
      virtual const char* getPatchName(int channel, int hbank, int lbank,
         int prog, MType type);
      virtual const MidiPatch* getNextPatch(int /*ch*/, const MidiPatch*) const { return 0;}

      virtual int getMidiInitEvent(int /*id*/, RawMidiEvent*) { return 0; }
      virtual void processreplace(int len);

      static void initMess(unsigned long id, const char* label, const char* maker,
         const char* name, const char* copyright, unsigned long ports,
         Mess* (inst)(const char*));
      };

//---------------------------------------------------------
//   allocMEvent
//---------------------------------------------------------

inline MEvent* Mess::allocMEvent()
      {
      pthread_mutex_lock(&lock);
      if (head == 0)
            grow();
      Verweis* p = head;
      head       = p->next;
      pthread_mutex_unlock(&lock);

      MEvent* me = reinterpret_cast<MEvent*>(p);
      me->setData(0);
      return me;
      }

//---------------------------------------------------------
//   freeMEvent
//---------------------------------------------------------

inline void Mess::freeMEvent(MEvent* b)
      {
      if (b->data())
            delete b->data();
      pthread_mutex_lock(&lock);
      Verweis* p = reinterpret_cast<Verweis*>(b);
      p->next    = head;
      head       = p;
      pthread_mutex_unlock(&lock);
      }

//---------------------------------------------------------
//   MessMono
//    implements some more functions for monophone
//    synthesizer
//---------------------------------------------------------

struct PitchVelo {
      signed char channel;
      signed char pitch;
      signed char velo;
      PitchVelo(signed char a, signed char b, signed char c)
         : channel(a), pitch(b), velo(c) {}
      };

class MessMono : public Mess {
      std::list<PitchVelo> pitchStack;

      void midiNoteOn(int channel, int pitch, int velo);
      void midiNoteOff(int channel, int pitch);

   protected:
	int ctrlHi;       //	Parametervariables
	int ctrlLo;
	int dataHi;
	int dataLo;
      virtual void processEvent(MEvent* ev);

   public:
      MessMono(const char*, int channels);
      virtual ~MessMono();
      virtual void noteon(int channel, int pitch, int velo) = 0;
      virtual void noteoff(int channel, int pitch) = 0;
      virtual void sysex(const unsigned char* /* data*/, int /*len*/) {}
	virtual void setController(int /*channel*/, int /*ctrl*/, int /*val*/) {}
      };

#endif

