55fd636d3e7a70f36f2ea4aa314b331523213caa
[ardour.git] / libs / temporal / time.cc
1 /*
2   Copyright (C) 2006-2010 Paul Davis
3
4   This program is free software; you can redistribute it and/or modify it
5   under the terms of the GNU Lesser General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or (at your
7   option) any later version.
8
9   This program is distributed in the hope that it will be useful, but WITHOUT
10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
12   License for more details.
13
14   You should have received a copy of the GNU Lesser General Public License
15   along with this program; if not, write to the Free Software Foundation,
16   Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #define Timecode_IS_AROUND_ZERO(sm) (!(sm).frames && !(sm).seconds && !(sm).minutes && !(sm).hours)
20 #define Timecode_IS_ZERO(sm) (!(sm).frames && !(sm).seconds && !(sm).minutes && !(sm).hours && !(sm.subframes))
21
22 #include <math.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include "timecode/time.h"
27
28 namespace Timecode {
29
30 double Time::default_rate = 30.0;
31
32
33 /** Increment @a timecode by exactly one sample (keep subframes value).
34  * Realtime safe.
35  * @return true if seconds wrap.
36  */
37 Wrap
38 increment (Time& timecode, uint32_t subframes_per_frame)
39 {
40         Wrap wrap = NONE;
41
42         if (timecode.negative) {
43                 if (Timecode_IS_AROUND_ZERO (timecode) && timecode.subframes) {
44                         // We have a zero transition involving only subframes
45                         timecode.subframes = subframes_per_frame - timecode.subframes;
46                         timecode.negative = false;
47                         return SECONDS;
48                 }
49
50                 timecode.negative = false;
51                 wrap = decrement (timecode, subframes_per_frame);
52                 if (!Timecode_IS_ZERO (timecode)) {
53                         timecode.negative = true;
54                 }
55                 return wrap;
56         }
57
58         switch ((int)ceil (timecode.rate)) {
59         case 24:
60                 if (timecode.frames == 23) {
61                         timecode.frames = 0;
62                         wrap = SECONDS;
63                 }
64                 break;
65         case 25:
66                 if (timecode.frames == 24) {
67                         timecode.frames = 0;
68                         wrap = SECONDS;
69                 }
70                 break;
71         case 30:
72                 if (timecode.drop) {
73                         if (timecode.frames == 29) {
74                                 if (((timecode.minutes + 1) % 10) && (timecode.seconds == 59)) {
75                                         timecode.frames = 2;
76                                 }
77                                 else {
78                                         timecode.frames = 0;
79                                 }
80                                 wrap = SECONDS;
81                         }
82                 } else {
83
84                         if (timecode.frames == 29) {
85                                 timecode.frames = 0;
86                                 wrap = SECONDS;
87                         }
88                 }
89                 break;
90         case 60:
91                 if (timecode.frames == 59) {
92                         timecode.frames = 0;
93                         wrap = SECONDS;
94                 }
95                 break;
96         }
97
98         if (wrap == SECONDS) {
99                 if (timecode.seconds == 59) {
100                         timecode.seconds = 0;
101                         wrap = MINUTES;
102                         if (timecode.minutes == 59) {
103                                 timecode.minutes = 0;
104                                 wrap = HOURS;
105                                 timecode.hours++;
106                         } else {
107                                 timecode.minutes++;
108                         }
109                 } else {
110                         timecode.seconds++;
111                 }
112         } else {
113                 timecode.frames++;
114         }
115
116         return wrap;
117 }
118
119
120 /** Decrement @a timecode by exactly one sample (keep subframes value)
121  * Realtime safe.
122  * @return true if seconds wrap. */
123 Wrap
124 decrement (Time& timecode, uint32_t subframes_per_frame)
125 {
126         Wrap wrap = NONE;
127
128         if (timecode.negative || Timecode_IS_ZERO (timecode)) {
129                 timecode.negative = false;
130                 wrap = increment (timecode, subframes_per_frame);
131                 timecode.negative = true;
132                 return wrap;
133         } else if (Timecode_IS_AROUND_ZERO (timecode) && timecode.subframes) {
134                 // We have a zero transition involving only subframes
135                 timecode.subframes = subframes_per_frame - timecode.subframes;
136                 timecode.negative = true;
137                 return SECONDS;
138         }
139
140         switch ((int)ceil (timecode.rate)) {
141         case 24:
142                 if (timecode.frames == 0) {
143                         timecode.frames = 23;
144                         wrap = SECONDS;
145                 }
146                 break;
147         case 25:
148                 if (timecode.frames == 0) {
149                         timecode.frames = 24;
150                         wrap = SECONDS;
151                 }
152                 break;
153         case 30:
154                 if (timecode.drop) {
155                         if ((timecode.minutes % 10) && (timecode.seconds == 0)) {
156                                 if (timecode.frames <= 2) {
157                                         timecode.frames = 29;
158                                         wrap = SECONDS;
159                                 }
160                         } else if (timecode.frames == 0) {
161                                 timecode.frames = 29;
162                                 wrap = SECONDS;
163                         }
164
165                 } else {
166                         if (timecode.frames == 0) {
167                                 timecode.frames = 29;
168                                 wrap = SECONDS;
169                         }
170                 }
171                 break;
172         case 60:
173                 if (timecode.frames == 0) {
174                         timecode.frames = 59;
175                         wrap = SECONDS;
176                 }
177                 break;
178         }
179
180         if (wrap == SECONDS) {
181                 if (timecode.seconds == 0) {
182                         timecode.seconds = 59;
183                         wrap = MINUTES;
184                         if (timecode.minutes == 0) {
185                                 timecode.minutes = 59;
186                                 wrap = HOURS;
187                                 timecode.hours--;
188                         }
189                         else {
190                                 timecode.minutes--;
191                         }
192                 } else {
193                         timecode.seconds--;
194                 }
195         } else {
196                 timecode.frames--;
197         }
198
199         if (Timecode_IS_ZERO (timecode)) {
200                 timecode.negative = false;
201         }
202
203         return wrap;
204 }
205
206
207 /** Go to lowest absolute subframe value in this sample (set to 0 :-)) */
208 void
209 frames_floot (Time& timecode)
210 {
211         timecode.subframes = 0;
212         if (Timecode_IS_ZERO (timecode)) {
213                 timecode.negative = false;
214         }
215 }
216
217
218 /** Increment @a timecode by one subframe */
219 Wrap
220 increment_subframes (Time& timecode, uint32_t subframes_per_frame)
221 {
222         Wrap wrap = NONE;
223
224         if (timecode.negative) {
225                 timecode.negative = false;
226                 wrap = decrement_subframes (timecode, subframes_per_frame);
227                 if (!Timecode_IS_ZERO (timecode)) {
228                         timecode.negative = true;
229                 }
230                 return wrap;
231         }
232
233         timecode.subframes++;
234         if (timecode.subframes >= subframes_per_frame) {
235                 timecode.subframes = 0;
236                 increment (timecode, subframes_per_frame);
237                 return FRAMES;
238         }
239         return NONE;
240 }
241
242
243 /** Decrement @a timecode by one subframe */
244 Wrap
245 decrement_subframes (Time& timecode, uint32_t subframes_per_frame)
246 {
247         Wrap wrap = NONE;
248
249         if (timecode.negative) {
250                 timecode.negative = false;
251                 wrap = increment_subframes (timecode, subframes_per_frame);
252                 timecode.negative = true;
253                 return wrap;
254         }
255
256         if (timecode.subframes <= 0) {
257                 timecode.subframes = 0;
258                 if (Timecode_IS_ZERO (timecode)) {
259                         timecode.negative = true;
260                         timecode.subframes = 1;
261                         return FRAMES;
262                 } else {
263                         decrement (timecode, subframes_per_frame);
264                         timecode.subframes = 79;
265                         return FRAMES;
266                 }
267         } else {
268                 timecode.subframes--;
269                 if (Timecode_IS_ZERO (timecode)) {
270                         timecode.negative = false;
271                 }
272                 return NONE;
273         }
274 }
275
276
277 /** Go to next whole second (frames == 0 or frames == 2) */
278 Wrap
279 increment_seconds (Time& timecode, uint32_t subframes_per_frame)
280 {
281         Wrap wrap = NONE;
282
283         // Clear subframes
284         frames_floot (timecode);
285
286         if (timecode.negative) {
287                 // Wrap second if on second boundary
288                 wrap = increment (timecode, subframes_per_frame);
289                 // Go to lowest absolute frame value
290                 seconds_floor (timecode);
291                 if (Timecode_IS_ZERO (timecode)) {
292                         timecode.negative = false;
293                 }
294         } else {
295                 // Go to highest possible frame in this second
296                 switch ((int)ceil (timecode.rate)) {
297                 case 24:
298                         timecode.frames = 23;
299                         break;
300                 case 25:
301                         timecode.frames = 24;
302                         break;
303                 case 30:
304                         timecode.frames = 29;
305                         break;
306                 case 60:
307                         timecode.frames = 59;
308                         break;
309                 }
310
311                 // Increment by one frame
312                 wrap = increment (timecode, subframes_per_frame);
313         }
314
315         return wrap;
316 }
317
318
319 /** Go to lowest (absolute) frame value in this second
320  * Doesn't care about positive/negative */
321 void
322 seconds_floor (Time& timecode)
323 {
324         // Clear subframes
325         frames_floot (timecode);
326
327         // Go to lowest possible frame in this second
328         switch ((int)ceil (timecode.rate)) {
329         case 24:
330         case 25:
331         case 30:
332         case 60:
333                 if (!(timecode.drop)) {
334                         timecode.frames = 0;
335                 } else {
336                         if ((timecode.minutes % 10) && (timecode.seconds == 0)) {
337                                 timecode.frames = 2;
338                         } else {
339                                 timecode.frames = 0;
340                         }
341                 }
342                 break;
343         }
344
345         if (Timecode_IS_ZERO (timecode)) {
346                 timecode.negative = false;
347         }
348 }
349
350
351 /** Go to next whole minute (seconds == 0, frames == 0 or frames == 2) */
352 Wrap
353 increment_minutes (Time& timecode, uint32_t subframes_per_frame)
354 {
355         Wrap wrap = NONE;
356
357         // Clear subframes
358         frames_floot (timecode);
359
360         if (timecode.negative) {
361                 // Wrap if on minute boundary
362                 wrap = increment_seconds (timecode, subframes_per_frame);
363                 // Go to lowest possible value in this minute
364                 minutes_floor (timecode);
365         } else {
366                 // Go to highest possible second
367                 timecode.seconds = 59;
368                 // Wrap minute by incrementing second
369                 wrap = increment_seconds (timecode, subframes_per_frame);
370         }
371
372         return wrap;
373 }
374
375
376 /** Go to lowest absolute value in this minute */
377 void
378 minutes_floor (Time& timecode)
379 {
380         // Go to lowest possible second
381         timecode.seconds = 0;
382         // Go to lowest possible frame
383         seconds_floor (timecode);
384
385         if (Timecode_IS_ZERO (timecode)) {
386                 timecode.negative = false;
387         }
388 }
389
390
391 /** Go to next whole hour (minute = 0, second = 0, frame = 0) */
392 Wrap
393 increment_hours (Time& timecode, uint32_t subframes_per_frame)
394 {
395         Wrap wrap = NONE;
396
397         // Clear subframes
398         frames_floot (timecode);
399
400         if (timecode.negative) {
401                 // Wrap if on hour boundary
402                 wrap = increment_minutes (timecode, subframes_per_frame);
403                 // Go to lowest possible value in this hour
404                 hours_floor(timecode);
405         } else {
406                 timecode.minutes = 59;
407                 wrap = increment_minutes (timecode, subframes_per_frame);
408         }
409
410         return wrap;
411 }
412
413
414 /** Go to lowest absolute value in this hour */
415 void
416 hours_floor(Time& timecode)
417 {
418         timecode.minutes   = 0;
419         timecode.seconds   = 0;
420         timecode.frames    = 0;
421         timecode.subframes = 0;
422
423         if (Timecode_IS_ZERO (timecode)) {
424                 timecode.negative = false;
425         }
426 }
427
428 double
429 timecode_to_frames_per_second(TimecodeFormat t)
430 {
431         switch (t) {
432         case timecode_23976:
433                 return (24000.0/1001.0); //23.976;
434
435                 break;
436         case timecode_24:
437                 return 24;
438
439                 break;
440         case timecode_24976:
441                 return (25000.0/1001.0); //24.976;
442
443                 break;
444         case timecode_25:
445                 return 25;
446
447                 break;
448         case timecode_2997:
449                 return (30000.0/1001.0); //29.97;
450
451                 break;
452         case timecode_2997drop:
453                 return (30000.0/1001.0); //29.97;
454
455                 break;
456         case timecode_2997000:
457                 return 29.97;
458
459                 break;
460         case timecode_2997000drop:
461                 return 29.97;
462
463                 break;
464         case timecode_30:
465                 return 30;
466
467                 break;
468         case timecode_30drop:
469                 return 30;
470
471                 break;
472         case timecode_5994:
473                 return (60000.0/1001.0); //59.94;
474
475                 break;
476         case timecode_60:
477                 return 60;
478
479                 break;
480         default:
481                 //std::cerr << "Editor received unexpected timecode type" << std::endl;
482                 break;
483         }
484         return 30.0;
485 }
486
487 bool
488 timecode_has_drop_frames(TimecodeFormat t)
489 {
490         switch (t) {
491         case timecode_23976:
492                 return false;
493
494                 break;
495         case timecode_24:
496                 return false;
497
498                 break;
499         case timecode_24976:
500                 return false;
501
502                 break;
503         case timecode_25:
504                 return false;
505
506                 break;
507         case timecode_2997:
508                 return false;
509
510                 break;
511         case timecode_2997drop:
512                 return true;
513
514                 break;
515         case timecode_2997000:
516                 return false;
517
518                 break;
519         case timecode_2997000drop:
520                 return true;
521
522                 break;
523         case timecode_30:
524                 return false;
525
526                 break;
527         case timecode_30drop:
528                 return true;
529
530                 break;
531         case timecode_5994:
532                 return false;
533
534                 break;
535         case timecode_60:
536                 return false;
537
538                 break;
539         default:
540                 //error << "Editor received unexpected timecode type" << endmsg;
541                 break;
542         }
543
544         return false;
545 }
546
547 std::string
548 timecode_format_name (TimecodeFormat const t)
549 {
550         switch (t) {
551         case timecode_23976:
552                 return "23.98";
553
554                 break;
555         case timecode_24:
556                 return "24";
557
558                 break;
559         case timecode_24976:
560                 return "24.98";
561
562                 break;
563         case timecode_25:
564                 return "25";
565
566                 break;
567         case timecode_2997000:
568         case timecode_2997:
569                 return "29.97";
570
571                 break;
572         case timecode_2997000drop:
573         case timecode_2997drop:
574                 return "29.97 drop";
575
576                 break;
577         case timecode_30:
578                 return "30";
579
580                 break;
581         case timecode_30drop:
582                 return "30 drop";
583
584                 break;
585         case timecode_5994:
586                 return "59.94";
587
588                 break;
589         case timecode_60:
590                 return "60";
591
592                 break;
593         default:
594                 break;
595         }
596
597         return "??";
598 }
599
600 std::string timecode_format_time (Timecode::Time TC)
601 {
602         char buf[32];
603         if (TC.negative) {
604                 snprintf (buf, sizeof (buf), "-%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 "%c%02" PRIu32,
605                           TC.hours, TC.minutes, TC.seconds, TC.drop ? ';' : ':', TC.frames);
606         } else {
607                 snprintf (buf, sizeof (buf), " %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 "%c%02" PRIu32,
608                           TC.hours, TC.minutes, TC.seconds, TC.drop ? ';' : ':', TC.frames);
609         }
610         return std::string(buf);
611 }
612
613 std::string timecode_format_sampletime (
614         int64_t sample,
615         double sample_sample_rate,
616         double timecode_frames_per_second, bool timecode_drop_frames)
617 {
618         Time t;
619         sample_to_timecode(
620                 sample, t, false, false,
621                 timecode_frames_per_second, timecode_drop_frames,
622                 sample_sample_rate,
623                 80, false, 0);
624         return timecode_format_time(t);
625 }
626
627 bool parse_timecode_format(std::string tc, Timecode::Time &TC) {
628         char negative[2];
629         char ignored[2];
630         TC.subframes = 0;
631         if (sscanf (tc.c_str(), "%[- ]%" PRId32 ":%" PRId32 ":%" PRId32 "%[:;]%" PRId32,
632                     negative, &TC.hours, &TC.minutes, &TC.seconds, ignored, &TC.frames) != 6) {
633                 TC.hours = TC.minutes = TC.seconds = TC.frames = 0;
634                 TC.negative = false;
635                 return false;
636         }
637         if (negative[0]=='-') {
638                 TC.negative = true;
639         } else {
640                 TC.negative = false;
641         }
642         return true;
643 }
644
645 void
646 timecode_to_sample(
647         Timecode::Time& timecode, int64_t& sample,
648         bool use_offset, bool use_subframes,
649         /* Note - framerate info is taken from Timecode::Time& */
650         double sample_sample_rate /**< may include pull up/down */,
651         uint32_t subframes_per_frame,
652         /* optional offset  - can be improved: function pointer to lazily query this*/
653         bool offset_is_negative, int64_t offset_samples
654         )
655 {
656         const double samples_per_timecode_frame = (double) sample_sample_rate / (double) timecode.rate;
657
658         if (timecode.drop) {
659                 // The drop frame format was created to better approximate the 30000/1001 = 29.97002997002997....
660                 // framerate of NTSC color TV. The used frame rate of drop fra,e is 29.97, which drifts by about
661                 // 0.108 frame per hour, or about 1.3 frames per 12 hours. This is not perfect, but a lot better
662                 // than using 30 non drop, which will drift with about 1.8 frame per minute.
663                 // Using 29.97, drop frame real time can be accurate only every 10th minute (10 minutes of 29.97 fps
664                 // is exactly 17982 samples). One minute is 1798.2 samples, but we count 30 frames per second
665                 // (30 * 60 = 1800). This means that at the first minute boundary (at the end of 0:0:59:29) we
666                 // are 1.8 framess too late relative to real time. By dropping 2 frames (jumping to 0:1:0:2) we are
667                 // approx. 0.2 frames too early. This adds up with 0.2 too early for each minute until we are 1.8
668                 // samples too early at 0:9:0:2 (9 * 0.2 = 1.8). The 10th minute brings us 1.8 frames later again
669                 // (at end of 0:9:59:29), which sums up to 0 (we are back to zero at 0:10:0:0 :-).
670                 //
671                 // In table form:
672                 //
673                 // Timecode value    frames offset   subframes offset   seconds (rounded)  44100 sample (rounded)
674                 //  0:00:00:00        0.0             0                     0.000                0 (accurate)
675                 //  0:00:59:29        1.8           144                    60.027          2647177
676                 //  0:01:00:02       -0.2           -16                    60.060          2648648
677                 //  0:01:59:29        1.6           128                   120.020          5292883
678                 //  0:02:00:02       -0.4           -32                   120.053          5294354
679                 //  0:02:59:29        1.4           112                   180.013          7938588
680                 //  0:03:00:02       -0.6           -48                   180.047          7940060
681                 //  0:03:59:29        1.2            96                   240.007         10584294
682                 //  0:04:00:02       -0.8           -64                   240.040         10585766
683                 //  0:04:59:29        1.0            80                   300.000         13230000
684                 //  0:05:00:02       -1.0           -80                   300.033         13231471
685                 //  0:05:59:29        0.8            64                   359.993         15875706
686                 //  0:06:00:02       -1.2           -96                   360.027         15877177
687                 //  0:06:59:29        0.6            48                   419.987         18521411
688                 //  0:07:00:02       -1.4          -112                   420.020         18522883
689                 //  0:07:59:29        0.4            32                   478.980         21167117
690                 //  0:08:00:02       -1.6          -128                   480.013         21168589
691                 //  0:08:59:29        0.2            16                   539.973         23812823
692                 //  0:09:00:02       -1.8          -144                   540.007         23814294
693                 //  0:09:59:29        0.0+            0+                  599.967         26458529
694                 //  0:10:00:00        0.0             0                   600.000         26460000 (accurate)
695                 //
696                 //  Per Sigmond <per@sigmond.no>
697                 //
698                 //  This schma would compensate exactly for a frame-rate of 30 * 0.999. but the
699                 //  actual rate is 30000/1001 - which results in an offset of -3.6ms per hour or
700                 //  about -86ms over a 24-hour period. (SMPTE 12M-1999)
701                 //
702                 //  Robin Gareus <robin@gareus.org>
703
704                 const int64_t fps_i = ceil(timecode.rate);
705                 int64_t totalMinutes = 60 * timecode.hours + timecode.minutes;
706                 int64_t frameNumber  = fps_i * 3600 * timecode.hours
707                         + fps_i * 60 * timecode.minutes
708                         + fps_i * timecode.seconds + timecode.frames
709                         - 2 * (totalMinutes - totalMinutes / 10);
710                 sample = frameNumber * sample_sample_rate / (double) timecode.rate;
711         } else {
712                 /*
713                   Non drop is easy.. just note the use of
714                   rint(timecode.rate) * samples_per_timecode_frame
715                   (frames per Timecode second), which is larger than
716                   sample_rate() in the non-integer Timecode rate case.
717                 */
718
719                 sample = (int64_t) rint(
720                         (
721                                 ((timecode.hours * 60 * 60) + (timecode.minutes * 60) + timecode.seconds)
722                                 *
723                                 (rint(timecode.rate) * samples_per_timecode_frame)
724                                 )
725                         + (timecode.frames * samples_per_timecode_frame)
726                         );
727         }
728
729         if (use_subframes) {
730                 sample += (int64_t) rint(((double)timecode.subframes * samples_per_timecode_frame) / (double)subframes_per_frame);
731         }
732
733         if (use_offset) {
734                 if (offset_is_negative) {
735                         if (sample >= offset_samples) {
736                                 sample -= offset_samples;
737                         } else {
738                                 /* Prevent song-time from becoming negative */
739                                 sample = 0;
740                         }
741                 } else {
742                         if (timecode.negative) {
743                                 if (sample <= offset_samples) {
744                                         sample = offset_samples - sample;
745                                 } else {
746                                         sample = 0;
747                                 }
748                         } else {
749                                 sample += offset_samples;
750                         }
751                 }
752         }
753 }
754
755
756 void
757 sample_to_timecode (
758         int64_t sample, Timecode::Time& timecode,
759         bool use_offset, bool use_subframes,
760         /* framerate info */
761         double timecode_frames_per_second,
762         bool   timecode_drop_frames,
763         double sample_sample_rate/**< can include pull up/down */,
764         uint32_t subframes_per_frame,
765         /* optional offset  - can be improved: function pointer to lazily query this*/
766         bool offset_is_negative, int64_t offset_samples
767         )
768 {
769         int64_t offset_sample;
770
771         if (!use_offset) {
772                 timecode.negative = (sample < 0);
773                 offset_sample = ::llabs(sample);
774         } else {
775                 if (offset_is_negative) {
776                         offset_sample = sample + offset_samples;
777                         timecode.negative = false;
778                 } else {
779                         if (sample < offset_samples) {
780                                 offset_sample = (offset_samples - sample);
781                                 timecode.negative = true;
782                         } else {
783                                 offset_sample =  sample - offset_samples;
784                                 timecode.negative = false;
785                         }
786                 }
787         }
788
789         if (timecode_drop_frames) {
790                 int64_t frameNumber = floor( (double)offset_sample * timecode_frames_per_second / sample_sample_rate);
791
792                 /* there are 17982 samples in 10 min @ 29.97df */
793                 const int64_t D = frameNumber / 17982;
794                 const int64_t M = frameNumber % 17982;
795
796                 timecode.subframes = rint(subframes_per_frame
797                                           * ((double)offset_sample * timecode_frames_per_second / sample_sample_rate - (double)frameNumber));
798
799                 if (timecode.subframes == subframes_per_frame) {
800                         timecode.subframes = 0;
801                         frameNumber++;
802                 }
803
804                 frameNumber +=  18*D + 2*((M - 2) / 1798);
805
806                 timecode.frames  =    frameNumber % 30;
807                 timecode.seconds =   (frameNumber / 30) % 60;
808                 timecode.minutes =  ((frameNumber / 30) / 60) % 60;
809                 timecode.hours   = (((frameNumber / 30) / 60) / 60);
810
811         } else {
812                 double timecode_frames_left_exact;
813                 double timecode_frames_fraction;
814                 int64_t timecode_frames_left;
815                 const double samples_per_timecode_frame = sample_sample_rate / timecode_frames_per_second;
816                 const int64_t frames_per_hour = (int64_t)(3600. * rint(timecode_frames_per_second) * samples_per_timecode_frame);
817
818                 timecode.hours = offset_sample / frames_per_hour;
819
820                 // Extract whole hours. Do this to prevent rounding errors with
821                 // high sample numbers in the calculations that follow.
822                 timecode_frames_left_exact = (double)(offset_sample % frames_per_hour) / samples_per_timecode_frame;
823                 timecode_frames_fraction = timecode_frames_left_exact - floor( timecode_frames_left_exact );
824
825                 timecode.subframes = (int32_t) rint(timecode_frames_fraction * subframes_per_frame);
826                 timecode_frames_left = (int64_t) floor (timecode_frames_left_exact);
827
828                 if (use_subframes && timecode.subframes == subframes_per_frame) {
829                         timecode_frames_left++;
830                         timecode.subframes = 0;
831                 }
832
833                 timecode.minutes = timecode_frames_left / ((int32_t) lrint (timecode_frames_per_second) * 60);
834                 timecode_frames_left = timecode_frames_left % ((int32_t) lrint (timecode_frames_per_second) * 60);
835                 timecode.seconds = timecode_frames_left / (int32_t) lrint(timecode_frames_per_second);
836                 timecode.frames = timecode_frames_left % (int32_t) lrint(timecode_frames_per_second);
837         }
838
839         if (!use_subframes) {
840                 timecode.subframes = 0;
841         }
842         /* set frame rate and drop sample */
843         timecode.rate = timecode_frames_per_second;
844         timecode.drop = timecode_drop_frames;
845 }
846
847 } // namespace Timecode
848
849 std::ostream&
850 operator<<(std::ostream& ostr, const Timecode::Time& t)
851 {
852         return t.print (ostr);
853 }