comparison base/RealTimeSV.cpp @ 1228:a2091d148d7f project-file-rework

Cut down vastly on the number of config.pri files and places where their contents has to be effectively duplicated without them
author Chris Cannam
date Mon, 24 Oct 2016 17:53:33 +0100
parents base/RealTime.cpp@c811991a5efa
children c4f873749ab5
comparison
equal deleted inserted replaced
1224:ab050519c4ba 1228:a2091d148d7f
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
28 #include "Debug.h"
29
30 #include "Preferences.h"
31
32 // A RealTime consists of two ints that must be at least 32 bits each.
33 // A signed 32-bit int can store values exceeding +/- 2 billion. This
34 // means we can safely use our lower int for nanoseconds, as there are
35 // 1 billion nanoseconds in a second and we need to handle double that
36 // because of the implementations of addition etc that we use.
37 //
38 // The maximum valid RealTime on a 32-bit system is somewhere around
39 // 68 years: 999999999 nanoseconds longer than the classic Unix epoch.
40
41 #define ONE_BILLION 1000000000
42
43 RealTime::RealTime(int s, int n) :
44 sec(s), nsec(n)
45 {
46 if (sec == 0) {
47 while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
48 while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
49 } else if (sec < 0) {
50 while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
51 while (nsec > 0) { nsec -= ONE_BILLION; ++sec; }
52 } else {
53 while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
54 while (nsec < 0) { nsec += ONE_BILLION; --sec; }
55 }
56 }
57
58 RealTime
59 RealTime::fromSeconds(double sec)
60 {
61 if (sec >= 0) {
62 return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5));
63 } else {
64 return -fromSeconds(-sec);
65 }
66 }
67
68 RealTime
69 RealTime::fromMilliseconds(int msec)
70 {
71 return RealTime(msec / 1000, (msec % 1000) * 1000000);
72 }
73
74 RealTime
75 RealTime::fromTimeval(const struct timeval &tv)
76 {
77 return RealTime(int(tv.tv_sec), int(tv.tv_usec * 1000));
78 }
79
80 RealTime
81 RealTime::fromXsdDuration(std::string xsdd)
82 {
83 RealTime t;
84
85 int year = 0, month = 0, day = 0, hour = 0, minute = 0;
86 double second = 0.0;
87
88 int i = 0;
89
90 const char *s = xsdd.c_str();
91 int len = int(xsdd.length());
92
93 bool negative = false, afterT = false;
94
95 while (i < len) {
96
97 if (s[i] == '-') {
98 if (i == 0) negative = true;
99 ++i;
100 continue;
101 }
102
103 double value = 0.0;
104 char *eptr = 0;
105
106 if (isdigit(s[i]) || s[i] == '.') {
107 value = strtod(&s[i], &eptr);
108 i = int(eptr - s);
109 }
110
111 if (i == len) break;
112
113 switch (s[i]) {
114 case 'Y': year = int(value + 0.1); break;
115 case 'D': day = int(value + 0.1); break;
116 case 'H': hour = int(value + 0.1); break;
117 case 'M':
118 if (afterT) minute = int(value + 0.1);
119 else month = int(value + 0.1);
120 break;
121 case 'S':
122 second = value;
123 break;
124 case 'T': afterT = true; break;
125 };
126
127 ++i;
128 }
129
130 if (year > 0) {
131 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;
132 t = t + RealTime(year * 31556952, 0);
133 }
134
135 if (month > 0) {
136 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;
137 t = t + RealTime(month * 2629746, 0);
138 }
139
140 if (day > 0) {
141 t = t + RealTime(day * 86400, 0);
142 }
143
144 if (hour > 0) {
145 t = t + RealTime(hour * 3600, 0);
146 }
147
148 if (minute > 0) {
149 t = t + RealTime(minute * 60, 0);
150 }
151
152 t = t + fromSeconds(second);
153
154 if (negative) {
155 return -t;
156 } else {
157 return t;
158 }
159 }
160
161 double
162 RealTime::toDouble() const
163 {
164 double d = sec;
165 d += double(nsec) / double(ONE_BILLION);
166 return d;
167 }
168
169 std::ostream &operator<<(std::ostream &out, const RealTime &rt)
170 {
171 if (rt < RealTime::zeroTime) {
172 out << "-";
173 } else {
174 out << " ";
175 }
176
177 int s = (rt.sec < 0 ? -rt.sec : rt.sec);
178 int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec);
179
180 out << s << ".";
181
182 int nn(n);
183 if (nn == 0) out << "00000000";
184 else while (nn < (ONE_BILLION / 10)) {
185 out << "0";
186 nn *= 10;
187 }
188
189 out << n << "R";
190 return out;
191 }
192
193 std::string
194 RealTime::toString(bool align) const
195 {
196 std::stringstream out;
197 out << *this;
198
199 std::string s = out.str();
200
201 if (!align && *this >= RealTime::zeroTime) {
202 // remove leading " "
203 s = s.substr(1, s.length() - 1);
204 }
205
206 // remove trailing R
207 return s.substr(0, s.length() - 1);
208 }
209
210 RealTime
211 RealTime::fromString(std::string s)
212 {
213 bool negative = false;
214 int section = 0;
215 std::string ssec, snsec;
216
217 for (size_t i = 0; i < s.length(); ++i) {
218
219 char c = s[i];
220 if (isspace(c)) continue;
221
222 if (section == 0) {
223
224 if (c == '-') negative = true;
225 else if (isdigit(c)) { section = 1; ssec += c; }
226 else if (c == '.') section = 2;
227 else break;
228
229 } else if (section == 1) {
230
231 if (c == '.') section = 2;
232 else if (isdigit(c)) ssec += c;
233 else break;
234
235 } else if (section == 2) {
236
237 if (isdigit(c)) snsec += c;
238 else break;
239 }
240 }
241
242 while (snsec.length() < 8) snsec += '0';
243
244 int sec = atoi(ssec.c_str());
245 int nsec = atoi(snsec.c_str());
246 if (negative) sec = -sec;
247
248 // SVDEBUG << "RealTime::fromString: string " << s << " -> "
249 // << sec << " sec, " << nsec << " nsec" << endl;
250
251 return RealTime(sec, nsec);
252 }
253
254 std::string
255 RealTime::toText(bool fixedDp) const
256 {
257 if (*this < RealTime::zeroTime) return "-" + (-*this).toText(fixedDp);
258
259 Preferences *p = Preferences::getInstance();
260 bool hms = true;
261
262 if (p) {
263 hms = p->getShowHMS();
264 int fps = 0;
265 switch (p->getTimeToTextMode()) {
266 case Preferences::TimeToTextMs: break;
267 case Preferences::TimeToTextUs: fps = 1000000; break;
268 case Preferences::TimeToText24Frame: fps = 24; break;
269 case Preferences::TimeToText25Frame: fps = 25; break;
270 case Preferences::TimeToText30Frame: fps = 30; break;
271 case Preferences::TimeToText50Frame: fps = 50; break;
272 case Preferences::TimeToText60Frame: fps = 60; break;
273 }
274 if (fps != 0) return toFrameText(fps, hms);
275 }
276
277 return toMSText(fixedDp, hms);
278 }
279
280 static void
281 writeSecPart(std::stringstream &out, bool hms, int sec)
282 {
283 if (hms) {
284 if (sec >= 3600) {
285 out << (sec / 3600) << ":";
286 }
287
288 if (sec >= 60) {
289 int minutes = (sec % 3600) / 60;
290 if (sec >= 3600 && minutes < 10) out << "0";
291 out << minutes << ":";
292 }
293
294 if (sec >= 10) {
295 out << ((sec % 60) / 10);
296 }
297
298 out << (sec % 10);
299
300 } else {
301 out << sec;
302 }
303 }
304
305 std::string
306 RealTime::toMSText(bool fixedDp, bool hms) const
307 {
308 if (*this < RealTime::zeroTime) return "-" + (-*this).toMSText(fixedDp, hms);
309
310 std::stringstream out;
311
312 writeSecPart(out, hms, sec);
313
314 int ms = msec();
315
316 if (ms != 0) {
317 out << ".";
318 out << (ms / 100);
319 ms = ms % 100;
320 if (ms != 0) {
321 out << (ms / 10);
322 ms = ms % 10;
323 } else if (fixedDp) {
324 out << "0";
325 }
326 if (ms != 0) {
327 out << ms;
328 } else if (fixedDp) {
329 out << "0";
330 }
331 } else if (fixedDp) {
332 out << ".000";
333 }
334
335 std::string s = out.str();
336
337 return s;
338 }
339
340 std::string
341 RealTime::toFrameText(int fps, bool hms) const
342 {
343 if (*this < RealTime::zeroTime) return "-" + (-*this).toFrameText(fps, hms);
344
345 std::stringstream out;
346
347 writeSecPart(out, hms, sec);
348
349 // avoid rounding error if fps does not divide into ONE_BILLION
350 int64_t fbig = nsec;
351 fbig *= fps;
352 int f = int(fbig / ONE_BILLION);
353
354 int div = 1;
355 int n = fps - 1;
356 while ((n = n / 10)) {
357 div *= 10;
358 }
359
360 out << ":";
361
362 // cerr << "div = " << div << ", f = "<< f << endl;
363
364 while (div) {
365 int d = (f / div) % 10;
366 out << d;
367 div /= 10;
368 }
369
370 std::string s = out.str();
371
372 // cerr << "converted " << toString() << " to " << s << endl;
373
374 return s;
375 }
376
377 std::string
378 RealTime::toSecText() const
379 {
380 if (*this < RealTime::zeroTime) return "-" + (-*this).toSecText();
381
382 std::stringstream out;
383
384 writeSecPart(out, true, sec);
385
386 if (sec < 60) {
387 out << "s";
388 }
389
390 std::string s = out.str();
391
392 return s;
393 }
394
395 std::string
396 RealTime::toXsdDuration() const
397 {
398 std::string s = "PT" + toString(false) + "S";
399 return s;
400 }
401
402 RealTime
403 RealTime::operator*(int m) const
404 {
405 double t = (double(nsec) / ONE_BILLION) * m;
406 t += sec * m;
407 return fromSeconds(t);
408 }
409
410 RealTime
411 RealTime::operator/(int d) const
412 {
413 int secdiv = sec / d;
414 int secrem = sec % d;
415
416 double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
417
418 return RealTime(secdiv, int(nsecdiv + 0.5));
419 }
420
421 RealTime
422 RealTime::operator*(double m) const
423 {
424 double t = (double(nsec) / ONE_BILLION) * m;
425 t += sec * m;
426 return fromSeconds(t);
427 }
428
429 RealTime
430 RealTime::operator/(double d) const
431 {
432 double t = (double(nsec) / ONE_BILLION) / d;
433 t += sec / d;
434 return fromSeconds(t);
435 }
436
437 double
438 RealTime::operator/(const RealTime &r) const
439 {
440 double lTotal = double(sec) * ONE_BILLION + double(nsec);
441 double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
442
443 if (rTotal == 0) return 0.0;
444 else return lTotal/rTotal;
445 }
446
447 static RealTime
448 frame2RealTime_i(sv_frame_t frame, sv_frame_t iSampleRate)
449 {
450 if (frame < 0) return -frame2RealTime_i(-frame, iSampleRate);
451
452 RealTime rt;
453 sv_frame_t sec = frame / iSampleRate;
454 rt.sec = int(sec);
455 frame -= sec * iSampleRate;
456 rt.nsec = (int)(((double(frame) * 1000000.0) / double(iSampleRate)) * 1000.0);
457 return rt;
458 }
459
460 sv_frame_t
461 RealTime::realTime2Frame(const RealTime &time, sv_samplerate_t sampleRate)
462 {
463 if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
464 double s = time.sec + double(time.nsec + 1) / 1000000000.0;
465 return sv_frame_t(s * sampleRate);
466 }
467
468 RealTime
469 RealTime::frame2RealTime(sv_frame_t frame, sv_samplerate_t sampleRate)
470 {
471 if (sampleRate == double(int(sampleRate))) {
472 return frame2RealTime_i(frame, int(sampleRate));
473 }
474
475 double sec = double(frame) / sampleRate;
476 return fromSeconds(sec);
477 }
478
479 const RealTime RealTime::zeroTime(0,0);
480