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

#ifndef __SONG_H__
#define __SONG_H__

#include <qstring.h>
#include <qobject.h>
#include <qfont.h>

#include "globaldefs.h"
#include "track.h"
#include "tempo.h"
#include "sig.h"
#include "undo.h"
#include "font.h"

class SynthI;
struct MidiMsg;
struct AudioMsg;
class MidiEvent;
class Xml;
class Sequencer;
class Track;
class TrackList;
class MidiTrack;
class Part;
class MidiPart;
class PartList;
class MPEventList;
class EventList;
class MarkerList;
class Marker;
class SNode;

class MidiPort;
class MidiDevice;
class AudioPort;
class AudioDevice;

#define SC_TRACK_INSERTED     1
#define SC_TRACK_REMOVED      2
#define SC_TRACK_MODIFIED     4
#define SC_PART_INSERTED      8
#define SC_PART_REMOVED       0x10
#define SC_PART_MODIFIED      0x20
#define SC_EVENT_INSERTED     0x40
#define SC_EVENT_REMOVED      0x80
#define SC_EVENT_MODIFIED     0x100
#define SC_SIG                0x200       // timing signature
#define SC_TEMPO              0x400       // tempo map changed
#define SC_MASTER             0x800       // master flag changed
#define SC_SELECTION          0x1000
#define SC_AUDIO_MIXER        0x2000      // must update audio mixer
#define SC_MUTE               0x4000
#define SC_SOLO               0x8000
#define SC_RECFLAG            0x10000
#define SC_ROUTE              0x20000
#define SC_CHANNELS           0x40000

//---------------------------------------------------------
//    Song
//---------------------------------------------------------

class Song : public QObject {
      Q_OBJECT

   public:
      enum POS        { CPOS = 0, LPOS, RPOS };
      enum FollowMode { NO, JUMP, CONTINUOUS };
      enum            { REC_OVERDUP, REC_REPLACE };
      enum            { CYCLE_NORMAL, CYCLE_MIX, CYCLE_REPLACE };
      enum { MARKER_CUR, MARKER_ADD, MARKER_REMOVE, MARKER_NAME,
         MARKER_TICK, MARKER_LOCK };

   private:
      int updateFlags;
      QString _name;
      QString _komponist1;
      QString _komponist2;

      Font _nameFont;
      Font _komponistFont;
      Font _pageNoFont;
      Font _measureNoFont;
      Font _tracknameFont;
      Font _lyricsFont;

      bool _showPageNo;
      bool _showMeasureNo;
      bool _showTrackname;

      TrackList _tracks;
      UndoList* undoList;
      UndoList* redoList;
      volatile int pos[3];
      MarkerList* _markerList;

      bool _masterFlag;
      bool loopFlag;
      bool punchinFlag;
      bool punchoutFlag;
      volatile bool playFlag;
      bool recordFlag;
      bool soloFlag;
      enum MType _mtype;
      bool _karaokeFlag;
      EventList* _karaoke;
      int _karaokeChannel;
      int _recMode;
      int _cycleMode;
      bool _click;
      bool _quantize;
      int _len;         // song len in ticks
      FollowMode _follow;
      QString _copyright;
      int _globalPitchShift;
      void readMarker(Xml&);

   public:
      Song(const char* name = 0);
      ~Song();

      void endMsgCmd();
      void processMidiMsg(const MidiMsg* msg);
      void processAudioMsg(const AudioMsg* msg);
      EventList* karaoke()             { return _karaoke;        }
      bool karaokeFlag() const         { return _karaokeFlag;    }
      void setKaraokeFlag(bool flag)   { _karaokeFlag = flag;    }
      void setKaraokeChannel(int n)    { _karaokeChannel = n;    }
      int karaokeChannel() const       { return _karaokeChannel; }
      QString copyright() const        { return _copyright;      }

      void setMType(MType t);
      MType mtype() const              { return _mtype; }

      void setShowPageNo(bool flag)    { _showPageNo = flag; }
      bool showPageNo() const          { return _showPageNo; }
      void setShowMeasureNo(bool flag) { _showMeasureNo = flag; }
      bool showMeasureNo() const       { return _showMeasureNo; }
      void setShowTrackname(bool flag) { _showTrackname = flag; }
      bool showTrackname() const       { return _showTrackname; }

      void setFollow(FollowMode m)     { _follow = m; }
      FollowMode follow() const        { return _follow; }

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

      void setKomponist1(const QString& n) { _komponist1 = n; }
      QString komponist1() const           { return _komponist1; }
      void setKomponist2(const QString& n) { _komponist2 = n; }
      QString komponist2() const           { return _komponist2; }

      void setNameFont(const QString& f, int s, int w=QFont::Normal, bool i=false) {
            _nameFont = Font(f, s, w, i);
            }
      void setKomponistFont(const QString& f, int s, int w=QFont::Normal, bool i=false) {
            _komponistFont = Font(f, s, w, i);
            }
      void setPageNoFont(const QString& f, int s, int w=QFont::Normal, bool i=false) {
            _pageNoFont = Font(f, s, w, i);
            }
      void setMeasureNoFont(const QString& f, int s, int w=QFont::Normal, bool i=false) {
            _measureNoFont = Font(f, s, w, i);
            }
      void setTracknameFont(const QString& f, int s, int w=QFont::Normal, bool i=false) {
            _tracknameFont = Font(f, s, w, i);
            }
      void setLyricsFont(const QString& f, int s, int w=QFont::Normal, bool i=false) {
            _lyricsFont = Font(f, s, w, i);
            }
      void setNameFont(const Font& f)      { _nameFont = f; }
      void setKomponistFont(const Font& f) { _komponistFont = f; }
      void setPageNoFont(const Font& f)    { _pageNoFont = f; }
      void setMeasureNoFont(const Font& f) { _measureNoFont = f; }
      void setTracknameFont(const Font& f) { _tracknameFont = f; }
      void setLyricsFont(const Font& f) { _lyricsFont = f; }
      Font& nameFont()              { return _nameFont; }
      Font& komponistFont()         { return _komponistFont; }
      Font& pageNoFont()            { return _pageNoFont; }
      Font& measureNoFont()         { return _measureNoFont; }
      Font& tracknameFont()         { return _tracknameFont; }
      Font& lyricsFont()            { return _lyricsFont; }

      bool dirty;
      WaveTrack* bounceTrack;

      void updatePos();
      TrackList* tracks()           { return &_tracks; }

      void read(Xml&);
      void write(int, Xml&) const;
      void writeFont(int level, Xml& xml, const char* name,
         const Font& font) const;
      Font readFont(Xml& xml, const char* name);

      void clear(bool signal);
      void update(int flags = -1);
      void beat(int tick);

      int globalPitchShift() const      { return _globalPitchShift; }
      void setGlobalPitchShift(int val) { _globalPitchShift = val; }

      //-----------------------------------------
      //   Marker
      //-----------------------------------------

      MarkerList* marker() const { return _markerList; }
      Marker* addMarker(const QString& s, int t, bool lck);
      void removeMarker(Marker*);
      Marker* setMarkerName(Marker*, const QString&);
      Marker* setMarkerTick(Marker*, int);
      Marker* setMarkerLock(Marker*, bool);
      void setMarkerCurrent(Marker* m, bool f);

      //-----------------------------------------
      //   transport
      //-----------------------------------------

      void setPos(int, int, bool sig = true, bool isSeek = true,
         bool adjustScrollbar = false);
      int cpos() const              { return pos[0]; }
      int lpos() const              { return pos[1]; }
      int rpos() const              { return pos[2]; }

      bool loop() const             { return loopFlag; }
      bool play() const             { return playFlag; }
      bool record() const           { return recordFlag; }
      bool punchin() const          { return punchinFlag; }
      bool punchout() const         { return punchoutFlag; }
      bool masterFlag() const       { return _masterFlag; }
      void setRecMode(int val)      { _recMode = val; }
      int  recMode() const          { return _recMode; }
      void setCycleMode(int val)    { _cycleMode = val; }
      int cycleMode() const         { return _cycleMode; }
      bool click() const            { return _click; }
      bool quantize() const         { return _quantize; }
      void setStopPlay(bool f);

      //-----------------------------------------
      //    access tempomap/sigmap  (Mastertrack)
      //-----------------------------------------

      int len() const { return _len; }
      void setLen(int l);     // set songlen in ticks
      int roundUpBar(int tick) const;
      int roundUpBeat(int tick) const;
      int roundDownBar(int tick) const;
      void initLen();

      //-----------------------------------------
      //   event manipulations
      //-----------------------------------------

      void cmdAddRecordedWave(WaveTrack* track, int start, int end);
      void cmdAddRecordedEvents(MidiTrack*, EventList*, int);
      void addEvent(MidiEvent*, MidiPart*);
      void changeEvent(MidiEvent*, MidiEvent*, MidiPart*);
      void deleteEvent(MidiEvent*, MidiPart*);

      //-----------------------------------------
      //   part manipulations
      //-----------------------------------------

      void cmdResizePart(Track* t, Part* p, int size);
      void cmdSplitPart(Track* t, Part* p, int tick);
      void cmdGluePart(Track* t, Part* p);

      void addPart(Part* part);
      void changePart(Part*, Part*);
      PartList* getSelectedMidiParts() const;
      PartList* getSelectedWaveParts() const;
      bool msgRemoveParts();

      //-----------------------------------------
      //   track manipulations
      //-----------------------------------------

      Track* addTrack(Track::TrackType t = Track::MIDI, Track* s = 0);
      void addTrack(Track* track);
      void removeMarkedTracks();
      void changeTrack(Track* oldTrack, Track* newTrack);
      MidiTrack* findTrack(const Part* part) const;
      void swapTracks(int i1, int i2);
      void setChannelMute(int channel, bool flag);
      void setRecordFlag(Track*, bool);

      //-----------------------------------------
      //   undo, redo
      //-----------------------------------------

      void startUndo();
      void endUndo(int);
      void undoOp(UndoOp::UndoType, int, Track*);
      void undoOp(UndoOp::UndoType, int, int, int = 0);
      void undoOp(UndoOp::UndoType, Part*);
      void undoOp(UndoOp::UndoType, Event* oevent, Event* nevent, Part*);
      void undoOp(UndoOp::UndoType, SigEvent* oevent, SigEvent* nevent);
      void undoOp(UndoOp::UndoType, int channel, int ctrl, int oval, int nval);
      void undoOp(UndoOp::UndoType, Part* oPart, Part* nPart);
      void doUndo();
      void doRedo();

      //-----------------------------------------
      //    audio mixing
      //-----------------------------------------

      void updateAudioMixer();

      //-----------------------------------------
      //   Configuration
      //-----------------------------------------

      SynthI* createSynthI(const QString& sclass);
      void attachSynthI(SynthI* si, int port);
      void removeSoftSynth();
      void rescanAlsaPorts();

      //-----------------------------------------
      //   Debug
      //-----------------------------------------

      void dumpMaster();

   public slots:
      void undo();
      void redo();

      void setTempo(int t);
      void setSig(int a, int b);
      void setTempo(double tempo)  { setTempo(int(60000000.0/tempo)); }

      void setMasterFlag(bool flag);
      void setLoop(bool f);
      void setRecord(bool f);
      void setPlay(bool f);
      void setStop(bool f);
      void forward();
      void rewindStart();
      void rewind();
      void setPunchin(bool f);
      void setPunchout(bool f);
      void setClick(bool val);
      void setQuantize(bool val);
      void setCopyright(const QString& s) { _copyright = s; }
      void panic();
      void masterVolChanged(int);
      void ctrlChanged(int, int, int, int);
      void appearanceChanged();

   signals:
      void songChanged(int);
      void posChanged(int, int, bool);
      void loopChanged(bool);
      void recordChanged(bool);
      void playChanged(bool);
      void punchinChanged(bool);
      void punchoutChanged(bool);
      void clickChanged(bool);
      void quantizeChanged(bool);
      void heartBeat();
      void markerChanged(int);
      void recordFlagChanged(Track*);
      void midiPortsChanged();
      };

struct PartColor {
      const char* name;
      int r, g, b;
      };

const int NUM_PARTCOLORS = 17;

extern PartColor partColors[NUM_PARTCOLORS];
extern Song* song;

#endif

