summaryrefslogtreecommitdiff
path: root/audio_codec/libmad/timer.c (plain)
blob: ea80706e3e810779c7bfd2d8632cf340a967b597
1/*
2 * libmad - MPEG audio decoder library
3 * Copyright (C) 2000-2004 Underbit Technologies, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * $Id: timer.c,v 1.18 2004/01/23 09:41:33 rob Exp $
20 */
21
22# ifdef HAVE_CONFIG_H
23# include "config.h"
24# endif
25
26# include "global.h"
27
28# include <stdio.h>
29
30# ifdef HAVE_ASSERT_H
31# include <assert.h>
32# endif
33
34# include "timer.h"
35
36mad_timer_t const mad_timer_zero = { 0, 0 };
37
38/*
39 * NAME: timer->compare()
40 * DESCRIPTION: indicate relative order of two timers
41 */
42int mad_timer_compare(mad_timer_t timer1, mad_timer_t timer2)
43{
44 signed long diff;
45
46 diff = timer1.seconds - timer2.seconds;
47 if (diff < 0) {
48 return -1;
49 } else if (diff > 0) {
50 return +1;
51 }
52
53 diff = timer1.fraction - timer2.fraction;
54 if (diff < 0) {
55 return -1;
56 } else if (diff > 0) {
57 return +1;
58 }
59
60 return 0;
61}
62
63/*
64 * NAME: timer->negate()
65 * DESCRIPTION: invert the sign of a timer
66 */
67void mad_timer_negate(mad_timer_t *timer)
68{
69 timer->seconds = -timer->seconds;
70
71 if (timer->fraction) {
72 timer->seconds -= 1;
73 timer->fraction = MAD_TIMER_RESOLUTION - timer->fraction;
74 }
75}
76
77/*
78 * NAME: timer->abs()
79 * DESCRIPTION: return the absolute value of a timer
80 */
81mad_timer_t mad_timer_abs(mad_timer_t timer)
82{
83 if (timer.seconds < 0) {
84 mad_timer_negate(&timer);
85 }
86
87 return timer;
88}
89
90/*
91 * NAME: reduce_timer()
92 * DESCRIPTION: carry timer fraction into seconds
93 */
94static
95void reduce_timer(mad_timer_t *timer)
96{
97 timer->seconds += timer->fraction / MAD_TIMER_RESOLUTION;
98 timer->fraction %= MAD_TIMER_RESOLUTION;
99}
100
101/*
102 * NAME: gcd()
103 * DESCRIPTION: compute greatest common denominator
104 */
105static
106unsigned long gcd(unsigned long num1, unsigned long num2)
107{
108 unsigned long tmp;
109
110 while (num2) {
111 tmp = num2;
112 num2 = num1 % num2;
113 num1 = tmp;
114 }
115
116 return num1;
117}
118
119/*
120 * NAME: reduce_rational()
121 * DESCRIPTION: convert rational expression to lowest terms
122 */
123static
124void reduce_rational(unsigned long *numer, unsigned long *denom)
125{
126 unsigned long factor;
127
128 factor = gcd(*numer, *denom);
129
130 assert(factor != 0);
131
132 *numer /= factor;
133 *denom /= factor;
134}
135
136/*
137 * NAME: scale_rational()
138 * DESCRIPTION: solve numer/denom == ?/scale avoiding overflowing
139 */
140static
141unsigned long scale_rational(unsigned long numer, unsigned long denom,
142 unsigned long scale)
143{
144 reduce_rational(&numer, &denom);
145 reduce_rational(&scale, &denom);
146
147 assert(denom != 0);
148
149 if (denom < scale) {
150 return numer * (scale / denom) + numer * (scale % denom) / denom;
151 }
152 if (denom < numer) {
153 return scale * (numer / denom) + scale * (numer % denom) / denom;
154 }
155
156 return numer * scale / denom;
157}
158
159/*
160 * NAME: timer->set()
161 * DESCRIPTION: set timer to specific (positive) value
162 */
163void mad_timer_set(mad_timer_t *timer, unsigned long seconds,
164 unsigned long numer, unsigned long denom)
165{
166 timer->seconds = seconds;
167 if (numer >= denom && denom > 0) {
168 timer->seconds += numer / denom;
169 numer %= denom;
170 }
171
172 switch (denom) {
173 case 0:
174 case 1:
175 timer->fraction = 0;
176 break;
177
178 case MAD_TIMER_RESOLUTION:
179 timer->fraction = numer;
180 break;
181
182 case 1000:
183 timer->fraction = numer * (MAD_TIMER_RESOLUTION / 1000);
184 break;
185
186 case 8000:
187 timer->fraction = numer * (MAD_TIMER_RESOLUTION / 8000);
188 break;
189
190 case 11025:
191 timer->fraction = numer * (MAD_TIMER_RESOLUTION / 11025);
192 break;
193
194 case 12000:
195 timer->fraction = numer * (MAD_TIMER_RESOLUTION / 12000);
196 break;
197
198 case 16000:
199 timer->fraction = numer * (MAD_TIMER_RESOLUTION / 16000);
200 break;
201
202 case 22050:
203 timer->fraction = numer * (MAD_TIMER_RESOLUTION / 22050);
204 break;
205
206 case 24000:
207 timer->fraction = numer * (MAD_TIMER_RESOLUTION / 24000);
208 break;
209
210 case 32000:
211 timer->fraction = numer * (MAD_TIMER_RESOLUTION / 32000);
212 break;
213
214 case 44100:
215 timer->fraction = numer * (MAD_TIMER_RESOLUTION / 44100);
216 break;
217
218 case 48000:
219 timer->fraction = numer * (MAD_TIMER_RESOLUTION / 48000);
220 break;
221
222 default:
223 timer->fraction = scale_rational(numer, denom, MAD_TIMER_RESOLUTION);
224 break;
225 }
226
227 if (timer->fraction >= MAD_TIMER_RESOLUTION) {
228 reduce_timer(timer);
229 }
230}
231
232/*
233 * NAME: timer->add()
234 * DESCRIPTION: add one timer to another
235 */
236void mad_timer_add(mad_timer_t *timer, mad_timer_t incr)
237{
238 timer->seconds += incr.seconds;
239 timer->fraction += incr.fraction;
240
241 if (timer->fraction >= MAD_TIMER_RESOLUTION) {
242 reduce_timer(timer);
243 }
244}
245
246/*
247 * NAME: timer->multiply()
248 * DESCRIPTION: multiply a timer by a scalar value
249 */
250void mad_timer_multiply(mad_timer_t *timer, signed long scalar)
251{
252 mad_timer_t addend;
253 unsigned long factor;
254
255 factor = scalar;
256 if (scalar < 0) {
257 factor = -scalar;
258 mad_timer_negate(timer);
259 }
260
261 addend = *timer;
262 *timer = mad_timer_zero;
263
264 while (factor) {
265 if (factor & 1) {
266 mad_timer_add(timer, addend);
267 }
268
269 mad_timer_add(&addend, addend);
270 factor >>= 1;
271 }
272}
273
274/*
275 * NAME: timer->count()
276 * DESCRIPTION: return timer value in selected units
277 */
278signed long mad_timer_count(mad_timer_t timer, enum mad_units units)
279{
280 switch (units) {
281 case MAD_UNITS_HOURS:
282 return timer.seconds / 60 / 60;
283
284 case MAD_UNITS_MINUTES:
285 return timer.seconds / 60;
286
287 case MAD_UNITS_SECONDS:
288 return timer.seconds;
289
290 case MAD_UNITS_DECISECONDS:
291 case MAD_UNITS_CENTISECONDS:
292 case MAD_UNITS_MILLISECONDS:
293
294 case MAD_UNITS_8000_HZ:
295 case MAD_UNITS_11025_HZ:
296 case MAD_UNITS_12000_HZ:
297 case MAD_UNITS_16000_HZ:
298 case MAD_UNITS_22050_HZ:
299 case MAD_UNITS_24000_HZ:
300 case MAD_UNITS_32000_HZ:
301 case MAD_UNITS_44100_HZ:
302 case MAD_UNITS_48000_HZ:
303
304 case MAD_UNITS_24_FPS:
305 case MAD_UNITS_25_FPS:
306 case MAD_UNITS_30_FPS:
307 case MAD_UNITS_48_FPS:
308 case MAD_UNITS_50_FPS:
309 case MAD_UNITS_60_FPS:
310 case MAD_UNITS_75_FPS:
311 return timer.seconds * (signed long) units +
312 (signed long) scale_rational(timer.fraction, MAD_TIMER_RESOLUTION,
313 units);
314
315 case MAD_UNITS_23_976_FPS:
316 case MAD_UNITS_24_975_FPS:
317 case MAD_UNITS_29_97_FPS:
318 case MAD_UNITS_47_952_FPS:
319 case MAD_UNITS_49_95_FPS:
320 case MAD_UNITS_59_94_FPS:
321 return (mad_timer_count(timer, -units) + 1) * 1000 / 1001;
322 }
323
324 /* unsupported units */
325 return 0;
326}
327
328/*
329 * NAME: timer->fraction()
330 * DESCRIPTION: return fractional part of timer in arbitrary terms
331 */
332unsigned long mad_timer_fraction(mad_timer_t timer, unsigned long denom)
333{
334 timer = mad_timer_abs(timer);
335
336 switch (denom) {
337 case 0:
338 return timer.fraction ?
339 MAD_TIMER_RESOLUTION / timer.fraction : MAD_TIMER_RESOLUTION + 1;
340
341 case MAD_TIMER_RESOLUTION:
342 return timer.fraction;
343
344 default:
345 return scale_rational(timer.fraction, MAD_TIMER_RESOLUTION, denom);
346 }
347}
348
349/*
350 * NAME: timer->string()
351 * DESCRIPTION: write a string representation of a timer using a template
352 */
353void mad_timer_string(mad_timer_t timer,
354 char *dest, char const *format, enum mad_units units,
355 enum mad_units fracunits, unsigned long subparts)
356{
357 unsigned long hours, minutes, seconds, sub;
358 unsigned int frac;
359
360 timer = mad_timer_abs(timer);
361
362 seconds = timer.seconds;
363 frac = sub = 0;
364
365 switch (fracunits) {
366 case MAD_UNITS_HOURS:
367 case MAD_UNITS_MINUTES:
368 case MAD_UNITS_SECONDS:
369 break;
370
371 case MAD_UNITS_DECISECONDS:
372 case MAD_UNITS_CENTISECONDS:
373 case MAD_UNITS_MILLISECONDS:
374
375 case MAD_UNITS_8000_HZ:
376 case MAD_UNITS_11025_HZ:
377 case MAD_UNITS_12000_HZ:
378 case MAD_UNITS_16000_HZ:
379 case MAD_UNITS_22050_HZ:
380 case MAD_UNITS_24000_HZ:
381 case MAD_UNITS_32000_HZ:
382 case MAD_UNITS_44100_HZ:
383 case MAD_UNITS_48000_HZ:
384
385 case MAD_UNITS_24_FPS:
386 case MAD_UNITS_25_FPS:
387 case MAD_UNITS_30_FPS:
388 case MAD_UNITS_48_FPS:
389 case MAD_UNITS_50_FPS:
390 case MAD_UNITS_60_FPS:
391 case MAD_UNITS_75_FPS: {
392 unsigned long denom;
393
394 denom = MAD_TIMER_RESOLUTION / fracunits;
395
396 frac = timer.fraction / denom;
397 sub = scale_rational(timer.fraction % denom, denom, subparts);
398 }
399 break;
400
401 case MAD_UNITS_23_976_FPS:
402 case MAD_UNITS_24_975_FPS:
403 case MAD_UNITS_29_97_FPS:
404 case MAD_UNITS_47_952_FPS:
405 case MAD_UNITS_49_95_FPS:
406 case MAD_UNITS_59_94_FPS:
407 /* drop-frame encoding */
408 /* N.B. this is only well-defined for MAD_UNITS_29_97_FPS */
409 {
410 unsigned long frame, cycle, d, m;
411
412 frame = mad_timer_count(timer, fracunits);
413
414 cycle = -fracunits * 60 * 10 - (10 - 1) * 2;
415
416 d = frame / cycle;
417 m = frame % cycle;
418 frame += (10 - 1) * 2 * d;
419 if (m > 2) {
420 frame += 2 * ((m - 2) / (cycle / 10));
421 }
422
423 frac = frame % -fracunits;
424 seconds = frame / -fracunits;
425 }
426 break;
427 }
428
429 switch (units) {
430 case MAD_UNITS_HOURS:
431 minutes = seconds / 60;
432 hours = minutes / 60;
433
434 sprintf(dest, format,
435 hours,
436 (unsigned int)(minutes % 60),
437 (unsigned int)(seconds % 60),
438 frac, sub);
439 break;
440
441 case MAD_UNITS_MINUTES:
442 minutes = seconds / 60;
443
444 sprintf(dest, format,
445 minutes,
446 (unsigned int)(seconds % 60),
447 frac, sub);
448 break;
449
450 case MAD_UNITS_SECONDS:
451 sprintf(dest, format,
452 seconds,
453 frac, sub);
454 break;
455
456 case MAD_UNITS_23_976_FPS:
457 case MAD_UNITS_24_975_FPS:
458 case MAD_UNITS_29_97_FPS:
459 case MAD_UNITS_47_952_FPS:
460 case MAD_UNITS_49_95_FPS:
461 case MAD_UNITS_59_94_FPS:
462 if (fracunits < 0) {
463 /* not yet implemented */
464 sub = 0;
465 }
466
467 /* fall through */
468
469 case MAD_UNITS_DECISECONDS:
470 case MAD_UNITS_CENTISECONDS:
471 case MAD_UNITS_MILLISECONDS:
472
473 case MAD_UNITS_8000_HZ:
474 case MAD_UNITS_11025_HZ:
475 case MAD_UNITS_12000_HZ:
476 case MAD_UNITS_16000_HZ:
477 case MAD_UNITS_22050_HZ:
478 case MAD_UNITS_24000_HZ:
479 case MAD_UNITS_32000_HZ:
480 case MAD_UNITS_44100_HZ:
481 case MAD_UNITS_48000_HZ:
482
483 case MAD_UNITS_24_FPS:
484 case MAD_UNITS_25_FPS:
485 case MAD_UNITS_30_FPS:
486 case MAD_UNITS_48_FPS:
487 case MAD_UNITS_50_FPS:
488 case MAD_UNITS_60_FPS:
489 case MAD_UNITS_75_FPS:
490 sprintf(dest, format, mad_timer_count(timer, units), sub);
491 break;
492 }
493}
494