#pragma once

#include "refISoundDevice.h"

namespace FDK
{
	public ref class CSoundDeviceWASAPI : ISoundDevice
	{
	public:
		enum class EWASAPIデバイスモード { 排他, 共有 };

		property ESoundDeviceType e出力デバイス
		{
			virtual ESoundDeviceType get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				return this->_e出力デバイス;
			}
		protected: void set( ESoundDeviceType value )
		   {
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				this->_e出力デバイス = value;
		   }
		}
		property Int32 nバッファ長bytes
		{
			Int32 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				return this->_nバッファ長bytes;
			}
		}
		property Int32 nサンプリング周波数Hz
		{
			Int32 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				return this->_nサンプリング周波数Hz;
			}
		}
		property Int32 nサンプリングバイト数
		{
			Int32 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				return this->_nサンプリングバイト数;
			}
		}
		property Int32 nチャンネル数
		{
			Int32 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				return this->_nチャンネル数;
			}
		}
		property Int64 n実出力遅延ms
		{
			virtual Int64 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				return this->_n実出力遅延ms;
			}
		protected:
			void set( Int64 value )
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				this->_n実出力遅延ms = value;
			}
		}

		// CSoundTimer 用に公開しているプロパティ
		
		property Int64 n経過時間ms
		{
			virtual Int64 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				return this->_n経過時間ms;
			}
		protected:
			void set( Int64 value )
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				this->_n経過時間ms = value;
			}
		}
		property Int64 n経過時間を更新したシステム時刻ms
		{
			virtual Int64 get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				return this->_n経過時間を更新したシステム時刻ms;
			}
		protected:
			void set( Int64 value )
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				this->_n経過時間を更新したシステム時刻ms = value;
			}
		}
		property CTimer^ tmシステムタイマ
		{
			virtual CTimer^ get()
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				return this->_timer;
			}
		protected:
			void set( CTimer^ value )
			{
				this->Disposed->tDispose済みまたは実行中なら例外発生( "CSoundDeviceWASAPI" );
				this->_timer = value;
			}
		}
			
		delegate DWORD WASAPIProcDelegate( void *buffer, DWORD length, void *user );

		CSoundDeviceWASAPI( EWASAPIデバイスモード mode, Int64 n希望バッファサイズms, Int64 n更新間隔ms, bool b排他モードでの作成失敗時に共有モードでの作成を行う );
		~CSoundDeviceWASAPI();
		!CSoundDeviceWASAPI();

		virtual CSound^ tサウンドを作成する( String^ stgファイル名 );
		virtual CSound^ tサウンドを作成する( array<byte>^ byArrWAVファイルイメージ );
		virtual void tサウンドを作成する( String^ stgファイル名, CSound^% sound );
		virtual void tサウンドを作成する( array<byte>^ byArrWAVファイルイメージ, CSound^% sound );

	protected:
		DWORD hMixer;
		GCHandle gchWASAPIProc;
		WASAPIProcDelegate^ dgWASAPIProc;

		DWORD tWASAPI処理( void *buffer, DWORD length, void *user );

	private:
		CDisposed^ Disposed;
		CAtomBool bDisposedOutput;	// WASAPI書き込み時専用。他のメソッドの処理のために書き込みを遅らせるべきではない。

		UInt64 nミキサーの1秒あたりのバイト数;
		UInt64 n累積転送バイト数;
		bool b最初の実出力遅延算出;

		ESoundDeviceType _e出力デバイス;
		Int32 _nバッファ長bytes;
		Int32 _nサンプリング周波数Hz;
		Int32 _nサンプリングバイト数;
		Int32 _nチャンネル数;
		Int64 _n実出力遅延ms;
		Int64 _n経過時間ms;
		Int64 _n経過時間を更新したシステム時刻ms;
		CTimer^ _timer;
	};
}
