move TimecodeFormat to libtimecode
[ardour.git] / libs / timecode / src / 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
24 #include "timecode/time.h"
25
26 namespace Timecode {
27
28 float Time::default_rate = 30.0;
29
30
31 /** Increment @a timecode by exactly one frame (keep subframes value).
32  * Realtime safe.
33  * @return true if seconds wrap.
34  */
35 Wrap
36 increment (Time& timecode, uint32_t subframes_per_frame)
37 {
38         Wrap wrap = NONE;
39
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;
45                         return SECONDS;
46                 }
47     
48                 timecode.negative = false;
49                 wrap = decrement (timecode, subframes_per_frame);
50                 if (!Timecode_IS_ZERO (timecode)) {
51                         timecode.negative = true;
52                 }
53                 return wrap;
54         }
55
56         switch ((int)ceil (timecode.rate)) {
57         case 24:
58                 if (timecode.frames == 23) {
59                         timecode.frames = 0;
60                         wrap = SECONDS;
61                 }
62                 break;
63         case 25:
64                 if (timecode.frames == 24) {
65                         timecode.frames = 0;
66                         wrap = SECONDS;
67                 }
68                 break;
69         case 30:
70                 if (timecode.drop) {
71                         if (timecode.frames == 29) {
72                                 if (((timecode.minutes + 1) % 10) && (timecode.seconds == 59)) {
73                                         timecode.frames = 2;
74                                 }
75                                 else {
76                                         timecode.frames = 0;
77                                 }
78                                 wrap = SECONDS;
79                         }
80                 } else {
81
82                         if (timecode.frames == 29) {
83                                 timecode.frames = 0;
84                                 wrap = SECONDS;
85                         }
86                 }
87                 break;
88         case 60:
89                 if (timecode.frames == 59) {
90                         timecode.frames = 0;
91                         wrap = SECONDS;
92                 }
93                 break;
94         }
95   
96         if (wrap == SECONDS) {
97                 if (timecode.seconds == 59) {
98                         timecode.seconds = 0;
99                         wrap = MINUTES;
100                         if (timecode.minutes == 59) {
101                                 timecode.minutes = 0;
102                                 wrap = HOURS;
103                                 timecode.hours++;
104                         } else {
105                                 timecode.minutes++;
106                         }
107                 } else {
108                         timecode.seconds++;
109                 }
110         } else {
111                 timecode.frames++;
112         }
113   
114         return wrap;
115 }
116
117
118 /** Decrement @a timecode by exactly one frame (keep subframes value)
119  * Realtime safe.
120  * @return true if seconds wrap. */
121 Wrap
122 decrement (Time& timecode, uint32_t subframes_per_frame)
123 {
124         Wrap wrap = NONE;
125   
126         if (timecode.negative || Timecode_IS_ZERO (timecode)) {
127                 timecode.negative = false;
128                 wrap = increment (timecode, subframes_per_frame);
129                 timecode.negative = true;
130                 return wrap;
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;
135                 return SECONDS;
136         }
137   
138         switch ((int)ceil (timecode.rate)) {
139         case 24:
140                 if (timecode.frames == 0) {
141                         timecode.frames = 23;
142                         wrap = SECONDS;
143                 }
144                 break;
145         case 25:
146                 if (timecode.frames == 0) {
147                         timecode.frames = 24;
148                         wrap = SECONDS;
149                 }
150                 break;
151         case 30:
152                 if (timecode.drop) {
153                         if ((timecode.minutes % 10) && (timecode.seconds == 0)) {
154                                 if (timecode.frames <= 2) {
155                                         timecode.frames = 29;
156                                         wrap = SECONDS;
157                                 }
158                         } else if (timecode.frames == 0) {
159                                 timecode.frames = 29;
160                                 wrap = SECONDS;
161                         }
162                         
163                 } else {
164                         if (timecode.frames == 0) {
165                                 timecode.frames = 29;
166                                 wrap = SECONDS;
167                         }
168                 }
169                 break;
170         case 60:
171                 if (timecode.frames == 0) {
172                         timecode.frames = 59;
173                         wrap = SECONDS;
174                 }
175                 break;
176         }
177   
178         if (wrap == SECONDS) {
179                 if (timecode.seconds == 0) {
180                         timecode.seconds = 59;
181                         wrap = MINUTES;
182                         if (timecode.minutes == 0) {
183                                 timecode.minutes = 59;
184                                 wrap = HOURS;
185                                 timecode.hours--;
186                         }
187                         else {
188                                 timecode.minutes--;
189                         }
190                 } else {
191                         timecode.seconds--;
192                 }
193         } else {
194                 timecode.frames--;
195         }
196   
197         if (Timecode_IS_ZERO (timecode)) {
198                 timecode.negative = false;
199         }
200   
201         return wrap;
202 }
203
204
205 /** Go to lowest absolute subframe value in this frame (set to 0 :-)) */
206 void
207 frames_floor (Time& timecode)
208 {
209         timecode.subframes = 0;
210         if (Timecode_IS_ZERO (timecode)) {
211                 timecode.negative = false;
212         }
213 }
214
215
216 /** Increment @a timecode by one subframe */
217 Wrap
218 increment_subframes (Time& timecode, uint32_t subframes_per_frame)
219 {
220         Wrap wrap = NONE;
221   
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;
227                 }
228                 return wrap;
229         }
230   
231         timecode.subframes++;
232         if (timecode.subframes >= subframes_per_frame) {
233                 timecode.subframes = 0;
234                 increment (timecode, subframes_per_frame);
235                 return FRAMES;
236         }
237         return NONE;
238 }
239
240
241 /** Decrement @a timecode by one subframe */
242 Wrap
243 decrement_subframes (Time& timecode, uint32_t subframes_per_frame)
244 {
245         Wrap wrap = NONE;
246   
247         if (timecode.negative) {
248                 timecode.negative = false;
249                 wrap = increment_subframes (timecode, subframes_per_frame);
250                 timecode.negative = true;
251                 return wrap;
252         }
253   
254         if (timecode.subframes <= 0) {
255                 timecode.subframes = 0;
256                 if (Timecode_IS_ZERO (timecode)) {
257                         timecode.negative = true;
258                         timecode.subframes = 1;
259                         return FRAMES;
260                 } else {
261                         decrement (timecode, subframes_per_frame);
262                         timecode.subframes = 79;
263                         return FRAMES;
264                 }
265         } else {
266                 timecode.subframes--;
267                 if (Timecode_IS_ZERO (timecode)) {
268                         timecode.negative = false;
269                 }
270                 return NONE;
271         }
272 }
273
274
275 /** Go to next whole second (frames == 0 or frames == 2) */
276 Wrap
277 increment_seconds (Time& timecode, uint32_t subframes_per_frame)
278 {
279         Wrap wrap = NONE;
280   
281         // Clear subframes
282         frames_floor (timecode);
283   
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;
291                 }
292         } else {
293                 // Go to highest possible frame in this second
294                 switch ((int)ceil (timecode.rate)) {
295                 case 24:
296                         timecode.frames = 23;
297                         break;
298                 case 25:
299                         timecode.frames = 24;
300                         break;
301                 case 30:
302                         timecode.frames = 29;
303                         break;
304                 case 60:
305                         timecode.frames = 59;
306                         break;
307                 }
308     
309                 // Increment by one frame
310                 wrap = increment (timecode, subframes_per_frame);
311         }
312   
313         return wrap;
314 }
315
316
317 /** Go to lowest (absolute) frame value in this second
318  * Doesn't care about positive/negative */
319 void
320 seconds_floor (Time& timecode)
321 {
322         // Clear subframes
323         frames_floor (timecode);
324   
325         // Go to lowest possible frame in this second
326         switch ((int)ceil (timecode.rate)) {
327         case 24:
328         case 25:
329         case 30:
330         case 60:
331                 if (!(timecode.drop)) {
332                         timecode.frames = 0;
333                 } else {
334                         if ((timecode.minutes % 10) && (timecode.seconds == 0)) {
335                                 timecode.frames = 2;
336                         } else {
337                                 timecode.frames = 0;
338                         }
339                 }
340                 break;
341         }
342   
343         if (Timecode_IS_ZERO (timecode)) {
344                 timecode.negative = false;
345         }
346 }
347
348
349 /** Go to next whole minute (seconds == 0, frames == 0 or frames == 2) */
350 Wrap
351 increment_minutes (Time& timecode, uint32_t subframes_per_frame)
352 {
353         Wrap wrap = NONE;
354   
355         // Clear subframes
356         frames_floor (timecode);
357   
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);
363         } else {
364                 // Go to highest possible second
365                 timecode.seconds = 59;
366                 // Wrap minute by incrementing second
367                 wrap = increment_seconds (timecode, subframes_per_frame);
368         }
369   
370         return wrap;
371 }
372
373
374 /** Go to lowest absolute value in this minute */
375 void
376 minutes_floor (Time& timecode)
377 {
378         // Go to lowest possible second
379         timecode.seconds = 0;
380         // Go to lowest possible frame
381         seconds_floor (timecode);
382
383         if (Timecode_IS_ZERO (timecode)) {
384                 timecode.negative = false;
385         }
386 }
387
388
389 /** Go to next whole hour (minute = 0, second = 0, frame = 0) */
390 Wrap
391 increment_hours (Time& timecode, uint32_t subframes_per_frame)
392 {
393         Wrap wrap = NONE;
394   
395         // Clear subframes
396         frames_floor (timecode);
397   
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);
403         } else {
404                 timecode.minutes = 59;
405                 wrap = increment_minutes (timecode, subframes_per_frame);
406         }
407   
408         return wrap;
409 }
410
411
412 /** Go to lowest absolute value in this hour */
413 void
414 hours_floor(Time& timecode)
415 {
416         timecode.minutes   = 0;
417         timecode.seconds   = 0;
418         timecode.frames    = 0;
419         timecode.subframes = 0;
420   
421         if (Timecode_IS_ZERO (timecode)) {
422                 timecode.negative = false;
423         }
424 }
425
426 float
427 timecode_to_frames_per_second(TimecodeFormat t)
428 {
429         switch (t) {
430                 case timecode_23976:
431                         return (24000.0/1001.0); //23.976;
432
433                         break;
434                 case timecode_24:
435                         return 24;
436
437                         break;
438                 case timecode_24976:
439                         return (25000.0/1001.0); //24.976;
440
441                         break;
442                 case timecode_25:
443                         return 25;
444
445                         break;
446                 case timecode_2997:
447                         return 29.97;
448
449                         break;
450                 case timecode_2997drop:
451                         return (30000.0/1001.0); //29.97;
452
453                         break;
454                 case timecode_30:
455                         return 30;
456
457                         break;
458                 case timecode_30drop:
459                         return 30;
460
461                         break;
462                 case timecode_5994:
463                         return (60000.0/1001.0); //59.94;
464
465                         break;
466                 case timecode_60:
467                         return 60;
468
469                         break;
470                 default:
471                         //std::cerr << "Editor received unexpected timecode type" << std::endl;
472                         break;
473         }
474         return 30.0;
475 }
476
477 bool
478 timecode_has_drop_frames(TimecodeFormat t)
479 {
480         switch (t) {
481                 case timecode_23976:
482                         return false;
483
484                         break;
485                 case timecode_24:
486                         return false;
487
488                         break;
489                 case timecode_24976:
490                         return false;
491
492                         break;
493                 case timecode_25:
494                         return false;
495
496                         break;
497                 case timecode_2997:
498                         return false;
499
500                         break;
501                 case timecode_2997drop:
502                         return true;
503
504                         break;
505                 case timecode_30:
506                         return false;
507
508                         break;
509                 case timecode_30drop:
510                         return true;
511
512                         break;
513                 case timecode_5994:
514                         return false;
515
516                         break;
517                 case timecode_60:
518                         return false;
519
520                         break;
521                 default:
522                         //error << "Editor received unexpected timecode type" << endmsg;
523                         break;
524         }
525
526         return false;
527 }
528
529 } // namespace Timecode
530
531 std::ostream& 
532 operator<<(std::ostream& ostr, const Timecode::Time& t) 
533 {
534         return t.print (ostr);
535 }