1 // SoundPage.cpp : implementation file
5 #include "source_sounds_builder.h"
6 #include "source_sounds_builderDlg.h"
9 #include "../src/sound/driver/buffer.h"
10 #include "../src/sound/audio_mixer_user.h"
12 #include "nel/sound/u_listener.h"
14 #include <nel/misc/common.h>
15 #include <nel/misc/vector.h>
16 using namespace NLMISC
;
26 static char THIS_FILE
[] = __FILE__
;
40 const char *PriorityStr
[NbSoundPriorities
] = { "Highest", "High", "Medium", "Low" };
43 //----------------------------------------------------------
44 // Name: ConvertLinearSliderPosToLogScale()
45 // Desc: Converts a linear slider position to a quasi logrithmic scale
46 //-----------------------------------------------------------------------------
47 float ConvertLinearSliderPosToLogScale( LONG lSliderPos
)
49 if( lSliderPos
> 0 && lSliderPos
<= 10 )
51 return lSliderPos
*0.01f
;
53 else if( lSliderPos
> 10 && lSliderPos
<= 20 )
55 return (lSliderPos
-10)*0.1f
;
57 else if( lSliderPos
> 20 && lSliderPos
<= 30 )
59 return (lSliderPos
-20)*1.0f
;
61 else if( lSliderPos
> 30 && lSliderPos
<= 40 )
63 return (lSliderPos
-30)*10.0f
;
72 //-----------------------------------------------------------------------------
73 // Name: ConvertLinearSliderPosToLogScale()
74 // Desc: Converts a quasi logrithmic scale to a slider position
75 //-----------------------------------------------------------------------------
76 LONG
ConvertLogScaleToLinearSliderPosTo( FLOAT fValue
)
78 if( fValue
> 0.0f
&& fValue
<= 0.1f
)
80 return (LONG
)(fValue
/0.01f
);
82 else if( fValue
> 0.1f
&& fValue
<= 1.0f
)
84 return (LONG
)(fValue
/0.1f
) + 10;
86 else if( fValue
> 1.0f
&& fValue
<= 10.0f
)
88 return (LONG
)(fValue
/1.0f
) + 20;
90 else if( fValue
> 10.0f
&& fValue
<= 100.0f
)
92 return (LONG
)(fValue
/10.0f
) + 30;
100 /////////////////////////////////////////////////////////////////////////////
104 CSoundPage::CSoundPage(CWnd
* pParent
/*=NULL*/)
105 : CDialog(CSoundPage::IDD
, pParent
)
107 //{{AFX_DATA_INIT(CSoundPage)
112 m_MaxDist
= 1000000.0f
;
113 m_InnerAngleDeg
= 360;
114 m_OuterAngleDeg
= 360;
120 m_SoundName
= _T("");
123 _CurrentSound
= NULL
;
132 BOOL
CSoundPage::OnInitDialog()
134 CDialog::OnInitDialog();
137 CWaitCursor waitcursor
;
138 _AudioMixer
= UAudioMixer::createAudioMixer();
142 //_AudioMixer->getListener()->setPos( CVector(0.0f,0.0001f,0.0f) );
144 catch( Exception
& e
)
147 s
.Format( "No sound driver: %s\n\nSound playback will be unavailable" , e
.what() );
154 for ( i
=0; i
!=NbSoundPriorities
; ++i
)
156 m_Priority
.AddString( PriorityStr
[i
] );
159 // We want to load nss files even if the corresponding waves are missing
160 CSound::allowMissingWave( true );
162 // Cone drawing: make it work with normal and big fonts (depending on system settings)
163 CRect parentrect
, sliderrect
;
164 this->GetWindowRect( &parentrect
);
165 GetDlgItem( IDC_SliderOuterAngle
)->GetWindowRect( &sliderrect
);
166 XCenter
= sliderrect
.right
- parentrect
.left
+ 15 + CONE_R
;
167 YCenter
= sliderrect
.top
- parentrect
.top
+ 10;
170 waitcursor
.Restore();
172 _NameFont
= new CFont();
174 GetFont()->GetLogFont( &logfont
);
175 logfont
.lfWeight
= FW_BOLD
;
176 _NameFont
->CreateFontIndirect( &logfont
);
178 GetDlgItem( IDC_SoundName
)->SetFont( _NameFont
);
180 ((CSliderCtrl
*)GetDlgItem( IDC_SliderGain
))->SetRange( 0, 40 );
181 ((CSliderCtrl
*)GetDlgItem( IDC_SliderPitch
))->SetRange( 0, 40 );
182 ((CSliderCtrl
*)GetDlgItem( IDC_SliderMinDist
))->SetRange( 0, 1000 );
183 ((CSliderCtrl
*)GetDlgItem( IDC_SliderMaxDist
))->SetRange( 0, 1000 );
184 ((CSliderCtrl
*)GetDlgItem( IDC_SliderInnerAngle
))->SetRange( 0, 360 );
185 ((CSliderCtrl
*)GetDlgItem( IDC_SliderOuterAngle
))->SetRange( 0, 360 );
186 ((CSliderCtrl
*)GetDlgItem( IDC_SliderOuterGain
))->SetRange( 0, 40 );
188 return TRUE
; // return TRUE unless you set the focus to a control
189 // EXCEPTION: OCX Property Pages should return FALSE
193 void CSoundPage::DoDataExchange(CDataExchange
* pDX
)
195 CDialog::DoDataExchange(pDX
);
196 //{{AFX_DATA_MAP(CSoundPage)
197 DDX_Control(pDX
, IDC_CbPriority
, m_Priority
);
198 DDX_Text(pDX
, IDC_EditFilename
, m_Filename
);
199 DDX_Text(pDX
, IDC_EditGain
, m_Gain
);
200 DDV_MinMaxFloat(pDX
, m_Gain
, 0.f
, 1.f
);
201 DDX_Check(pDX
, IDC_Pos3D
, m_Pos3D
);
202 DDX_Text(pDX
, IDC_EditMinDist
, m_MinDist
);
203 DDV_MinMaxFloat(pDX
, m_MinDist
, 0.f
, 1.e
+006f
);
204 DDX_Text(pDX
, IDC_EditMaxDist
, m_MaxDist
);
205 DDV_MinMaxFloat(pDX
, m_MaxDist
, 0.f
, 1.e
+006f
);
206 DDX_Text(pDX
, IDC_EditInnerAngle
, m_InnerAngleDeg
);
207 DDV_MinMaxUInt(pDX
, m_InnerAngleDeg
, 0, 360);
208 DDX_Text(pDX
, IDC_EditOuterAngle
, m_OuterAngleDeg
);
209 DDV_MinMaxUInt(pDX
, m_OuterAngleDeg
, 0, 360);
210 DDX_Text(pDX
, IDC_EditOuterGain
, m_OuterGain
);
211 DDV_MinMaxFloat(pDX
, m_OuterGain
, 0.f
, 1.f
);
212 DDX_Check(pDX
, IDC_Looped
, m_Looped
);
213 DDX_Text(pDX
, IDC_Stereo
, m_Stereo
);
214 DDX_Text(pDX
, IDC_EditPitch
, m_Pitch
);
215 DDV_MinMaxFloat(pDX
, m_Pitch
, 1.e
-011f
, 1.f
);
216 DDX_Check(pDX
, IDC_Looping
, m_Looping
);
217 DDX_Text(pDX
, IDC_SoundName
, m_SoundName
);
222 BEGIN_MESSAGE_MAP(CSoundPage
, CDialog
)
223 //{{AFX_MSG_MAP(CSoundPage)
224 ON_BN_CLICKED(IDC_Pos3D
, OnPos3D
)
225 ON_BN_CLICKED(IDC_ChooseFile
, OnChooseFile
)
226 ON_BN_CLICKED(IDC_Remove
, OnRemove
)
227 ON_BN_CLICKED(IDC_PlaySound
, OnPlaySound
)
229 ON_BN_CLICKED(IDC_Looped
, OnLooped
)
230 ON_EN_CHANGE(IDC_EditInnerAngle
, OnChangeEditInnerAngle
)
231 ON_EN_CHANGE(IDC_EditOuterAngle
, OnChangeEditOuterAngle
)
233 ON_EN_CHANGE(IDC_EditOuterGain
, OnChangeEditOuterGain
)
235 ON_EN_CHANGE(IDC_EditMinDist
, OnChangeEditMinDist
)
236 ON_EN_CHANGE(IDC_EditMaxDist
, OnChangeEditMaxDist
)
237 ON_BN_CLICKED(IDC_ButtonHelp
, OnButtonHelp
)
238 ON_EN_CHANGE(IDC_EditGain
, OnChangeEditGain
)
239 ON_BN_CLICKED(IDC_ButtonTestOuterGain
, OnButtonTestOuterGain
)
240 ON_EN_CHANGE(IDC_EditPitch
, OnChangeEditPitch
)
241 ON_BN_CLICKED(IDC_Cancel
, OnCancel
)
242 ON_BN_CLICKED(IDC_Home
, OnHome
)
250 const char *StereoToCStr( CSound
* snd
, bool *st
)
252 static const char empty
[] = "";
253 static const char mono
[] = "Mono";
254 static const char stereo
[] = "Stereo";
255 if ( snd
->getBuffer() == NULL
)
262 if ( snd
->getBuffer()->isStereo() )
279 void CSoundPage::UpdateStereo()
282 m_Stereo
= StereoToCStr( _CurrentSound
, &stereo
);
287 GetDlgItem( IDC_Pos3D
)->EnableWindow( ! stereo
);
294 void CSoundPage::getPropertiesFromSound()
296 m_SoundName
= _CurrentSound
->getName().c_str();
297 m_Filename
= _CurrentSound
->getFilename().c_str();
298 m_Gain
= _CurrentSound
->getGain();
299 m_Pitch
= _CurrentSound
->getPitch();
300 m_Priority
.SetCurSel( _CurrentSound
->getPriority() );
301 m_Looping
= _CurrentSound
->getLooping();
302 m_Pos3D
= _CurrentSound
->isDetailed();
303 ((CSliderCtrl
*)GetDlgItem( IDC_SliderGain
))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_Gain
*100.0f
) );
304 ((CSliderCtrl
*)GetDlgItem( IDC_SliderPitch
))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_Pitch
*100.0f
) );
309 m_MinDist
= _CurrentSound
->getMinDistance();
310 m_MaxDist
= _CurrentSound
->getMaxDistance();
311 m_InnerAngleDeg
= (uint
)radToDeg( _CurrentSound
->getConeInnerAngle() );
312 m_OuterAngleDeg
= (uint
)radToDeg( _CurrentSound
->getConeOuterAngle() );
313 m_OuterGain
= _CurrentSound
->getConeOuterGain();
315 ((CSliderCtrl
*)GetDlgItem( IDC_SliderMinDist
))->SetPos( (int)m_MinDist
);
316 ((CSliderCtrl
*)GetDlgItem( IDC_SliderMaxDist
))->SetPos( (int)m_MaxDist
);
317 ((CSliderCtrl
*)GetDlgItem( IDC_SliderInnerAngle
))->SetPos( m_InnerAngleDeg
);
318 ((CSliderCtrl
*)GetDlgItem( IDC_SliderOuterAngle
))->SetPos( m_OuterAngleDeg
);
319 ((CSliderCtrl
*)GetDlgItem( IDC_SliderOuterGain
))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_OuterGain
*100.0f
) );
323 OnPos3D(); // enable/disable 3d properties
330 void CSoundPage::UpdateCurrentSound()
332 CString name
= ((CSource_sounds_builderDlg
*)GetOwner())->SoundName( _HItem
);
335 _CurrentSound
->setProperties( string(name
), string(m_Filename
), m_Gain
, m_Pitch
, (TSoundPriority
)(m_Priority
.GetCurSel()), m_Looping
!=0, m_Pos3D
!=0 );
339 _CurrentSound
->setProperties( string(name
), string(m_Filename
), m_Gain
, m_Pitch
, (TSoundPriority
)(m_Priority
.GetCurSel()), m_Looping
!=0, m_Pos3D
!=0,
340 m_MinDist
, m_MaxDist
, degToRad((float)m_InnerAngleDeg
), degToRad((float)m_OuterAngleDeg
), m_OuterGain
);
342 // Argument checking is already done by the dialog wizard
348 /////////////////////////////////////////////////////////////////////////////
349 // CSoundPage message handlers
355 void CSoundPage::setCurrentSound( CSound
*sound
, HTREEITEM hitem
)
357 _CurrentSound
= sound
;
359 if ( _Source
!= NULL
)
371 void CSoundPage::OnPos3D()
374 GetDlgItem( IDC_Pos3DGroup
)->EnableWindow( m_Pos3D
);
375 GetDlgItem( IDC_MinDist
)->EnableWindow( m_Pos3D
);
376 GetDlgItem( IDC_MaxDist
)->EnableWindow( m_Pos3D
);
377 GetDlgItem( IDC_ConeInnerAngle
)->EnableWindow( m_Pos3D
);
378 GetDlgItem( IDC_ConeOuterAngle
)->EnableWindow( m_Pos3D
);
379 GetDlgItem( IDC_ConeOuterGain
)->EnableWindow( m_Pos3D
);
380 GetDlgItem( IDC_EditMinDist
)->EnableWindow( m_Pos3D
);
381 GetDlgItem( IDC_EditMaxDist
)->EnableWindow( m_Pos3D
);
382 GetDlgItem( IDC_EditInnerAngle
)->EnableWindow( m_Pos3D
);
383 GetDlgItem( IDC_EditOuterAngle
)->EnableWindow( m_Pos3D
);
384 GetDlgItem( IDC_EditOuterGain
)->EnableWindow( m_Pos3D
);
385 GetDlgItem( IDC_SliderMinDist
)->EnableWindow( m_Pos3D
);
386 GetDlgItem( IDC_SliderMaxDist
)->EnableWindow( m_Pos3D
);
387 GetDlgItem( IDC_SliderInnerAngle
)->EnableWindow( m_Pos3D
);
388 GetDlgItem( IDC_SliderOuterAngle
)->EnableWindow( m_Pos3D
);
389 GetDlgItem( IDC_SliderOuterGain
)->EnableWindow( m_Pos3D
);
390 GetDlgItem( IDC_ButtonTestOuterGain
)->EnableWindow( m_Pos3D
);
399 void CSoundPage::apply()
403 if ( _Source
!= NULL
)
410 UpdateCurrentSound();
412 //(static_cast<CSource_sounds_builderDlg*>(GetOwner()))->setModified();
416 if ( !m_Filename
.empty() )
418 CString s
= ((CSource_sounds_builderDlg
*)GetOwner())->SoundName( _HItem
) + " (" + m_Filename
+ ")";
419 _Tree
->SetItemText( _HItem
, s
);
422 //_Tree->SelectItem( NULL );
424 GetOwner()->SetFocus();
432 void CSoundPage::rename( CString s
)
434 // Quick way to do it (should be simplified)
436 getPropertiesFromSound();
438 _Tree
->SetItemText( _HItem
, s
);
439 UpdateCurrentSound();
447 * Reverts the changes
449 void CSoundPage::OnCancel()
451 getPropertiesFromSound();
456 * Unselects the current sound
458 void CSoundPage::cancel()
460 if ( _Source
!= NULL
)
465 _CurrentSound
= NULL
;
472 void CSoundPage::OnHome()
475 _Tree
->SelectItem( _Tree
->GetRootItem() );
476 GetOwner()->SetFocus();
483 void CSoundPage::OnChooseFile()
486 CFileDialog
opendlg( true, "wav", "", OFN_OVERWRITEPROMPT
, "PCM Wave files (*.wav)|*.wav||", this );
487 if ( opendlg
.DoModal()==IDOK
)
490 m_Filename
= opendlg
.GetFileName();
495 catch ( Exception
& e
)
498 s
.Format( "%s", e
.what() );
509 bool CSoundPage::loadSound()
511 UpdateCurrentSound();
512 nlassert( _CurrentSound
);
513 if ( (m_Filename
!= "") && (_AudioMixer
!= NULL
) )
515 _CurrentSound
->loadBuffer( string(m_Filename
) );
529 void CSoundPage::OnRemove()
538 void CSoundPage::removeSound()
540 /*if ( AfxMessageBox( "Are you sure to remove the current sound from the list ?", MB_YESNO | MB_ICONQUESTION ) == IDYES )
545 _Tree
->DeleteItem( _HItem
);
554 void CSoundPage::Play( bool outsidecone
)
556 CWaitCursor waitcursor
;
566 if ( _Source
== NULL
)
568 _Source
= _AudioMixer
->createSource( _CurrentSound
);
573 _Source
->setSound( _CurrentSound
);
575 _Source
->setLooping( m_Looped
!=0 );
578 // The listener is just behind the source
579 _Source
->setPos( CVector(0.0f
,0.1f
,0.0f
) );
580 _Source
->setDirection( CVector(0.0f
,1.0f
,0.0f
) ); // directional
584 // The listener is at the source pos
585 _Source
->setPos( CVector(0.0f
,0.0f
,0.0f
) );
586 _Source
->setDirection( CVector(0.0f
,0.0f
,0.0f
) ); // non-directional
591 waitcursor
.Restore();
593 catch ( Exception
& e
)
595 waitcursor
.Restore();
598 s
.Format( "%s", e
.what() );
607 void CSoundPage::OnPlaySound()
618 void CSoundPage::OnLooped()
627 if ( _Source
!= NULL
)
638 void CSoundPage::OnButtonTestOuterGain()
649 void CSoundPage::OnClose()
651 if ( _AudioMixer
!= NULL
)
653 if ( _Source
!= NULL
)
665 void CSoundPage::DrawCones()
667 if ( m_InnerAngleDeg
> m_OuterAngleDeg
)
669 GetDlgItem( IDC_BadCone
)->SetWindowText( "Inner > Outer !" );
673 GetDlgItem( IDC_BadCone
)->SetWindowText( "" );
676 CRect
rect( XCenter
-Radius
, YCenter
-Radius
, XCenter
+Radius
+1, YCenter
+Radius
+1 );
677 InvalidateRect( &rect
, true );
684 void CSoundPage::OnChangeEditGain()
687 ((CSliderCtrl
*)GetDlgItem( IDC_SliderGain
))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_Gain
*100.0f
) );
694 void CSoundPage::OnChangeEditPitch()
697 ((CSliderCtrl
*)GetDlgItem( IDC_SliderPitch
))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_Pitch
*100.0f
) );
704 void CSoundPage::OnChangeEditMinDist()
707 ((CSliderCtrl
*)GetDlgItem( IDC_SliderMinDist
))->SetPos( (int)m_MinDist
);
714 void CSoundPage::OnChangeEditMaxDist()
717 ((CSliderCtrl
*)GetDlgItem( IDC_SliderMaxDist
))->SetPos( (int)m_MaxDist
);
724 void CSoundPage::OnChangeEditInnerAngle()
727 ((CSliderCtrl
*)GetDlgItem( IDC_SliderInnerAngle
))->SetPos( m_InnerAngleDeg
);
735 void CSoundPage::OnChangeEditOuterAngle()
738 ((CSliderCtrl
*)GetDlgItem( IDC_SliderOuterAngle
))->SetPos( m_OuterAngleDeg
);
746 void CSoundPage::OnChangeEditOuterGain()
749 ((CSliderCtrl
*)GetDlgItem( IDC_SliderOuterGain
))->SetPos( ConvertLogScaleToLinearSliderPosTo( m_OuterGain
*100.0f
) );
757 void CSoundPage::OnHScroll( UINT nSBCode
, UINT nPos
, CScrollBar
* pScrollBar
)
759 CSliderCtrl
*slider
= (CSliderCtrl
*)pScrollBar
; // MFC sucks
761 nPos
= slider
->GetPos();
763 if ( slider
== GetDlgItem( IDC_SliderGain
) )
765 m_Gain
= ConvertLinearSliderPosToLogScale( nPos
) / 100.0f
;
766 if ( _Source
!= NULL
)
768 _Source
->setGain( m_Gain
);
771 else if ( slider
== GetDlgItem( IDC_SliderPitch
) )
773 m_Pitch
= ConvertLinearSliderPosToLogScale( nPos
) / 100.0f
;
774 if ( _Source
!= NULL
)
776 _Source
->setPitch( m_Pitch
);
779 else if ( slider
== GetDlgItem( IDC_SliderMinDist
) )
781 m_MinDist
= (float)nPos
;
783 else if ( slider
== GetDlgItem( IDC_SliderMaxDist
) )
785 m_MaxDist
= (float)nPos
;
787 else if ( slider
== GetDlgItem( IDC_SliderInnerAngle
) )
789 m_InnerAngleDeg
= nPos
;
791 else if ( slider
== GetDlgItem( IDC_SliderOuterAngle
) )
793 m_OuterAngleDeg
= nPos
;
795 else if ( slider
== GetDlgItem( IDC_SliderOuterGain
) )
797 m_OuterGain
= ConvertLinearSliderPosToLogScale( nPos
) / 100.0f
;
808 void CSoundPage::OnPaint()
810 CPaintDC
dc(this); // device context for painting
812 float innerangle
= degToRad((float)m_InnerAngleDeg
);
813 float outerangle
= degToRad((float)m_OuterAngleDeg
);
815 /*// Erase background (done by InvalidateRect())
816 CRect rect( XCenter-Radius, YCenter-Radius, XCenter+Radius+1, YCenter+Radius+1 );
818 brush.CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) );
819 dc.FillRect( &rect, &brush );*/
823 COLORREF innercolor
= RGB(255,0,0);
824 uint8 c
= (uint
)(255.0f
* (1.0f
- (float)(ConvertLogScaleToLinearSliderPosTo( m_OuterGain
*100.0f
))/40.0f
)); // linear, not logarithmic
825 COLORREF outercolor
= RGB(255,c
,c
);
826 COLORREF tcolor
= RGB(255,c
/1.5,c
/1.5); // not progressive
827 if ( m_OuterGain
== 0.0f
) // change white to background color
829 outercolor
= GetSysColor( COLOR_BTNFACE
);
832 uint dx
= (uint
)(Radius
*sin(outerangle
/2.0f
));
833 uint y
= YCenter
-(uint
)(Radius
*cos(outerangle
/2.0f
));
836 CPen
outpen( PS_SOLID
, 1, outercolor
);
838 outbrush
.CreateSolidBrush( outercolor
);
839 dc
.SelectObject( &outpen
);
840 dc
.SelectObject( &outbrush
);
841 dc
.Pie( XCenter
-Radius
, YCenter
-Radius
, XCenter
+Radius
+1, YCenter
+Radius
+1, XCenter
-dx
, y
, XCenter
+dx
, y
);
844 if ( (dx
!= 0) || (outerangle
> 3.14) )
846 CPen
tpen( PS_SOLID
, 1, tcolor
);
848 tbrush
.CreateSolidBrush( tcolor
);
849 dc
.SelectObject( &tpen
);
850 dc
.SelectObject( &tbrush
);
851 dc
.Pie( XCenter
-Radius
, YCenter
-Radius
, XCenter
+Radius
+1, YCenter
+Radius
+1, XCenter
+dx
, y
, XCenter
-dx
, y
);
854 dx
= (uint
)(Radius
*sin(innerangle
/2.0f
));
855 y
= YCenter
-(uint
)(Radius
*cos(innerangle
/2.0f
));
858 if ( (dx
!= 0) || (innerangle
> 3.14) )
860 CPen
inpen( PS_SOLID
, 1, innercolor
);
862 inbrush
.CreateSolidBrush( innercolor
);
863 dc
.SelectObject( &inpen
);
864 dc
.SelectObject( &inbrush
);
865 dc
.Pie( XCenter
-Radius
, YCenter
-Radius
, XCenter
+Radius
+1, YCenter
+Radius
+1, XCenter
+dx
, y
, XCenter
-dx
, y
);
874 BOOL
CSoundPage::DestroyWindow()
878 return CDialog::DestroyWindow();
885 void CSoundPage::OnButtonHelp()
888 Gain: Range: [0, 1]. A gain factor is logarithmic ; 1.0 means no attenuation (full volume) ; 0.5 \
889 means an attenuation of 6 dB ; 0 means silence.\n\n\
890 Pitch: Range: ]0, 1]. 1.0 means normal ; dividing by 2 means pitching one octave down. Pitching up \
891 is not supported. 0 is not a legal value.\n\n\
892 Min Dist: Distance threshold below which gain is clamped (does not increase anymore).\n\
893 Unit: meters. Range: 0 - 1000000 (the maximum value 1e+006 is considered as infinite).\n\n\
894 Max Dist: Distance threshold above which gain is clamped (does not decrease anymore).\n\
895 Unit: meters. Range: 0 - 1000000 m (the maximum value 1e+006 is considered as infinite).\n\n\
896 Cone Inner Angle: Inside angle of the sound cone where the main gain is applied. \
897 The default of 360 means that the inner angle covers the entire world, which is equivalent to \
898 an omnidirectional source.\n\
899 Unit: degrees. Range: 0 - 360.\n\n\
900 Cone Outer Angle: Outer angle of the sound cone where the outer gain is applied \
901 to the main gain. The default of 360 means that the outer angle covers the entire world. If \
902 the inner angle is also 360, then there is no transition zone for angle-dependent (progressive) \
904 Unit: degress. Range: 0 - 360.\n\n\
905 Cone Outer Gain: The factor with which the main gain is multiplied to determine the effective \
906 gain outside the cone defined by the outer angle. To test the outer gain, you can play the \
907 sound source as if you were outside the cone.\n\
909 ", "Help about types" );