//=========================================================
//  MusE
//  Linux Music Editor
//  $Id: track.h,v 1.39 2004/07/14 15:27:26 wschweer Exp $
//
//  (C) Copyright 1999-2004 Werner Schweer (ws@seh.de)
//=========================================================

#ifndef __TRACK_H__
#define __TRACK_H__

#include <qstring.h>
#include <vector>
#include <algorithm>

#include "part.h"
#include "key.h"
#include "node.h"
#include "route.h"
#include "ctrl.h"
#include "globaldefs.h"

class Pipeline;
class Xml;
class SndFile;
class MPEventList;
class SynthI;
class PluginI;

//---------------------------------------------------------
//   Track
//---------------------------------------------------------

class Track {
   public:
      enum TrackType {
         MIDI=0, DRUM, WAVE, AUDIO_OUTPUT, AUDIO_INPUT, AUDIO_GROUP,
         AUDIO_AUX, AUDIO_SOFTSYNTH
         };
   private:
      TrackType _type;
      QString _comment;

      PartList _parts;

      void init();

   protected:
      QString _name;
      bool _recordFlag;
      bool _mute;
      bool _solo;
      bool _off;
      int _channels;          // 1 - mono, 2 - stereo

      int _activity;
      int _lastActivity;
      int _meter[MAX_CHANNELS];
      int _peak[MAX_CHANNELS];

      int _y;
      int _height;            // visual height in arranger

      bool _locked;
      bool _selected;
      bool readProperties(Xml& xml, const QString& tag);
      void writeProperties(int level, Xml& xml) const;

   public:
      Track(TrackType);
      Track(const Track&);
      virtual ~Track() {}
      QString comment() const         { return _comment; }
      void setComment(const QString& s) { _comment = s; }

      int y() const;
      void setY(int n)                { _y = n;         }
      int height() const              { return _height; }
      void setHeight(int n)           { _height = n;    }

      bool selected() const           { return _selected; }
      void setSelected(bool f)        { _selected = f; }
      bool locked() const             { return _locked; }
      void setLocked(bool b)          { _locked = b; }

      const QString& name() const     { return _name; }
      virtual void setName(const QString& s)  { _name = s; }

      TrackType type() const          { return _type; }
      void setType(TrackType t)       { _type = t; }

      PartList* parts()               { return &_parts; }
      const PartList* cparts() const  { return &_parts; }
      Part* findPart(unsigned tick);
      iPart addPart(Part* p);

      virtual void write(int, Xml&) const = 0;

      virtual Track* newTrack() const = 0;
      virtual Track* clone() const    = 0;

      virtual void setRecordFlag1(bool f) = 0;
      virtual void setRecordFlag2(bool f) = 0;

      virtual Part* newPart(Part*p=0, bool clone = false) = 0;
      void dump() const;
      virtual void splitPart(Part*, int, Part*&, Part*&);

      virtual void setMute(bool val);
      virtual void setOff(bool val);
      virtual void setSolo(bool val) = 0;
      virtual bool isMute() const = 0;

      bool solo() const                  { return _solo;         }
      bool mute() const                  { return _mute;         }
      bool off() const                   { return _off;          }
      bool recordFlag() const            { return _recordFlag;   }

      int activity()                     { return _activity;     }
      void setActivity(int v)            { _activity = v;        }
      int lastActivity()                 { return _lastActivity; }
      void setLastActivity(int v)        { _lastActivity = v;    }
      void addActivity(int v)            { _activity += v;       }
      void resetPeaks();
      static void resetAllMeter();
      int meter(int ch) const  { return _meter[ch]; }
      int peak(int ch) const   { return _peak[ch]; }
      void resetMeter();

      bool readProperty(Xml& xml, const QString& tag);
      void setDefaultName();
      int channels() const                { return _channels; }
      virtual void setChannels(int n);
      bool isMidiTrack() const       { return type() == MIDI || type() == DRUM; }
      virtual bool canRecord() const { return false; }
      virtual AutomationType automationType() const    = 0;
      virtual void setAutomationType(AutomationType t) = 0;
      };

//---------------------------------------------------------
//   MidiTrack
//---------------------------------------------------------

class MidiTrack : public Track {
      static bool _soloMode;
      int _outPort;
      int _outChannel;
      int _inPortMask;        // bitmask of accepted record ports
      int _inChannelMask;     // bitmask of accepted record channels

      EventList* _events;     // tmp Events during midi import
      MPEventList* _mpevents; // tmp Events druring recording

   public:
      MidiTrack();
      MidiTrack(const MidiTrack&);
      virtual ~MidiTrack();

      void init();
      virtual AutomationType automationType() const;
      virtual void setAutomationType(AutomationType);

      // play parameter
      int transposition;
      int velocity;
      int delay;
      int len;
      int compression;

      virtual void setRecordFlag1(bool f) { _recordFlag = f; }
      virtual void setRecordFlag2(bool) {}

      EventList* events() const          { return _events; }
      MPEventList* mpevents() const      { return _mpevents; }

      virtual void read(Xml&);
      virtual void write(int, Xml&) const;

      virtual MidiTrack* newTrack() const { return new MidiTrack(); }
      virtual MidiTrack* clone() const { return new MidiTrack(*this); }
      virtual Part* newPart(Part*p=0, bool clone=false);

      void setOutChannel(int i)       { _outChannel = i; }
      void setOutPort(int i)          { _outPort = i; }
      void setInPortMask(int i)       { _inPortMask = i; }
      void setInChannelMask(int i)    { _inChannelMask = i; }
      int outPort() const             { return _outPort;     }
      int inPortMask() const          { return _inPortMask;  }
      int outChannel() const          { return _outChannel;  }
      int inChannelMask() const       { return _inChannelMask; }

      virtual bool isMute() const;
      virtual void setSolo(bool val);
      bool soloMode() const           { return _soloMode; }
      virtual bool canRecord() const  { return true; }
      };

//---------------------------------------------------------
//   AudioTrack
//    this track can hold audio automation data and can
//    hold tracktypes AUDIO, AUDIO_MASTER, AUDIO_GROUP,
//    AUDIO_INPUT, AUDIO_SOFTSYNTH, AUDIO_AUX
//---------------------------------------------------------

class AudioTrack : public Track {
      static bool _soloMode;
      CtrlListList _controller;
      CtrlRecList _recEvents;     // recorded automation events

      bool _prefader;               // prefader metering
      std::vector<double> _auxSend;
      Pipeline* _efxPipe;

      AutomationType _automationType;

      RouteList _inRoutes;
      RouteList _outRoutes;

      void readRecfile(Xml& xml);
      void readAuxSend(Xml& xml);

   protected:
      float** outBuffers;
      unsigned bufferPos;
      virtual bool getData(unsigned, int, unsigned, float**);
      SndFile* _recFile;
      Fifo fifo;                    // fifo -> _recFile

   public:
      AudioTrack(TrackType t);
      AudioTrack(const AudioTrack&);
      virtual ~AudioTrack();

      virtual void setRecordFlag1(bool f);
      virtual void setRecordFlag2(bool f);

      void addController(CtrlList*);
      void removeController(int id);

      bool readProperties(Xml&, const QString&);
      void writeProperties(int, Xml&) const;

      virtual AudioTrack* clone() const = 0;
      virtual Part* newPart(Part*p=0, bool clone=false);

      SndFile* recFile() const           { return _recFile; }
      void setRecFile(SndFile* sf)       { _recFile = sf;   }

      CtrlListList* controller()         { return &_controller; }

      virtual void setChannels(int n);

      virtual bool isMute() const;
      virtual void setSolo(bool val);
      bool soloMode() const               { return _soloMode; }

      void putFifo(int channels, unsigned long n, float** bp);

      void record();

      virtual void setMute(bool val);
      virtual void setOff(bool val);

      double volume() const;
      void setVolume(double val);
      double pan() const;
      void setPan(double val);

      bool prefader() const              { return _prefader; }
      double auxSend(int idx) const;
      void setAuxSend(int idx, double v);
      void addAuxSend(int n);

      void setPrefader(bool val);
      Pipeline* efxPipe()                { return _efxPipe;  }
      void addPlugin(PluginI* plugin, int idx);

      void readVolume(Xml& xml);
      void writeRouting(int, Xml&) const;

      // routing
      RouteList* inRoutes()    { return &_inRoutes; }
      RouteList* outRoutes()   { return &_outRoutes; }
      bool noInRoute() const   { return _inRoutes.empty();  }
      bool noOutRoute() const  { return _outRoutes.empty(); }

      virtual void addData(unsigned, int, unsigned, float**);
      virtual void copyData(unsigned, int, unsigned, float**);
      virtual bool hasAuxSend() const { return false; }

      // automation
      virtual AutomationType automationType() const    { return _automationType; }
      virtual void setAutomationType(AutomationType t) { _automationType = t; }
      CtrlRecList* recEvents()                         { return &_recEvents; }
      void recordAutomation(int n, float v);
      void startAutoRecord(int);
      void stopAutoRecord(int);
      };

//---------------------------------------------------------
//   AudioInput
//---------------------------------------------------------

class AudioInput : public AudioTrack {
      void* jackPorts[MAX_CHANNELS];
      virtual bool getData(unsigned, int, unsigned, float**);

   public:
      AudioInput();
      AudioInput(const AudioInput&);
      virtual ~AudioInput();
      AudioInput* clone() const { return new AudioInput(*this); }
      virtual AudioInput* newTrack() const { return new AudioInput(); }
      virtual void read(Xml&);
      virtual void write(int, Xml&) const;
      virtual void setName(const QString& s);
      void* jackPort(int channel) { return jackPorts[channel]; }
      void setJackPort(int channel, void*p) { jackPorts[channel] = p; }
      virtual void setChannels(int n);
      virtual bool hasAuxSend() const { return true; }
      };

//---------------------------------------------------------
//   AudioOutput
//---------------------------------------------------------

class AudioOutput : public AudioTrack {
      void* jackPorts[MAX_CHANNELS];
      float* buffer[MAX_CHANNELS];
      float* buffer1[MAX_CHANNELS];
      unsigned long _nframes;

      float* _monitorBuffer[MAX_CHANNELS];

   public:
      AudioOutput();
      AudioOutput(const AudioOutput&);
      virtual ~AudioOutput();
      AudioOutput* clone() const { return new AudioOutput(*this); }
      virtual AudioOutput* newTrack() const { return new AudioOutput(); }
      virtual void read(Xml&);
      virtual void write(int, Xml&) const;
      virtual void setName(const QString& s);
      void* jackPort(int channel) { return jackPorts[channel]; }
      void setJackPort(int channel, void*p) { jackPorts[channel] = p; }
      virtual void setChannels(int n);

      void processInit(unsigned);
      void process(unsigned pos, unsigned offset, unsigned);
      void processWrite();
      void silence(unsigned);
      virtual bool canRecord() const { return true; }

      float** monitorBuffer() { return _monitorBuffer; }
      };

//---------------------------------------------------------
//   AudioGroup
//---------------------------------------------------------

class AudioGroup : public AudioTrack {
   public:
      AudioGroup() : AudioTrack(AUDIO_GROUP) {}
      AudioGroup* clone() const { return new AudioGroup(*this); }
      virtual AudioGroup* newTrack() const { return new AudioGroup(); }
      virtual void read(Xml&);
      virtual void write(int, Xml&) const;
      virtual bool hasAuxSend() const { return true; }
      };

//---------------------------------------------------------
//   AudioAux
//---------------------------------------------------------

class AudioAux : public AudioTrack {
      float* buffer[MAX_CHANNELS];

   public:
      AudioAux();
      AudioAux* clone() const { return new AudioAux(*this); }
      ~AudioAux();
      virtual AudioAux* newTrack() const { return new AudioAux(); }
      virtual void read(Xml&);
      virtual void write(int, Xml&) const;
      virtual bool getData(unsigned, int, unsigned, float**);
      virtual void setChannels(int n);
      float** sendBuffer() { return buffer; }
      };

//---------------------------------------------------------
//   WaveTrack
//---------------------------------------------------------

class WaveTrack : public AudioTrack {
      Fifo _prefetchFifo;  // prefetch Fifo

   public:
      static bool firstWaveTrack;

      WaveTrack() : AudioTrack(Track::WAVE) {}
      WaveTrack(const WaveTrack& wt) : AudioTrack(wt) {}

      virtual WaveTrack* clone() const    { return new WaveTrack(*this); }
      virtual WaveTrack* newTrack() const { return new WaveTrack(); }
      virtual Part* newPart(Part*p=0, bool clone=false);

      virtual void read(Xml&);
      virtual void write(int, Xml&) const;

      virtual void fetchData(unsigned pos, unsigned frames, float** bp);
      virtual bool getData(unsigned, int ch, unsigned, float** bp);

      void clearPrefetchFifo()      { _prefetchFifo.clear(); }
      Fifo* prefetchFifo()          { return &_prefetchFifo; }
      virtual void setChannels(int n);
      virtual bool hasAuxSend() const { return true; }
      bool canEnableRecord() const;
      virtual bool canRecord() const { return true; }
      };

//---------------------------------------------------------
//   TrackList
//---------------------------------------------------------

template<class T> class tracklist : public std::vector<Track*> {
      typedef std::vector<Track*> vlist;

   public:
      class iterator : public vlist::iterator {
         public:
            iterator() : vlist::iterator() {}
            iterator(vlist::iterator i) : vlist::iterator(i) {}

            T operator*() {
                  return (T)(**((vlist::iterator*)this));
                  }
            iterator operator++(int) {
                  return iterator ((*(vlist::iterator*)this).operator++(0));
                  }
            iterator& operator++() {
                  return (iterator&) ((*(vlist::iterator*)this).operator++());
                  }
            };

      class const_iterator : public vlist::const_iterator {
         public:
            const_iterator() : vlist::const_iterator() {}
            const_iterator(vlist::const_iterator i) : vlist::const_iterator(i) {}
            const_iterator(vlist::iterator i) : vlist::const_iterator(i) {}

            const T operator*() const {
                  return (T)(**((vlist::const_iterator*)this));
                  }
            };

      class reverse_iterator : public vlist::reverse_iterator {
         public:
            reverse_iterator() : vlist::reverse_iterator() {}
            reverse_iterator(vlist::reverse_iterator i) : vlist::reverse_iterator(i) {}

            T operator*() {
                  return (T)(**((vlist::reverse_iterator*)this));
                  }
            };

      tracklist() : vlist() {}
      virtual ~tracklist() {}

      void push_back(T v)             { vlist::push_back(v); }
      iterator begin()                { return vlist::begin(); }
      iterator end()                  { return vlist::end(); }
      const_iterator begin() const    { return vlist::begin(); }
      const_iterator end() const      { return vlist::end(); }
      reverse_iterator rbegin()       { return vlist::rbegin(); }
      reverse_iterator rend()         { return vlist::rend(); }
      T& back() const                 { return (T&)(vlist::back()); }
      T& front() const                { return (T&)(vlist::front()); }
      iterator find(const Track* t)       {
            return std::find(begin(), end(), t);
            }
      const_iterator find(const Track* t) const {
            return std::find(begin(), end(), t);
            }
      unsigned index(const Track* t) const {
            unsigned n = 0;
            for (vlist::const_iterator i = begin(); i != end(); ++i, ++n) {
                  if (*i == t)
                        return n;
                  }
            return -1;
            }
      T index(int k) const           { return (*this)[k]; }
      iterator index2iterator(int k) {
            if ((unsigned)k >= size())
                  return end();
            return begin() + k;
            }
      void erase(Track* t)           { vlist::erase(find(t)); }

      void clearDelete() {
            for (vlist::iterator i = begin(); i != end(); ++i)
                  delete *i;
            vlist::clear();
            }
      void erase(vlist::iterator i) { vlist::erase(i); }
      void replace(Track* ot, Track* nt) {
            for (vlist::iterator i = begin(); i != end(); ++i) {
                  if (*i == ot) {
                        *i = nt;
                        return;
                        }
                  }
            }
      };

typedef tracklist<Track*> TrackList;
typedef TrackList::iterator iTrack;
typedef TrackList::const_iterator ciTrack;

typedef tracklist<MidiTrack*>::iterator iMidiTrack;
typedef tracklist<MidiTrack*>::const_iterator ciMidiTrack;
typedef tracklist<MidiTrack*> MidiTrackList;

typedef tracklist<WaveTrack*>::iterator iWaveTrack;
typedef tracklist<WaveTrack*>::const_iterator ciWaveTrack;
typedef tracklist<WaveTrack*> WaveTrackList;

typedef tracklist<AudioInput*>::iterator iAudioInput;
typedef tracklist<AudioInput*>::const_iterator ciAudioInput;
typedef tracklist<AudioInput*> InputList;

typedef tracklist<AudioOutput*>::iterator iAudioOutput;
typedef tracklist<AudioOutput*>::const_iterator ciAudioOutput;
typedef tracklist<AudioOutput*> OutputList;

typedef tracklist<AudioGroup*>::iterator iAudioGroup;
typedef tracklist<AudioGroup*>::const_iterator ciAudioGroup;
typedef tracklist<AudioGroup*> GroupList;

typedef tracklist<AudioAux*>::iterator iAudioAux;
typedef tracklist<AudioAux*>::const_iterator ciAudioAux;
typedef tracklist<AudioAux*> AuxList;

typedef tracklist<SynthI*>::iterator iSynthI;
typedef tracklist<SynthI*>::const_iterator ciSynthI;
typedef tracklist<SynthI*> SynthIList;


#endif

