Cleanup: remove redundant doxygen \file argument
[blender.git] / source / blender / blenlib / intern / timecode.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file \ingroup blendlib
21  *
22  * Time-Code string formatting
23  */
24
25 #include <stdio.h>
26
27
28 #include "BLI_utildefines.h"
29 #include "BLI_string.h"
30 #include "BLI_math.h"
31
32 #include "BLI_timecode.h"  /* own include */
33
34 #include "DNA_userdef_types.h"  /* for eTimecodeStyles only */
35
36 #include "BLI_strict_flags.h"
37
38 /**
39  * Generate timecode/frame number string and store in \a str
40  *
41  * \param str: destination string
42  * \param maxncpy: maximum number of characters to copy ``sizeof(str)``
43  * \param power: special setting for #View2D grid drawing,
44  *        used to specify how detailed we need to be
45  * \param time_seconds: time total time in seconds
46  * \param fps: frames per second, typically from the #FPS macro
47  * \param timecode_style: enum from eTimecodeStyles
48  * \return length of \a str
49  */
50
51 size_t BLI_timecode_string_from_time(
52         char *str, const size_t maxncpy, const int power, const float time_seconds,
53         const double fps, const short timecode_style)
54 {
55         int hours = 0, minutes = 0, seconds = 0, frames = 0;
56         float time = time_seconds;
57         char neg[2] = {'\0'};
58         size_t rlen;
59
60         /* get cframes */
61         if (time < 0) {
62                 /* correction for negative cfraues */
63                 neg[0] = '-';
64                 time = -time;
65         }
66
67         if (time >= 3600.0f) {
68                 /* hours */
69                 /* XXX should we only display a single digit for hours since clips are
70                  *     VERY UNLIKELY to be more than 1-2 hours max? However, that would
71                  *     go against conventions...
72                  */
73                 hours = (int)time / 3600;
74                 time = fmodf(time, 3600);
75         }
76
77         if (time >= 60.0f) {
78                 /* minutes */
79                 minutes = (int)time / 60;
80                 time = fmodf(time, 60);
81         }
82
83         if (power <= 0) {
84                 /* seconds + frames
85                  * Frames are derived from 'fraction' of second. We need to perform some additional rounding
86                  * to cope with 'half' frames, etc., which should be fine in most cases
87                  */
88                 seconds = (int)time;
89                 frames = round_fl_to_int((float)(((double)time - (double)seconds) * fps));
90         }
91         else {
92                 /* seconds (with pixel offset rounding) */
93                 seconds = round_fl_to_int(time);
94         }
95
96         switch (timecode_style) {
97                 case USER_TIMECODE_MINIMAL:
98                 {
99                         /* - In general, minutes and seconds should be shown, as most clips will be
100                          *   within this length. Hours will only be included if relevant.
101                          * - Only show frames when zoomed in enough for them to be relevant
102                          *   (using separator of '+' for frames).
103                          *   When showing frames, use slightly different display to avoid confusion with mm:ss format
104                          */
105                         if (power <= 0) {
106                                 /* include "frames" in display */
107                                 if (hours) {
108                                         rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
109                                 }
110                                 else if (minutes) {
111                                         rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
112                                 }
113                                 else {
114                                         rlen = BLI_snprintf_rlen(str, maxncpy, "%s%d+%02d", neg, seconds, frames);
115                                 }
116                         }
117                         else {
118                                 /* don't include 'frames' in display */
119                                 if (hours) {
120                                         rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
121                                 }
122                                 else {
123                                         rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds);
124                                 }
125                         }
126                         break;
127                 }
128                 case USER_TIMECODE_SMPTE_MSF:
129                 {
130                         /* reduced SMPTE format that always shows minutes, seconds, frames.
131                          * Hours only shown as needed. */
132                         if (hours) {
133                                 rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
134                         }
135                         else {
136                                 rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
137                         }
138                         break;
139                 }
140                 case USER_TIMECODE_MILLISECONDS:
141                 {
142                         /* reduced SMPTE. Instead of frames, milliseconds are shown */
143
144                         /* precision of decimal part */
145                         const int ms_dp = (power <= 0) ? (1 - power) : 1;
146
147                         /* to get 2 digit whole-number part for seconds display
148                          * (i.e. 3 is for 2 digits + radix, on top of full length) */
149                         const int s_pad = ms_dp + 3;
150
151                         if (hours) {
152                                 rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time);
153                         }
154                         else {
155                                 rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad,  ms_dp, time);
156                         }
157                         break;
158                 }
159                 case USER_TIMECODE_SUBRIP:
160                 {
161                         /* SubRip, like SMPTE milliseconds but seconds and milliseconds
162                          * are separated by a comma, not a dot... */
163
164                         /* precision of decimal part */
165                         const int ms_dp = (power <= 0) ? (1 - power) : 1;
166                         const int ms = round_fl_to_int((time - (float)seconds) * 1000.0f);
167
168                         rlen = BLI_snprintf_rlen(
169                                    str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms);
170                         break;
171                 }
172                 case USER_TIMECODE_SECONDS_ONLY:
173                 {
174                         /* only show the original seconds display */
175                         /* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
176                         if (power <= 0) {
177                                 rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds);
178                         }
179                         else {
180                                 rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
181                         }
182                         break;
183                 }
184                 case USER_TIMECODE_SMPTE_FULL:
185                 default:
186                 {
187                         /* full SMPTE format */
188                         rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
189                         break;
190                 }
191         }
192
193         return rlen;
194 }
195
196 /**
197  * Generate time string and store in \a str
198  *
199  * \param str: destination string
200  * \param maxncpy: maximum number of characters to copy ``sizeof(str)``
201  * \param time_seconds: time total time in seconds
202  * \return length of \a str
203  */
204 size_t BLI_timecode_string_from_time_simple(
205         char *str, const size_t maxncpy, const double time_seconds)
206 {
207         size_t rlen;
208
209         /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
210         const int  hr = ( (int)  time_seconds) / (60 * 60);
211         const int min = (((int)  time_seconds) / 60 ) % 60;
212         const int sec = ( (int)  time_seconds) % 60;
213         const int hun = ( (int) (time_seconds   * 100.0)) % 100;
214
215         if (hr) {
216                 rlen = BLI_snprintf(str, maxncpy, "%.2d:%.2d:%.2d.%.2d", hr, min, sec, hun);
217         }
218         else {
219                 rlen = BLI_snprintf(str, maxncpy, "%.2d:%.2d.%.2d", min, sec, hun);
220         }
221
222         return rlen;
223 }
224
225 /**
226  * Generate time string and store in \a str
227  *
228  * \param str: destination string
229  * \param maxncpy: maximum number of characters to copy ``sizeof(str)``
230  * \param power: special setting for #View2D grid drawing,
231  *        used to specify how detailed we need to be
232  * \param time_seconds: time total time in seconds
233  * \return length of \a str
234  *
235  * \note in some cases this is used to print non-seconds values.
236  */
237 size_t BLI_timecode_string_from_time_seconds(
238         char *str, const size_t maxncpy, const int power, const float time_seconds)
239 {
240         size_t rlen;
241
242         /* round to whole numbers if power is >= 1 (i.e. scale is coarse) */
243         if (power <= 0) {
244                 rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - power, time_seconds);
245         }
246         else {
247                 rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
248         }
249
250         return rlen;
251 }