#pragma once

#include <streams.h>
#include <math.h>
#include "../CSimpleFilter/CSimpleFilter.h"
#include "gain_analysis.h"

#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 3
#endif

#pragma comment(lib, "winmm.lib")

#ifdef DEBUG
#pragma comment(lib, "../lib/strmbasd.lib")
#pragma comment(lib, "../lib/CSimpleFilter_d.lib")
#else
#pragma comment(lib, "../lib/strmbase.lib")
#pragma comment(lib, "../lib/CSimpleFilter.lib")
#endif

struct SmplData{double l,r;};

// {EFBF44B7-BB1F-48c8-BA59-EB9803579B1E}
static const GUID CLSID_ConvertWav = 
{ 0xefbf44b7, 0xbb1f, 0x48c8, { 0xba, 0x59, 0xeb, 0x98, 0x3, 0x57, 0x9b, 0x1e } };

// {BDA4CAB0-2EB2-42cb-A631-E89E82352DD1}
static const GUID IID_IConvertWavInterface = 
{ 0xbda4cab0, 0x2eb2, 0x42cb, { 0xa6, 0x31, 0xe8, 0x9e, 0x82, 0x35, 0x2d, 0xd1} };
// -----------------------------------------------------------------------------------------------------------------------------------
// 出力設定インターフェイス
__interface
IConvertWavInterface : public IUnknown
{
public:
   HRESULT GetInFormat(WAVEFORMATEX *);
   HRESULT GetOutFormat(WAVEFORMATEX *);
   HRESULT SetOutFormat(WAVEFORMATEX *);

   HRESULT SetNormalize(bool, double);
   HRESULT SetReplaygain(bool);
   HRESULT GetReplaygainResult(double *, double *);
};
// -----------------------------------------------------------------------------------------------------------------------------------
class CConvertSamples
{
public:

   // ユーザ関数
   HRESULT ConvertInit(WAVEFORMATEX *, WAVEFORMATEX *, int, double);
   void Convert(struct SmplData *, int, BYTE *, int *);
   void ConvertSSE2(struct SmplData *, int, BYTE *, int *);
   void ConvertEnd(struct SmplData *, int, BYTE *, int *);

private:

   // ユーザ関数
   double bessel0(double);

   // ユーザ変数
   WAVEFORMATEX m_inFormat;
   WAVEFORMATEX m_outFormat;

   int iptr;
	int ismd, ismr;
   long firodrv;
   int isrm, osrm;
   int sptr, sptrr, eptr, eptrr;
   double m_hfir[65536];
   double m_dMaxData, m_dMinData;
   double m_dRatioPlus, m_dRatioMinus;
};
// -----------------------------------------------------------------------------------------------------------------------------------
class CConvertChannels
{
public:

   // ユーザ関数
   HRESULT SetFormat(WAVEFORMATEX *, WAVEFORMATEX *);
   HRESULT Convert(BYTE *, int, BYTE *, int *);
   HRESULT Convert(BYTE *, int, int *);

private:

   // ユーザ変数
   WAVEFORMATEX m_inFormat;
   WAVEFORMATEX m_outFormat;

};
// -----------------------------------------------------------------------------------------------------------------------------------
class CConvertBits
{
public:

   // ユーザ関数
   HRESULT SetFormat(WAVEFORMATEX *, WAVEFORMATEX *);
   HRESULT Convert(BYTE *, int, BYTE *, int *);

private:

   // ユーザ変数
   WAVEFORMATEX m_inFormat;
   WAVEFORMATEX m_outFormat;
   double m_dRatio;

   // ユーザ関数
   HRESULT Convert8(BYTE *, int, BYTE *, int *);
   HRESULT Convert16(BYTE *, int, BYTE *, int *);
   HRESULT Convert24(BYTE *, int, BYTE *, int *);
   HRESULT Convert32i(BYTE *, int, BYTE *, int *);
   HRESULT Convert32f(float *, int, BYTE *, int *);
   HRESULT Convert64(double *, int, BYTE *, int *);
};
// -----------------------------------------------------------------------------------------------------------------------------------
class CConvertWav : public CSimpleTransform , public IConvertWavInterface
{
   friend class CConvertBits;
   friend class CConvertChannels;
   friend class CConvertSamples;

public:
   DECLARE_IUNKNOWN

   // コンストラクタとデストラクタ
   CConvertWav(LPUNKNOWN, HRESULT *);
   ~CConvertWav();

   // オブジェクト作成関数
   static CUnknown * WINAPI CreateInstance(LPUNKNOWN, HRESULT *);

   // CSimpleTransformの純粋仮想メソッド
   HRESULT OnConnectInPin(const CMediaType *);
   HRESULT OnConnectOutPin(const CMediaType *, int, CMediaType *, int *);
   HRESULT OnTransform(IMediaSample *, IMediaSample *);

   // IConvertWavInterface
   HRESULT GetInFormat(WAVEFORMATEX *);
   HRESULT GetOutFormat(WAVEFORMATEX *);
   HRESULT SetOutFormat(WAVEFORMATEX *);
   HRESULT SetNormalize(bool, double);
   HRESULT SetReplaygain(bool);
   HRESULT GetReplaygainResult(double *, double *);

   // CSimpleTransformのオーバーライド
   HRESULT OnStart();
   HRESULT OnSeek();
   HRESULT OnStop(bool);
   STDMETHODIMP OnQueryInterface(REFIID, void **);

private:

   // ユーザ関数
   void ConvertToDouble(BYTE *, int);
   HRESULT Convert(BYTE *, int, BYTE *, int *);
   void Normalize(BYTE *, int, WAVEFORMATEX *);
   void Replaygain(BYTE *, int, WAVEFORMATEX *);

   // ユーザ変数
   bool m_bSetOutFormat;
   bool m_bUseSSE2;

   bool m_bUseNormalize;
   double m_dNormalizeScale;

   bool m_bUseReplaygain;
   double m_dPeak;

   REFERENCE_TIME m_rtCurrent;
   WAVEFORMATEX m_inFormat;
   WAVEFORMATEX m_outFormat;

   CConvertBits     *m_pConvertBits;
   CConvertChannels *m_pConvertChannels;
   CConvertSamples  *m_pConvertSamples;

   int m_nSmplSize;
   struct SmplData *m_smpld;
};
// -----------------------------------------------------------------------------------------------------------------------------------
