1 /*
2  * Copyright (C) 2017 Paul Davis <paul@linuxaudiosystems.com>
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 of the License, or
7  * (at your option) 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 along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #ifndef __timecode_time_h__
20 #define __timecode_time_h__
21 
22 #include <cmath>
23 #include <inttypes.h>
24 #include <ostream>
25 
26 #include "temporal/visibility.h"
27 
28 namespace Timecode
29 {
30 
31 enum Wrap {
32 	NONE = 0,
33 	FRAMES,
34 	SECONDS,
35 	MINUTES,
36 	HOURS
37 };
38 
39 enum TimecodeFormat {
40 	timecode_23976,
41 	timecode_24,
42 	timecode_24976,
43 	timecode_25,
44 	timecode_2997,
45 	timecode_2997drop,
46 	timecode_2997000,
47 	timecode_2997000drop,
48 	timecode_30,
49 	timecode_30drop,
50 	timecode_5994,
51 	timecode_60
52 };
53 
54 struct LIBTEMPORAL_API Time {
55 	bool          negative;
56 	uint32_t      hours;
57 	uint32_t      minutes;
58 	uint32_t      seconds;
59 	uint32_t      frames;       ///< Timecode frames (not audio frames)
60 	uint32_t      subframes;    ///< Typically unused
61 	double        rate;         ///< Frame rate of this Time
62 	static double default_rate; ///< Rate to use for default constructor
63 	bool          drop;         ///< Whether this Time uses dropframe Timecode
64 
65 	Time (double a_rate = default_rate)
66 	{
67 		negative  = false;
68 		hours     = 0;
69 		minutes   = 0;
70 		seconds   = 0;
71 		frames    = 0;
72 		subframes = 0;
73 		rate      = a_rate;
74 		drop      = (lrintf (100.f * (float)a_rate) == (long)2997);
75 	}
76 
77 	bool operator== (const Time& other) const
78 	{
79 		return negative == other.negative && hours == other.hours &&
80 		       minutes == other.minutes && seconds == other.seconds &&
81 		       frames == other.frames && subframes == other.subframes &&
82 		       rate == other.rate && drop == other.drop;
83 	}
84 
printTime85 	std::ostream& print (std::ostream& ostr) const
86 	{
87 		if (negative) {
88 			ostr << '-';
89 		}
90 		ostr << hours << ':' << minutes << ':' << seconds << ':'
91 		     << frames << '.' << subframes
92 		     << " @" << rate << (drop ? " drop" : " nondrop");
93 		return ostr;
94 	}
95 };
96 
97 Wrap LIBTEMPORAL_API increment (Time& timecode, uint32_t);
98 Wrap LIBTEMPORAL_API decrement (Time& timecode, uint32_t);
99 Wrap LIBTEMPORAL_API increment_subframes (Time& timecode, uint32_t);
100 Wrap LIBTEMPORAL_API decrement_subframes (Time& timecode, uint32_t);
101 Wrap LIBTEMPORAL_API increment_seconds (Time& timecode, uint32_t);
102 Wrap LIBTEMPORAL_API increment_minutes (Time& timecode, uint32_t);
103 Wrap LIBTEMPORAL_API increment_hours (Time& timecode, uint32_t);
104 void LIBTEMPORAL_API frames_floot (Time& timecode);
105 void LIBTEMPORAL_API seconds_floor (Time& timecode);
106 void LIBTEMPORAL_API minutes_floor (Time& timecode);
107 void LIBTEMPORAL_API hours_floor (Time& timecode);
108 
109 double LIBTEMPORAL_API timecode_to_frames_per_second (TimecodeFormat const t);
110 bool LIBTEMPORAL_API timecode_has_drop_frames (TimecodeFormat const t);
111 
112 std::string LIBTEMPORAL_API timecode_format_name (TimecodeFormat const t);
113 std::string LIBTEMPORAL_API timecode_format_time (Timecode::Time const timecode);
114 
115 bool LIBTEMPORAL_API parse_timecode_format (std::string tc, Timecode::Time& TC);
116 
117 std::string LIBTEMPORAL_API
118 timecode_format_sampletime (
119     int64_t sample,
120     double  sample_sample_rate,
121     double timecode_frames_per_second, bool timecode_drop_frames);
122 
123 /** Convert timecode (frames per second) to audio sample time (samples per second)
124  *
125  * @param timecode Timecode to convert (also includes frame-rate)
126  * @param sample returned corresponding audio sample time
127  * @param use_offset apply offset as given by \p offset_is_negative and \p offset_samples
128  * @param use_subframes use \p subframes_per_frame when converting
129  * @param sample_sample_rate target sample-rate, may include pull up/down
130  * @param subframes_per_frame sub-frames per frame -- must not be 0 if \p use_subframes \c == \c true
131  * @param offset_is_negative true if offset_samples is to be subtracted
132  * @param offset_samples sample offset to add or subtract
133  */
134 void LIBTEMPORAL_API
135 timecode_to_sample (
136     Timecode::Time const& timecode, int64_t& sample,
137     bool use_offset, bool use_subframes,
138     double   sample_sample_rate,
139     uint32_t subframes_per_frame,
140     bool offset_is_negative, int64_t offset_samples);
141 
142 /** Convert audio sample time (samples per second) to timecode (frames per second)
143  *
144  * @param sample audio sample time to convert
145  * @param timecode resulting Timecode
146  * @param use_offset apply offset as given by \p offset_is_negative and \p offset_samples
147  * @param use_subframes use \p subframes_per_frame when converting
148  * @param timecode_frames_per_second target framerate
149  * @param timecode_drop_frames true if fps uses drop-frame-counting. only valid for \c 29.97 \c = \c 30000/1001 fps
150  * @param sample_sample_rate source sample-rate, may include pull up/down
151  * @param subframes_per_frame sub-frames per frame -- must not be 0 if \p use_subframes \c == \c true
152  * @param offset_is_negative true if offset_samples is to be subtracted
153  * @param offset_samples sample offset to add or subtract
154  */
155 void LIBTEMPORAL_API
156 sample_to_timecode (
157     int64_t sample, Timecode::Time& timecode,
158     bool use_offset, bool use_subframes,
159     double   timecode_frames_per_second,
160     bool     timecode_drop_frames,
161     double   sample_sample_rate,
162     uint32_t subframes_per_frame,
163     bool offset_is_negative, int64_t offset_samples);
164 
165 } // namespace Timecode
166 
167 extern LIBTEMPORAL_API std::ostream& operator<< (std::ostream& ostr, const Timecode::Time& t);
168 
169 #endif // __timecode_time_h__
170