
/*
**  jazz - a midi sequencer for Linux
**
**  Copyright (C) 1994-1996 Andreas Voss (andreas@avix.rhein-neckar.de)
**
**  Copyright (C) 1995-1996 Per Sigmond (Per.Sigmond@hia.no)
**
**  This program is free software; you can redistribute it and/or modify
**  it under the terms of the GNU General Public License as published by
**  the Free Software Foundation; either version 2 of the License, or
**  (at your option) any later version.
**
**  This program is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**  GNU General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with this program; if not, write to the Free Software
**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/


#ifndef track_h
#define track_h

#ifndef events_h
#include "events.h"
#endif

#ifndef wx_wxh
#include "wx.h"
#endif

#ifndef util_h
#include "util.h"
#endif


// ************************************************************************

// ************************************************************************


// Track-States

#define tsPlay 0
#define tsMute 1
#define tsSolo 2

// Mixer-defs
enum { MxVol = 0, MxPan, MxRev, MxCho, MxParams };


// Param (Nrpn / Rpn) things
enum { NrpnVibRate = 0, NrpnVibDepth, NrpnVibDelay, NrpnVibParams };
enum { NrpnCutoff = 0, NrpnResonance, NrpnSoundParams };
enum { NrpnEnvAttack = 0, NrpnEnvDecay, NrpnEnvRelease, NrpnEnvParams };

class tParam {
public:
	tControl Msb;
	tControl Lsb;
	tControl Data;
	tParam( int cha, uchar id1, uchar msb, uchar id2, uchar lsb, uchar val ) :
		Msb( 0, cha, id1, msb ),
		Lsb( 0, cha, id2, lsb ),
		Data( 0, cha, 0x06, val ) {
	}
	virtual int Write(tWriteBase &io);
	virtual void SetCha( uchar cha );
	virtual int GetVal() { return( Data.Value ); }
};

class tNrpn : public tParam {
public:
	tNrpn( int cha, uchar msb, uchar lsb, uchar val ) : 
		tParam( cha, 0x63, msb, 0x62, lsb, val ) {
	}
};

class tRpn : public tParam {
public:
	tRpn( int cha, uchar msb, uchar lsb, uchar val ) : 
		tParam( cha, 0x65, msb, 0x64, lsb, val ) {
	}
};

uchar *SysExDT1( uchar aa, uchar bb, uchar cc, int length, uchar* dd );
int sysex_channel( int Channel );

enum ModulationSysexParameter { 
	mspModPitchControl = 0, mspModTvfCut, mspModAmpl, mspModLfo1Rate,
	mspModLfo1Pitch, mspModLfo1Tvf, mspModLfo1Tva, mspModLfo2Rate,
	mspModLfo2Pitch, mspModLfo2Tvf, mspModLfo2Tva, mspModulationSysexParameters
};

enum BenderSysexParameter { 
	bspBendPitchControl = 0, bspBendTvfCut, bspBendAmpl, bspBendLfo1Rate,
	bspBendLfo1Pitch, bspBendLfo1Tvf, bspBendLfo1Tva, bspBendLfo2Rate,
	bspBendLfo2Pitch, bspBendLfo2Tvf, bspBendLfo2Tva, bspBenderSysexParameters
};

enum CAfSysexParameter { 
	cspCAfPitchControl = 0, cspCAfTvfCut, cspCAfAmpl, cspCAfLfo1Rate,
	cspCAfLfo1Pitch, cspCAfLfo1Tvf, cspCAfLfo1Tva, cspCAfLfo2Rate,
	cspCAfLfo2Pitch, cspCAfLfo2Tvf, cspCAfLfo2Tva, cspCAfSysexParameters
};

enum PAfSysexParameter { 
	pspPAfPitchControl = 0, pspPAfTvfCut, pspPAfAmpl, pspPAfLfo1Rate,
	pspPAfLfo1Pitch, pspPAfLfo1Tvf, pspPAfLfo1Tva, pspPAfLfo2Rate,
	pspPAfLfo2Pitch, pspPAfLfo2Tvf, pspPAfLfo2Tva, pspPAfSysexParameters
};

enum CC1SysexParameter { 
	cspCC1PitchControl = 0, cspCC1TvfCut, cspCC1Ampl, cspCC1Lfo1Rate,
	cspCC1Lfo1Pitch, cspCC1Lfo1Tvf, cspCC1Lfo1Tva, cspCC1Lfo2Rate,
	cspCC1Lfo2Pitch, cspCC1Lfo2Tvf, cspCC1Lfo2Tva, cspCC1SysexParameters
};

enum CC2SysexParameter { 
	cspCC2PitchControl = 0, cspCC2TvfCut, cspCC2Ampl, cspCC2Lfo1Rate,
	cspCC2Lfo1Pitch, cspCC2Lfo1Tvf, cspCC2Lfo1Tva, cspCC2Lfo2Rate,
	cspCC2Lfo2Pitch, cspCC2Lfo2Tvf, cspCC2Lfo2Tva, cspCC2SysexParameters
};

enum ReverbSysexParameter {
	rspRevCharacter = 0, rspRevPreLpf, rspRevLevel, rspRevTime,
	rspRevDelayFeedback, rspRevSendChorus, rspReverbSysexParameters
};

enum ChorusSysexParameter {
	cspChoPreLpf = 0, cspChoLevel, cspChoFeedback, cspChoDelay,
	cspChoRate, cspChoDepth, cspChoSendReverb, cspChorusSysexParameters
};

enum ModeSysexParameter {
	mspRxChannel = 0x02, mspRxCAf = 0x04, mspRxPAf = 0x07, mspUseForRythm = 0x15
};

enum DrumInstrumentParameter {
	drumPitch = 0x18, 
	drumTva = 0x1a, 
	drumPan = 0x1c, 
	drumReverb = 0x1d, 
	drumChorus = 0x1e
};

enum DrumInstrumentParameterIndex {
	drumPitchIndex = 0,
	drumTvaIndex,
	drumPanIndex,
	drumReverbIndex,
	drumChorusIndex,
	numDrumParameters
};

int drumParam2Index( int par );
int drumIndex2Param( int index );

class tDrumInstrumentParameterList;

class tDrumInstrumentParameter {

	friend class tDrumInstrumentParameterList;

    private:
	int pitch;
	tNrpn *param[numDrumParameters];
	tDrumInstrumentParameter *next;
    public:
	tDrumInstrumentParameter( tNrpn *par );
	tNrpn *Get( int index );
	void Put( tNrpn *par );
	tDrumInstrumentParameter *Next();
	int Pitch();
};

class tDrumInstrumentParameterList {
    private:
	tDrumInstrumentParameter *list;
    public:
	tDrumInstrumentParameterList() : list(0) {}
	tDrumInstrumentParameter *GetElem( int pit );
	tNrpn *GetParam( int pit, int index );
	void PutParam( tNrpn *par );
	void DelParam( int pit, int index );
	tDrumInstrumentParameter *FirstElem();
	tDrumInstrumentParameter *NextElem( tDrumInstrumentParameter *cur );
	void DelElem( int pit );
	void Clear();
	int IsEmpty() { return( list == 0 ); }
};

enum tMtcType { Mtc24 = 0, Mtc25, Mtc30Df, Mtc30Ndf };
 
class tMtcTime {
public:
  tMtcType type;
  long hour;
  long min;
  long sec;
  long fm;
 
  tMtcTime( tMtcOffset *s ); // an mtc offset or mtc full message
  tMtcTime( long millisek, tMtcType t );
  tMtcTime( char *str, tMtcType t );
  tMtcTime( unsigned h, unsigned m, unsigned s, unsigned f, unsigned t );
  void ToString( char *str );
  tMtcOffset *ToOffset();
  long ToMillisec();
};


class tEventArray : public wxObject
{
    friend class tEventIterator;
    friend class tTrackDlg;
    friend class tTrack;
    friend class tUndoBuffer;

  public:

    long nEvents;	// act Number of Events in **Events
    long MaxEvents;	// Memory allocated in **Events
    tEvent **Events;
    void Resize();	// resize **Events

    // Events set by Cleanup
    tTrackName *Name;
    tCopyright *Copyright;
    tProgram   *Patch;
    tSetTempo  *Speed;
    tControl   *Volume;
    tControl   *Pan;
    tControl   *Reverb;
    tControl   *Chorus;
    tControl   *Bank;

    tSysEx  *ModulationSettings[mspModulationSysexParameters];
    tSysEx  *BenderSettings[bspBenderSysexParameters];
    tSysEx  *CAfSettings[cspCAfSysexParameters];
    tSysEx  *PAfSettings[pspPAfSysexParameters];
    tSysEx  *CC1Settings[cspCC1SysexParameters];
    tSysEx  *CC2Settings[cspCC2SysexParameters];

    tSysEx  *CC1ControllerNr;
    tSysEx  *CC2ControllerNr;

    tSysEx  *ReverbType;
    tSysEx  *ChorusType;

    tSysEx  *ReverbSettings[rspReverbSysexParameters];
    tSysEx  *ChorusSettings[cspChorusSysexParameters];

    tSysEx  *PartialReserve;
    tSysEx  *MasterVol;
    tSysEx  *MasterPan;

    tSysEx  *RxChannel;
    tSysEx  *RxCAf;
    tSysEx  *RxPAf;
    tSysEx  *UseForRythm;

    tMtcOffset  *MtcOffset;

    tNrpn   *VibRate;
    tNrpn   *VibDepth;
    tNrpn   *VibDelay;
    tNrpn   *Cutoff;
    tNrpn   *Resonance;
    tNrpn   *EnvAttack;
    tNrpn   *EnvDecay;
    tNrpn   *EnvRelease;
    tRpn    *BendPitchSens;

    tDrumInstrumentParameterList DrumParams;

    void Sort();

    int Channel;	// 1..16, set from first ChannelEvent, 0 = multichannel/nochannel
    int ForceChannel;

    void Put(tEvent *e);
    virtual void Clear();
    void Cleanup(tUndoBuffer *UndoBuffer);	

    void Keyoff2Length();
    void Length2Keyoff();

    tEventArray();
    virtual ~tEventArray();

    void Read(tReadBase &io);
    void Write(tWriteBase &io);

    long GetLastClock();
    int  IsEmpty();
    long GetFirstClock();

};

/*
 * UndoBuffer enthaelt geloeschte Events (IsKilled) und
 * Referenzen(!) auf kopierte Events
 */

class tUndoBuffer 
{
    friend class tTrack;

    tEventArray Killed;	// copies of Killed events
    tEventArray Copies; // references! to copied events

  public:

    tUndoBuffer();
    void Clear();	// deleted nur IsKilled() Events
    void Put(tEvent *e);
    void Debug();
};



#define MaxUndo 10

class tTrack : public tEventArray
{
  public:

    static int changed;

    tTrack();
    ~tTrack() { Clear(); }

    Bool IsDrumTrack();

    int iUndo;
    tUndoBuffer UndoBuffers[MaxUndo];

    int State;		// tsXXX

    wxDialogBox *DialogBox;
    tNamedValue *PatchNames;

    void Dialog(wxFrame *parent);

    void Put(tEvent *e)
    {
      changed = 1;
      tEventArray::Put(e);
      UndoBuffers[iUndo].Put(e);
    }

    void Kill(tEvent *e)
    {
      changed = 1;
      e->Kill();
    }

    void Merge(tEventArray *other);
    void MergeRange(tEventArray *other, long FromClock, long ToClock, int Replace = 0);
    void Undo();
    void NewUndoBuffer();
    void Clear();
    void Cleanup();

    char *GetName();
    void SetName(char *Name);

    char *GetCopyright();
    void SetCopyright(char *Copyright);

    char *GetStateChar();
    void SetState(int NewState);
    void ToggleState(int Direction); 	// +1 = next, -1 = prev

    int  GetChannel() { return Channel; }
    void SetChannel(int NewChannel);

    int  GetPatch();
    void SetPatch(int PatchNr);

    int  GetVolume();
    void SetVolume(int Volume);

    int  GetPan();
    void SetPan(int Pan);

    int  GetReverb();
    void SetReverb(int Reverb);

    int  GetChorus();
    void SetChorus(int Chorus);

    int  GetVibRate();
    void SetVibRate(int VibRate);

    int  GetVibDepth();
    void SetVibDepth(int VibDepth);

    int  GetVibDelay();
    void SetVibDelay(int VibDelay);

    int  GetCutoff();
    void SetCutoff(int Cutoff);

    int  GetResonance();
    void SetResonance(int Resonance);

    int  GetEnvAttack();
    void SetEnvAttack(int EnvAttack);

    int  GetEnvDecay();
    void SetEnvDecay(int EnvDecay);

    int  GetEnvRelease();
    void SetEnvRelease(int EnvRelease);

    int GetDrumParam( int pitch, int index );
    void SetDrumParam(int pitch, int index, int Value);

    int  GetBendPitchSens();
    void SetBendPitchSens(int BendPitchSens);

    int  GetModulationSysex( int msp );
    void SetModulationSysex( int msp, int value);

    int  GetBenderSysex( int bsp );
    void SetBenderSysex( int bsp, int value);

    int  GetCAfSysex( int csp );
    void SetCAfSysex( int csp, int value);

    int  GetPAfSysex( int psp );
    void SetPAfSysex( int psp, int value);

    int  GetCC1Sysex( int csp );
    void SetCC1Sysex( int csp, int value);

    int  GetCC2Sysex( int csp );
    void SetCC2Sysex( int csp, int value);

    int  GetCC1ControllerNr();
    void SetCC1ControllerNr(int ReverbType);

    int  GetCC2ControllerNr();
    void SetCC2ControllerNr(int ReverbType);

    int  GetReverbType();
    void SetReverbType(int ReverbType);

    int  GetChorusType();
    void SetChorusType(int ChorusType);

    int  GetRevSysex( int rsp );
    void SetRevSysex( int rsp, int value);

    int  GetChoSysex( int csp );
    void SetChoSysex( int csp, int value);

    int  GetBank();
    void SetBank(int Bank);

    int  GetSpeed();	// beats per minute
    void SetSpeed(int bpm);

    int  GetMasterVol();
    void SetMasterVol(int MasterVol);

    int  GetMasterPan();
    void SetMasterPan(int MasterPan);

    int GetPartRsrv( int chan );
    void SetPartRsrv( uchar *rsrv );

    int  GetModeSysex( int param );
    void SetModeSysex( int param, int value);

    tMtcTime* GetMtcOffset();
    void SetMtcOffset( tMtcTime* mtc );

};


// ***********************************************************************
// tEventIterator
// *********************************************************************

class tEventIterator
{
    tEventArray *Track;
    long Start, Stop, Actual;

  public:

    tEventIterator(tEventArray *t)
    {
      Track  = t;
      Start  = 0;
      Stop   = Track->nEvents;
      Actual = Start;
    }


    tEvent *GreaterEqual(long Clock)
    {
      long lo = Start;
      long hi = Stop;
      long clk = 0;
      while (lo < hi)
      {
	Actual  = (hi + lo) / 2;
        clk = Track->Events[Actual]->Clock;
        if (clk < Clock)
          lo = Actual + 1;
	else 
	  hi = Actual;
      }
      if (Actual < Stop-1 && clk < Clock)
	clk = Track->Events[++Actual]->Clock;
      if (Actual < Stop && clk >= Clock)
	return Track->Events[Actual];
      return 0;
    }


    tEvent *First(long Clock = 0)
    {
      Actual = Start;
      return GreaterEqual(Clock);
    }


    tEvent *Range(long frClock, ulong toClock)
    {
      Start = Actual = 0;
      Stop  = Track->nEvents;

      if (!GreaterEqual(frClock))
        return 0;
      Start = Actual;
      if (GreaterEqual(toClock))
        Stop = Actual;
      Actual = Start;
      return (Actual < Stop ? Track->Events[Actual] : 0);
    }


    tEvent *Next()
    {
      if (Actual < Stop)
	++ Actual;
      return (Actual < Stop ? Track->Events[Actual] : 0);
    }

    long EventsLeft()
    {
      return Stop - Actual;
    }

};

#endif

