mad: Avoid calling mad_timer_add() twice
[cmus.git] / nomad.c
blob076b4c787be6744f92e312989caa5d079f6b2b76
1 /*
2 * Copyright 2004-2005 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
21 * Xing code copied from xmms-mad plugin.
25 #include "nomad.h"
26 #include "id3.h"
27 #include "xmalloc.h"
28 #include "debug.h"
30 #include <mad.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <errno.h>
35 struct seek_idx_entry {
36 off_t offset;
37 mad_timer_t timer;
40 struct nomad {
41 struct mad_stream stream;
42 struct mad_frame frame;
43 struct mad_synth synth;
44 mad_timer_t timer;
45 unsigned long cur_frame;
46 off_t input_offset;
47 unsigned char input_buffer[INPUT_BUFFER_SIZE];
48 int i;
49 unsigned int fast : 1;
50 unsigned int has_xing : 1;
52 struct {
53 unsigned int flags;
54 unsigned int nr_frames;
55 unsigned int bytes;
56 unsigned int scale;
57 unsigned char toc[100];
58 } xing;
60 struct {
61 int size;
62 struct seek_idx_entry *table;
63 } seek_idx;
65 struct nomad_info info;
66 void *datasource;
67 int datasource_fd;
68 struct nomad_callbacks cbs;
71 /* ------------------------------------------------------------------------- */
73 static ssize_t default_read(void *datasource, void *buffer, size_t count)
75 int fd = *(int *)datasource;
77 return read(fd, buffer, count);
80 static off_t default_lseek(void *datasource, off_t offset, int whence)
82 int fd = *(int *)datasource;
84 return lseek(fd, offset, whence);
87 static int default_close(void *datasource)
89 int fd = *(int *)datasource;
91 return close(fd);
94 /* ------------------------------------------------------------------------- */
96 static inline int scale(mad_fixed_t sample)
98 sample += 1L << (MAD_F_FRACBITS - 16);
99 if (sample >= MAD_F_ONE) {
100 sample = MAD_F_ONE - 1;
101 } else if (sample < -MAD_F_ONE) {
102 sample = -MAD_F_ONE;
104 return sample >> (MAD_F_FRACBITS - 15);
107 static inline double timer_to_seconds(mad_timer_t timer)
109 signed long ms;
111 ms = mad_timer_count(timer, MAD_UNITS_MILLISECONDS);
112 return (double)ms / 1000.0;
115 enum {
116 XING_FRAMES = 0x00000001L,
117 XING_BYTES = 0x00000002L,
118 XING_TOC = 0x00000004L,
119 XING_SCALE = 0x00000008L
123 * format:
125 * 4 "Xing"
126 * 4 flags
127 * 4 frames (optional)
128 * 4 bytes (optional)
129 * 100 TOC (optional)
130 * 4 scale (optional)
132 static int xing_parse(struct nomad *nomad)
134 struct mad_bitptr ptr = nomad->stream.anc_ptr;
135 int bitlen = nomad->stream.anc_bitlen;
137 nomad->has_xing = 0;
138 if (bitlen < 64)
139 return -1;
140 if (mad_bit_read(&ptr, 32) != (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g'))
141 return -1;
142 nomad->xing.flags = mad_bit_read(&ptr, 32);
143 bitlen -= 64;
144 if (nomad->xing.flags & XING_FRAMES) {
145 if (bitlen < 32)
146 return -1;
147 nomad->xing.nr_frames = mad_bit_read(&ptr, 32);
148 bitlen -= 32;
150 if (nomad->xing.flags & XING_BYTES) {
151 if (bitlen < 32)
152 return -1;
153 nomad->xing.bytes = mad_bit_read(&ptr, 32);
154 bitlen -= 32;
156 if (nomad->xing.flags & XING_TOC) {
157 int i;
159 if (bitlen < 800)
160 return -1;
161 for (i = 0; i < 100; i++)
162 nomad->xing.toc[i] = mad_bit_read(&ptr, 8);
163 bitlen -= 800;
165 if (nomad->xing.flags & XING_SCALE) {
166 if (bitlen < 32)
167 return -1;
168 nomad->xing.scale = mad_bit_read(&ptr, 32);
169 bitlen -= 32;
171 nomad->has_xing = 1;
172 #if defined(DEBUG_XING)
173 if (nomad->xing.flags & XING_FRAMES)
174 d_print("frames: %d (xing)\n", nomad->xing.nr_frames);
175 #endif
176 return 0;
180 * returns:
181 * 0: eof
182 * -1: error
183 * >0: ok
185 static int fill_buffer(struct nomad *nomad)
187 if (nomad->stream.buffer == NULL || nomad->stream.error == MAD_ERROR_BUFLEN) {
188 ssize_t read_size, remaining, len;
189 unsigned char *read_start;
191 if (nomad->stream.next_frame != NULL) {
192 remaining = nomad->stream.bufend - nomad->stream.next_frame;
193 memmove(nomad->input_buffer, nomad->stream.next_frame, remaining);
194 read_start = nomad->input_buffer + remaining;
195 read_size = INPUT_BUFFER_SIZE - remaining;
196 } else {
197 read_size = INPUT_BUFFER_SIZE;
198 read_start = nomad->input_buffer;
199 remaining = 0;
201 read_size = nomad->cbs.read(nomad->datasource, read_start, read_size);
202 if (read_size == -1) {
203 if (errno != EAGAIN)
204 d_print("read error on bitstream (%d:%s)\n", errno, strerror(errno));
205 return -1;
207 if (read_size == 0)
208 return 0;
210 len = read_size + remaining;
212 nomad->input_offset += read_size;
213 #if 0
214 if (len < MAD_BUFFER_GUARD) {
215 memset(nomad->input_buffer + len, 0, MAD_BUFFER_GUARD - len);
216 len = MAD_BUFFER_GUARD;
218 #endif
219 mad_stream_buffer(&nomad->stream, nomad->input_buffer, len);
220 nomad->stream.error = 0;
222 return 1;
225 static void handle_lost_sync(struct nomad *nomad)
227 unsigned long frame;
228 int size;
230 frame = nomad->cur_frame;
231 if (frame == 0) {
232 /* cur_frame is not set when scanning file */
233 frame = nomad->info.nr_frames;
236 size = id3_tag_size((const char *)nomad->stream.this_frame,
237 nomad->stream.bufend - nomad->stream.this_frame);
238 if (size > 0) {
239 d_print("frame %ld, skipping ID3 tag (%d bytes)\n", frame, size);
240 mad_stream_skip(&nomad->stream, size);
241 } else {
242 d_print("frame %ld\n", frame);
247 /* Builds a seek index as the file is decoded
248 * NOTE: increases nomad->timer (current position)
250 static void build_seek_index(struct nomad *nomad)
252 mad_timer_t timer_now = nomad->timer;
253 off_t offset;
254 int idx;
256 mad_timer_add(&nomad->timer, nomad->frame.header.duration);
258 if (nomad->has_xing)
259 return;
261 if (nomad->timer.seconds < (nomad->seek_idx.size + 1) * SEEK_IDX_INTERVAL)
262 return;
264 /* offset = ftell() */
265 offset = nomad->input_offset;
266 /* subtract by buffer length to get offset to start of buffer */
267 offset -= (nomad->stream.bufend - nomad->input_buffer);
268 /* then add offset to the current frame */
269 offset += (nomad->stream.this_frame - nomad->input_buffer);
271 idx = nomad->seek_idx.size;
273 nomad->seek_idx.table = xrenew(struct seek_idx_entry, nomad->seek_idx.table, idx + 1);
274 nomad->seek_idx.table[idx].offset = offset;
275 nomad->seek_idx.table[idx].timer = timer_now;
277 nomad->seek_idx.size++;
280 static void calc_fast(struct nomad *nomad)
282 nomad->info.avg_bitrate = -1;
283 nomad->info.vbr = -1;
284 if (nomad->has_xing && (nomad->xing.flags & XING_FRAMES)) {
285 nomad->info.nr_frames = nomad->xing.nr_frames;
286 mad_timer_multiply(&nomad->timer, nomad->info.nr_frames);
287 } else {
288 nomad->info.nr_frames = nomad->info.filesize /
289 (nomad->stream.next_frame - nomad->stream.this_frame);
290 mad_timer_multiply(&nomad->timer, nomad->info.nr_frames);
295 * fields
296 * nomad->info.avg_bitrate and
297 * nomad->info.vbr
298 * are filled only if fast = 0
300 static int scan(struct nomad *nomad)
302 struct mad_header *header = &nomad->frame.header;
303 int frame_decoded = 0;
304 int old_bitrate = 0;
305 unsigned long long int bitrate_sum = 0;
307 nomad->info.nr_frames = 0;
308 nomad->info.vbr = 0;
309 while (1) {
310 int rc;
312 rc = fill_buffer(nomad);
313 if (rc == -1)
314 return -1;
315 if (rc == 0)
316 break;
318 if (mad_header_decode(header, &nomad->stream)) {
319 if (!MAD_RECOVERABLE(nomad->stream.error) && nomad->stream.error != MAD_ERROR_BUFLEN) {
320 d_print("unrecoverable frame level error.\n");
321 return -1;
323 if (nomad->stream.error == MAD_ERROR_LOSTSYNC)
324 handle_lost_sync(nomad);
325 continue;
328 build_seek_index(nomad);
329 bitrate_sum += header->bitrate;
330 nomad->info.nr_frames++;
332 if (!frame_decoded) {
333 nomad->info.sample_rate = header->samplerate;
334 nomad->info.channels = MAD_NCHANNELS(header);
335 nomad->info.layer = header->layer;
336 nomad->info.dual_channel = header->mode == MAD_MODE_DUAL_CHANNEL;
337 nomad->info.joint_stereo = header->mode == MAD_MODE_JOINT_STEREO;
339 if (mad_frame_decode(&nomad->frame, &nomad->stream) == -1) {
340 if (nomad->stream.error == MAD_ERROR_BUFLEN)
341 continue;
342 if (!MAD_RECOVERABLE(nomad->stream.error)) {
343 d_print("unrecoverable frame level error.\n");
344 return -1;
346 if (nomad->stream.error == MAD_ERROR_LOSTSYNC)
347 handle_lost_sync(nomad);
348 continue;
350 frame_decoded = 1;
351 xing_parse(nomad);
353 if (nomad->fast) {
354 calc_fast(nomad);
355 break;
357 } else {
358 if (old_bitrate != header->bitrate)
359 nomad->info.vbr = 1;
361 old_bitrate = header->bitrate;
363 if (nomad->info.nr_frames == 0) {
364 d_print("error: not an mp3 file!\n");
365 return -NOMAD_ERROR_FILE_FORMAT;
367 nomad->info.duration = timer_to_seconds(nomad->timer);
368 if (!nomad->fast)
369 nomad->info.avg_bitrate = bitrate_sum / nomad->info.nr_frames;
370 nomad->cur_frame = 0;
371 nomad->cbs.lseek(nomad->datasource, 0, SEEK_SET);
372 nomad->input_offset = 0;
373 return 0;
376 static int decode(struct nomad *nomad)
378 int rc;
380 start:
381 rc = fill_buffer(nomad);
382 if (rc == -1)
383 return -1;
384 if (rc == 0)
385 return 1;
387 if (mad_frame_decode(&nomad->frame, &nomad->stream)) {
388 if (nomad->stream.error == MAD_ERROR_BUFLEN)
389 goto start;
390 if (!MAD_RECOVERABLE(nomad->stream.error)) {
391 d_print("unrecoverable frame level error.\n");
392 return -1;
394 if (nomad->stream.error == MAD_ERROR_LOSTSYNC)
395 handle_lost_sync(nomad);
396 goto start;
398 nomad->cur_frame++;
399 if (nomad->info.filesize > 0) {
400 build_seek_index(nomad);
401 } else {
402 mad_timer_add(&nomad->timer, nomad->frame.header.duration);
404 mad_synth_frame(&nomad->synth, &nomad->frame);
405 return 0;
408 static void init_mad(struct nomad *nomad)
410 mad_stream_init(&nomad->stream);
411 mad_frame_init(&nomad->frame);
412 mad_synth_init(&nomad->synth);
413 mad_timer_reset(&nomad->timer);
414 nomad->cur_frame = 0;
415 nomad->i = -1;
416 nomad->input_offset = 0;
419 static void free_mad(struct nomad *nomad)
421 mad_stream_finish(&nomad->stream);
422 mad_frame_finish(&nomad->frame);
423 mad_synth_finish(nomad->synth);
426 static int do_open(struct nomad *nomad, int fast)
428 int rc;
430 init_mad(nomad);
431 nomad->info.filesize = nomad->cbs.lseek(nomad->datasource, 0, SEEK_END);
432 if (nomad->info.filesize == -1) {
433 nomad->fast = 1;
434 } else {
435 nomad->fast = fast != 0;
436 nomad->cbs.lseek(nomad->datasource, 0, SEEK_SET);
438 if (nomad->info.filesize == -1) {
439 rc = decode(nomad);
440 if (rc < 0)
441 goto error;
442 if (rc == 1)
443 goto eof;
444 nomad->info.sample_rate = nomad->frame.header.samplerate;
445 nomad->info.channels = MAD_NCHANNELS(&nomad->frame.header);
446 nomad->info.layer = nomad->frame.header.layer;
447 nomad->info.dual_channel = nomad->frame.header.mode == MAD_MODE_DUAL_CHANNEL;
448 nomad->info.joint_stereo = nomad->frame.header.mode == MAD_MODE_JOINT_STEREO;
450 /* unknown */
451 nomad->info.duration = -1.0;
452 nomad->info.nr_frames = -1;
453 nomad->info.vbr = -1;
454 nomad->info.avg_bitrate = -1;
455 } else {
456 rc = scan(nomad);
457 if (rc < 0)
458 goto error;
459 if (rc == 1)
460 goto eof;
461 free_mad(nomad);
462 init_mad(nomad);
464 d_print("\n frames: %d, br: %d b/s, sr: %d Hz, ch: %d, layer: %d, joint stereo: %d\n"
465 " dual channel: %d, vbr: %d, duration: %g s, xing: %d\n",
466 nomad->info.nr_frames, nomad->info.avg_bitrate,
467 nomad->info.sample_rate, nomad->info.channels,
468 nomad->info.layer, nomad->info.joint_stereo,
469 nomad->info.dual_channel, nomad->info.vbr,
470 nomad->info.duration,
471 nomad->has_xing);
472 #if defined(DEBUG_XING)
473 if (nomad->has_xing)
474 d_print("xing: flags: 0x%x, frames: %d, bytes: %d, scale: %d\n",
475 nomad->xing.flags,
476 nomad->xing.nr_frames,
477 nomad->xing.bytes,
478 nomad->xing.scale);
479 #endif
480 return 0;
481 error:
482 nomad_close(nomad);
483 return rc;
484 eof:
485 nomad_close(nomad);
486 return -NOMAD_ERROR_FILE_FORMAT;
489 int nomad_open(struct nomad **nomadp, int fd, int fast)
491 struct nomad *nomad;
493 nomad = xnew0(struct nomad, 1);
494 nomad->datasource = &nomad->datasource_fd;
495 nomad->datasource_fd = fd;
496 nomad->cbs.read = default_read;
497 nomad->cbs.lseek = default_lseek;
498 nomad->cbs.close = default_close;
499 *nomadp = nomad;
500 /* on error do_open calls nomad_close */
501 return do_open(nomad, fast);
504 int nomad_open_callbacks(struct nomad **nomadp, void *datasource, int fast, struct nomad_callbacks *cbs)
506 struct nomad *nomad;
508 nomad = xnew0(struct nomad, 1);
509 nomad->datasource = datasource;
510 nomad->cbs = *cbs;
511 *nomadp = nomad;
512 /* on error do_open calls nomad_close */
513 return do_open(nomad, fast);
516 void nomad_close(struct nomad *nomad)
518 free_mad(nomad);
519 nomad->cbs.close(nomad->datasource);
520 free(nomad->seek_idx.table);
521 free(nomad);
524 void nomad_info(struct nomad *nomad, struct nomad_info *info)
526 *info = nomad->info;
529 int nomad_read(struct nomad *nomad, char *buffer, int count)
531 int i, j, size, psize, to;
533 if (nomad->i == -1) {
534 int rc;
536 rc = decode(nomad);
537 if (rc < 0)
538 return rc;
539 if (rc == 1)
540 return 0;
541 nomad->i = 0;
543 psize = nomad->info.channels * 16 / 8;
544 size = (nomad->synth.pcm.length - nomad->i) * psize;
545 if (size > count) {
546 to = nomad->i + count / psize;
547 } else {
548 to = nomad->synth.pcm.length;
550 j = 0;
551 for (i = nomad->i; i < to; i++) {
552 short sample;
554 sample = scale(nomad->synth.pcm.samples[0][i]);
555 buffer[j++] = (sample >> 0) & 0xff;
556 buffer[j++] = (sample >> 8) & 0xff;
558 if (nomad->info.channels == 2) {
559 sample = scale(nomad->synth.pcm.samples[1][i]);
560 buffer[j++] = (sample >> 0) & 0xff;
561 buffer[j++] = (sample >> 8) & 0xff;
564 if (to != nomad->synth.pcm.length) {
565 nomad->i = i;
566 } else {
567 nomad->i = -1;
569 return j;
572 int nomad_time_seek(struct nomad *nomad, double pos)
574 off_t offset = 0;
576 if (pos < 0.0 || pos > nomad->info.duration) {
577 errno = EINVAL;
578 return -1;
580 if (nomad->info.filesize == -1) {
581 errno = ESPIPE;
582 return -1;
584 free_mad(nomad);
585 init_mad(nomad);
587 /* calculate seek offset */
588 if (nomad->has_xing) {
589 /* seek to truncate(pos / duration * 100) / 100 * duration */
590 double k, tmp_pos;
591 int ki;
593 k = pos / nomad->info.duration * 100.0;
594 ki = k;
595 tmp_pos = ((double)ki) / 100.0 * nomad->info.duration;
596 nomad->timer.seconds = (signed int)tmp_pos;
597 nomad->timer.fraction = (tmp_pos - (double)nomad->timer.seconds) * MAD_TIMER_RESOLUTION;
598 #if defined(DEBUG_XING)
599 d_print("seeking to %g = %g %d%%\n",
600 pos,
601 timer_to_seconds(nomad->timer),
602 ki);
603 #endif
604 offset = ((unsigned long long)nomad->xing.toc[ki] * nomad->xing.bytes) / 256;
605 } else if (nomad->seek_idx.size > 0) {
606 int idx = (int)(pos / SEEK_IDX_INTERVAL) - 1;
608 if (idx > nomad->seek_idx.size - 1)
609 idx = nomad->seek_idx.size - 1;
611 if (idx >= 0) {
612 offset = nomad->seek_idx.table[idx].offset;
613 nomad->timer = nomad->seek_idx.table[idx].timer;
616 if (nomad->cbs.lseek(nomad->datasource, offset, SEEK_SET) < 0)
617 return -1;
619 nomad->input_offset = offset;
620 while (timer_to_seconds(nomad->timer) < pos) {
621 int rc;
623 rc = fill_buffer(nomad);
624 if (rc == -1)
625 return -1;
626 if (rc == 0)
627 return 0;
629 if (mad_header_decode(&nomad->frame.header, &nomad->stream) == 0) {
630 build_seek_index(nomad);
631 } else {
632 if (!MAD_RECOVERABLE(nomad->stream.error) && nomad->stream.error != MAD_ERROR_BUFLEN) {
633 d_print("unrecoverable frame level error.\n");
634 return -1;
636 if (nomad->stream.error == MAD_ERROR_LOSTSYNC)
637 handle_lost_sync(nomad);
640 #if defined(DEBUG_XING)
641 if (nomad->has_xing)
642 d_print("seeked to %g = %g\n", pos, timer_to_seconds(nomad->timer));
643 #endif
644 return 0;
647 double nomad_time_tell(struct nomad *nomad)
649 return timer_to_seconds(nomad->timer);
652 double nomad_time_total(struct nomad *nomad)
654 return nomad->info.duration;