Merged with trunk revision 610
[ardour.git] / libs / surfaces / control_protocol / smpte.cc
1 /*
2         Copyright (C) 2006 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
6         by 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, but WITHOUT
10         ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11         FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12         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         675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #define SMPTE_IS_AROUND_ZERO( sm ) (!(sm).frames && !(sm).seconds && !(sm).minutes && !(sm).hours)
20 #define SMPTE_IS_ZERO( sm ) (!(sm).frames && !(sm).seconds && !(sm).minutes && !(sm).hours && !(sm.subframes))
21
22 #include <control_protocol/smpte.h>
23
24 namespace SMPTE {
25
26 FPS Time::default_rate = MTC_30_FPS;
27
28
29 /** Increment @a smpte by exactly one frame (keep subframes value).
30  * Realtime safe.
31  * @return true if seconds wrap.
32  */
33 Wrap
34 increment( Time& smpte )
35 {
36         Wrap wrap = NONE;
37
38         if (smpte.negative) {
39                 if (SMPTE_IS_AROUND_ZERO(smpte) && smpte.subframes) {
40                         // We have a zero transition involving only subframes
41                         smpte.subframes = 80 - smpte.subframes;
42                         smpte.negative = false;
43                         return SECONDS;
44                 }
45     
46                 smpte.negative = false;
47                 wrap = decrement( smpte );
48                 if (!SMPTE_IS_ZERO( smpte )) {
49                         smpte.negative = true;
50                 }
51                 return wrap;
52         }
53   
54         switch (smpte.rate) {
55         case MTC_24_FPS:
56                 if (smpte.frames == 23) {
57                         smpte.frames = 0;
58                         wrap = SECONDS;
59                 }
60                 break;
61         case MTC_25_FPS:
62                 if (smpte.frames == 24) {
63                         smpte.frames = 0;
64                         wrap = SECONDS;
65                 }
66                 break;
67         case MTC_30_FPS_DROP:
68                 if (smpte.frames == 29) {
69                         if ( ((smpte.minutes + 1) % 10) && (smpte.seconds == 59) ) {
70                                 smpte.frames = 2;
71                         }
72                         else {
73                                 smpte.frames = 0;
74                         }
75                         wrap = SECONDS;
76                 }
77                 break;
78         case MTC_30_FPS:
79                 if (smpte.frames == 29) {
80                         smpte.frames = 0;
81                         wrap = SECONDS;
82                 }
83                 break;
84         }
85   
86         if (wrap == SECONDS) {
87                 if (smpte.seconds == 59) {
88                         smpte.seconds = 0;
89                         wrap = MINUTES;
90                         if (smpte.minutes == 59) {
91                                 smpte.minutes = 0;
92                                 wrap = HOURS;
93                                 smpte.hours++;
94                         } else {
95                                 smpte.minutes++;
96                         }
97                 } else {
98                         smpte.seconds++;
99                 }
100         } else {
101                 smpte.frames++;
102         }
103   
104         return wrap;
105 }
106
107
108 /** Decrement @a smpte by exactly one frame (keep subframes value)
109  * Realtime safe.
110  * @return true if seconds wrap. */
111 Wrap
112 decrement( Time& smpte )
113 {
114         Wrap wrap = NONE;
115   
116   
117         if (smpte.negative || SMPTE_IS_ZERO(smpte)) {
118                 smpte.negative = false;
119                 wrap = increment( smpte );
120                 smpte.negative = true;
121                 return wrap;
122         } else if (SMPTE_IS_AROUND_ZERO(smpte) && smpte.subframes) {
123                 // We have a zero transition involving only subframes
124                 smpte.subframes = 80 - smpte.subframes;
125                 smpte.negative = true;
126                 return SECONDS;
127         }
128   
129         switch (smpte.rate) {
130         case MTC_24_FPS:
131                 if (smpte.frames == 0) {
132                         smpte.frames = 23;
133                         wrap = SECONDS;
134                 }
135                 break;
136         case MTC_25_FPS:
137                 if (smpte.frames == 0) {
138                         smpte.frames = 24;
139                         wrap = SECONDS;
140                 }
141                 break;
142         case MTC_30_FPS_DROP:
143                 if ((smpte.minutes % 10) && (smpte.seconds == 0)) {
144                         if (smpte.frames <= 2) {
145                                 smpte.frames = 29;
146                                 wrap = SECONDS;
147                         }
148                 } else if (smpte.frames == 0) {
149                         smpte.frames = 29;
150                         wrap = SECONDS;
151                 }
152                 break;
153         case MTC_30_FPS:
154                 if (smpte.frames == 0) {
155                         smpte.frames = 29;
156                         wrap = SECONDS;
157                 }
158                 break;
159         }
160   
161         if (wrap == SECONDS) {
162                 if (smpte.seconds == 0) {
163                         smpte.seconds = 59;
164                         wrap = MINUTES;
165                         if (smpte.minutes == 0) {
166                                 smpte.minutes = 59;
167                                 wrap = HOURS;
168                                 smpte.hours--;
169                         }
170                         else {
171                                 smpte.minutes--;
172                         }
173                 } else {
174                         smpte.seconds--;
175                 }
176         } else {
177                 smpte.frames--;
178         }
179   
180         if (SMPTE_IS_ZERO( smpte )) {
181                 smpte.negative = false;
182         }
183   
184         return wrap;
185 }
186
187
188 /** Go to lowest absolute subframe value in this frame (set to 0 :-) ) */
189 void
190 frames_floor( Time& smpte )
191 {
192         smpte.subframes = 0;
193         if (SMPTE_IS_ZERO(smpte)) {
194                 smpte.negative = false;
195         }
196 }
197
198
199 /** Increment @a smpte by one subframe */
200 Wrap
201 increment_subframes( Time& smpte )
202 {
203         Wrap wrap = NONE;
204   
205         if (smpte.negative) {
206                 smpte.negative = false;
207                 wrap = decrement_subframes( smpte );
208                 if (!SMPTE_IS_ZERO(smpte)) {
209                         smpte.negative = true;
210                 }
211                 return wrap;
212         }
213   
214         smpte.subframes++;
215         if (smpte.subframes >= 80) {
216                 smpte.subframes = 0;
217                 increment( smpte );
218                 return FRAMES;
219         }
220         return NONE;
221 }
222
223
224 /** Decrement @a smpte by one subframe */
225 Wrap
226 decrement_subframes( Time& smpte )
227 {
228         Wrap wrap = NONE;
229   
230         if (smpte.negative) {
231                 smpte.negative = false;
232                 wrap = increment_subframes( smpte );
233                 smpte.negative = true;
234                 return wrap;
235         }
236   
237         if (smpte.subframes <= 0) {
238                 smpte.subframes = 0;
239                 if (SMPTE_IS_ZERO(smpte)) {
240                         smpte.negative = true;
241                         smpte.subframes = 1;
242                         return FRAMES;
243                 } else {
244                         decrement( smpte );
245                         smpte.subframes = 79;
246                         return FRAMES;
247                 }
248         } else {
249                 smpte.subframes--;
250                 if (SMPTE_IS_ZERO(smpte)) {
251                         smpte.negative = false;
252                 }
253                 return NONE;
254         }
255 }
256
257
258 /** Go to next whole second (frames == 0 or frames == 2) */
259 Wrap
260 increment_seconds( Time& smpte )
261 {
262         Wrap wrap = NONE;
263   
264         // Clear subframes
265         frames_floor( smpte );
266   
267         if (smpte.negative) {
268                 // Wrap second if on second boundary
269                 wrap = increment(smpte);
270                 // Go to lowest absolute frame value
271                 seconds_floor( smpte );
272                 if (SMPTE_IS_ZERO(smpte)) {
273                         smpte.negative = false;
274                 }
275         } else {
276                 // Go to highest possible frame in this second
277                 switch (smpte.rate) {
278                 case MTC_24_FPS:
279                         smpte.frames = 23;
280                         break;
281                 case MTC_25_FPS:
282                         smpte.frames = 24;
283                         break;
284                 case MTC_30_FPS_DROP:
285                 case MTC_30_FPS:
286                         smpte.frames = 29;
287                         break;
288                 }
289     
290                 // Increment by one frame
291                 wrap = increment( smpte );
292         }
293   
294         return wrap;
295 }
296
297
298 /** Go to lowest (absolute) frame value in this second
299  * Doesn't care about positive/negative */
300 void
301 seconds_floor( Time& smpte )
302 {
303         // Clear subframes
304         frames_floor( smpte );
305   
306         // Go to lowest possible frame in this second
307         switch (smpte.rate) {
308         case MTC_24_FPS:
309         case MTC_25_FPS:
310         case MTC_30_FPS:
311                 smpte.frames = 0;
312                 break;
313         case MTC_30_FPS_DROP:
314                 if ((smpte.minutes % 10) && (smpte.seconds == 0)) {
315                         smpte.frames = 2;
316                 } else {
317                         smpte.frames = 0;
318                 }
319                 break;
320         }
321   
322         if (SMPTE_IS_ZERO(smpte)) {
323                 smpte.negative = false;
324         }
325 }
326
327
328 /** Go to next whole minute (seconds == 0, frames == 0 or frames == 2) */
329 Wrap
330 increment_minutes( Time& smpte )
331 {
332         Wrap wrap = NONE;
333   
334         // Clear subframes
335         frames_floor( smpte );
336   
337         if (smpte.negative) {
338                 // Wrap if on minute boundary
339                 wrap = increment_seconds( smpte );
340                 // Go to lowest possible value in this minute
341                 minutes_floor( smpte );
342         } else {
343                 // Go to highest possible second
344                 smpte.seconds = 59;
345                 // Wrap minute by incrementing second
346                 wrap = increment_seconds( smpte );
347         }
348   
349         return wrap;
350 }
351
352
353 /** Go to lowest absolute value in this minute */
354 void
355 minutes_floor( Time& smpte )
356 {
357         // Go to lowest possible second
358         smpte.seconds = 0;
359         // Go to lowest possible frame
360         seconds_floor( smpte );
361
362         if (SMPTE_IS_ZERO(smpte)) {
363                 smpte.negative = false;
364         }
365 }
366
367
368 /** Go to next whole hour (minute = 0, second = 0, frame = 0) */
369 Wrap
370 increment_hours( Time& smpte )
371 {
372         Wrap wrap = NONE;
373   
374         // Clear subframes
375         frames_floor(smpte);
376   
377         if (smpte.negative) {
378                 // Wrap if on hour boundary
379                 wrap = increment_minutes( smpte );
380                 // Go to lowest possible value in this hour
381                 hours_floor( smpte );
382         } else {
383                 smpte.minutes = 59;
384                 wrap = increment_minutes( smpte );
385         }
386   
387         return wrap;
388 }
389
390
391 /** Go to lowest absolute value in this hour */
392 void
393 hours_floor( Time& smpte )
394 {
395         smpte.minutes = 0;
396         smpte.seconds = 0;
397         smpte.frames = 0;
398         smpte.subframes = 0;
399   
400         if (SMPTE_IS_ZERO(smpte)) {
401                 smpte.negative = false;
402         }
403 }
404
405
406 } // namespace SMPTE