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