/***************************************************************************
                          MIDIMelodyAdapter.h  -  description
                             -------------------
    begin                : Mit Feb 2 2005
    copyright            : (C) 2005 by klaus frieler
    email                : kgf@omniversum.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
#ifndef _MIDIMELODYADAPTER_H
#define _MIDIMELODYADAPTER_H

#include "types.h"
#include "Melody.h"

#include "jdkmidi/world.h"
#include "jdkmidi/fileread.h"
#include "jdkmidi/msg.h"
using namespace jdkmidi;

class MIDIChanMsg
{
public:
   MIDIChanMsg(const uint time, const uint pitch, const uint vel): m_iTime(time), m_iPitch(pitch), m_iVel(vel)
   {}
   MIDIChanMsg(const MIDIChanMsg& msg): m_iTime(msg.m_iTime), m_iPitch(msg.m_iPitch), m_iVel(msg.m_iVel)
   {}
   MIDIChanMsg(const MIDITimedMessage& msg)
   {
      m_iTime  = msg.GetTime();
      m_iPitch = msg.GetNote();
      m_iVel   = msg.GetVelocity();
   }
   MIDIChanMsg& operator=(const MIDIChanMsg& msg)
   {
      m_iTime  = msg.m_iTime;
      m_iPitch = msg.m_iPitch;
      m_iVel   = msg.m_iVel;
      return *this;
   }
   MIDIChanMsg& operator=(const MIDITimedMessage& msg)
   {
      m_iTime  = msg.GetTime();
      m_iPitch = msg.GetNote();
      m_iVel   = msg.GetVelocity();
      return *this;
   }
   uint   getTime(){ return m_iTime;}
   uint   getPitch(){ return m_iPitch;}
   uint   getVelocity(){ return m_iVel;}

   void  dump(){ cout<<"Time: = "<<m_iTime<<" Pitch: "<<m_iPitch<<" Vel: = "<<m_iVel<<endl;}
protected:
   uint  m_iTime;
   uint  m_iPitch;
   uint  m_iVel;
};

class MIDIMelodyAdapter: public MIDIFileEvents
{
public:
   MIDIMelodyAdapter(Melody *pMel)
      :m_pMel(pMel)
      ,m_sErrText("")
      ,m_nTrkNum(0)
      ,m_nSigTrkNum(0)
      ,m_iLastOnset(0)
      ,m_dLastOnset(0.0)
      ,m_dTempo(0.000002), m_dNewTempo(-1)
      ,m_nDivision(1024)
      ,m_nTickScaling(1)
      ,m_nMinIOITicks(4096)
      ,m_dTotalLen(0.0)
      ,m_bFirstOnset(true)
      ,m_curBarPos(invalidBarPosition)
      ,m_nQuantLevel(0)
      ,m_bIgnoreTempoChanges(false)
   {
      if(m_pMel){
         m_pMel->setKey(0);   //C- Major
         m_pMel->setSignature(4,4, 96); // 4/4, ticks must be overidden anyway
         m_pMel->setTempo(500); //120 bpm
      }
   }
   virtual ~MIDIMelodyAdapter()
   {}
   
   void     reset(){ m_bFirstOnset = true;}
   
   string   getErrText() const{ return m_sErrText;}
   uint     getMinIOITicks(){ return m_nMinIOITicks;}
   
   void     setTrackNum(const uint nTrkNum){ m_nTrkNum = nTrkNum;}
   void     setSigTrackNum(const uint nTrkNum){ m_nSigTrkNum = nTrkNum;}
   void     setCut(const double cut){m_dCut = cut;}
   void     setTempo(const double tempo){m_dTempo = tempo;}
   void     setQuantization(const uint nQuantLevel){m_nQuantLevel = nQuantLevel;}
   void     setIgnoreTempoChanges(const bool bIgnoreTempoChanges){m_bIgnoreTempoChanges = bIgnoreTempoChanges;}
   void     scheduleNewTempo(double tempo);
   void     checkScheduledTempo();
// The possible events in a MIDI Files


   virtual void    mf_note_on( const MIDITimedMessage &msg );
   virtual void    mf_note_off( const  MIDITimedMessage &msg );

   virtual void    mf_timesig( MIDIClockTime time, int, int, int, int );
   virtual void    mf_tempo( MIDIClockTime time, unsigned long tempo );
   virtual void    mf_keysig(MIDIClockTime time, int, int );


   virtual void    mf_error( char * err){ m_sErrText = err; }

   virtual void    mf_starttrack( int trk );
   virtual void    mf_endtrack( int trk );
   virtual void    mf_header( int, int, int );

protected:
   Melody   *m_pMel;
   string   m_sErrText;
   uint     m_nTrkNum;
   uint     m_nSigTrkNum;
   uint     m_nCurTrk;
   uint     m_iLastPitch;
   uint     m_iLastOnset;
   double   m_dLastOnset;
   double   m_dTempo, m_dNewTempo;
   ulong    m_nDivision;
   ulong    m_nTickScaling;
   uint     m_nMinIOITicks;
   double   m_dTotalLen;
   double   m_dCut;
   bool     m_bFirstOnset;
   BarPosition m_curBarPos;
   uint     m_nQuantLevel;
   queue<MIDIChanMsg>  m_msgQueue;
   uint     calcTime(const uint rawTime) const;
   bool     m_bIgnoreTempoChanges;
private:
   
};
#endif
