1 /*
2    Copyright (C) 2013 Robin Gareus <robin@gareus.org>
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <math.h>
21 
22 #include "timecode.h"
23 
24 #define TCtoDbl(r) ( (double)((r)->num) / (double)((r)->den) )
25 
timecode_rate_to_double(TimecodeRate const * const r)26 double timecode_rate_to_double(TimecodeRate const * const r) {
27   return TCtoDbl(r);
28 }
29 
timecode_sample_to_time(TimecodeTime * const t,TimecodeRate const * const r,const double samplerate,const int64_t sample)30 static void timecode_sample_to_time (TimecodeTime * const t, TimecodeRate const * const r, const double samplerate, const int64_t sample) {
31   const double  fps_d = TCtoDbl(r);
32   const int64_t fps_i = ceil(fps_d);
33 
34   if (r->drop) {
35     int64_t frameNumber = floor((double)sample * fps_d / samplerate);
36 
37     /* there are 17982 frames in 10 min @ 29.97df */
38     const int64_t D = frameNumber / 17982;
39     const int64_t M = frameNumber % 17982;
40 
41     t->subframe =  rint(r->subframes * ((double)sample * fps_d / samplerate - (double)frameNumber));
42 
43     if (t->subframe == r->subframes && r->subframes != 0) {
44             t->subframe = 0;
45             frameNumber++;
46     }
47 
48     frameNumber +=  18*D + 2*((M - 2) / 1798);
49 
50     t->frame  =    frameNumber % 30;
51     t->second =   (frameNumber / 30) % 60;
52     t->minute =  ((frameNumber / 30) / 60) % 60;
53     t->hour   = (((frameNumber / 30) / 60) / 60);
54 
55   } else {
56     double timecode_frames_left_exact;
57     double timecode_frames_fraction;
58     int64_t timecode_frames_left;
59     const double frames_per_timecode_frame = samplerate / fps_d;
60     const int64_t frames_per_hour = (int64_t)(3600 * fps_i * frames_per_timecode_frame);
61 
62     t->hour = sample / frames_per_hour;
63     double sample_d = sample % frames_per_hour;
64 
65     timecode_frames_left_exact = sample_d / frames_per_timecode_frame;
66     timecode_frames_fraction = timecode_frames_left_exact - floor(timecode_frames_left_exact);
67 
68     t->subframe = (int32_t) rint(timecode_frames_fraction * r->subframes);
69 
70     timecode_frames_left = (int64_t) floor (timecode_frames_left_exact);
71 
72     if (t->subframe == r->subframes && r->subframes != 0) {
73       t->subframe = 0;
74       timecode_frames_left++;
75     }
76 
77     t->minute = timecode_frames_left / (fps_i * 60);
78     timecode_frames_left = timecode_frames_left % (fps_i * 60);
79     t->second = timecode_frames_left / fps_i;
80     t->frame  = timecode_frames_left % fps_i;
81   }
82 }
83 
timecode_framenumber_to_time(TimecodeTime * const t,TimecodeRate const * const r,const int64_t frameno)84 void timecode_framenumber_to_time (TimecodeTime * const t, TimecodeRate const * const r, const int64_t frameno) {
85   timecode_sample_to_time(t, r, TCtoDbl(r), frameno);
86 }
87 
timecode_time_to_string(char * smptestring,TimecodeTime const * const t)88 void timecode_time_to_string (char *smptestring, TimecodeTime const * const t) {
89   snprintf(smptestring, 12, "%02d:%02d:%02d:%02d",
90       t->hour, t->minute, t->second, t->frame);
91 }
92 
timecode_framenumber_to_string(char * smptestring,TimecodeRate const * const r,const int64_t frameno)93 void timecode_framenumber_to_string (char *smptestring, TimecodeRate const * const r, const int64_t frameno) {
94   TimecodeTime t;
95   timecode_framenumber_to_time(&t, r, frameno);
96   timecode_time_to_string(smptestring, &t);
97 }
98 
99 // vim:sw=2 sts=2 ts=8 et:
100