/*************************************************************************************************/
/*!
   	@file		AudioSettingDlg.h
	@author 	Fanzo
*/
/*************************************************************************************************/
#pragma		once

///////////////////////////////////////////////////////////////////////////////////////////////////
//include files


#pragma pack( push , 8 )		//set align

using namespace icubic;
using namespace icubic_audio;
using namespace shared;

///////////////////////////////////////////////////////////////////////////////////////////////////
// preprocessor deifne

///////////////////////////////////////////////////////////////////////////////////////////////////
// type define

///////////////////////////////////////////////////////////////////////////////////////////////////
// classes define

/**************************************************************************************************
"ChannelSettingDlg" class 
**************************************************************************************************/
class ChannelSettingDlg : 
	public Dialog
{
	msg_dlg_map_begin()
	msg_dlg_hook( WM_INITDIALOG					, OnInitDialog );
	msg_dlg_cmd_hook( IDOK						, BN_CLICKED	, OnOK );
	msg_dlg_cmd_hook( IDCANCEL					, BN_CLICKED	, OnCancel );
	msg_dlg_map_end()
	
// variable member
private:
	uint32						m_channel[2];
	iAudioDeviceAsio			m_device;
	IAudioDeviceAsio::Format	m_format;
// private functions
private:

// msg handler
public:
//=================================================================================================
void OnInitDialog
		(
		WPARAM	wparam,
		LPARAM	lparam
		)
{
	listview_SetExtendedListViewStyle( IDC_LIST_INPUTALIGN , LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_CHECKBOXES );
	listview_SetExtendedListViewStyle( IDC_LIST_OUTPUTALIGN , LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_CHECKBOXES );

	listview_InsertColumn( IDC_LIST_INPUTALIGN , 0 , 40 , L"" );
	listview_InsertColumn( IDC_LIST_INPUTALIGN , 1 , 220 , L"名前" );
	listview_InsertColumn( IDC_LIST_OUTPUTALIGN , 0 , 40 , L"" );
	listview_InsertColumn( IDC_LIST_OUTPUTALIGN , 1 , 220 , L"名前" );

	uint32	chmax[2];
	if( false == m_device->GetChannels( &chmax[0] , &chmax[1] ) )
		return;
	m_channel[0]	= min( chmax[0] , m_channel[0] );
	m_channel[1]	= min( chmax[1] , m_channel[1] );
	
	uint32	ch;
	for( ch = 0 ; ch < m_channel[0] && ch < _countof( m_format.m_channel_enable[0] ) ; ch++ )
	{
		IAsio::ChannelInfo	info;
		m_device->GetChannelInfo( ch , true , &info );

		wostringstream	os;
		os << ch + 1;
		listview_InsertItem( IDC_LIST_INPUTALIGN , ch , os.str().c_str() );
		listview_SetItem( IDC_LIST_INPUTALIGN , ch , 1 , info.name.c_str() );
		listview_SetCheckState( IDC_LIST_INPUTALIGN , ch , m_format.m_channel_enable[0][ch] );
	}	
	for( ch = 0 ; ch < m_channel[1] && ch < _countof( m_format.m_channel_enable[1] ) ; ch++ )
	{
		IAsio::ChannelInfo	info;
		m_device->GetChannelInfo( ch , false , &info );

		wostringstream	os;
		os << ch + 1;
		listview_InsertItem( IDC_LIST_OUTPUTALIGN , ch , os.str().c_str() );
		listview_SetItem( IDC_LIST_OUTPUTALIGN , ch , 1 , info.name.c_str() );
		listview_SetCheckState( IDC_LIST_OUTPUTALIGN , ch , m_format.m_channel_enable[1][ch] );
	}	
}
//=================================================================================================
void OnOK()
{
	bool	ck = false;
	uint32	ch;
	for( ch = 0 ; ch < m_channel[0] && ch < _countof( m_format.m_channel_enable[0] ) ; ch++ )
	{
		m_format.m_channel_enable[0][ch]	= listview_GetCheckState( IDC_LIST_INPUTALIGN , ch );
		ck	= m_format.m_channel_enable[0][ch] == true ? true : ck;
	}	
	for( ch = 0 ; ch < m_channel[1] && ch < _countof( m_format.m_channel_enable[1] ) ; ch++ )
	{
		m_format.m_channel_enable[1][ch]	= listview_GetCheckState( IDC_LIST_OUTPUTALIGN , ch );
		ck	= m_format.m_channel_enable[1][ch] == true ? true : ck;
	}
	if( ck == false )
	{
		::MessageBox( m_hwnd , L"チャンネルが割り当てられていません" , L"エラー" , MB_OK | MB_ICONINFORMATION );
		return;
	}
	Dialog::EndDialog( IDOK );
}
//=================================================================================================
void OnCancel()
{
	Dialog::EndDialog( IDCANCEL );
}

// public functions
public:
//=================================================================================================
ChannelSettingDlg()
{
	m_channel[0]	= 0;
	m_channel[1]	= 0;
}
//=================================================================================================
bool DoModal
		(
		HINSTANCE						hinst , 
		HWND							parent , 
		iAudioDeviceAsio&				device , 
		IAudioDeviceAsio::Format*		format , 
		uint32							ch[2]
		)
{
	if( device == false )
		return false;
	int	retval = IDCANCEL;
	m_device	= device;
	m_format	= *format;
	m_channel[0]= ch[0];
	m_channel[1]= ch[1];
	if( false == Dialog::DoModal( hinst , parent , L"IDD_CHANNEL_SETTING" , &retval ) )
		return false;
	if( retval == IDOK )
		*format	= m_format;
	return true;
}
};
/**************************************************************************************************
"DeviceSettingDlg" class 
**************************************************************************************************/
class DeviceSettingDlg : 
	public Dialog
{
	msg_dlg_map_begin()
	msg_dlg_hook( WM_INITDIALOG					, OnInitDialog );
	msg_dlg_hook( WM_HSCROLL					, OnHScroll );
	msg_dlg_cmd_hook( IDC_BUTTON_CHANNELSETTING	, BN_CLICKED	, OnChannelSetting );
	msg_dlg_cmd_hook( IDOK						, BN_CLICKED	, OnOK );
	msg_dlg_cmd_hook( IDCANCEL					, BN_CLICKED	, OnCancel );

	msg_dlg_cmd_hook( IDC_COMBO_DRIVER			, CBN_SELCHANGE	, OnDriverChange );
	msg_dlg_cmd_hook( IDC_COMBO_INPUTDEVICE		, CBN_SELCHANGE	, OnDeviceChange );
	msg_dlg_cmd_hook( IDC_COMBO_OUTPUTDEVICE	, CBN_SELCHANGE	, OnDeviceChange );
	msg_dlg_cmd_hook( IDC_COMBO_INOUTDEVICE		, CBN_SELCHANGE	, OnDeviceChange );
	msg_dlg_cmd_hook( IDC_COMBO_INPUTCHANNEL	, CBN_SELCHANGE	, OnInputChannelChange );
	msg_dlg_cmd_hook( IDC_COMBO_OUTPUTCHANNEL	, CBN_SELCHANGE	, OnOutputChannelChange );
	msg_dlg_cmd_hook( IDC_COMBO_SAMPLESPERSEC	, CBN_SELCHANGE	, OnSamplesPerSecChange );
	msg_dlg_cmd_hook( IDC_COMBO_CLOCKSOURCE		, CBN_SELCHANGE	, OnClockSourceChange );
	msg_dlg_cmd_hook( IDC_BUTTON_ASIOPANEL		, BN_CLICKED	, OnAsioPanel );
	msg_dlg_map_end()

	class FormatInfo
	{
	public:
		uint32			m_samplespersec;
		Array<uint32>	m_channels[2];
	};
// variable member
private:
	iEnumAudioDriver			m_enum_drv;
	iEnumAudioDevice			m_enum_dev;

	int32						m_drvid;
	int32						m_devid;
	IAudioDeviceAsio::Format	m_format;
	iAudioDeviceId				m_id;
	
	iAudioDevice				m_device;
	Straightdata<FormatInfo>	m_formats;

// private functions
private:
//=================================================================================================
void InitializeChannelEnable()
{
	int		flow;
	for( flow = 0 ; flow < _countof( m_format.m_channel_enable ) ; flow++ )
	{
		int	ch;
		for( ch = 0 ; ch < _countof( m_format.m_channel_enable[flow] ) ; ch++ )
			m_format.m_channel_enable[flow][ch] = true;
	}
}
//=================================================================================================
void UpdateFormats()
{
	m_formats.Resize( 0 );
	if( m_device == false )
		return;
	
	static
	uint32	samplerate[] = 
	{
		11025 , 
		22050 , 
		44100 , 
		48000 ,
		88200 ,  
		96000 , 
		176400 , 
		192000 , 
	};
	IAudioDevice::Format	fmt;
	uint32					ch_max[2];
	m_device->GetChannelMaximum( &ch_max[0] , &ch_max[1] );
	int		sr_off;
	for( sr_off = 0 ; sr_off < _countof( samplerate ) ; sr_off++ )
	{
		cb_trace( L"[ %dHz ]\n" , samplerate[sr_off] );
		int	foff = m_formats.Add();
		m_formats[foff].m_samplespersec	= samplerate[sr_off];
		int	flow;
		for( flow = 0 ; flow  < 2 ; flow++ )
		{
			uint32	ch;
			for( ch = 1 ; ch <= ch_max[flow] ; ch++ )
			{
				fmt.m_channel[0]	= flow == 0 ? ch : 0;
				fmt.m_channel[1]	= flow == 1 ? ch : 0;
				fmt.m_samplespersec	= samplerate[sr_off];
				if( true == m_device->IsFormatAvailable( fmt ) )
				{
cb_trace( L"･%s %d\n" , flow == 0 ? L"in" : L"out" , ch );
					m_formats[foff].m_channels[flow][ m_formats[foff].m_channels[flow].Add() ] = ch;
				}
			}
		}
		if( m_formats[foff].m_channels[0].GetDatanum() == 0 
		&&  m_formats[foff].m_channels[1].GetDatanum() == 0 )
			m_formats.Delete( foff );
	}
}
//=================================================================================================
void UpdateDriver()
{
	combobox_ResetContent( IDC_COMBO_DRIVER );
	if( m_enum_drv == false )
		return;
	m_enum_dev.release();

	int		drvoff , drvnum = m_enum_drv->GetDriverNum();
	for( drvoff = 0 ; drvoff < drvnum ; drvoff++ )
	{
		iEnumAudioDevice	dev_enums = m_enum_drv->GetEnumAudioDevice( drvoff );
		combobox_AddString( IDC_COMBO_DRIVER , dev_enums->GetDriverName().c_str() );
	}
	m_drvid	= m_drvid < 0 ? 0 : ( m_drvid >= drvnum ? drvnum - 1 : m_drvid );
	if( m_drvid < 0  )
		return;

	combobox_SetCurSel( IDC_COMBO_DRIVER , m_drvid );
	m_enum_dev	= m_enum_drv->GetEnumAudioDevice( m_drvid );
}
//=================================================================================================
void UpdateDeviceSingle
		(
		iEnumAudioDevice&		enum_dev
		)
{
	ctrl_Show( IDC_COMBO_INPUTDEVICE , false );
	ctrl_Show( IDC_STATIC_INPUTDEVICE , false );
	ctrl_Show( IDC_COMBO_OUTPUTDEVICE , false );
	ctrl_Show( IDC_STATIC_OUTPUTDEVICE , false );
	ctrl_Show( IDC_COMBO_INOUTDEVICE , true );
	ctrl_Show( IDC_STATIC_INOUTDEVICE , true );

	combobox_ResetContent( IDC_COMBO_INOUTDEVICE );
	m_device.release();
	if( enum_dev == false )
		return;
		
	int		off , num = enum_dev->GetDeviceNum();
	for( off = 0 ; off < num ; off++ )
	{
		IEnumAudioDevice::DeviceInfo	info;
		enum_dev->GetDeviceInfo( off , &info );
		combobox_AddString( IDC_COMBO_INOUTDEVICE , info.m_name.c_str() );
	}
	m_devid		= m_devid	 < 0 ? 0 : ( m_devid	 >= num ? num - 1 : m_devid	 );
	combobox_SetCurSel( IDC_COMBO_INOUTDEVICE , m_devid	 );
	m_device	= enum_dev->CreateDevice( m_devid , m_hwnd );
}
//=================================================================================================
void UpdateDevicePair
		(
		iEnumAudioDevicePair&	enum_dev
		)
{
	ctrl_Show( IDC_COMBO_INPUTDEVICE , true );
	ctrl_Show( IDC_STATIC_INPUTDEVICE , true );
	ctrl_Show( IDC_COMBO_OUTPUTDEVICE , true );
	ctrl_Show( IDC_STATIC_OUTPUTDEVICE , true );
	ctrl_Show( IDC_COMBO_INOUTDEVICE , false );
	ctrl_Show( IDC_STATIC_INOUTDEVICE , false );

	combobox_ResetContent( IDC_COMBO_INPUTDEVICE );
	combobox_ResetContent( IDC_COMBO_OUTPUTDEVICE );
	m_device.release();
	if( enum_dev == false )
		return;	
	
	{
		combobox_AddString( IDC_COMBO_INPUTDEVICE , L"なし" );
		int		devoff , devnum = enum_dev->GetInputDeviceNum();
		for( devoff = 0 ; devoff < devnum ; devoff++ )
		{
			IEnumAudioDevice::DeviceInfo	info;
			enum_dev->GetInputDeviceInfo( devoff , &info );
			combobox_AddString( IDC_COMBO_INPUTDEVICE , info.m_name.c_str() );
		}
	}
	{
		combobox_AddString( IDC_COMBO_OUTPUTDEVICE , L"なし" );
		int		devoff , devnum = enum_dev->GetOutputDeviceNum();
		for( devoff = 0 ; devoff < devnum ; devoff++ )
		{
			IEnumAudioDevice::DeviceInfo	info;
			enum_dev->GetOutputDeviceInfo( devoff , &info );
			combobox_AddString( IDC_COMBO_OUTPUTDEVICE , info.m_name.c_str() );
		}
	}
	int		devnum	= enum_dev->GetDeviceNum();
	m_devid	= m_devid < 0 ? 0 : ( m_devid >= devnum ? devnum - 1 : m_devid );
	int32	in , out;
	if( false == enum_dev->DeviceToPair( m_devid , &in , &out )  )
	{
		combobox_SetCurSel( IDC_COMBO_INPUTDEVICE , 0 );
		combobox_SetCurSel( IDC_COMBO_OUTPUTDEVICE , 0 );
		return;
	}
	combobox_SetCurSel( IDC_COMBO_INPUTDEVICE , in + 1 );
	combobox_SetCurSel( IDC_COMBO_OUTPUTDEVICE , out + 1 );
	m_device	= enum_dev->CreateDevice( m_devid , m_hwnd );
}
//=================================================================================================
void UpdateDevice()
{
	combobox_ResetContent( IDC_COMBO_INPUTDEVICE );
	combobox_ResetContent( IDC_COMBO_OUTPUTDEVICE );
	combobox_ResetContent( IDC_COMBO_INOUTDEVICE );
	if( m_enum_dev == false )
	{
		ctrl_Enable( IDC_COMBO_INPUTDEVICE , false );
		ctrl_Enable( IDC_COMBO_OUTPUTDEVICE , false );
		ctrl_Enable( IDC_COMBO_INOUTDEVICE , false );
		return;
	}
	iEnumAudioDevicePair	enum_pair	= m_enum_dev;
	if( enum_pair == true )
		UpdateDevicePair( enum_pair );
	else
		UpdateDeviceSingle( m_enum_dev );
	UpdateFormats();
}
//=================================================================================================
void UpdateSamplerate()
{
	combobox_ResetContent( IDC_COMBO_SAMPLESPERSEC );
	int		index = -1;
	{
		int		off , num = m_formats.GetDatanum();
		for( off = 0 ; off < num ; off++ )
		{
			wostringstream	os;
			os << m_formats[off].m_samplespersec;
			combobox_AddString( IDC_COMBO_SAMPLESPERSEC , ( os.str() + L"Hz" ).c_str() );
			if( m_format.m_samplespersec == m_formats[off].m_samplespersec )
				index = off;
		}
	}
	if( index == -1 && m_formats.GetDatanum() > 0 )
	{
		index	= 0;
		m_format.m_samplespersec = m_formats[0].m_samplespersec;
	}
	else if( index == -1 )
	{
		index	= -1;
		m_format.m_samplespersec	= 0;
	}
	combobox_SetCurSel( IDC_COMBO_SAMPLESPERSEC , index );
}
//=================================================================================================
void UpdateChannel
		(
		uint32		flow
		)
{
	int32	ctrlid[] = { IDC_COMBO_INPUTCHANNEL , IDC_COMBO_OUTPUTCHANNEL };
	combobox_ResetContent( ctrlid[flow] );
	int		fmtoff = combobox_GetCurSel( IDC_COMBO_SAMPLESPERSEC );
	if( fmtoff < 0 )
		return;
	
	int		ch		= ( flow == 0 ) ? m_format.m_channel[0] : m_format.m_channel[1];
	int		index	= -1;
	int		ch_off;
	for( ch_off = 0 ; ch_off < m_formats[fmtoff].m_channels[flow].GetDatanum() ; ch_off++ )
	{
		wostringstream	os;
		os << m_formats[fmtoff].m_channels[flow][ch_off];
		combobox_AddString( ctrlid[flow] , ( os.str() + L"ch" ).c_str() );
		if( ch == m_formats[fmtoff].m_channels[flow][ch_off] )
			index = ch_off;
	}
	if( index == -1 )
	{
		index	= m_formats[fmtoff].m_channels[flow].GetDatanum() -1;
		ch		= m_formats[fmtoff].m_channels[flow].GetDatanum() == 0 ? 0 : m_formats[fmtoff].m_channels[flow][m_formats[fmtoff].m_channels[flow].GetDatanum() - 1];
	}
	combobox_SetCurSel( ctrlid[flow] , index );
	ctrl_Enable( ctrlid[flow] , index == -1 ? false : true );
	m_format.m_channel[flow]	= ch;
}
//=================================================================================================
void UpdateChannelSetting()
{
	iAudioDeviceAsio	asio	= (iAudioDeviceAsio)m_device;
	ctrl_Enable( IDC_BUTTON_CHANNELSETTING , asio == true ? true : false );
}
//=================================================================================================
void UpdateBuffersize()
{
	if( m_device == false )
		return;
	
	uint32	min , max , prefer;
	if( false == m_device->GetBufferSamplesMaximum( &min , &max , &prefer ) )
	{
		ctrl_Enable( IDC_SLIDER_BUFFERSAMPLES , false );
		return;
	}
	ctrl_Enable( IDC_SLIDER_BUFFERSAMPLES , true );
	if( m_format.m_buffersamples == 0 )
		m_format.m_buffersamples = prefer;
	min	= max( min , 64 );
	max	= min( max , 10 * 1024 );
	m_format.m_buffersamples	= clip( m_format.m_buffersamples , min , max );
	slider_SetRange( IDC_SLIDER_BUFFERSAMPLES , min , max , false );
	slider_SetPos( IDC_SLIDER_BUFFERSAMPLES , m_format.m_buffersamples , true );
}
//=================================================================================================
void UpdateLatency()
{
	edit_SetText( IDC_EDIT_INPUTLATENCY , L"" );
	edit_SetText( IDC_EDIT_OUTPUTLATENCY , L"" );
	if( m_device == false )
		return;
	if( false == m_device->Create( m_format ) )
		return;

	uint32	latency[2] = { 0 , 0 };
	if( false == m_device->GetLatency( &latency[0] , &latency[1] ) )
		return;
	{
		wostringstream	os;
		os << latency[0] << L" ms";
		edit_SetText( IDC_EDIT_INPUTLATENCY , os.str().c_str() );
	}	
	{
		wostringstream	os;
		os << latency[1] << L" ms";
		edit_SetText( IDC_EDIT_OUTPUTLATENCY , os.str().c_str() );
	}	
}
//=================================================================================================
void UpdateClockSource()
{
	combobox_ResetContent( IDC_COMBO_CLOCKSOURCE );
	iAudioDeviceAsio	asio = (iAudioDeviceAsio)m_device;
	if( asio == false || asio->GetClockSourceNum() == 0 )
	{
		ctrl_Enable( IDC_COMBO_CLOCKSOURCE , false );
		ctrl_Enable( IDC_BUTTON_ASIOPANEL , false );
		return;
	}
	ctrl_Enable( IDC_COMBO_CLOCKSOURCE , true );
	ctrl_Enable( IDC_BUTTON_ASIOPANEL , true );
	
	int		ckoff , cknum = asio->GetClockSourceNum();
	for( ckoff = 0 ; ckoff < cknum ; ckoff++ )
	{
		IAsio::ClockSource	clock;
		asio->GetClockSource( ckoff , &clock );
		combobox_AddString( IDC_COMBO_CLOCKSOURCE , clock.name.c_str() );
	}
	m_format.m_clocksource	= clip( (int)m_format.m_clocksource , 0 , cknum - 1 );
	combobox_SetCurSel( IDC_COMBO_CLOCKSOURCE , m_format.m_clocksource );
}
// msg handler
private:
//=================================================================================================
void OnInitDialog
		(
		WPARAM	wparam,
		LPARAM	lparam
		)
{
	UpdateDriver();
	UpdateDevice();
	UpdateSamplerate();
	UpdateChannel( 0 );
	UpdateChannel( 1 );
	UpdateChannelSetting();
	UpdateBuffersize();
	UpdateLatency();
	UpdateClockSource();
}
//=================================================================================================
void OnHScroll
		(
		WPARAM	wparam,
		LPARAM	lparam
		)
{
	int		msg = LOWORD( wparam );
	int		pos = HIWORD( wparam );
	if( msg == TB_THUMBTRACK
		 ||  msg == TB_THUMBPOSITION
	     ||  msg == TB_PAGEUP
	     ||  msg == TB_PAGEDOWN )
	{
		cb_trace( L"OnHScroll\n" );
		m_format.m_buffersamples = slider_GetPos( IDC_SLIDER_BUFFERSAMPLES );
		UpdateLatency();
	}
}
//=================================================================================================
void OnDriverChange()
{
	m_format.m_buffersamples = 0;
	m_drvid = combobox_GetCurSel( IDC_COMBO_DRIVER );
	m_devid	= 0;
	UpdateDriver();
	UpdateDevice();
	UpdateSamplerate();
	UpdateChannel( 0 );
	UpdateChannel( 1 );
	UpdateChannelSetting();
	UpdateBuffersize();
	UpdateLatency();
	UpdateClockSource();
}
//=================================================================================================
void OnDeviceChange()
{
	InitializeChannelEnable();
	m_format.m_buffersamples	= 0;
	
	iEnumAudioDevice		enum_dev	= m_enum_dev;
	iEnumAudioDevicePair	enum_pair	= (iEnumAudioDevicePair)enum_dev;

	if( enum_pair == true )
		enum_pair->PairToDevice( &m_devid , combobox_GetCurSel( IDC_COMBO_INPUTDEVICE ) - 1 , combobox_GetCurSel( IDC_COMBO_OUTPUTDEVICE )- 1 );
	else
		m_devid = combobox_GetCurSel( IDC_COMBO_INOUTDEVICE );

	UpdateDevice();
	UpdateSamplerate();
	UpdateChannel( 0 );
	UpdateChannel( 1 );
	UpdateChannelSetting();
	UpdateBuffersize();
	UpdateLatency();
	UpdateClockSource();
}
//=================================================================================================
void OnInputChannelChange()
{
	int	index = combobox_GetCurSel( IDC_COMBO_INPUTCHANNEL );
	int	fmtoff , fmtnum = m_formats.GetDatanum();
	for( fmtoff = 0 ; fmtoff < fmtnum ; fmtoff++ )
	{
		if( m_formats[fmtoff].m_samplespersec == m_format.m_samplespersec )
			break;
	}
	if( fmtoff == fmtnum )
		return;
	if( index < 0 || index >= m_formats[fmtoff].m_channels[0].GetDatanum() )
		return;
	m_format.m_channel[0] = m_formats[fmtoff].m_channels[0][index];
}
//=================================================================================================
void OnOutputChannelChange()
{
	int	index = combobox_GetCurSel( IDC_COMBO_OUTPUTCHANNEL );
	int	fmtoff , fmtnum = m_formats.GetDatanum();
	for( fmtoff = 0 ; fmtoff < fmtnum ; fmtoff++ )
	{
		if( m_formats[fmtoff].m_samplespersec == m_format.m_samplespersec )
			break;
	}
	if( fmtoff == fmtnum )
		return;
	if( index < 0 || index >= m_formats[fmtoff].m_channels[1].GetDatanum() )
		return;
	m_format.m_channel[1] = m_formats[fmtoff].m_channels[1][index];
}
//=================================================================================================
void OnSamplesPerSecChange()
{
	int	index = combobox_GetCurSel( IDC_COMBO_SAMPLESPERSEC );
	if( 0 <= index && index < m_formats.GetDatanum() )
		m_format.m_samplespersec = m_formats[index].m_samplespersec;
	UpdateSamplerate();
	UpdateChannel( 0 );
	UpdateChannel( 1 );
	UpdateLatency();
}
//=================================================================================================
void OnChannelSetting()
{
	instance<ChannelSettingDlg>	dlg;
	uint32	ch[2] = { m_format.m_channel[0] , m_format.m_channel[1] };
	dlg->DoModal( m_hinst , m_hwnd , (iAudioDeviceAsio)m_device , &m_format , ch );
}
//=================================================================================================
void OnClockSourceChange()
{
	m_format.m_clocksource	= combobox_GetCurSel( IDC_COMBO_CLOCKSOURCE );
}
//=================================================================================================
void OnAsioPanel()
{
	iAudioDeviceAsio	asio = (iAudioDeviceAsio)m_device;
	if( asio == false )
		return;
	asio->ControlPanel();
}
//=================================================================================================
void OnOK()
{
	m_id.release();
	instance<AudioDeviceId>	id;
	if( true == m_enum_dev->GetAudioDeviceId( m_devid , (iAudioDeviceId)id ) )
		m_id	= (iAudioDeviceId)id;
	m_device.release();
	Dialog::EndDialog( IDOK );
}
//=================================================================================================
void OnCancel()
{
	if( m_device == true )
		m_device->Destroy();
	m_device.release();
	Dialog::EndDialog( IDCANCEL );
}
// public functions
public:
//=================================================================================================
DeviceSettingDlg() : 
		m_drvid( 0 ) , 
		m_devid( 0 )
{
}
//=================================================================================================
~DeviceSettingDlg()
{
	Destroy();
}
//=================================================================================================
bool DoModal
		(
		HINSTANCE						hinst , 
		HWND							parent , 
		iEnumAudioDriver&				drivers , 
		iAudioDeviceId*					id , 
		IAudioDeviceAsio::Format*		fmt
		)
{
	if( drivers == false || id == 0 || fmt == 0 )
		return false;

	m_enum_drv	= drivers;
	m_drvid	= 0;
	m_devid	= 0;
	if( *id == true )
		m_enum_drv->SearchDevice( &m_drvid , &m_devid , (iAudioDeviceId)*id );
	m_format	= *fmt;

	int	r = IDCANCEL;
	if( false == Dialog::DoModal( hinst , parent , L"IDD_DEVICE_SETTING" , &r ) )
		return false;
	if( r == IDCANCEL )
		return false;
		
	*id		= m_id;
	*fmt	= m_format;
	return true;
}
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// global variable define

///////////////////////////////////////////////////////////////////////////////////////////////////
// global functions define


//using namespace icubic;		

#pragma pack( pop )			//release align
