

//------------------------------------------------------------------------------
// File: AsyncFlt.h
//
// Desc: DirectShow sample code - header file for async filter.
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------


/*------------------------------------------------------------------------------
--------------------------------------------------------------------------------
	Here we take the SDK sample Async Filter and modify it to
	read an audio CD drive's .cda files.

	Cda files are just descriptors of the cd disc content, which
	is all parsed out in CAsyncCDFilter::Load().

	The MPC CDDAReader filter, which this code is completely based 
	on, does the same, but is slow - probably due to attemps to get 
	the CDROM_READ_TOC_EX_FORMAT_CDTEXT. That text, (titles, authors, 
	etc) seems to never exist, and Windows takes some 6 seconds 
	trying to get it (on XP at least).

	Code used from:
		-MPC CDDAReader filter by Gabest
		-LAV Filters
		-https://www.codeproject.com/Articles/15725/Tutorial-on-reading-Audio-CDs

	Info:
	 TextFiles\MultipleGraphs.pdf
	 https://www.gdcl.co.uk/q_and_a.htm
	 https://www.gdcl.co.uk/q_and_a.htm#IAsyncReader
	 https://microsoft.public.win32.programmer.directx.video.narkive.com/lsEYd1c7/
			  directshow-fastest-way-to-load-another-file-to-playout
	 http://www.gdcl.co.uk/gmfbridge/index.htm

-------------------------------------------------------------------------------
------------------------------------------------------------------------------*/

#pragma warning(disable:4710)	// 'function' not inlined (optimization)
#pragma warning(disable:4995)	// #pragma deprecated strings

// For track storage - do not Ignore All Default Libs.
#include <valarray>
#include <string>

// Win DDK files, copied to widdk folder like MPC did.
//  todo update to new ddk files
#include "..\winddk\ntddcdrm.h"

// Defs for CD Drive parsing.
#define CD_BLOCKS_PER_SECOND	75

#define RAW_SECTOR_SIZE 2352

// Structure for cd-track data.
struct CDTRACK
{
	CDTRACK() { Zero(); };
	ULONG	 Address_sector;
	ULONG	 Length_sectors;
	LONGLONG Length_bytes;
	UCHAR	 TrackNumber;
	void Zero() { Address_sector = 0; Length_sectors = 0; Length_bytes = 0; TrackNumber = 0; };
};

///////////////////////////////////////////////////////////
// Class CWaveFileHeader - for creating a wave-file header.
class CWaveFileHeader
{
	public:
		CWaveFileHeader();
		CWaveFileHeader( ULONG SamplingRate, USHORT BitsPerSample, USHORT Channels, ULONG DataSize );
		void Set( ULONG SamplingRate, USHORT BitsPerSample, USHORT Channels, ULONG DataSize );

	private:
		UCHAR  m_Riff_ID[4];		//'RIFF'
		ULONG  m_Riff_Size;			// FileSize-8
		UCHAR  m_Riff_Type[4];		// 'WAVE'

		UCHAR  m_Fmt_ID[4];			// 'FMT '
		ULONG  m_Fmt_Length;		// 16
		USHORT m_Fmt_Format;		// 1 (=MS PCM)
		USHORT m_Fmt_Channels;		// 1 = mono, 2 = stereo
		ULONG  m_Fmt_SamplingRate;	// Abtastrate pro Sekunde (z.B. 44100)
		ULONG  m_Fmt_DataRate;		// SamplingRate * BlockAlign
		USHORT m_Fmt_BlockAlign;	// Channels * BitsPerSample / 8
		USHORT m_Fmt_BitsPerSample;	// 8 or 16

		UCHAR  m_Data_ID[4];		// 'data'
		ULONG  m_Data_DataSize;		// Size of the following data
};

// CLSID_AsyncCDFilter
//  { 0440ADA7-00DF-492d-87AA-51A150876202 }
DEFINE_GUID(CLSID_AsyncCDFilter, 0x440ada7, 0xdf, 0x492d, 0x87, 0xaa, 0x51, 0xa1, 0x50, 0x87, 0x62, 0x2);			

// CAsyncCDStream - an internal filter that wraps the base CBaseReader stuff
class CAsyncCDStream : public CAsyncStream
{
public:
    CAsyncCDStream();
	virtual ~CAsyncCDStream();

	bool Load(std::wstring fileName, int iTrack);
	bool CreateWaveHeader();

	// CAsyncStream overrides.
	HRESULT SetPointer(LONGLONG llPos);
	HRESULT	Read(PBYTE pbBuffer,
				 DWORD dwBytesToRead,
				 BOOL bAlign,
				 LPDWORD pdwBytesRead);
	LONGLONG Size(LONGLONG *pSizeAvailable);
	DWORD	Alignment();
	void	Lock();
	void	Unlock();

private:
	CCritSec    m_csLock;
	LONGLONG	m_curReadPos;
	HANDLE		m_hDrive;

	// Wave header.
	CWaveFileHeader m_waveHeader;
	UINT m_waveHeaderSz;

	// CD Parsing.
	CDROM_TOC	m_toc;
	std::valarray<CDTRACK> m_tracks;
	ULONG AddressToSectors(UCHAR Addr[4]);

	// Current track.
	CDTRACK m_curTrack;		// m_curTrack.TrackNumber is ones based
};

class CAsyncCDFilter : public CAsyncReader, public IFileSourceFilter
{
public:

	// Construction
    CAsyncCDFilter(LPUNKNOWN pUnk, HRESULT *phr);
    ~CAsyncCDFilter();
    static CUnknown * WINAPI CreateInstance(LPUNKNOWN, HRESULT *);

    DECLARE_IUNKNOWN
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);

    // IFileSourceFilter methods
	//
    //  Load a (new) file
    STDMETHODIMP Load(LPCOLESTR lpwszFileName, const AM_MEDIA_TYPE *pmt);

	// Modeled on IPersistFile::Load
	// Caller needs to CoTaskMemFree or equivalent.
	STDMETHODIMP GetCurFile(LPOLESTR * ppszFileName, AM_MEDIA_TYPE *pmt);

private:
	CAsyncCDStream m_stream;
	std::wstring   m_fileName;
	int	m_iTrack;
};


