svcore  1.9
RealTime.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version. See the file
12  COPYING included with this distribution for more information.
13 */
14 
15 /*
16  This is a modified version of a source file from the
17  Rosegarden MIDI and audio sequencer and notation editor.
18  This file copyright 2000-2006 Chris Cannam.
19 */
20 
21 #include <iostream>
22 
23 #include <cstdlib>
24 #include <sstream>
25 
26 #include "RealTime.h"
27 #include "sys/time.h"
28 
29 #include "Debug.h"
30 
31 #include "Preferences.h"
32 
33 // A RealTime consists of two ints that must be at least 32 bits each.
34 // A signed 32-bit int can store values exceeding +/- 2 billion. This
35 // means we can safely use our lower int for nanoseconds, as there are
36 // 1 billion nanoseconds in a second and we need to handle double that
37 // because of the implementations of addition etc that we use.
38 //
39 // The maximum valid RealTime on a 32-bit system is somewhere around
40 // 68 years: 999999999 nanoseconds longer than the classic Unix epoch.
41 
42 #define ONE_BILLION 1000000000
43 
44 RealTime::RealTime(int s, int n) :
45  sec(s), nsec(n)
46 {
47  if (sec == 0) {
48  while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
49  while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
50  } else if (sec < 0) {
51  while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
52  while (nsec > 0) { nsec -= ONE_BILLION; ++sec; }
53  } else {
54  while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
55  while (nsec < 0) { nsec += ONE_BILLION; --sec; }
56  }
57 }
58 
61 {
62  return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5));
63 }
64 
67 {
68  return RealTime(msec / 1000, (msec % 1000) * 1000000);
69 }
70 
72 RealTime::fromTimeval(const struct timeval &tv)
73 {
74  return RealTime(tv.tv_sec, tv.tv_usec * 1000);
75 }
76 
78 RealTime::fromXsdDuration(std::string xsdd)
79 {
80  RealTime t;
81 
82  int year = 0, month = 0, day = 0, hour = 0, minute = 0;
83  double second = 0.0;
84 
85  int i = 0;
86 
87  const char *s = xsdd.c_str();
88  int len = xsdd.length();
89 
90  bool negative = false, afterT = false;
91 
92  while (i < len) {
93 
94  if (s[i] == '-') {
95  if (i == 0) negative = true;
96  ++i;
97  continue;
98  }
99 
100  double value = 0.0;
101  char *eptr = 0;
102 
103  if (isdigit(s[i]) || s[i] == '.') {
104  value = strtod(&s[i], &eptr);
105  i = eptr - s;
106  }
107 
108  if (i == len) break;
109 
110  switch (s[i]) {
111  case 'Y': year = int(value + 0.1); break;
112  case 'D': day = int(value + 0.1); break;
113  case 'H': hour = int(value + 0.1); break;
114  case 'M':
115  if (afterT) minute = int(value + 0.1);
116  else month = int(value + 0.1);
117  break;
118  case 'S':
119  second = value;
120  break;
121  case 'T': afterT = true; break;
122  };
123 
124  ++i;
125  }
126 
127  if (year > 0) {
128  cerr << "WARNING: This xsd:duration (\"" << xsdd << "\") contains a non-zero year.\nWith no origin and a limited data size, I will treat a year as exactly 31556952\nseconds and you should expect overflow and/or poor results." << endl;
129  t = t + RealTime(year * 31556952, 0);
130  }
131 
132  if (month > 0) {
133  cerr << "WARNING: This xsd:duration (\"" << xsdd << "\") contains a non-zero month.\nWith no origin and a limited data size, I will treat a month as exactly 2629746\nseconds and you should expect overflow and/or poor results." << endl;
134  t = t + RealTime(month * 2629746, 0);
135  }
136 
137  if (day > 0) {
138  t = t + RealTime(day * 86400, 0);
139  }
140 
141  if (hour > 0) {
142  t = t + RealTime(hour * 3600, 0);
143  }
144 
145  if (minute > 0) {
146  t = t + RealTime(minute * 60, 0);
147  }
148 
149  t = t + fromSeconds(second);
150 
151  if (negative) {
152  return -t;
153  } else {
154  return t;
155  }
156 }
157 
158 double
160 {
161  double d = sec;
162  d += double(nsec) / double(ONE_BILLION);
163  return d;
164 }
165 
166 std::ostream &operator<<(std::ostream &out, const RealTime &rt)
167 {
168  if (rt < RealTime::zeroTime) {
169  out << "-";
170  } else {
171  out << " ";
172  }
173 
174  int s = (rt.sec < 0 ? -rt.sec : rt.sec);
175  int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec);
176 
177  out << s << ".";
178 
179  int nn(n);
180  if (nn == 0) out << "00000000";
181  else while (nn < (ONE_BILLION / 10)) {
182  out << "0";
183  nn *= 10;
184  }
185 
186  out << n << "R";
187  return out;
188 }
189 
190 std::string
191 RealTime::toString(bool align) const
192 {
193  std::stringstream out;
194  out << *this;
195 
196  std::string s = out.str();
197 
198  if (!align && *this >= RealTime::zeroTime) {
199  // remove leading " "
200  s = s.substr(1, s.length() - 1);
201  }
202 
203  // remove trailing R
204  return s.substr(0, s.length() - 1);
205 }
206 
207 RealTime
208 RealTime::fromString(std::string s)
209 {
210  bool negative = false;
211  int section = 0;
212  std::string ssec, snsec;
213 
214  for (size_t i = 0; i < s.length(); ++i) {
215 
216  char c = s[i];
217  if (isspace(c)) continue;
218 
219  if (section == 0) {
220 
221  if (c == '-') negative = true;
222  else if (isdigit(c)) { section = 1; ssec += c; }
223  else if (c == '.') section = 2;
224  else break;
225 
226  } else if (section == 1) {
227 
228  if (c == '.') section = 2;
229  else if (isdigit(c)) ssec += c;
230  else break;
231 
232  } else if (section == 2) {
233 
234  if (isdigit(c)) snsec += c;
235  else break;
236  }
237  }
238 
239  while (snsec.length() < 8) snsec += '0';
240 
241  int sec = atoi(ssec.c_str());
242  int nsec = atoi(snsec.c_str());
243  if (negative) sec = -sec;
244 
245 // SVDEBUG << "RealTime::fromString: string " << s << " -> "
246 // << sec << " sec, " << nsec << " nsec" << endl;
247 
248  return RealTime(sec, nsec);
249 }
250 
251 std::string
252 RealTime::toText(bool fixedDp) const
253 {
254  if (*this < RealTime::zeroTime) return "-" + (-*this).toText(fixedDp);
255 
257  if (p) {
258  int fps = 0;
259  switch (p->getTimeToTextMode()) {
260  case Preferences::TimeToTextMs: break;
261  case Preferences::TimeToTextUs: fps = 1000000; break;
262  case Preferences::TimeToText24Frame: fps = 24; break;
263  case Preferences::TimeToText25Frame: fps = 25; break;
264  case Preferences::TimeToText30Frame: fps = 30; break;
265  case Preferences::TimeToText50Frame: fps = 50; break;
266  case Preferences::TimeToText60Frame: fps = 60; break;
267  }
268  if (fps != 0) return toFrameText(fps);
269  }
270 
271  std::stringstream out;
272 
273  if (sec >= 3600) {
274  out << (sec / 3600) << ":";
275  }
276 
277  if (sec >= 60) {
278  out << (sec % 3600) / 60 << ":";
279  }
280 
281  if (sec >= 10) {
282  out << ((sec % 60) / 10);
283  }
284 
285  out << (sec % 10);
286 
287  int ms = msec();
288 
289  if (ms != 0) {
290  out << ".";
291  out << (ms / 100);
292  ms = ms % 100;
293  if (ms != 0) {
294  out << (ms / 10);
295  ms = ms % 10;
296  } else if (fixedDp) {
297  out << "0";
298  }
299  if (ms != 0) {
300  out << ms;
301  } else if (fixedDp) {
302  out << "0";
303  }
304  } else if (fixedDp) {
305  out << ".000";
306  }
307 
308  std::string s = out.str();
309 
310  return s;
311 }
312 
313 std::string
314 RealTime::toFrameText(int fps) const
315 {
316  if (*this < RealTime::zeroTime) return "-" + (-*this).toFrameText(fps);
317 
318  std::stringstream out;
319 
320  if (sec >= 3600) {
321  out << (sec / 3600) << ":";
322  }
323 
324  if (sec >= 60) {
325  out << (sec % 3600) / 60 << ":";
326  }
327 
328  if (sec >= 10) {
329  out << ((sec % 60) / 10);
330  }
331 
332  out << (sec % 10);
333 
334  int f = nsec / (ONE_BILLION / fps);
335 
336  int div = 1;
337  int n = fps - 1;
338  while ((n = n / 10)) {
339  div *= 10;
340  }
341 
342  out << ":";
343 
344 // cerr << "div = " << div << ", f = "<< f << endl;
345 
346  while (div) {
347  int d = (f / div) % 10;
348  out << d;
349  div /= 10;
350  }
351 
352  std::string s = out.str();
353 
354 // cerr << "converted " << toString() << " to " << s << endl;
355 
356  return s;
357 }
358 
359 std::string
361 {
362  if (*this < RealTime::zeroTime) return "-" + (-*this).toSecText();
363 
364  std::stringstream out;
365 
366  if (sec >= 3600) {
367  out << (sec / 3600) << ":";
368  }
369 
370  if (sec >= 60) {
371  out << (sec % 3600) / 60 << ":";
372  }
373 
374  if (sec >= 10) {
375  out << ((sec % 60) / 10);
376  }
377 
378  out << (sec % 10);
379 
380  if (sec < 60) {
381  out << "s";
382  }
383 
384  std::string s = out.str();
385 
386  return s;
387 }
388 
389 std::string
391 {
392  std::string s = "PT" + toString(false) + "S";
393  return s;
394 }
395 
396 RealTime
398 {
399  double t = (double(nsec) / ONE_BILLION) * m;
400  t += sec * m;
401  return fromSeconds(t);
402 }
403 
404 RealTime
406 {
407  int secdiv = sec / d;
408  int secrem = sec % d;
409 
410  double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
411 
412  return RealTime(secdiv, int(nsecdiv + 0.5));
413 }
414 
415 RealTime
416 RealTime::operator*(double m) const
417 {
418  double t = (double(nsec) / ONE_BILLION) * m;
419  t += sec * m;
420  return fromSeconds(t);
421 }
422 
423 RealTime
424 RealTime::operator/(double d) const
425 {
426  double t = (double(nsec) / ONE_BILLION) / d;
427  t += sec / d;
428  return fromSeconds(t);
429 }
430 
431 double
433 {
434  double lTotal = double(sec) * ONE_BILLION + double(nsec);
435  double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
436 
437  if (rTotal == 0) return 0.0;
438  else return lTotal/rTotal;
439 }
440 
441 long
442 RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate)
443 {
444  if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
445  double s = time.sec + double(time.nsec + 1) / 1000000000.0;
446  return long(s * double(sampleRate));
447 }
448 
449 RealTime
450 RealTime::frame2RealTime(long frame, unsigned int sampleRate)
451 {
452  if (frame < 0) return -frame2RealTime(-frame, sampleRate);
453 
454  RealTime rt;
455  rt.sec = frame / long(sampleRate);
456  frame -= rt.sec * long(sampleRate);
457  rt.nsec = (int)(((double(frame) * 1000000.0) / long(sampleRate)) * 1000.0);
458  return rt;
459 }
460 
461 const RealTime RealTime::zeroTime(0,0);
462 
static RealTime fromTimeval(const struct timeval &)
Definition: RealTime.cpp:72
static RealTime fromString(std::string)
Convert a string as obtained from toString back to a RealTime object.
Definition: RealTime.cpp:208
static RealTime frame2RealTime(long frame, unsigned int sampleRate)
Convert a sample frame at the given sample rate into a RealTime.
Definition: RealTime.cpp:450
std::string toText(bool fixedDp=false) const
Return a user-readable string to the nearest millisecond, in a form like HH:MM:SS....
Definition: RealTime.cpp:252
TimeToTextMode getTimeToTextMode() const
Definition: Preferences.h:94
std::ostream & operator<<(std::ostream &out, const RealTime &rt)
Definition: RealTime.cpp:166
std::string toXsdDuration() const
Return a string in xsd:duration format.
Definition: RealTime.cpp:390
static RealTime fromSeconds(double sec)
Definition: RealTime.cpp:60
int nsec
Definition: RealTime.h:38
static Preferences * getInstance()
Definition: Preferences.cpp:31
#define ONE_BILLION
Definition: RealTime.cpp:42
RealTime operator/(int d) const
Definition: RealTime.cpp:405
std::string toSecText() const
Return a user-readable string to the nearest second, in a form like "6s" (for less than a minute) or ...
Definition: RealTime.cpp:360
static RealTime fromMilliseconds(int msec)
Definition: RealTime.cpp:66
int sec
Definition: RealTime.h:37
RealTime()
Definition: RealTime.h:43
static long realTime2Frame(const RealTime &r, unsigned int sampleRate)
Convert a RealTime into a sample frame at the given sample rate.
Definition: RealTime.cpp:442
double toDouble() const
Definition: RealTime.cpp:159
static const RealTime zeroTime
Definition: RealTime.h:159
int msec() const
Definition: RealTime.h:41
std::string toString(bool align=false) const
Return a human-readable debug-type string to full precision (probably not a format to show to a user ...
Definition: RealTime.cpp:191
static RealTime fromXsdDuration(std::string xsdd)
Definition: RealTime.cpp:78
std::string toFrameText(int fps) const
Return a user-readable string in which seconds are divided into frames (presumably at a lower frame r...
Definition: RealTime.cpp:314
RealTime operator *(int m) const
Definition: RealTime.cpp:397
RealTime represents time values to nanosecond precision with accurate arithmetic and frame-rate conve...
Definition: RealTime.h:35