[dasher] Frame- and bit-rate calculation are centralised in CFrameRate,



commit e6fe32322e3283e57f3b47ad719368c7c9ecd91c
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Wed Jun 17 10:09:29 2009 +0100

    Frame- and bit-rate calculation are centralised in CFrameRate,
    which is now a superclass to CDasherModel (rather than a contained
    object). Framerate preserved in LP_FRAMERATE setting; LP_SPEEDDIVISOR
    removed in favour of preserving LP_BOOSTFACTOR. Control mode's pause
    method inlined/removed, awaiting further refactoring in future, and
    changed to use same BP_SLOW_START mechanism as elsewhere (rather than
    resetting framerate!).

 ChangeLog                              |   11 +++
 Src/DasherCore/ControlManager.cpp      |   22 ++++--
 Src/DasherCore/ControlManager.h        |    5 ++
 Src/DasherCore/DasherInterfaceBase.cpp |   15 +---
 Src/DasherCore/DasherInterfaceBase.h   |    4 -
 Src/DasherCore/DasherModel.cpp         |   23 ++----
 Src/DasherCore/DasherModel.h           |   47 ++-----------
 Src/DasherCore/FrameRate.h             |  125 ++++++++------------------------
 Src/DasherCore/Makefile.am             |    1 +
 Src/DasherCore/Parameters.h            |    6 +-
 10 files changed, 83 insertions(+), 176 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 437f895..59df8c2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2009-06-16  Alan Lawrence <acl33 inf phy cam ac uk>
+
+	* Frame- and bit-rate calculation are centralised in CFrameRate,
+	which is now a superclass to CDasherModel (rather than
+	a contained object). Framerate preserved in LP_FRAMERATE
+	setting; LP_SPEEDDIVISOR removed in favour of preserving
+	LP_BOOSTFACTOR. Control mode's pause method inlined/removed,
+	awaiting further refactoring in future, and changed to use same
+	BP_SLOW_START mechanism as elsewhere (rather than resetting
+	framerate!).
+
 2009-06-11  Andre Klapper  <a9016009 gmx de>
 
 	* Src/main.cc: Remove commented "#include <gnome.h>" to clean up 
diff --git a/Src/DasherCore/ControlManager.cpp b/Src/DasherCore/ControlManager.cpp
index 83ed584..85c9a6a 100644
--- a/Src/DasherCore/ControlManager.cpp
+++ b/Src/DasherCore/ControlManager.cpp
@@ -375,25 +375,33 @@ void CControlManager::Output( CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PROB* pA
 void CControlManager::Undo( CDasherNode *pNode ) {
   // Do we ever need this?
   // One other thing we probably want is notification when we leave a node - that way we can eg speed up again if we slowed down
-  m_pNCManager->SetLongParameter(LP_SPEED_DIVISOR, 100);
+  m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 100);
   //Re-enable auto speed control!
-  m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
-  
+  if (bDisabledSpeedControl)
+  {
+    bDisabledSpeedControl = false;
+    m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
+  }
 }
 
 void CControlManager::Enter(CDasherNode *pNode) {
   // Slow down to half the speed we were at
-  m_pNCManager->SetLongParameter(LP_SPEED_DIVISOR, 200);
+  m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 50);
   //Disable auto speed control!
-  m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 0);
+  if ((bDisabledSpeedControl = m_pNCManager->GetBoolParameter(BP_AUTO_SPEEDCONTROL)) == true)
+    m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 0);
 }
 
 
 void CControlManager::Leave(CDasherNode *pNode) {
   // Now speed back up, by doubling the speed we were at in control mode
-  m_pNCManager->SetLongParameter(LP_SPEED_DIVISOR, 100);
+  m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 100);
   //Re-enable auto speed control!
-  m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
+  if (bDisabledSpeedControl)
+  {
+    bDisabledSpeedControl = false;
+    m_pNCManager->SetBoolParameter(BP_AUTO_SPEEDCONTROL, 1);
+  }
 }
 
 
diff --git a/Src/DasherCore/ControlManager.h b/Src/DasherCore/ControlManager.h
index ebe8bfb..b873c77 100644
--- a/Src/DasherCore/ControlManager.h
+++ b/Src/DasherCore/ControlManager.h
@@ -139,6 +139,11 @@ namespace Dasher {
       CControlNode *pControlNode;
       int iOffset;
     };
+
+    ///Whether we'd temporarily disabled Automatic Speed Control
+    ///(if _and only if_ so, should re-enable it when leaving a node)
+    bool bDisabledSpeedControl;
+
   };
   /// @}
 }
diff --git a/Src/DasherCore/DasherInterfaceBase.cpp b/Src/DasherCore/DasherInterfaceBase.cpp
index 3240409..ac80e75 100644
--- a/Src/DasherCore/DasherInterfaceBase.cpp
+++ b/Src/DasherCore/DasherInterfaceBase.cpp
@@ -350,8 +350,10 @@ void CDasherInterfaceBase::InterfaceEventHandler(Dasher::CEvent *pEvent) {
       PauseAt(0,0);
       break;
     case CControlManager::CTL_PAUSE:
-      Halt();
-      break;
+  //Halt Dasher - without a stop event, so does not result in speech etc.
+      SetBoolParameter(BP_DASHER_PAUSED, true);
+
+      m_pDasherModel->TriggerSlowdown();
     }
   }
   else if(pEvent->m_iEventType == EV_LOCK) {
@@ -475,15 +477,6 @@ void CDasherInterfaceBase::GameMessageIn(int message, void* messagedata) {
   GameMode::CDasherGameMode::GetTeacher()->Message(message, messagedata);
 }
 
-
-void CDasherInterfaceBase::Halt() {
-  SetBoolParameter(BP_DASHER_PAUSED, true);
-
-  // This will cause us to reinitialise the frame rate counter - ie we start off slowly
-  if(m_pDasherModel != 0)
-    m_pDasherModel->Halt();
-}
-
 void CDasherInterfaceBase::Unpause(unsigned long Time) {
   SetBoolParameter(BP_DASHER_PAUSED, false);
 
diff --git a/Src/DasherCore/DasherInterfaceBase.h b/Src/DasherCore/DasherInterfaceBase.h
index 2321abf..2c9c9b9 100644
--- a/Src/DasherCore/DasherInterfaceBase.h
+++ b/Src/DasherCore/DasherInterfaceBase.h
@@ -225,10 +225,6 @@ public:
 
   void PauseAt(int MouseX, int MouseY); // are required to make
 
-  /// Halt Dasher. This simply freezes Dasher but does not emit a stop event, so does not result in speech etc.
-
-  void Halt();
-
   /// Unpause Dasher
   /// \param Time Time in ms, used to keep a constant frame rate
 
diff --git a/Src/DasherCore/DasherModel.cpp b/Src/DasherCore/DasherModel.cpp
index 52536ab..b64ef23 100644
--- a/Src/DasherCore/DasherModel.cpp
+++ b/Src/DasherCore/DasherModel.cpp
@@ -59,7 +59,7 @@ CDasherModel::CDasherModel(CEventHandler *pEventHandler,
 			   CNodeCreationManager *pNCManager,
 			   CDasherInterfaceBase *pDasherInterface,
 			   CDasherView *pView, int iOffset)
-  : CDasherComponent(pEventHandler, pSettingsStore) {
+  : CFrameRate(pEventHandler, pSettingsStore) {
   m_pNodeCreationManager = pNCManager;
   m_pDasherInterface = pDasherInterface;
 
@@ -85,9 +85,6 @@ CDasherModel::CDasherModel(CEventHandler *pEventHandler,
 
   SetBoolParameter(BP_CONVERSION_MODE, m_bRequireConversion);
 
-  // Set max bitrate in the FrameRate class
-  m_dMaxRate = GetLongParameter(LP_MAX_BITRATE) / 100.0;
-  m_fr.SetMaxBitrate(m_dMaxRate);
   m_dAddProb = 0.003;
 
   int iNormalization = GetLongParameter(LP_NORMALIZATION);
@@ -112,17 +109,12 @@ CDasherModel::~CDasherModel() {
 }
 
 void CDasherModel::HandleEvent(Dasher::CEvent *pEvent) {
+  CFrameRate::HandleEvent(pEvent);
 
   if(pEvent->m_iEventType == EV_PARAM_NOTIFY) {
     Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
 
     switch (pEvt->m_iParameter) {
-    case LP_MAX_BITRATE: // Delibarate fallthrough
-    case LP_BOOSTFACTOR: // Deliberate fallthrough
-    case LP_SPEED_DIVISOR:
-      m_dMaxRate = GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR) / 100 / static_cast<double>(GetLongParameter(LP_SPEED_DIVISOR));
-      m_fr.SetMaxBitrate(m_dMaxRate);
-      break;
     case BP_CONTROL_MODE: // Rebuild the model if control mode is switched on/off
       RebuildAroundNode(Get_node_under_crosshair());
       break;
@@ -131,9 +123,8 @@ void CDasherModel::HandleEvent(Dasher::CEvent *pEvent) {
       break;
     case BP_DASHER_PAUSED:
       if(GetBoolParameter(BP_SLOW_START))
-	m_iStartTime = 0;
-      else
-	m_iStartTime = 1;
+	TriggerSlowdown();
+      //else, leave m_iStartTime as is - will result in no slow start
       break;
     case BP_GAME_MODE:
       m_bGameMode = GetBoolParameter(BP_GAME_MODE);
@@ -385,7 +376,7 @@ void CDasherModel::Get_new_root_coords(dasherint X, dasherint Y, dasherint &r1,
   if(m_iStartTime == 0)
     m_iStartTime = iTime;
 
-  int iSteps = m_fr.Steps();
+  int iSteps = Steps();
 
   double dFactor;
 
@@ -441,7 +432,7 @@ void CDasherModel::Get_new_root_coords(dasherint X, dasherint Y, dasherint &r1,
   // Calculate the minimum size of the viewport corresponding to the
   // maximum zoom.
 
-  dasherint iMinSize(m_fr.MinSize(Y2, dFactor));
+  dasherint iMinSize(MinSize(Y2, dFactor));
 
   if((y2 - y1) < iMinSize) {
     newy1 = y1 * (Y2 - iMinSize) / (Y2 - (y2 - y1));
@@ -517,7 +508,7 @@ bool CDasherModel::UpdateBounds(myint iNewMin, myint iNewMax, unsigned long iTim
 }
 
 void CDasherModel::NewFrame(unsigned long Time) {
-  m_fr.NewFrame(Time);
+  CFrameRate::NewFrame(Time);
   ///GAME MODE TEMP///Pass new frame events onto our teacher
   GameMode::CDasherGameMode* pTeacher = GameMode::CDasherGameMode::GetTeacher();
   if(m_bGameMode && pTeacher)
diff --git a/Src/DasherCore/DasherModel.h b/Src/DasherCore/DasherModel.h
index 7cae616..f5c0e03 100644
--- a/Src/DasherCore/DasherModel.h
+++ b/Src/DasherCore/DasherModel.h
@@ -55,7 +55,7 @@ namespace Dasher {
 ///             knows the current viewpoint
 ///             knows how to evolve the viewpoint
 ///
-class Dasher::CDasherModel:public Dasher::CDasherComponent, private NoClones
+class Dasher::CDasherModel:public CFrameRate, private NoClones
 {
  public:
 
@@ -99,44 +99,6 @@ class Dasher::CDasherModel:public Dasher::CDasherComponent, private NoClones
   /// @}
 
   ///
-  /// Get the current framerate
-  ///
-
-  double Framerate() const {
-    return m_fr.Framerate();
-  }
-
-  ///
-  /// Reset the framerate class
-  /// TODO: Need to check semantics here
-  /// Called from CDasherInterfaceBase::UnPause;
-  ///
-
-  void Reset_framerate(unsigned long Time) {
-    m_fr.Reset(Time);
-  }
-
-  ///
-  /// Initialise the framerate class - presumably called whenever
-  /// dasher is stoppe, but the actual semantics here need to be
-  /// verified
-  /// Called from CDasherInterfacebase::Halt 
-  ///
-
-  void Halt() {
-    m_fr.Initialise();
-  }
-
-  ///
-  /// Set the target bitrate - probably shouldn't be called externally
-  /// - could implement through the event subsystem instead
-  ///
-  
-/*   void SetBitrate(double TargetRate) { */
-/*     m_fr.SetBitrate(TargetRate); */
-/*   }  */
-
-  ///
   /// Reset counter of total nats entered
   ///
  
@@ -304,12 +266,13 @@ class Dasher::CDasherModel:public Dasher::CDasherComponent, private NoClones
 
   // Model status...
 
-  // Helper class to estimate frame rate
-  CFrameRate m_fr;  
 
   // Time at which the model was started (ie last unpaused, used for gradual speed up)
   // TODO: Implementation is very hacky at the moment
-  // TODO: Duplicates functionality previously implemented elsewhere
+  // TODO: Duplicates functionality previously implemented elsewhere...
+  //   ...ACL 22/5/09 does it? There was an even hackier implementation, of resetting the
+  //   framerate, used for control mode (ControlManager.cpp), but that's all I could find
+  //   - and that seemed even worse, so I've removed it in favour of this here....?
   unsigned long m_iStartTime;
   
   // Offset into buffer of node currently under crosshair
diff --git a/Src/DasherCore/FrameRate.h b/Src/DasherCore/FrameRate.h
index 9ca3998..ed56195 100644
--- a/Src/DasherCore/FrameRate.h
+++ b/Src/DasherCore/FrameRate.h
@@ -9,7 +9,11 @@
 #ifndef __FrameRate_h__
 #define __FrameRate_h__
 
+#include <cmath>
 #include "../Common/Common.h"
+#include "Event.h"
+#include "Parameters.h"
+#include "DasherComponent.h"
 
 // Should this using directive really be in a header file?
 using namespace Dasher;
@@ -22,10 +26,11 @@ const double LN2 = log(2.0);
 /// keeps track of framerate
 /// computes the Steps parameter
 /// computes RXmax - which controls the maximum rate of zooming in
-class CFrameRate {
+class CFrameRate : public CDasherComponent {
 public:
-  CFrameRate();
-  void Initialise();
+  CFrameRate(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore);
+  
+  virtual void HandleEvent(Dasher::CEvent *pEvent);
 
   /// Get the minimum size of the target viewport
   ////// TODO: Eventually fix this so that it uses integer maths internally. 
@@ -43,104 +48,38 @@ public:
     return m_iSteps;
   }; 
 
+  ///
+  /// Get the current framerate
+  ///
   double Framerate() const {
     return m_dFr;
   };
 
-  void Reset(unsigned long Time);
-  void NewFrame(unsigned long Time);
-  void SetBitrate(double TargetRate);
-  void SetMaxBitrate(double MaxRate);
+  double Bitrate() const {
+    return m_dMaxbitrate;
+  }
+
+  virtual void BitrateChanged(double dMaxbitrate) {m_dMaxbitrate = dMaxbitrate;}
+  virtual void FramerateChanged(double dFr) {m_dFr = dFr;}
+  ///
+  /// Reset the framerate class
+  /// TODO: Need to check semantics here
+  /// Called from CDasherInterfaceBase::UnPause;
+  ///
+  void Reset_framerate(unsigned long Time) {
+    m_iFrames = 0;
+    m_iTime = Time;
+  }
+
 
+  void NewFrame(unsigned long Time);
+  
 private:
-  double m_dFr;
-  double m_dMaxbitrate;         // the maximum rate of entering information
+  double m_dFr;                 // current frame rate (cache of LP_FRAMERATE/100.0)
+  double m_dMaxbitrate;         // the maximum rate of entering information (cache)
   double m_dRXmax;              // the maximum zoomin per frame
   int m_iFrames, m_iTime, m_iTime2, m_iSamples;
   int m_iSteps;                 // the 'Steps' parameter. See djw thesis.
 };
 /// \}
-
-inline CFrameRate::CFrameRate() {
-  // TODO: This looks obsolete - need to rationalise this
-  // maxbitrate should be user-defined and/or adaptive. Currently it is not.
-#if defined(_WIN32_WCE)
-  m_dMaxbitrate = 5;
-#else
-  m_dMaxbitrate = 5.5;
-#endif
-
-  Initialise();
-}
-
-inline void CFrameRate::Initialise(void) {
-  m_dRXmax = 2;                 // only a transient effect
-  m_iFrames = 0;
-  m_iSamples = 1;
-
-  // we dont know the framerate yet - play it safe by setting it high
-  m_dFr = 1 << 5;
-
-  // start off very slow until we have sampled framerate adequately
-  m_iSteps = 2000;
-  m_iTime = 0;                  // Hmmm, User must reset framerate before starting.
-}
-
-inline void CFrameRate::NewFrame(unsigned long Time)
-{
-  m_iFrames++;
-
-  // Update values once enough samples have been collected
-  if(m_iFrames == m_iSamples) {
-    m_iTime2 = Time;
-
-    // If samples are collected in < 50ms, collect more
-    if(m_iTime2 - m_iTime < 50)
-      m_iSamples++; 
-    // And if it's taking longer than > 80ms, collect fewer, down to a
-    // limit of 2
-    else if(m_iTime2 - m_iTime > 80) {
-      m_iSamples--;
-      if(m_iSamples < 2)
-        m_iSamples = 2;
-    }
-
-    // Calculate the framerate and reset framerate statistics for next
-    // sampling period
-    if(m_iTime2 - m_iTime) {
-      m_dFr = m_iFrames * 1000.0 / (m_iTime2 - m_iTime);
-      m_iTime = m_iTime2;
-      m_iFrames = 0;
-    }
-
-    // Update auxiliary variablesq
-    m_dRXmax = exp(m_dMaxbitrate * LN2 / m_dFr);
-    
-    // Note that m_iSteps is smoothed here - 50:50 interpolation with
-    // previous value
-    m_iSteps = m_iSteps / 2 + (int)(-log(0.2) * m_dFr / LN2 / m_dMaxbitrate) / 2;
-
-    // If the framerate slows to < 4 then we end up with steps < 1 ! 
-    if(m_iSteps == 0)
-      m_iSteps = 1;
-
-    DASHER_TRACEOUTPUT("Fr %f Steps %d Samples %d Time2 %d rxmax %f\n", m_dFr, m_iSteps, m_iSamples, m_iTime2, m_dRXmax);
-  }
-}
-
-inline void CFrameRate::Reset(unsigned long Time) {
-  m_iFrames = 0;
-  m_iTime = Time;
-}
-
-// TODO: Need to clarify the exact relation between these two values -
-// at the moment the max bitrate is all that is used
-inline void CFrameRate::SetBitrate(double TargetRate) {
-  m_dMaxbitrate = TargetRate;
-}
-
-inline void CFrameRate::SetMaxBitrate(double MaxRate) {
-  m_dMaxbitrate = MaxRate;
-}
-
-#endif /* #ifndef __FrameRate_h__ */
+#endif /* #ifndef __FrameRate_h__ */
\ No newline at end of file
diff --git a/Src/DasherCore/Makefile.am b/Src/DasherCore/Makefile.am
index c53c4f0..539c293 100644
--- a/Src/DasherCore/Makefile.am
+++ b/Src/DasherCore/Makefile.am
@@ -76,6 +76,7 @@ libdashercore_a_SOURCES = \
 		FileLogger.cpp \
 		FileLogger.h \
 		FrameRate.h \
+		FrameRate.cpp \
 		GameLevel.cpp \
 		GameLevel.h \
 		GameMessages.h \
diff --git a/Src/DasherCore/Parameters.h b/Src/DasherCore/Parameters.h
index 26699a8..ab20a9a 100644
--- a/Src/DasherCore/Parameters.h
+++ b/Src/DasherCore/Parameters.h
@@ -48,13 +48,13 @@ enum {
 };
 
 enum { 
-  LP_ORIENTATION = END_OF_BPS, LP_REAL_ORIENTATION, LP_MAX_BITRATE,
+  LP_ORIENTATION = END_OF_BPS, LP_REAL_ORIENTATION, LP_MAX_BITRATE, LP_FRAMERATE,
   LP_VIEW_ID, LP_LANGUAGE_MODEL_ID, LP_DASHER_FONTSIZE,
   LP_UNIFORM, LP_YSCALE, LP_MOUSEPOSDIST, LP_STOP_IDLETIME, LP_TRUNCATION, 
   LP_TRUNCATIONTYPE, LP_LM_MAX_ORDER, LP_LM_EXCLUSION,
   LP_LM_UPDATE_EXCLUSION, LP_LM_ALPHA, LP_LM_BETA,
   LP_LM_MIXTURE, LP_MOUSE_POS_BOX, LP_NORMALIZATION, LP_LINE_WIDTH, 
-  LP_LM_WORD_ALPHA, LP_USER_LOG_LEVEL_MASK, LP_SPEED_DIVISOR, 
+  LP_LM_WORD_ALPHA, LP_USER_LOG_LEVEL_MASK, 
   LP_ZOOMSTEPS, LP_B, LP_S, LP_Z, LP_R, LP_RIGHTZOOM,
   LP_BOOSTFACTOR, LP_AUTOSPEED_SENSITIVITY, LP_SOCKET_PORT, LP_SOCKET_INPUT_X_MIN, LP_SOCKET_INPUT_X_MAX,
   LP_SOCKET_INPUT_Y_MIN, LP_SOCKET_INPUT_Y_MAX, LP_OX, LP_OY, LP_MAX_Y, LP_INPUT_FILTER, 
@@ -167,6 +167,7 @@ static lp_table longparamtable[] = {
   {LP_ORIENTATION, "ScreenOrientation", PERS, -2, "Screen Orientation"},
   {LP_REAL_ORIENTATION, "RealOrientation", !PERS, 0, "Actual screen orientation (allowing for alphabet default)"},
   {LP_MAX_BITRATE, "MaxBitRateTimes100", PERS, 80, "Max Bit Rate Times 100"},
+  {LP_FRAMERATE, "FrameRate", PERS, 3200, "Last known frame rate, times 100"},
   {LP_VIEW_ID, "ViewID", PERS, 1, "ViewID"},
   {LP_LANGUAGE_MODEL_ID, "LanguageModelID", PERS, 0, "LanguageModelID"},
   {LP_DASHER_FONTSIZE, "DasherFontSize", PERS, 2, "DasherFontSize"},
@@ -187,7 +188,6 @@ static lp_table longparamtable[] = {
   {LP_LINE_WIDTH, "LineWidth", PERS, 1, "Width to draw crosshair and mouse line"},
   {LP_LM_WORD_ALPHA, "WordAlpha", PERS, 50, "Alpha value for word-based model"},
   {LP_USER_LOG_LEVEL_MASK, "UserLogLevelMask", PERS, 0, "Controls level of user logging, 0 = none, 1 = short, 2 = detailed, 3 = both"},
-  {LP_SPEED_DIVISOR, "SpeedDivisor", !PERS, 100, "Factor by which to slow down (multiplied by 100)"},
   {LP_ZOOMSTEPS, "Zoomsteps", PERS, 32, "Integerised ratio of zoom size for click/button mode, denom 64."},
   {LP_B, "ButtonMenuBoxes", PERS, 4, "Number of boxes for button menu mode"},
   {LP_S, "ButtonMenuSafety", PERS, 25, "Safety parameter for button mode, in percent."},



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]