Handle streams separately in tree_add_track()
[cmus.git] / nomad.c
blob74a05a27b122a65060c6c002baaa2df389f765e4
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 old_bitrate = 0;
304 unsigned long long int bitrate_sum = 0;
306 nomad->info.nr_frames = 0;
307 nomad->info.vbr = 0;
308 while (1) {
309 int rc;
311 rc = fill_buffer(nomad);
312 if (rc == -1)
313 return -1;
314 if (rc == 0)
315 break;
317 if (mad_frame_decode(&nomad->frame, &nomad->stream) == -1) {
318 if (nomad->stream.error == MAD_ERROR_BUFLEN)
319 continue;
320 if (!MAD_RECOVERABLE(nomad->stream.error)) {
321 d_print("unrecoverable frame level error.\n");
322 return -1;
324 if (nomad->stream.error == MAD_ERROR_LOSTSYNC)
325 handle_lost_sync(nomad);
326 continue;
329 build_seek_index(nomad);
330 bitrate_sum += header->bitrate;
331 nomad->info.nr_frames++;
333 if (nomad->info.nr_frames == 1) {
334 // first valid frame
335 nomad->info.sample_rate = header->samplerate;
336 nomad->info.channels = MAD_NCHANNELS(header);
337 nomad->info.layer = header->layer;
338 nomad->info.dual_channel = header->mode == MAD_MODE_DUAL_CHANNEL;
339 nomad->info.joint_stereo = header->mode == MAD_MODE_JOINT_STEREO;
341 xing_parse(nomad);
343 if (nomad->fast) {
344 calc_fast(nomad);
345 break;
347 } else {
348 if (old_bitrate != header->bitrate)
349 nomad->info.vbr = 1;
351 old_bitrate = header->bitrate;
353 if (nomad->info.nr_frames == 0) {
354 d_print("error: not an mp3 file!\n");
355 return -NOMAD_ERROR_FILE_FORMAT;
357 nomad->info.duration = timer_to_seconds(nomad->timer);
358 if (!nomad->fast)
359 nomad->info.avg_bitrate = bitrate_sum / nomad->info.nr_frames;
360 nomad->cur_frame = 0;
361 nomad->cbs.lseek(nomad->datasource, 0, SEEK_SET);
362 nomad->input_offset = 0;
363 return 0;
366 static int decode(struct nomad *nomad)
368 int rc;
370 start:
371 rc = fill_buffer(nomad);
372 if (rc == -1)
373 return -1;
374 if (rc == 0)
375 return 1;
377 if (mad_frame_decode(&nomad->frame, &nomad->stream)) {
378 if (nomad->stream.error == MAD_ERROR_BUFLEN)
379 goto start;
380 if (!MAD_RECOVERABLE(nomad->stream.error)) {
381 d_print("unrecoverable frame level error.\n");
382 return -1;
384 if (nomad->stream.error == MAD_ERROR_LOSTSYNC)
385 handle_lost_sync(nomad);
386 goto start;
388 nomad->cur_frame++;
389 if (nomad->info.filesize > 0) {
390 build_seek_index(nomad);
391 } else {
392 mad_timer_add(&nomad->timer, nomad->frame.header.duration);
394 mad_synth_frame(&nomad->synth, &nomad->frame);
395 return 0;
398 static void init_mad(struct nomad *nomad)
400 mad_stream_init(&nomad->stream);
401 mad_frame_init(&nomad->frame);
402 mad_synth_init(&nomad->synth);
403 mad_timer_reset(&nomad->timer);
404 nomad->cur_frame = 0;
405 nomad->i = -1;
406 nomad->input_offset = 0;
409 static void free_mad(struct nomad *nomad)
411 mad_stream_finish(&nomad->stream);
412 mad_frame_finish(&nomad->frame);
413 mad_synth_finish(nomad->synth);
416 static int do_open(struct nomad *nomad, int fast)
418 int rc;
420 init_mad(nomad);
421 nomad->info.filesize = nomad->cbs.lseek(nomad->datasource, 0, SEEK_END);
422 if (nomad->info.filesize == -1) {
423 nomad->fast = 1;
424 } else {
425 nomad->fast = fast != 0;
426 nomad->cbs.lseek(nomad->datasource, 0, SEEK_SET);
428 if (nomad->info.filesize == -1) {
429 rc = decode(nomad);
430 if (rc < 0)
431 goto error;
432 if (rc == 1)
433 goto eof;
434 nomad->info.sample_rate = nomad->frame.header.samplerate;
435 nomad->info.channels = MAD_NCHANNELS(&nomad->frame.header);
436 nomad->info.layer = nomad->frame.header.layer;
437 nomad->info.dual_channel = nomad->frame.header.mode == MAD_MODE_DUAL_CHANNEL;
438 nomad->info.joint_stereo = nomad->frame.header.mode == MAD_MODE_JOINT_STEREO;
440 /* unknown */
441 nomad->info.duration = -1.0;
442 nomad->info.nr_frames = -1;
443 nomad->info.vbr = -1;
444 nomad->info.avg_bitrate = -1;
445 } else {
446 rc = scan(nomad);
447 if (rc < 0)
448 goto error;
449 if (rc == 1)
450 goto eof;
451 free_mad(nomad);
452 init_mad(nomad);
454 d_print("\n frames: %d, br: %d b/s, sr: %d Hz, ch: %d, layer: %d, joint stereo: %d\n"
455 " dual channel: %d, vbr: %d, duration: %g s, xing: %d\n",
456 nomad->info.nr_frames, nomad->info.avg_bitrate,
457 nomad->info.sample_rate, nomad->info.channels,
458 nomad->info.layer, nomad->info.joint_stereo,
459 nomad->info.dual_channel, nomad->info.vbr,
460 nomad->info.duration,
461 nomad->has_xing);
462 #if defined(DEBUG_XING)
463 if (nomad->has_xing)
464 d_print("xing: flags: 0x%x, frames: %d, bytes: %d, scale: %d\n",
465 nomad->xing.flags,
466 nomad->xing.nr_frames,
467 nomad->xing.bytes,
468 nomad->xing.scale);
469 #endif
470 return 0;
471 error:
472 nomad_close(nomad);
473 return rc;
474 eof:
475 nomad_close(nomad);
476 return -NOMAD_ERROR_FILE_FORMAT;
479 int nomad_open(struct nomad **nomadp, int fd, int fast)
481 struct nomad *nomad;
483 nomad = xnew0(struct nomad, 1);
484 nomad->datasource = &nomad->datasource_fd;
485 nomad->datasource_fd = fd;
486 nomad->cbs.read = default_read;
487 nomad->cbs.lseek = default_lseek;
488 nomad->cbs.close = default_close;
489 *nomadp = nomad;
490 /* on error do_open calls nomad_close */
491 return do_open(nomad, fast);
494 int nomad_open_callbacks(struct nomad **nomadp, void *datasource, int fast, struct nomad_callbacks *cbs)
496 struct nomad *nomad;
498 nomad = xnew0(struct nomad, 1);
499 nomad->datasource = datasource;
500 nomad->cbs = *cbs;
501 *nomadp = nomad;
502 /* on error do_open calls nomad_close */
503 return do_open(nomad, fast);
506 void nomad_close(struct nomad *nomad)
508 free_mad(nomad);
509 nomad->cbs.close(nomad->datasource);
510 free(nomad->seek_idx.table);
511 free(nomad);
514 void nomad_info(struct nomad *nomad, struct nomad_info *info)
516 *info = nomad->info;
519 int nomad_read(struct nomad *nomad, char *buffer, int count)
521 int i, j, size, psize, to;
523 if (nomad->i == -1) {
524 int rc;
526 rc = decode(nomad);
527 if (rc < 0)
528 return rc;
529 if (rc == 1)
530 return 0;
531 nomad->i = 0;
533 psize = nomad->info.channels * 16 / 8;
534 size = (nomad->synth.pcm.length - nomad->i) * psize;
535 if (size > count) {
536 to = nomad->i + count / psize;
537 } else {
538 to = nomad->synth.pcm.length;
540 j = 0;
541 for (i = nomad->i; i < to; i++) {
542 short sample;
544 sample = scale(nomad->synth.pcm.samples[0][i]);
545 buffer[j++] = (sample >> 0) & 0xff;
546 buffer[j++] = (sample >> 8) & 0xff;
548 if (nomad->info.channels == 2) {
549 sample = scale(nomad->synth.pcm.samples[1][i]);
550 buffer[j++] = (sample >> 0) & 0xff;
551 buffer[j++] = (sample >> 8) & 0xff;
554 if (to != nomad->synth.pcm.length) {
555 nomad->i = i;
556 } else {
557 nomad->i = -1;
559 return j;
562 int nomad_time_seek(struct nomad *nomad, double pos)
564 off_t offset = 0;
566 if (pos < 0.0 || pos > nomad->info.duration) {
567 errno = EINVAL;
568 return -1;
570 if (nomad->info.filesize == -1) {
571 errno = ESPIPE;
572 return -1;
574 free_mad(nomad);
575 init_mad(nomad);
577 /* calculate seek offset */
578 if (nomad->has_xing) {
579 /* seek to truncate(pos / duration * 100) / 100 * duration */
580 double k, tmp_pos;
581 int ki;
583 k = pos / nomad->info.duration * 100.0;
584 ki = k;
585 tmp_pos = ((double)ki) / 100.0 * nomad->info.duration;
586 nomad->timer.seconds = (signed int)tmp_pos;
587 nomad->timer.fraction = (tmp_pos - (double)nomad->timer.seconds) * MAD_TIMER_RESOLUTION;
588 #if defined(DEBUG_XING)
589 d_print("seeking to %g = %g %d%%\n",
590 pos,
591 timer_to_seconds(nomad->timer),
592 ki);
593 #endif
594 offset = ((unsigned long long)nomad->xing.toc[ki] * nomad->xing.bytes) / 256;
595 } else if (nomad->seek_idx.size > 0) {
596 int idx = (int)(pos / SEEK_IDX_INTERVAL) - 1;
598 if (idx > nomad->seek_idx.size - 1)
599 idx = nomad->seek_idx.size - 1;
601 if (idx >= 0) {
602 offset = nomad->seek_idx.table[idx].offset;
603 nomad->timer = nomad->seek_idx.table[idx].timer;
606 if (nomad->cbs.lseek(nomad->datasource, offset, SEEK_SET) < 0)
607 return -1;
609 nomad->input_offset = offset;
610 while (timer_to_seconds(nomad->timer) < pos) {
611 int rc;
613 rc = fill_buffer(nomad);
614 if (rc == -1)
615 return -1;
616 if (rc == 0)
617 return 0;
619 if (mad_header_decode(&nomad->frame.header, &nomad->stream) == 0) {
620 build_seek_index(nomad);
621 } else {
622 if (!MAD_RECOVERABLE(nomad->stream.error) && nomad->stream.error != MAD_ERROR_BUFLEN) {
623 d_print("unrecoverable frame level error.\n");
624 return -1;
626 if (nomad->stream.error == MAD_ERROR_LOSTSYNC)
627 handle_lost_sync(nomad);
630 #if defined(DEBUG_XING)
631 if (nomad->has_xing)
632 d_print("seeked to %g = %g\n", pos, timer_to_seconds(nomad->timer));
633 #endif
634 return 0;
637 double nomad_time_tell(struct nomad *nomad)
639 return timer_to_seconds(nomad->timer);
642 double nomad_time_total(struct nomad *nomad)
644 return nomad->info.duration;