/*
 
 //#######################################################################################
 //Class to insert Midiclock messages into a given MidiBuffer, suitable for block
 //based audio callbacks. The class can act on position jumps e.g. "Loops" by sending a 
 //positioning message.
 //NOTE: No ballistik came in to play so I wouldn't recommend using it to drive a mechanical
 //tape deck!!!
 //
 //solar3d-software, April- 10- 2012
 //#######################################################################################
 
 */
#ifndef __JK_MIDICLOCK
#define __JK_MIDICLOCK

#include <JuceHeader.h>

//#include "Includes.h"

class JK_MidiClock
{
public:
    JK_MidiClock();
    
	void setPositionJumpThreshold(const double ms)						{m_posChangeThreshold = ms / 1000.0;}
	double getPositionJumpThreshold()									{return m_posChangeThreshold;}
    void setFollowSongPosition(const bool shouldFollow)                 {m_followSongPosition = shouldFollow;}
	bool getFollowSongPosition()										{return m_followSongPosition;}
    void setOffset(const int offset)                                    {m_ppqOffset = offset;}
    int  getOffset()                                                    {return m_ppqOffset;}
    
    void generateMidiclock(const AudioPlayHead::CurrentPositionInfo &lastPosInfo,
                           MidiBuffer* midiBuffer,
                           const int bufferSize,
                           const double sampleRate);
    
    //=================================================================================================
    juce_UseDebuggingNewOperator
    
private:
    inline int64 roundToInt64 (const double val) noexcept
	{
		return (val - floor(val) >= 0.5) ? (int64)(ceil(val)) : (int64)(floor(val));
	}
	
	
	bool   m_wasPlaying;
	double m_syncPpqPosition;
	double m_posChangeThreshold;
    double m_ppqToStartSyncAt;
    bool   m_followSongPosition;   
	uint8  m_syncFlag;
    int    m_ppqOffset;
	int    m_sample_remain;
    static const int cycleEnd_   = 1;
    static const int startSlave_ = 2;
	
	ScopedPointer <MidiMessage> m_clockMessage;
	ScopedPointer <MidiMessage> m_continueMessage;
	ScopedPointer <MidiMessage> m_stopMessage;
	ScopedPointer <MidiMessage> m_songPositionMessage;
    
	void sendSongPositionPointerMessage(const double ppqPosition, const int posInBuffer, MidiBuffer* buffer);
    
	bool positionJumped(const double lastPosInPPQ, const double currentPosInPPQ, 
                        const double sampleRate, const double ppqPerSample);
    
	double getNearestSixteenthInPPQ(const double ppqPosition)  	           {return ceil(ppqPosition * 4.0) / 4.0;}
	double getNearestInPPQ(const double ppqPosition, double quantizer)     {return ceil(ppqPosition * quantizer / 4) / (quantizer / 4);}
    
	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JK_MidiClock);
};
#endif
