//--------------------------------------------------------------------------------------
// AtgAudio.h
//
// Simple WAV file reader and other audio utilities
//
// Xbox Advanced Technology Group.
// Copyright (C) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#pragma once

#ifdef SOUNDSYSTEM_USE_XENON_XAUDIO

#ifndef ATGAUDIO_H
#define ATGAUDIO_H

#include <XAudDefs.h>

namespace ATG
{

//--------------------------------------------------------------------------------------
// Misc type definitions
//--------------------------------------------------------------------------------------
typedef DWORD FOURCC, *PFOURCC, *LPFOURCC;


//--------------------------------------------------------------------------------------
// Format tags
//--------------------------------------------------------------------------------------
#define WAVE_FORMAT_PCM                     1
#define WAVE_FORMAT_EXTENSIBLE              0xFFFE


//--------------------------------------------------------------------------------------
// For parsing WAV files
//--------------------------------------------------------------------------------------
#ifndef _WAVEFORMATEX_
#define _WAVEFORMATEX_

typedef struct tWAVEFORMATEX
{
    WORD            wFormatTag;             // Format type
    WORD            nChannels;              // Channel count
    DWORD           nSamplesPerSec;         // Sampling rate
    DWORD           nAvgBytesPerSec;        // Average number of bytes per second
    WORD            nBlockAlign;            // Block size of data
    WORD            wBitsPerSample;         // Count of bits per mono sample
    WORD            cbSize;                 // Bytes of extra format information following this structure
} WAVEFORMATEX, *PWAVEFORMATEX, *LPWAVEFORMATEX;

typedef const WAVEFORMATEX *LPCWAVEFORMATEX;

#endif // _WAVEFORMATEX_


//--------------------------------------------------------------------------------------
// For parsing WAV files
//--------------------------------------------------------------------------------------
#ifndef _WAVEFORMATEXTENSIBLE_
#define _WAVEFORMATEXTENSIBLE_

typedef struct 
{
    WAVEFORMATEX    Format;                 // WAVEFORMATEX data

    union 
    {
        WORD        wValidBitsPerSample;    // Bits of precision
        WORD        wSamplesPerBlock;       // Samples per block of audio data
        WORD        wReserved;              // Unused -- must be 0
    } Samples;

    DWORD           dwChannelMask;          // Channel usage bitmask
    GUID            SubFormat;              // Sub-format identifier
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE, *LPWAVEFORMATEXTENSIBLE;

typedef const WAVEFORMATEXTENSIBLE *LPCWAVEFORMATEXTENSIBLE;

#endif // _WAVEFORMATEXTENSIBLE_


//--------------------------------------------------------------------------------------
// For parsing WAV files
//--------------------------------------------------------------------------------------
struct RIFFHEADER
{
    FOURCC  fccChunkId;
    DWORD   dwDataSize;
};

#define RIFFCHUNK_FLAGS_VALID   0x00000001


//--------------------------------------------------------------------------------------
// Name: class RiffChunk
// Desc: RIFF chunk utility class
//--------------------------------------------------------------------------------------
class RiffChunk
{
    FOURCC            m_fccChunkId;       // Chunk identifier
    const RiffChunk* m_pParentChunk;     // Parent chunk
    HANDLE            m_hFile;
    DWORD             m_dwDataOffset;     // Chunk data offset
    DWORD             m_dwDataSize;       // Chunk data size
    DWORD             m_dwFlags;          // Chunk flags

public:
    RiffChunk();

    // Initialization
    VOID    Initialize( FOURCC fccChunkId, const RiffChunk* pParentChunk,
                        HANDLE hFile );
    HRESULT Open();
    BOOL    IsValid() const { return !!(m_dwFlags & RIFFCHUNK_FLAGS_VALID); }

    // Data
    HRESULT ReadData( LONG lOffset, VOID* pData, DWORD dwDataSize ) const;

    // Chunk information
    FOURCC  GetChunkId() const  { return m_fccChunkId; }
    DWORD   GetDataSize() const { return m_dwDataSize; }
};


//--------------------------------------------------------------------------------------
// Name: class WaveFile
// Desc: Wave file utility class
//--------------------------------------------------------------------------------------
class WaveFile
{
    HANDLE      m_hFile;            // File handle
    RiffChunk  m_RiffChunk;        // RIFF chunk
    RiffChunk  m_FormatChunk;      // Format chunk
    RiffChunk  m_DataChunk;        // Data chunk
    RiffChunk  m_WaveSampleChunk;  // Wave Sample chunk
    RiffChunk  m_SamplerChunk;     // Sampler chunk
    
public:
    WaveFile();
    ~WaveFile();

    // Initialization
    HRESULT Open( const CHAR* strFileName );
    VOID    Close();

    // File format
    HRESULT GetFormat( WAVEFORMATEXTENSIBLE* pwfxFormat ) const;

    // File data
    HRESULT ReadSample( DWORD dwPosition, VOID* pBuffer, DWORD dwBufferSize, 
                        DWORD* pdwRead ) const;

    // Loop region
    HRESULT GetLoopRegion( DWORD* pdwStart, DWORD* pdwLength ) const;
    HRESULT GetLoopRegionBytes( DWORD *pdwStart, DWORD* pdwLength ) const;

    // File properties
    VOID    GetDuration( DWORD* pdwDuration ) const { *pdwDuration = m_DataChunk.GetDataSize(); }
};

//--------------------------------------------------------------------------------------
// Name: class RiffChunkMemory
// Desc: RIFF chunk utility class
//--------------------------------------------------------------------------------------
class RiffChunkMemory
{
	FOURCC									m_fccChunkId;       // Chunk identifier
	const RiffChunkMemory*	m_pParentChunk;     // Parent chunk
	const char* 						m_pFileData;
	uint32									m_nFileSize;				// File Size
	DWORD										m_dwDataOffset;     // Chunk data offset
	DWORD										m_dwDataSize;       // Chunk data size
	DWORD										m_dwFlags;          // Chunk flags

public:
	RiffChunkMemory();

	// Initialization
	VOID    Initialize( FOURCC fccChunkId, const RiffChunkMemory* pParentChunk, const char* pFileData, uint32 nFileSize );
	HRESULT Open();
	BOOL    IsValid() const { return !!(m_dwFlags & RIFFCHUNK_FLAGS_VALID); }

	// Data
	HRESULT ReadData( LONG lOffset, VOID* pData, DWORD dwDataSize ) const;

	// Chunk information
	FOURCC  GetChunkId() const  { return m_fccChunkId; }
	DWORD   GetDataSize() const { return m_dwDataSize; }
};

//--------------------------------------------------------------------------------------
// Name: class WaveFile
// Desc: Wave file utility class
//--------------------------------------------------------------------------------------
class WaveFileMemory
{
	const char* 			m_pFileData;        // Ptr to File data
	uint32						m_nFileSize;				// Size of Sound file
	RiffChunkMemory		m_RiffChunk;        // RIFF chunk
	RiffChunkMemory		m_FormatChunk;      // Format chunk
	RiffChunkMemory		m_DataChunk;        // Data chunk
	RiffChunkMemory		m_WaveSampleChunk;  // Wave Sample chunk
	RiffChunkMemory		m_SamplerChunk;     // Sampler chunk

public:
	WaveFileMemory();
	~WaveFileMemory();

	// Initialization
	HRESULT Init( const char* pFileData, uint32 nFileSize ) ;

	// File format
	HRESULT GetFormat( WAVEFORMATEXTENSIBLE* pwfxFormat ) const;

	// File data
	HRESULT ReadSample( DWORD dwPosition, VOID* pBuffer, DWORD dwBufferSize, 
		DWORD* pdwRead ) const;

	// Loop region
	HRESULT GetLoopRegion( DWORD* pdwStart, DWORD* pdwLength ) const;
	HRESULT GetLoopRegionBytes( DWORD *pdwStart, DWORD* pdwLength ) const;

	// File properties
	VOID    GetDuration( DWORD* pdwDuration ) const { *pdwDuration = m_DataChunk.GetDataSize(); }
};

} // namespace ATG

#endif // ATGAUDIO_H

#endif