2 * Copyright 2004-2005 Timo Hirvonen
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
21 * Xing code copied from xmms-mad plugin.
35 struct seek_idx_entry
{
41 struct mad_stream stream
;
42 struct mad_frame frame
;
43 struct mad_synth synth
;
45 unsigned long cur_frame
;
47 unsigned char input_buffer
[INPUT_BUFFER_SIZE
];
49 unsigned int fast
: 1;
50 unsigned int has_xing
: 1;
54 unsigned int nr_frames
;
57 unsigned char toc
[100];
62 struct seek_idx_entry
*table
;
65 struct nomad_info info
;
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
;
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
) {
104 return sample
>> (MAD_F_FRACBITS
- 15);
107 static inline double timer_to_seconds(mad_timer_t timer
)
111 ms
= mad_timer_count(timer
, MAD_UNITS_MILLISECONDS
);
112 return (double)ms
/ 1000.0;
116 XING_FRAMES
= 0x00000001L
,
117 XING_BYTES
= 0x00000002L
,
118 XING_TOC
= 0x00000004L
,
119 XING_SCALE
= 0x00000008L
127 * 4 frames (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
;
140 if (mad_bit_read(&ptr
, 32) != (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g'))
142 nomad
->xing
.flags
= mad_bit_read(&ptr
, 32);
144 if (nomad
->xing
.flags
& XING_FRAMES
) {
147 nomad
->xing
.nr_frames
= mad_bit_read(&ptr
, 32);
150 if (nomad
->xing
.flags
& XING_BYTES
) {
153 nomad
->xing
.bytes
= mad_bit_read(&ptr
, 32);
156 if (nomad
->xing
.flags
& XING_TOC
) {
161 for (i
= 0; i
< 100; i
++)
162 nomad
->xing
.toc
[i
] = mad_bit_read(&ptr
, 8);
165 if (nomad
->xing
.flags
& XING_SCALE
) {
168 nomad
->xing
.scale
= mad_bit_read(&ptr
, 32);
172 #if defined(DEBUG_XING)
173 if (nomad
->xing
.flags
& XING_FRAMES
)
174 d_print("frames: %d (xing)\n", nomad
->xing
.nr_frames
);
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
;
197 read_size
= INPUT_BUFFER_SIZE
;
198 read_start
= nomad
->input_buffer
;
201 read_size
= nomad
->cbs
.read(nomad
->datasource
, read_start
, read_size
);
202 if (read_size
== -1) {
204 d_print("read error on bitstream (%d:%s)\n", errno
, strerror(errno
));
210 len
= read_size
+ remaining
;
212 nomad
->input_offset
+= read_size
;
214 if (len
< MAD_BUFFER_GUARD
) {
215 memset(nomad
->input_buffer
+ len
, 0, MAD_BUFFER_GUARD
- len
);
216 len
= MAD_BUFFER_GUARD
;
219 mad_stream_buffer(&nomad
->stream
, nomad
->input_buffer
, len
);
220 nomad
->stream
.error
= 0;
225 static void handle_lost_sync(struct nomad
*nomad
)
230 frame
= nomad
->cur_frame
;
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
);
239 d_print("frame %ld, skipping ID3 tag (%d bytes)\n", frame
, size
);
240 mad_stream_skip(&nomad
->stream
, size
);
242 d_print("frame %ld\n", frame
);
247 /* builds a seek index as the file is decoded
248 * should be called after every call to mad_decode_header,
249 * and before increasing nomad->timer
251 static void build_seek_index(struct nomad
*nomad
)
260 timer
= nomad
->timer
;
261 mad_timer_add(&timer
, nomad
->frame
.header
.duration
);
263 if (timer
.seconds
< (nomad
->seek_idx
.size
+ 1) * SEEK_IDX_INTERVAL
)
266 /* offset = ftell() */
267 offset
= nomad
->input_offset
;
268 /* subtract by buffer length to get offset to start of buffer */
269 offset
-= (nomad
->stream
.bufend
- nomad
->input_buffer
);
270 /* then add offset to the current frame */
271 offset
+= (nomad
->stream
.this_frame
- nomad
->input_buffer
);
273 idx
= nomad
->seek_idx
.size
;
275 nomad
->seek_idx
.table
= xrenew(struct seek_idx_entry
, nomad
->seek_idx
.table
, idx
+ 1);
276 nomad
->seek_idx
.table
[idx
].offset
= offset
;
277 nomad
->seek_idx
.table
[idx
].timer
= nomad
->timer
;
279 nomad
->seek_idx
.size
++;
282 static void calc_fast(struct nomad
*nomad
)
284 nomad
->info
.avg_bitrate
= -1;
285 nomad
->info
.vbr
= -1;
286 if (nomad
->has_xing
&& (nomad
->xing
.flags
& XING_FRAMES
)) {
287 nomad
->info
.nr_frames
= nomad
->xing
.nr_frames
;
288 mad_timer_multiply(&nomad
->timer
, nomad
->info
.nr_frames
);
290 nomad
->info
.nr_frames
= nomad
->info
.filesize
/
291 (nomad
->stream
.next_frame
- nomad
->stream
.this_frame
);
292 mad_timer_multiply(&nomad
->timer
, nomad
->info
.nr_frames
);
298 * nomad->info.avg_bitrate and
300 * are filled only if fast = 0
302 static int scan(struct nomad
*nomad
)
304 struct mad_header
*header
= &nomad
->frame
.header
;
305 int frame_decoded
= 0;
307 unsigned long long int bitrate_sum
= 0;
309 nomad
->info
.nr_frames
= 0;
314 rc
= fill_buffer(nomad
);
320 if (mad_header_decode(header
, &nomad
->stream
)) {
321 if (!MAD_RECOVERABLE(nomad
->stream
.error
) && nomad
->stream
.error
!= MAD_ERROR_BUFLEN
) {
322 d_print("unrecoverable frame level error.\n");
325 if (nomad
->stream
.error
== MAD_ERROR_LOSTSYNC
)
326 handle_lost_sync(nomad
);
330 bitrate_sum
+= header
->bitrate
;
331 build_seek_index(nomad
);
332 mad_timer_add(&nomad
->timer
, header
->duration
);
333 nomad
->info
.nr_frames
++;
334 if (!frame_decoded
) {
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 if (mad_frame_decode(&nomad
->frame
, &nomad
->stream
) == -1) {
342 if (nomad
->stream
.error
== MAD_ERROR_BUFLEN
)
344 if (!MAD_RECOVERABLE(nomad
->stream
.error
)) {
345 d_print("unrecoverable frame level error.\n");
348 if (nomad
->stream
.error
== MAD_ERROR_LOSTSYNC
)
349 handle_lost_sync(nomad
);
360 if (old_bitrate
!= header
->bitrate
)
363 old_bitrate
= header
->bitrate
;
365 if (nomad
->info
.nr_frames
== 0) {
366 d_print("error: not an mp3 file!\n");
367 return -NOMAD_ERROR_FILE_FORMAT
;
369 nomad
->info
.duration
= timer_to_seconds(nomad
->timer
);
371 nomad
->info
.avg_bitrate
= bitrate_sum
/ nomad
->info
.nr_frames
;
372 nomad
->cur_frame
= 0;
373 nomad
->cbs
.lseek(nomad
->datasource
, 0, SEEK_SET
);
374 nomad
->input_offset
= 0;
378 static int decode(struct nomad
*nomad
)
383 rc
= fill_buffer(nomad
);
389 if (mad_frame_decode(&nomad
->frame
, &nomad
->stream
)) {
390 if (nomad
->stream
.error
== MAD_ERROR_BUFLEN
)
392 if (!MAD_RECOVERABLE(nomad
->stream
.error
)) {
393 d_print("unrecoverable frame level error.\n");
396 if (nomad
->stream
.error
== MAD_ERROR_LOSTSYNC
)
397 handle_lost_sync(nomad
);
401 if (nomad
->info
.filesize
> 0)
402 build_seek_index(nomad
);
403 mad_timer_add(&nomad
->timer
, nomad
->frame
.header
.duration
);
404 mad_synth_frame(&nomad
->synth
, &nomad
->frame
);
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;
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
)
431 nomad
->info
.filesize
= nomad
->cbs
.lseek(nomad
->datasource
, 0, SEEK_END
);
432 if (nomad
->info
.filesize
== -1) {
435 nomad
->fast
= fast
!= 0;
436 nomad
->cbs
.lseek(nomad
->datasource
, 0, SEEK_SET
);
438 if (nomad
->info
.filesize
== -1) {
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
;
451 nomad
->info
.duration
= -1.0;
452 nomad
->info
.nr_frames
= -1;
453 nomad
->info
.vbr
= -1;
454 nomad
->info
.avg_bitrate
= -1;
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
,
472 #if defined(DEBUG_XING)
474 d_print("xing: flags: 0x%x, frames: %d, bytes: %d, scale: %d\n",
476 nomad
->xing
.nr_frames
,
486 return -NOMAD_ERROR_FILE_FORMAT
;
489 int nomad_open(struct nomad
**nomadp
, int fd
, int fast
)
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
;
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
)
508 nomad
= xnew0(struct nomad
, 1);
509 nomad
->datasource
= datasource
;
512 /* on error do_open calls nomad_close */
513 return do_open(nomad
, fast
);
516 void nomad_close(struct nomad
*nomad
)
519 nomad
->cbs
.close(nomad
->datasource
);
520 free(nomad
->seek_idx
.table
);
524 void nomad_info(struct nomad
*nomad
, struct nomad_info
*info
)
529 int nomad_read(struct nomad
*nomad
, char *buffer
, int count
)
531 int i
, j
, size
, psize
, to
;
533 if (nomad
->i
== -1) {
543 psize
= nomad
->info
.channels
* 16 / 8;
544 size
= (nomad
->synth
.pcm
.length
- nomad
->i
) * psize
;
546 to
= nomad
->i
+ count
/ psize
;
548 to
= nomad
->synth
.pcm
.length
;
551 for (i
= nomad
->i
; i
< to
; i
++) {
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
) {
572 int nomad_time_seek(struct nomad
*nomad
, double pos
)
576 if (pos
< 0.0 || pos
> nomad
->info
.duration
) {
580 if (nomad
->info
.filesize
== -1) {
587 /* calculate seek offset */
588 if (nomad
->has_xing
) {
589 /* seek to truncate(pos / duration * 100) / 100 * duration */
593 k
= pos
/ nomad
->info
.duration
* 100.0;
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",
601 timer_to_seconds(nomad
->timer
),
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;
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)
619 nomad
->input_offset
= offset
;
620 while (timer_to_seconds(nomad
->timer
) < pos
) {
623 rc
= fill_buffer(nomad
);
629 if (mad_header_decode(&nomad
->frame
.header
, &nomad
->stream
) == 0) {
630 build_seek_index(nomad
);
631 mad_timer_add(&nomad
->timer
, nomad
->frame
.header
.duration
);
633 if (!MAD_RECOVERABLE(nomad
->stream
.error
) && nomad
->stream
.error
!= MAD_ERROR_BUFLEN
) {
634 d_print("unrecoverable frame level error.\n");
637 if (nomad
->stream
.error
== MAD_ERROR_LOSTSYNC
)
638 handle_lost_sync(nomad
);
641 #if defined(DEBUG_XING)
643 d_print("seeked to %g = %g\n", pos
, timer_to_seconds(nomad
->timer
));
648 double nomad_time_tell(struct nomad
*nomad
)
650 return timer_to_seconds(nomad
->timer
);
653 double nomad_time_total(struct nomad
*nomad
)
655 return nomad
->info
.duration
;