5 #include "../Common/Common.h"
7 #include "AutoSpeedControl.h"
14 double round(double dVal
) {
15 double dF
= floor(dVal
);
16 double dC
= ceil(dVal
);
18 if(dVal
- dF
< dC
- dVal
)
25 CAutoSpeedControl::CAutoSpeedControl(Dasher::CEventHandler
* pEventHandler
, CSettingsStore
* pSettingsStore
, double dFrameRate
)
26 : CDasherComponent(pEventHandler
, pSettingsStore
) {
28 //scale #samples by #samples = m_dSamplesScale / (current bitrate) + m_dSampleOffset
30 m_dSampleOffset
= 1.3;
32 m_dSensitivity
= GetLongParameter(LP_AUTOSPEED_SENSITIVITY
) / 100.0; //param only, no GUI!
33 //tolerance for automatic speed control
34 m_dTier1
= 0.0005; // should be arranged so that tier4 > tier3 > tier2 > tier1 !!!
38 //bitrate fractional changes for auto-speed control
46 //variance of two-centred-gaussians for adaptive radius
49 //Initialise auto-speed control
51 m_dBitrate
= double(round(GetLongParameter(LP_MAX_BITRATE
) / 100.0));
54 UpdateSampleSize(dFrameRate
);
57 ////////////////////////////////////////////////
59 /// Change max bitrate based on variance of angle
62 /////////////////////////////////////////////////
64 inline double CAutoSpeedControl::UpdateBitrate()
66 double var
= Variance();
69 m_dBitrate
*= m_dChange1
;
71 else if(var
< m_dTier2
)
73 m_dBitrate
*= m_dChange2
;
75 else if(var
> m_dTier4
) //Tier 4 comes before tier 3 because tier4 > tier3 !!!
77 m_dBitrate
*= m_dChange4
;
79 else if(var
> m_dTier3
)
81 m_dBitrate
*= m_dChange3
;
83 //else if( in the middle )
86 //always keep bitrate values sane
87 if(m_dBitrate
> m_dSpeedMax
)
89 m_dBitrate
= m_dSpeedMax
;
91 else if(m_dBitrate
< m_dSpeedMin
)
93 m_dBitrate
= m_dSpeedMin
;
98 ///////////////////////////////////////////////
100 /// Finds variance for automatic speed control
102 //////////////////////////////////////////////
104 inline double CAutoSpeedControl::Variance()
106 double avgcos
, avgsin
;
107 avgsin
= avgcos
= 0.0;
108 DOUBLE_DEQUE::iterator i
;
109 // find average of cos(theta) and sin(theta)
110 for(i
= m_dequeAngles
.begin(); i
!= m_dequeAngles
.end(); i
++) {
114 avgcos
/= (1.0 * m_dequeAngles
.size());
115 avgsin
/= (1.0 * m_dequeAngles
.size());
116 //return variance (see dasher/Doc/speedcontrol.tex)
117 return -log(avgcos
* avgcos
+ avgsin
* avgsin
);
120 //////////////////////////////////////////////////////////////////////
122 /// The number of samples depends on the clock rate of the
123 /// machine (framerate) and the user's speed (bitrate). See
124 /// speedcontrol.tex in dasher/Doc/ dir.
126 /////////////////////////////////////////////////////////////////////
129 inline int CAutoSpeedControl::UpdateSampleSize(double dFrameRate
)
131 double dFramerate
= dFrameRate
;
132 double dSpeedSamples
= 0.0;
133 double dBitrate
= m_dBitrate
;
134 if(dBitrate
< 1.0)// for the purposes of this function
135 dBitrate
= 1.0; // we don't care exactly how slow we're going
136 // *really* low speeds are ~ equivalent?
137 dSpeedSamples
= dFramerate
* (m_dSampleScale
/ dBitrate
+ m_dSampleOffset
);
139 m_nSpeedSamples
= int(round(dSpeedSamples
));
141 return m_nSpeedSamples
;
143 /////////////////////////////////////////////////////////////
145 /// double UpdateMinRadius() - find adaptive min radius for
146 /// auto-speed control. Calculated by DJCM's
147 /// mixture-of-2-centred-gaussians model.
149 ///////////////////////////////////////////////////////////
151 inline double CAutoSpeedControl::UpdateMinRadius()
153 m_dMinRadius
= sqrt( log( (m_dSigma2
* m_dSigma2
) / (m_dSigma1
* m_dSigma1
) ) /
154 ( 1 / (m_dSigma1
* m_dSigma1
) - 1 / (m_dSigma2
* m_dSigma2
)) );
158 //////////////////////////////////////////////////////////////
160 /// NB: updates VARIANCES of two populations of
161 /// mixture-of-2-centred-Gaussians model!
163 //////////////////////////////////////////////////////////////
165 inline void CAutoSpeedControl::UpdateSigmas(double r
, double dFrameRate
)
167 double dSamples
= m_dMinRRate
* dFrameRate
/ m_dBitrate
;
169 m_dSigma1
= m_dSigma1
- (m_dSigma1
- r
* r
) / dSamples
;
171 m_dSigma2
= m_dSigma2
- (m_dSigma2
- r
* r
) / dSamples
;
174 /////////////////////////////////////////////////////////////////
176 /// AUTOMATIC SPEED CONTROL, CEH 7/05: Analyse variance of angle
177 /// mouse position makes with +ve x-axis in Dasher-space
179 ////////////////////////////////////////////////////////////////
182 void CAutoSpeedControl::SpeedControl(myint iDasherX
, myint iDasherY
, double dFrameRate
, CDasherView
*pView
) {
183 if(GetBoolParameter(BP_AUTO_SPEEDCONTROL
) && !GetBoolParameter(BP_DASHER_PAUSED
)) {
185 // Coordinate transforms:
186 iDasherX
= myint(pView
->xmap(iDasherX
/ static_cast < double >(GetLongParameter(LP_MAX_Y
))) * GetLongParameter(LP_MAX_Y
));
187 iDasherY
= myint(pView
->ymap(iDasherY
));
189 myint iDasherOX
= myint(pView
->xmap(GetLongParameter(LP_OX
) / static_cast < double >(GetLongParameter(LP_MAX_Y
))) * GetLongParameter(LP_MAX_Y
));
190 myint iDasherOY
= myint(pView
->ymap(GetLongParameter(LP_OY
)));
192 double x
= -(iDasherX
- iDasherOX
) / double(iDasherOX
); //Use normalised coords so min r works
193 double y
= -(iDasherY
- iDasherOY
) / double(iDasherOY
);
194 double theta
= atan2(y
, x
);
195 double r
= sqrt(x
* x
+ y
* y
);
197 m_dBitrate
= GetLongParameter(LP_MAX_BITRATE
) / 100.0; // stored as long(round(true bitrate * 100))
199 UpdateSigmas(r
, dFrameRate
);
203 if(r
> m_dMinRadius
&& fabs(theta
) < 1.25) {
205 m_dequeAngles
.push_back(theta
);
206 while(m_dequeAngles
.size() > m_nSpeedSamples
) {
207 m_dequeAngles
.pop_front();
211 m_dSensitivity
= GetLongParameter(LP_AUTOSPEED_SENSITIVITY
) / 100.0;
212 if(m_nSpeedCounter
> round(m_nSpeedSamples
/ m_dSensitivity
)) {
213 //do speed control every so often!
215 UpdateSampleSize(dFrameRate
);
218 long lBitrateTimes100
= long(round(m_dBitrate
* 100)); //Dasher settings want long numerical parameters
219 SetLongParameter(LP_MAX_BITRATE
, lBitrateTimes100
);