Jamoma API  0.6.0.a19
System.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup modularSystem
4  *
5  * @brief System clock class
6  *
7  * @details
8  *
9  * @authors Théo de la Hogue
10  *
11  * @copyright © 2013, Théo de la Hogue @n
12  * This code is licensed under the terms of the "New BSD License" @n
13  * http://creativecommons.org/licenses/BSD/
14  */
15 
16 #include "System.h"
17 
18 #define thisTTClass System
19 #define thisTTClassName "system"
20 #define thisTTClassTags "clock, System"
21 
22 #define thisClockVersion "0.1"
23 #define thisClockAuthor "Theo de la Hogue"
24 #define thisClockStretchable YES
25 
26 extern "C" TT_EXTENSION_EXPORT TTErr TTLoadJamomaExtension_System(void)
27 {
28  TTFoundationInit();
29  System::registerClass();
30  return kTTErrNone;
31 }
32 
33 TT_CLOCK_CONSTRUCTOR,
34 mGranularity(20.0)
35 {
36  TT_CLOCK_INITIALIZE
37 
38  addAttribute(Granularity, kTypeFloat64);
39 }
40 
41 System::~System()
42 {
43  stopThread();
44 }
45 
46 TTErr System::getParameterNames(TTValue& value)
47 {
48  value.clear();
49  value.append(TTSymbol("granularity"));
50  value.append(TTSymbol("offset"));
51  value.append(TTSymbol("speed"));
52 
53  return kTTErrNone;
54 }
55 
56 TTErr System::Go()
57 {
58  // do we need to ramp at all ?
59  if (mDuration <= mOffset)
60  {
61  stopThread();
62  mRunning = false;
63  mPaused = NO;
64  mPosition = 0.;
65  mDate = 0.;
66 
67  (mCallback)(mBaton, mPosition, mDate);
68 
69  // notify each observers
70  sendNotification(TTSymbol("ClockRunningChanged"), mRunning);
71  sendNotification(TTSymbol("ClockTicked"), TTValue(mPosition, mDate));
72  }
73  else if (mExternalTick)
74  {
75 
76  // reset timing informations
77  mRunning = true;
78  mPaused = NO;
79  mLastTime = 0.;
80 
81  // notify each observers
82  sendNotification(TTSymbol("ClockRunningChanged"), mRunning);
83 
84  // launch a first tick if the duration is valid
85  if (mDuration > 0.)
86  Tick();
87  }
88  // if the thread is not running
89  else if (!mRunning)
90  {
91  if (mThread.joinable())
92  mThread.join();
93 
94  // launch a new thread to run the clock execution
95  mThread = std::thread(&System::SystemThreadCallback, this);
96  }
97 
98  return kTTErrNone;
99 }
100 
101 TTErr System::Stop()
102 {
103  mPaused = NO;
104 
105  // stop thread execution
106  stopThread();
107 
108  // notify each observers
109  sendNotification(TTSymbol("ClockRunningChanged"), mRunning);
110 
111  // reset all time info
112  mOffset = 0.;
113  mPosition = 0.;
114  mDate = 0.;
115 
116  return kTTErrNone;
117 }
118 
119 TTErr System::Tick()
120 {
121  TTFloat64 delta = computeDeltaTime() * mSpeed;
122 
123  // test paused and running status after the computeDeltatTime because there is a sleep inside
124  if (mPaused || !mRunning)
125  return kTTErrNone;
126 
127  mPosition += delta / mDuration;
128  mDate += delta;
129 
130  if (mPosition < 1. || mInfinite)
131  {
132  // notify the owner
133  (mCallback)(mBaton, mPosition, mDate);
134 
135  // notify each observers
136  sendNotification(TTSymbol("ClockTicked"), TTValue(mPosition, mDate));
137  }
138  else
139  {
140  // forcing position to 1. to allow filtering
141  mPosition = 1.;
142 
143  // notify the owner
144  (mCallback)(mBaton, mPosition, mDate);
145 
146  // notify each observers
147  sendNotification(TTSymbol("ClockTicked"), TTValue(mPosition, mDate));
148 
149  // if the clock is still running : stop it
150  // note : because it is possible that another thread stops the clock before
151  if (mRunning)
152  Stop();
153  }
154 
155  return kTTErrNone;
156 }
157 
158 TTErr System::Pause()
159 {
160  mPaused = YES;
161 
162  return kTTErrNone;
163 }
164 
165 TTErr System::Resume()
166 {
167  mPaused = NO;
168 
169  return kTTErrNone;
170 }
171 
172 TTFloat64 System::computeDeltaTime()
173 {
174  TTUInt64 deltaInUs = 0;
175  TTUInt64 granularityInUs = mGranularity * 1000;
176 
177  struct timeval tv;
178 
179  // get the current time (in µs)
180  #ifdef TT_PLATFORM_WIN
181  Time2 time2;
182  time2.gettimeofday(&tv, NULL);
183  #else
184  struct timezone tz;
185  gettimeofday(&tv, &tz);
186  #endif
187 
188  TTUInt64 currentTime = tv.tv_sec * 1000000L + tv.tv_usec;
189 
190  if (mLastTime != 0)
191  {
192  // it seems the currentTime is lower than the lastTime sometimes ...
193  if (currentTime < mLastTime)
194  {
195  TTLogMessage("System::computeDeltaTime() : current time is lower than last time\n");
196  deltaInUs = 0;
197  }
198  else
199  deltaInUs = (currentTime - mLastTime);
200 
201  if (deltaInUs < granularityInUs)
202  {
203  std::this_thread::sleep_for(std::chrono::microseconds(granularityInUs - deltaInUs));
204 
205  deltaInUs = granularityInUs;
206  }
207 
208  mLastTime += deltaInUs;
209  }
210  else
211  mLastTime = currentTime;
212 
213  // return the delta in ms
214  return TTFloat64(deltaInUs / 1000.);
215 }
216 
217 void System::SystemThreadCallback()
218 {
219  // reset timing informations
220  mRunning = true;
221  mPaused = NO;
222  mLastTime = 0.;
223 
224  // notify each observers
225  sendNotification(TTSymbol("ClockRunningChanged"), mRunning);
226 
227  // launch the tick if the duration is valid and while it have to run
228  if (mDuration > 0.)
229  while (mRunning)
230  Tick();
231 }
232 
233 void System::stopThread()
234 {
235  if (mRunning)
236  {
237  mRunning = false;
238  while (!mThread.joinable())
239  std::this_thread::sleep_for(std::chrono::milliseconds(500));
240 
241  try
242  {
243  mThread.join();
244  }
245  catch (std::system_error& e)
246  {
247  TTLogError("System::stopThread() : %s\n", e.what());
248  }
249  }
250 }
std::uint64_t TTUInt64
64 bit unsigned integer
Definition: TTBase.h:180
#define addAttribute(name, type)
A convenience macro to be used by subclasses for registering attributes with a custom getter...
Definition: TTAttribute.h:29
double TTFloat64
64 bit floating point number
Definition: TTBase.h:188
void append(const T &anElementValueToAppend)
Insert a single TTElement at the end.
Definition: TTValue.h:243
64-bit floating point
Definition: TTBase.h:272
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
System clock class is based on the time of the system.
void TTFOUNDATION_EXPORT TTLogError(TTImmutableCString message,...)
Platform and host independent method for posting errors.
Definition: TTBase.cpp:572
void clear()
Clear all values from the vector, leaving with size of 0.
Definition: TTValue.h:131
void TTFOUNDATION_EXPORT TTLogMessage(TTImmutableCString message,...)
Platform and host independent method for posting log messages.
Definition: TTBase.cpp:534
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
No Error.
Definition: TTBase.h:343
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34