2 Copyright (C) 2006-2010 Paul Davis
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.
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.
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.
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))
24 #include "timecode/time.h"
28 float Time::default_rate = 30.0;
31 /** Increment @a timecode by exactly one frame (keep subframes value).
33 * @return true if seconds wrap.
36 increment (Time& timecode, uint32_t subframes_per_frame)
40 if (timecode.negative) {
41 if (Timecode_IS_AROUND_ZERO (timecode) && timecode.subframes) {
42 // We have a zero transition involving only subframes
43 timecode.subframes = subframes_per_frame - timecode.subframes;
44 timecode.negative = false;
48 timecode.negative = false;
49 wrap = decrement (timecode, subframes_per_frame);
50 if (!Timecode_IS_ZERO (timecode)) {
51 timecode.negative = true;
56 switch ((int)ceil (timecode.rate)) {
58 if (timecode.frames == 23) {
64 if (timecode.frames == 24) {
71 if (timecode.frames == 29) {
72 if (((timecode.minutes + 1) % 10) && (timecode.seconds == 59)) {
82 if (timecode.frames == 29) {
89 if (timecode.frames == 59) {
96 if (wrap == SECONDS) {
97 if (timecode.seconds == 59) {
100 if (timecode.minutes == 59) {
101 timecode.minutes = 0;
118 /** Decrement @a timecode by exactly one frame (keep subframes value)
120 * @return true if seconds wrap. */
122 decrement (Time& timecode, uint32_t subframes_per_frame)
126 if (timecode.negative || Timecode_IS_ZERO (timecode)) {
127 timecode.negative = false;
128 wrap = increment (timecode, subframes_per_frame);
129 timecode.negative = true;
131 } else if (Timecode_IS_AROUND_ZERO (timecode) && timecode.subframes) {
132 // We have a zero transition involving only subframes
133 timecode.subframes = subframes_per_frame - timecode.subframes;
134 timecode.negative = true;
138 switch ((int)ceil (timecode.rate)) {
140 if (timecode.frames == 0) {
141 timecode.frames = 23;
146 if (timecode.frames == 0) {
147 timecode.frames = 24;
153 if ((timecode.minutes % 10) && (timecode.seconds == 0)) {
154 if (timecode.frames <= 2) {
155 timecode.frames = 29;
158 } else if (timecode.frames == 0) {
159 timecode.frames = 29;
164 if (timecode.frames == 0) {
165 timecode.frames = 29;
171 if (timecode.frames == 0) {
172 timecode.frames = 59;
178 if (wrap == SECONDS) {
179 if (timecode.seconds == 0) {
180 timecode.seconds = 59;
182 if (timecode.minutes == 0) {
183 timecode.minutes = 59;
197 if (Timecode_IS_ZERO (timecode)) {
198 timecode.negative = false;
205 /** Go to lowest absolute subframe value in this frame (set to 0 :-)) */
207 frames_floor (Time& timecode)
209 timecode.subframes = 0;
210 if (Timecode_IS_ZERO (timecode)) {
211 timecode.negative = false;
216 /** Increment @a timecode by one subframe */
218 increment_subframes (Time& timecode, uint32_t subframes_per_frame)
222 if (timecode.negative) {
223 timecode.negative = false;
224 wrap = decrement_subframes (timecode, subframes_per_frame);
225 if (!Timecode_IS_ZERO (timecode)) {
226 timecode.negative = true;
231 timecode.subframes++;
232 if (timecode.subframes >= subframes_per_frame) {
233 timecode.subframes = 0;
234 increment (timecode, subframes_per_frame);
241 /** Decrement @a timecode by one subframe */
243 decrement_subframes (Time& timecode, uint32_t subframes_per_frame)
247 if (timecode.negative) {
248 timecode.negative = false;
249 wrap = increment_subframes (timecode, subframes_per_frame);
250 timecode.negative = true;
254 if (timecode.subframes <= 0) {
255 timecode.subframes = 0;
256 if (Timecode_IS_ZERO (timecode)) {
257 timecode.negative = true;
258 timecode.subframes = 1;
261 decrement (timecode, subframes_per_frame);
262 timecode.subframes = 79;
266 timecode.subframes--;
267 if (Timecode_IS_ZERO (timecode)) {
268 timecode.negative = false;
275 /** Go to next whole second (frames == 0 or frames == 2) */
277 increment_seconds (Time& timecode, uint32_t subframes_per_frame)
282 frames_floor (timecode);
284 if (timecode.negative) {
285 // Wrap second if on second boundary
286 wrap = increment (timecode, subframes_per_frame);
287 // Go to lowest absolute frame value
288 seconds_floor (timecode);
289 if (Timecode_IS_ZERO (timecode)) {
290 timecode.negative = false;
293 // Go to highest possible frame in this second
294 switch ((int)ceil (timecode.rate)) {
296 timecode.frames = 23;
299 timecode.frames = 24;
302 timecode.frames = 29;
305 timecode.frames = 59;
309 // Increment by one frame
310 wrap = increment (timecode, subframes_per_frame);
317 /** Go to lowest (absolute) frame value in this second
318 * Doesn't care about positive/negative */
320 seconds_floor (Time& timecode)
323 frames_floor (timecode);
325 // Go to lowest possible frame in this second
326 switch ((int)ceil (timecode.rate)) {
331 if (!(timecode.drop)) {
334 if ((timecode.minutes % 10) && (timecode.seconds == 0)) {
343 if (Timecode_IS_ZERO (timecode)) {
344 timecode.negative = false;
349 /** Go to next whole minute (seconds == 0, frames == 0 or frames == 2) */
351 increment_minutes (Time& timecode, uint32_t subframes_per_frame)
356 frames_floor (timecode);
358 if (timecode.negative) {
359 // Wrap if on minute boundary
360 wrap = increment_seconds (timecode, subframes_per_frame);
361 // Go to lowest possible value in this minute
362 minutes_floor (timecode);
364 // Go to highest possible second
365 timecode.seconds = 59;
366 // Wrap minute by incrementing second
367 wrap = increment_seconds (timecode, subframes_per_frame);
374 /** Go to lowest absolute value in this minute */
376 minutes_floor (Time& timecode)
378 // Go to lowest possible second
379 timecode.seconds = 0;
380 // Go to lowest possible frame
381 seconds_floor (timecode);
383 if (Timecode_IS_ZERO (timecode)) {
384 timecode.negative = false;
389 /** Go to next whole hour (minute = 0, second = 0, frame = 0) */
391 increment_hours (Time& timecode, uint32_t subframes_per_frame)
396 frames_floor (timecode);
398 if (timecode.negative) {
399 // Wrap if on hour boundary
400 wrap = increment_minutes (timecode, subframes_per_frame);
401 // Go to lowest possible value in this hour
402 hours_floor(timecode);
404 timecode.minutes = 59;
405 wrap = increment_minutes (timecode, subframes_per_frame);
412 /** Go to lowest absolute value in this hour */
414 hours_floor(Time& timecode)
416 timecode.minutes = 0;
417 timecode.seconds = 0;
419 timecode.subframes = 0;
421 if (Timecode_IS_ZERO (timecode)) {
422 timecode.negative = false;
427 timecode_to_frames_per_second(TimecodeFormat t)
431 return (24000.0/1001.0); //23.976;
439 return (25000.0/1001.0); //24.976;
450 case timecode_2997drop:
451 return (30000.0/1001.0); //29.97;
458 case timecode_30drop:
463 return (60000.0/1001.0); //59.94;
471 //std::cerr << "Editor received unexpected timecode type" << std::endl;
478 timecode_has_drop_frames(TimecodeFormat t)
501 case timecode_2997drop:
509 case timecode_30drop:
522 //error << "Editor received unexpected timecode type" << endmsg;
529 } // namespace Timecode
532 operator<<(std::ostream& ostr, const Timecode::Time& t)
534 return t.print (ostr);