// SoundPage.cpp : implementation file
//

#include "stdafx.h"
#include "source_sounds_builder.h"
#include "source_sounds_builderDlg.h"
#include "SoundPage.h"

#include "../src/sound/driver/buffer.h"
#include "../src/sound/audio_mixer_user.h"

#include "nel/sound/u_listener.h"

#include <nel/misc/common.h>
#include <nel/misc/vector.h>
using namespace NLMISC;

#include <math.h>

using namespace std;


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


#define CONE_X 340
#define CONE_Y 280
#define CONE_R 30


uint XCenter;
uint YCenter;
uint Radius;


const char *PriorityStr [NbSoundPriorities] = { "Highest", "High", "Medium", "Low" };


//----------------------------------------------------------
// Name: ConvertLinearSliderPosToLogScale()
// Desc: Converts a linear slider position to a quasi logrithmic scale
//-----------------------------------------------------------------------------
float ConvertLinearSliderPosToLogScale( LONG lSliderPos )
{
    if( lSliderPos > 0 && lSliderPos <= 10 )
    {
        return lSliderPos*0.01f;
    }
    else if( lSliderPos > 10 && lSliderPos <= 20 )
    {
        return (lSliderPos-10)*0.1f;
    }
    else if( lSliderPos > 20 && lSliderPos <= 30 )
    {
        return (lSliderPos-20)*1.0f;
    }
    else if( lSliderPos > 30 && lSliderPos <= 40 )
    {
        return (lSliderPos-30)*10.0f;
    }

    return 0.0f;
}




//-----------------------------------------------------------------------------
// Name: ConvertLinearSliderPosToLogScale()
// Desc: Converts a quasi logrithmic scale to a slider position
//-----------------------------------------------------------------------------
LONG ConvertLogScaleToLinearSliderPosTo( FLOAT fValue )
{
    if( fValue > 0.0f && fValue <= 0.1f )
    {
        return (LONG)(fValue/0.01f);
    }
    else if( fValue > 0.1f && fValue <= 1.0f )
    {
        return (LONG)(fValue/0.1f) + 10;
    }
    else if( fValue > 1.0f && fValue <= 10.0f )
    {
        return (LONG)(fValue/1.0f) + 20;
    }
    else if( fValue > 10.0f && fValue <= 100.0f )
    {
        return (LONG)(fValue/10.0f) + 30;
    }

    return 0;
}



/////////////////////////////////////////////////////////////////////////////
// CSoundPage dialog


CSoundPage::CSoundPage(CWnd* pParent /*=NULL*/)
	: CDialog(CSoundPage::IDD, pParent)
{
	//{{AFX_DATA_INIT(CSoundPage)
	m_Filename = _T("");
	m_Gain = 1.0f;
	m_Pos3D = FALSE;
	m_MinDist = 1.0f;
	m_MaxDist = 1000000.0f;
	m_InnerAngleDeg = 360;
	m_OuterAngleDeg = 360;
	m_OuterGain = 1.0f;
	m_Looped = FALSE;
	m_Stereo = _T("");
	m_Pitch = 1.0f;
	m_Looping = false;
	m_SoundName = _T("");
	//}}AFX_DATA_INIT

	_CurrentSound = NULL;
	_Tree = NULL;
	_Source = NULL;
}


/*
 *
 */
BOOL CSoundPage::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	// Load driver
	CWaitCursor waitcursor;
	_AudioMixer = UAudioMixer::createAudioMixer();
	try
	{
		_AudioMixer->init();
		//_AudioMixer->getListener()->setPos( CVector(0.0f,0.0001f,0.0f) );
	}
	catch( Exception& e )
	{
		CString s;
		s.Format( "No sound driver: %s\n\nSound playback will be unavailable" , e.what() );
		AfxMessageBox( s );
		_AudioMixer = NULL;
	}

	// Fill priorities
	uint i;
	for ( i=0; i!=NbSoundPriorities; ++i )
	{
		m_Priority.AddString( PriorityStr[i] );
	}

	// We want to load nss files even if the corresponding waves are missing
	CSound::allowMissingWave( true );

	// Cone drawing: make it work with normal and big fonts (depending on system settings)
	CRect parentrect, sliderrect;
	this->GetWindowRect( &parentrect );
	GetDlgItem( IDC_SliderOuterAngle )->GetWindowRect( &sliderrect );
	XCenter = sliderrect.right - parentrect.left + 15 + CONE_R;
	YCenter = sliderrect.top - parentrect.top + 10;
	Radius = CONE_R;

	waitcursor.Restore();

	_NameFont = new CFont();
	LOGFONT logfont;
	GetFont()->GetLogFont( &logfont );
	logfont.lfWeight = FW_BOLD;
	_NameFont->CreateFontIndirect( &logfont );
	
	GetDlgItem( IDC_SoundName )->SetFont( _NameFont );

	((CSliderCtrl*)GetDlgItem( IDC_SliderGain ))->SetRange( 0, 40 );
	((CSliderCtrl*)GetDlgItem( IDC_SliderPitch ))->SetRange( 0, 40 );
	((CSliderCtrl*)GetDlgItem( IDC_SliderMinDist ))->SetRange( 0, 1000 );
	((CSliderCtrl*)GetDlgItem( IDC_SliderMaxDist ))->SetRange( 0, 1000 );
	((CSliderCtrl*)GetDlgItem( IDC_SliderInnerAngle ))->SetRange( 0, 360 );
	((CSliderCtrl*)GetDlgItem( IDC_SliderOuterAngle ))->SetRange( 0, 360 );
	((CSliderCtrl*)GetDlgItem( IDC_SliderOuterGain ))->SetRange( 0, 40 );

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}


void CSoundPage::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CSoundPage)
	DDX_Control(pDX, IDC_CbPriority, m_Priority);
	DDX_Text(pDX, IDC_EditFilename, m_Filename);
	DDX_Text(pDX, IDC_EditGain, m_Gain);
	DDV_MinMaxFloat(pDX, m_Gain, 0.f, 1.f);
	DDX_Check(pDX, IDC_Pos3D, m_Pos3D);
	DDX_Text(pDX, IDC_EditMinDist, m_MinDist);
	DDV_MinMaxFloat(pDX, m_MinDist, 0.f, 1.e+006f);
	DDX_Text(pDX, IDC_EditMaxDist, m_MaxDist);
	DDV_MinMaxFloat(pDX, m_MaxDist, 0.f, 1.e+006f);
	DDX_Text(pDX, IDC_EditInnerAngle, m_InnerAngleDeg);
	DDV_MinMaxUInt(pDX, m_InnerAngleDeg, 0, 360);
	DDX_Text(pDX, IDC_EditOuterAngle, m_OuterAngleDeg);
	DDV_MinMaxUInt(pDX, m_OuterAngleDeg, 0, 360);
	DDX_Text(pDX, IDC_EditOuterGain, m_OuterGain);
	DDV_MinMaxFloat(pDX, m_OuterGain, 0.f, 1.f);
	DDX_Check(pDX, IDC_Looped, m_Looped);
	DDX_Text(pDX, IDC_Stereo, m_Stereo);
	DDX_Text(pDX, IDC_EditPitch, m_Pitch);
	DDV_MinMaxFloat(pDX, m_Pitch, 1.e-011f, 1.f);
	DDX_Check(pDX, IDC_Looping, m_Looping);
	DDX_Text(pDX, IDC_SoundName, m_SoundName);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CSoundPage, CDialog)
	//{{AFX_MSG_MAP(CSoundPage)
	ON_BN_CLICKED(IDC_Pos3D, OnPos3D)
	ON_BN_CLICKED(IDC_ChooseFile, OnChooseFile)
	ON_BN_CLICKED(IDC_Remove, OnRemove)
	ON_BN_CLICKED(IDC_PlaySound, OnPlaySound)
	ON_WM_CLOSE()
	ON_BN_CLICKED(IDC_Looped, OnLooped)
	ON_EN_CHANGE(IDC_EditInnerAngle, OnChangeEditInnerAngle)
	ON_EN_CHANGE(IDC_EditOuterAngle, OnChangeEditOuterAngle)
	ON_WM_PAINT()
	ON_EN_CHANGE(IDC_EditOuterGain, OnChangeEditOuterGain)
	ON_WM_HSCROLL()
	ON_EN_CHANGE(IDC_EditMinDist, OnChangeEditMinDist)
	ON_EN_CHANGE(IDC_EditMaxDist, OnChangeEditMaxDist)
	ON_BN_CLICKED(IDC_ButtonHelp, OnButtonHelp)
	ON_EN_CHANGE(IDC_EditGain, OnChangeEditGain)
	ON_BN_CLICKED(IDC_ButtonTestOuterGain, OnButtonTestOuterGain)
	ON_EN_CHANGE(IDC_EditPitch, OnChangeEditPitch)
	ON_BN_CLICKED(IDC_Cancel, OnCancel)
	ON_BN_CLICKED(IDC_Home, OnHome)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/*
 *
 */
const char *StereoToCStr( CSound* snd, bool *st )
{
	static const char empty [] = "";
	static const char mono [] = "Mono";
	static const char stereo [] = "Stereo";
	if ( snd->getBuffer() == NULL )
	{
		*st = false;
		return empty;
	}
	else
	{
		if ( snd->getBuffer()->isStereo() )
		{
			*st = true;
			return stereo;
		}
		else
		{
			*st = false;
			return mono;
		}
	}
}


/*
 *
 */
void		CSoundPage::UpdateStereo()
{
	bool stereo;
	m_Stereo = StereoToCStr( _CurrentSound, &stereo );
	if ( stereo )
	{
		m_Pos3D = false;
	}
	GetDlgItem( IDC_Pos3D )->EnableWindow( ! stereo );
}


/*
 *
 */
void		CSoundPage::getPropertiesFromSound()
{
	m_SoundName = _CurrentSound->getName().c_str();
	m_Filename = _CurrentSound->getFilename().c_str();
	m_Gain = _CurrentSound->getGain();
	m_Pitch = _CurrentSound->getPitch();
	m_Priority.SetCurSel( _CurrentSound->getPriority() );
	m_Looping = _CurrentSound->getLooping();
	m_Pos3D = _CurrentSound->isDetailed();
	((CSliderCtrl*)GetDlgItem( IDC_SliderGain ))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_Gain*100.0f ) );
	((CSliderCtrl*)GetDlgItem( IDC_SliderPitch ))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_Pitch*100.0f ) );
	UpdateStereo();

	if ( m_Pos3D )
	{
		m_MinDist = _CurrentSound->getMinDistance();
		m_MaxDist = _CurrentSound->getMaxDistance();
		m_InnerAngleDeg = (uint)radToDeg( _CurrentSound->getConeInnerAngle() );
		m_OuterAngleDeg = (uint)radToDeg( _CurrentSound->getConeOuterAngle() );
		m_OuterGain = _CurrentSound->getConeOuterGain();
	}
	((CSliderCtrl*)GetDlgItem( IDC_SliderMinDist ))->SetPos( (int)m_MinDist );
	((CSliderCtrl*)GetDlgItem( IDC_SliderMaxDist ))->SetPos( (int)m_MaxDist );
	((CSliderCtrl*)GetDlgItem( IDC_SliderInnerAngle ))->SetPos( m_InnerAngleDeg );
	((CSliderCtrl*)GetDlgItem( IDC_SliderOuterAngle ))->SetPos( m_OuterAngleDeg );
	((CSliderCtrl*)GetDlgItem( IDC_SliderOuterGain ))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_OuterGain*100.0f ) );
	UpdateData( false );

	Invalidate();
	OnPos3D(); // enable/disable 3d properties
}


/*
 *
 */
void CSoundPage::UpdateCurrentSound()
{
	CString name = ((CSource_sounds_builderDlg*)GetOwner())->SoundName( _HItem );
	if ( ! m_Pos3D )
	{
		_CurrentSound->setProperties( string(name), string(m_Filename), m_Gain, m_Pitch, (TSoundPriority)(m_Priority.GetCurSel()), m_Looping!=0, m_Pos3D!=0 );
	}
	else
	{
		_CurrentSound->setProperties( string(name), string(m_Filename), m_Gain, m_Pitch, (TSoundPriority)(m_Priority.GetCurSel()), m_Looping!=0, m_Pos3D!=0,
			m_MinDist, m_MaxDist, degToRad((float)m_InnerAngleDeg), degToRad((float)m_OuterAngleDeg), m_OuterGain );
	}
	// Argument checking is already done by the dialog wizard
}




/////////////////////////////////////////////////////////////////////////////
// CSoundPage message handlers


/*
 *
 */
void CSoundPage::setCurrentSound( CSound *sound, HTREEITEM hitem )
{
	_CurrentSound = sound;
	_HItem = hitem;
	if ( _Source != NULL )
	{
	 	_Source->stop();
	}
	m_Looped = false;
	UpdateData( false );
}


/*
 *
 */
void CSoundPage::OnPos3D() 
{
	UpdateData( true );
	GetDlgItem( IDC_Pos3DGroup )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_MinDist )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_MaxDist )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_ConeInnerAngle )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_ConeOuterAngle )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_ConeOuterGain )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_EditMinDist )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_EditMaxDist )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_EditInnerAngle )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_EditOuterAngle )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_EditOuterGain )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_SliderMinDist )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_SliderMaxDist )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_SliderInnerAngle )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_SliderOuterAngle )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_SliderOuterGain )->EnableWindow( m_Pos3D );
	GetDlgItem( IDC_ButtonTestOuterGain )->EnableWindow( m_Pos3D );

	DrawCones();
}


/*
 *
 */
void CSoundPage::apply()
{
	if ( _CurrentSound )
	{
		if ( _Source != NULL )
		{
			_Source->stop();
		}

		UpdateData( true );

		UpdateCurrentSound();

		//(static_cast<CSource_sounds_builderDlg*>(GetOwner()))->setModified();

		nlassert( _Tree );

		if ( !m_Filename.empty() )
		{
			CString s = ((CSource_sounds_builderDlg*)GetOwner())->SoundName( _HItem ) + " (" + m_Filename + ")";
			_Tree->SetItemText( _HItem, s );
		}

		//_Tree->SelectItem( NULL );

		GetOwner()->SetFocus();
	}
}


/*
 *
 */
void CSoundPage::rename( CString s )
{
	// Quick way to do it (should be simplified)
	
	getPropertiesFromSound();
	nlassert( _Tree );
	_Tree->SetItemText( _HItem, s );
	UpdateCurrentSound();

	m_SoundName = s;
	UpdateData( false );
}


/*
 * Reverts the changes
 */
void CSoundPage::OnCancel()
{
	getPropertiesFromSound();
}


/*
 * Unselects the current sound
 */
void CSoundPage::cancel()
{
	if ( _Source != NULL )
	{
		_Source->stop();
	}

	_CurrentSound = NULL;
}


/*
 *
 */
void CSoundPage::OnHome() 
{
	nlassert( _Tree );
	_Tree->SelectItem( _Tree->GetRootItem() );
	GetOwner()->SetFocus();
}


/*
 *
 */
void CSoundPage::OnChooseFile() 
{
	// Prompt filename
	CFileDialog opendlg( true, "wav", "", OFN_OVERWRITEPROMPT, "PCM Wave files (*.wav)|*.wav||", this );
	if ( opendlg.DoModal()==IDOK )
	{
		UpdateData( true );
		m_Filename = opendlg.GetFileName();
		try 
		{
			loadSound();
		}
		catch ( Exception& e )
		{
			CString s;
			s.Format( "%s", e.what() );
			AfxMessageBox( s );
		}
		UpdateData( false );
	}
}


/*
 *
 */
bool CSoundPage::loadSound()
{
	UpdateCurrentSound();
	nlassert( _CurrentSound );
	if ( (m_Filename != "") && (_AudioMixer != NULL) )
	{
		_CurrentSound->loadBuffer( string(m_Filename) );
		UpdateStereo();
		return true;
	}
	else
	{
		return false;
	}
}


/*
 *
 */
void CSoundPage::OnRemove() 
{
	removeSound();
}


/*
 *
 */
void CSoundPage::removeSound()
{
	/*if ( AfxMessageBox( "Are you sure to remove the current sound from the list ?", MB_YESNO | MB_ICONQUESTION ) == IDYES )
	{*/
	if ( _CurrentSound )
	{
		nlassert( _Tree );
		_Tree->DeleteItem( _HItem );
	}
	/*}*/
}


/*
 *
 */
void CSoundPage::Play( bool outsidecone ) 
{
	CWaitCursor waitcursor;

	// Load sound
	try 
	{
		if ( loadSound() )
		{
			UpdateData( false );
			
			// Play source
			if ( _Source == NULL )
			{
				_Source = _AudioMixer->createSource( _CurrentSound );
			}
			else
			{
				_Source->stop();
				_Source->setSound( _CurrentSound );
			}
			_Source->setLooping( m_Looped!=0 );
			if ( outsidecone )
			{
				// The listener is just behind the source
				_Source->setPos( CVector(0.0f,0.1f,0.0f) );
				_Source->setDirection( CVector(0.0f,1.0f,0.0f) ); // directional
			}
			else
			{
				// The listener is at the source pos
				_Source->setPos( CVector(0.0f,0.0f,0.0f) );
				_Source->setDirection( CVector(0.0f,0.0f,0.0f) ); // non-directional
			}
			_Source->play();
		}

		waitcursor.Restore();
	}
	catch ( Exception& e )
	{
		waitcursor.Restore();

		CString s;
		s.Format( "%s", e.what() );
		AfxMessageBox( s );
	}
}


/*
 *
 */
void CSoundPage::OnPlaySound()
{
	UpdateData( true );
	m_Looped = false;
	Play( false );
}


/*
 *
 */
void CSoundPage::OnLooped() 
{
	UpdateData( true );
	if ( m_Looped )
	{
		Play( false );
	}
	else
	{
		if ( _Source != NULL )
		{
			_Source->stop();
		}
	}
}


/*
 *
 */
void CSoundPage::OnButtonTestOuterGain() 
{
	UpdateData( true );
	m_Looped = false;
	Play( true );
}


/*
 *
 */
void CSoundPage::OnClose() 
{
	if ( _AudioMixer != NULL )
	{
		if ( _Source != NULL )
		{
			delete _Source;
		}
		delete _AudioMixer;
	}
}


/*
 *
 */
void CSoundPage::DrawCones()
{
	if ( m_InnerAngleDeg > m_OuterAngleDeg )
	{
		GetDlgItem( IDC_BadCone )->SetWindowText( "Inner > Outer !" );
	}
	else
	{
		GetDlgItem( IDC_BadCone )->SetWindowText( "" );
	}

	CRect rect( XCenter-Radius, YCenter-Radius, XCenter+Radius+1, YCenter+Radius+1 );
	InvalidateRect( &rect, true );
}


/*
 *
 */
void CSoundPage::OnChangeEditGain() 
{
	UpdateData( true );
	((CSliderCtrl*)GetDlgItem( IDC_SliderGain ))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_Gain*100.0f ) );
}


/*
 *
 */
void CSoundPage::OnChangeEditPitch() 
{
	UpdateData( true );
	((CSliderCtrl*)GetDlgItem( IDC_SliderPitch ))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_Pitch*100.0f ) );
}


/*
 *
 */
void CSoundPage::OnChangeEditMinDist() 
{
	UpdateData( true );
	((CSliderCtrl*)GetDlgItem( IDC_SliderMinDist ))->SetPos( (int)m_MinDist );
}


/*
 *
 */
void CSoundPage::OnChangeEditMaxDist() 
{
	UpdateData( true );
	((CSliderCtrl*)GetDlgItem( IDC_SliderMaxDist ))->SetPos( (int)m_MaxDist );
}


/*
 *
 */
void CSoundPage::OnChangeEditInnerAngle() 
{
	UpdateData( true );
	((CSliderCtrl*)GetDlgItem( IDC_SliderInnerAngle ))->SetPos( m_InnerAngleDeg );
	DrawCones();
}


/*
 *
 */
void CSoundPage::OnChangeEditOuterAngle() 
{
	UpdateData( true );
	((CSliderCtrl*)GetDlgItem( IDC_SliderOuterAngle ))->SetPos( m_OuterAngleDeg );
	DrawCones();
}


/*
 *
 */
void CSoundPage::OnChangeEditOuterGain() 
{
	UpdateData( true );
	((CSliderCtrl*)GetDlgItem( IDC_SliderOuterGain ))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_OuterGain*100.0f) );
	DrawCones();
}


/*
 *
 */
void CSoundPage::OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
{
	CSliderCtrl *slider = (CSliderCtrl*)pScrollBar; // MFC sucks

	nPos = slider->GetPos();
	{
		if ( slider == GetDlgItem( IDC_SliderGain ) )
		{
			m_Gain = ConvertLinearSliderPosToLogScale( nPos ) / 100.0f;
			if ( _Source != NULL )
			{
				_Source->setGain( m_Gain );
			}
		}
		else if ( slider == GetDlgItem( IDC_SliderPitch ) )
		{
			m_Pitch = ConvertLinearSliderPosToLogScale( nPos ) / 100.0f;
			if ( _Source != NULL )
			{
				_Source->setPitch( m_Pitch );
			}
		}
		else if ( slider == GetDlgItem( IDC_SliderMinDist ) )
		{
			m_MinDist = (float)nPos;
		}
		else if ( slider == GetDlgItem( IDC_SliderMaxDist ) )
		{
			m_MaxDist = (float)nPos;
		}
		else if ( slider == GetDlgItem( IDC_SliderInnerAngle ) )
		{
			m_InnerAngleDeg = nPos;
		}
		else if ( slider == GetDlgItem( IDC_SliderOuterAngle ) )
		{
			m_OuterAngleDeg = nPos;
		}
		else if ( slider == GetDlgItem( IDC_SliderOuterGain ) )
		{
			m_OuterGain = ConvertLinearSliderPosToLogScale( nPos ) / 100.0f;
		}
		UpdateData( false );
		DrawCones();
	}
}


/*
 *
 */
void CSoundPage::OnPaint() 
{
	CPaintDC dc(this); // device context for painting

	float innerangle = degToRad((float)m_InnerAngleDeg);
	float outerangle = degToRad((float)m_OuterAngleDeg);

	/*// Erase background (done by InvalidateRect())
	CRect rect( XCenter-Radius, YCenter-Radius, XCenter+Radius+1, YCenter+Radius+1 );
	CBrush brush;
	brush.CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) );
	dc.FillRect( &rect, &brush );*/

	if ( m_Pos3D )
	{
		COLORREF innercolor = RGB(255,0,0);
		uint8 c = (uint)(255.0f * (1.0f - (float)(ConvertLogScaleToLinearSliderPosTo( m_OuterGain*100.0f ))/40.0f )); // linear, not logarithmic
		COLORREF outercolor = RGB(255,c,c);
		COLORREF tcolor = RGB(255,c/1.5,c/1.5); // not progressive
		if ( m_OuterGain == 0.0f ) // change white to background color
		{
			outercolor = GetSysColor( COLOR_BTNFACE );
		}

		uint dx = (uint)(Radius*sin(outerangle/2.0f));
		uint y = YCenter-(uint)(Radius*cos(outerangle/2.0f));

		// Outside
		CPen outpen( PS_SOLID, 1, outercolor );
		CBrush outbrush;
		outbrush.CreateSolidBrush( outercolor );
		dc.SelectObject( &outpen );
		dc.SelectObject( &outbrush );
		dc.Pie( XCenter-Radius, YCenter-Radius, XCenter+Radius+1, YCenter+Radius+1,	XCenter-dx, y, XCenter+dx, y );

		// Transition
		if ( (dx != 0) || (outerangle > 3.14) )
		{
			CPen tpen( PS_SOLID, 1, tcolor );
			CBrush tbrush;
			tbrush.CreateSolidBrush( tcolor );
			dc.SelectObject( &tpen );
			dc.SelectObject( &tbrush );
			dc.Pie( XCenter-Radius, YCenter-Radius, XCenter+Radius+1, YCenter+Radius+1,	XCenter+dx, y, XCenter-dx, y );
		}

		dx = (uint)(Radius*sin(innerangle/2.0f));
		y = YCenter-(uint)(Radius*cos(innerangle/2.0f));

		// Inner
		if ( (dx != 0) || (innerangle > 3.14) )
		{
			CPen inpen( PS_SOLID, 1, innercolor );
			CBrush inbrush;
			inbrush.CreateSolidBrush( innercolor );
			dc.SelectObject( &inpen );
			dc.SelectObject( &inbrush );
			dc.Pie( XCenter-Radius, YCenter-Radius, XCenter+Radius+1, YCenter+Radius+1,	XCenter+dx, y, XCenter-dx, y );
		}
	}
}


/*
 *
 */
BOOL CSoundPage::DestroyWindow() 
{
	delete _NameFont;

	return CDialog::DestroyWindow();
}


/*
 *
 */
void CSoundPage::OnButtonHelp() 
{
	MessageBox( "\
Gain: Range: [0, 1]. A gain factor is logarithmic ; 1.0 means no attenuation (full volume) ; 0.5 \
means an attenuation of 6 dB ; 0 means silence.\n\n\
Pitch: Range: ]0, 1]. 1.0 means normal ; dividing by 2 means pitching one octave down. Pitching up \
is not supported. 0 is not a legal value.\n\n\
Min Dist: Distance threshold below which gain is clamped (does not increase anymore).\n\
Unit: meters. Range: 0 - 1000000 (the maximum value 1e+006 is considered as infinite).\n\n\
Max Dist: Distance threshold above which gain is clamped (does not decrease anymore).\n\
Unit: meters. Range: 0 - 1000000 m (the maximum value 1e+006 is considered as infinite).\n\n\
Cone Inner Angle: Inside angle of the sound cone where the main gain is applied. \
The default of 360 means that the inner angle covers the entire world, which is equivalent to \
an omnidirectional source.\n\
Unit: degrees. Range: 0 - 360.\n\n\
Cone Outer Angle: Outer angle of the sound cone where the outer gain is applied \
to the main gain. The default of 360 means that the outer angle covers the entire world. If \
the inner angle is also 360, then there is no transition zone for angle-dependent (progressive) \
attenuation.\n\
Unit: degress. Range: 0 - 360.\n\n\
Cone Outer Gain: The factor with which the main gain is multiplied to determine the effective \
gain outside the cone defined by the outer angle. To test the outer gain, you can play the \
sound source as if you were outside the cone.\n\
Range: 0 - 1.\
", "Help about types" );	
}