2 * Copyright 2006 Chun-Yu Shei <cshei AT cs.indiana.edu>
4 * Cleaned up by Timo Hirvonen <tihirvon@gmail.com>
11 #include "read_wrapper.h"
13 #include <mpcdec/mpcdec.h>
17 /* http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html */
19 #define PREAMBLE_SIZE (8)
20 static const char preamble
[PREAMBLE_SIZE
] = { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' };
22 /* NOTE: not sizeof(struct ape_header)! */
23 #define HEADER_SIZE (32)
26 /* 1000 or 2000 (1.0, 2.0) */
29 /* tag size (header + tags, excluding footer) */
35 /* global flags for each tag
36 * there are also private flags for every tag
37 * NOTE: 0 for version 1.0 (1000)
43 #define AF_IS_UTF8(f) (((f) & 6) == 0)
44 #define AF_IS_FOOTER(f) (((f) & (1 << 29)) == 0)
58 * the api doc says this is pcm samples per mpc frame
59 * but it's really pcm _frames_ per mpc frame
60 * MPC_FRAME_LENGTH = 36 * 32 (1152)
62 * this is wrong, it should be 2 * MPC_FRAME_LENGTH (2304)
63 * MPC_DECODER_BUFFER_LENGTH = 4 * MPC_FRAME_LENGTH (4608)
65 * use MPC_DECODER_BUFFER_LENGTH just to be sure it works
67 MPC_SAMPLE_FORMAT samples
[MPC_DECODER_BUFFER_LENGTH
];
70 static inline uint32_t get_le32(const char *buf
)
72 const unsigned char *b
= (const unsigned char *)buf
;
74 return b
[0] | (b
[1] << 8) | (b
[2] << 16) | (b
[3] << 24);
78 static mpc_int32_t
read_impl(void *data
, void *ptr
, mpc_int32_t size
)
80 struct input_plugin_data
*ip_data
= data
;
83 rc
= read_wrapper(ip_data
, ptr
, size
);
93 static mpc_bool_t
seek_impl(void *data
, mpc_int32_t offset
)
95 struct input_plugin_data
*ip_data
= data
;
98 rc
= lseek(ip_data
->fd
, offset
, SEEK_SET
);
104 static mpc_int32_t
tell_impl(void *data
)
106 struct input_plugin_data
*ip_data
= data
;
108 return lseek(ip_data
->fd
, 0, SEEK_CUR
);
111 static mpc_int32_t
get_size_impl(void *data
)
113 struct input_plugin_data
*ip_data
= data
;
114 struct mpc_private
*priv
= ip_data
->private;
116 return priv
->file_size
;
119 static mpc_bool_t
canseek_impl(void *data
)
121 struct input_plugin_data
*ip_data
= data
;
123 return !ip_data
->remote
;
129 /* returns position of APE header or -1 if not found */
130 static int find_ape_tag_slow(int fd
)
136 /* seek to start of file */
137 if (lseek(fd
, pos
, SEEK_SET
) == -1)
141 int i
, got
= read(fd
, buf
, sizeof(buf
));
144 if (errno
== EAGAIN
|| errno
== EINTR
)
151 for (i
= 0; i
< got
; i
++) {
152 if (buf
[i
] != preamble
[match
]) {
158 if (match
== PREAMBLE_SIZE
)
159 return pos
+ i
+ 1 - PREAMBLE_SIZE
;
166 static int ape_parse_header(const char *buf
, struct ape_header
*h
)
168 if (memcmp(buf
, preamble
, PREAMBLE_SIZE
))
171 h
->version
= get_le32(buf
+ 8);
172 h
->size
= get_le32(buf
+ 12);
173 h
->count
= get_le32(buf
+ 16);
174 h
->flags
= get_le32(buf
+ 20);
178 static int read_header(int fd
, struct ape_header
*h
)
180 char buf
[HEADER_SIZE
];
182 if (read_all(fd
, buf
, sizeof(buf
)) != sizeof(buf
))
184 return ape_parse_header(buf
, h
);
187 /* sets fd right after the header and returns 1 if found,
188 * otherwise returns 0
190 static int find_ape_tag(int fd
, struct ape_header
*h
)
194 if (lseek(fd
, -HEADER_SIZE
, SEEK_END
) == -1)
196 if (read_header(fd
, h
))
199 pos
= find_ape_tag_slow(fd
);
202 if (lseek(fd
, pos
, SEEK_SET
) == -1)
204 return read_header(fd
, h
);
208 * All keys are ASCII and length is 2..255
210 * UTF-8: Artist, Album, Title, Genre
211 * Integer: Track (N or N/M)
212 * Date: Year (release), "Record Date"
214 * UTF-8 strings are NOT zero terminated.
216 * Also support "discnumber" (vorbis) and "disc" (non-standard)
218 static int ape_parse_one(const char *buf
, int size
, char **keyp
, char **valp
)
222 while (size
- pos
> 8) {
223 uint32_t val_len
, flags
;
225 int max_key_len
, key_len
;
227 val_len
= get_le32(buf
+ pos
); pos
+= 4;
228 flags
= get_le32(buf
+ pos
); pos
+= 4;
230 max_key_len
= size
- pos
- val_len
- 1;
231 if (max_key_len
< 0) {
236 for (key_len
= 0; key_len
< max_key_len
&& buf
[pos
+ key_len
]; key_len
++)
238 if (buf
[pos
+ key_len
]) {
243 if (!AF_IS_UTF8(flags
)) {
244 /* ignore binary data */
245 pos
+= key_len
+ 1 + val_len
;
249 key
= xstrdup(buf
+ pos
);
252 /* should not be NUL-terminated */
253 val
= xstrndup(buf
+ pos
, val_len
);
256 /* could be moved to comment.c but I don't think anyone else would use it */
257 if (!strcasecmp(key
, "record date") || !strcasecmp(key
, "year")) {
259 key
= xstrdup("date");
262 if (!strcasecmp(key
, "date")) {
265 * 1999-08-11 12:34:56
270 * 1999-W34 (week 34, totally crazy)
272 * convert to year, pl.c supports only years anyways
274 * FIXME: which one is the most common tag (year or record date)?
289 static int mpc_open(struct input_plugin_data
*ip_data
)
291 struct mpc_private
*priv
;
293 priv
= xnew0(struct mpc_private
, 1);
295 priv
->file_size
= -1;
296 if (!ip_data
->remote
) {
297 priv
->file_size
= lseek(ip_data
->fd
, 0, SEEK_END
);
298 lseek(ip_data
->fd
, 0, SEEK_SET
);
301 /* set up an mpc_reader linked to our function implementations */
302 priv
->reader
.read
= read_impl
;
303 priv
->reader
.seek
= seek_impl
;
304 priv
->reader
.tell
= tell_impl
;
305 priv
->reader
.get_size
= get_size_impl
;
306 priv
->reader
.canseek
= canseek_impl
;
307 priv
->reader
.data
= ip_data
;
309 /* must be before mpc_streaminfo_read() */
310 ip_data
->private = priv
;
312 /* read file's streaminfo data */
313 mpc_streaminfo_init(&priv
->info
);
314 if (mpc_streaminfo_read(&priv
->info
, &priv
->reader
) != ERROR_CODE_OK
) {
316 return -IP_ERROR_FILE_FORMAT
;
319 /* instantiate a decoder with our file reader */
320 mpc_decoder_setup(&priv
->decoder
, &priv
->reader
);
321 if (!mpc_decoder_initialize(&priv
->decoder
, &priv
->info
)) {
323 return -IP_ERROR_FILE_FORMAT
;
326 priv
->samples_avail
= 0;
327 priv
->samples_pos
= 0;
329 ip_data
->sf
= sf_rate(priv
->info
.sample_freq
) | sf_channels(priv
->info
.channels
) |
330 sf_bits(16) | sf_signed(1);
334 static int mpc_close(struct input_plugin_data
*ip_data
)
336 struct mpc_private
*priv
= ip_data
->private;
339 ip_data
->private = NULL
;
343 static int scale(struct input_plugin_data
*ip_data
, char *buffer
, int count
)
345 struct mpc_private
*priv
= ip_data
->private;
346 const MPC_SAMPLE_FORMAT
*samples
;
347 const int clip_min
= -1 << (16 - 1);
348 const int clip_max
= (1 << (16 - 1)) - 1;
349 const int float_scale
= 1 << (16 - 1);
352 /* number of bytes to 16-bit samples */
353 sample_count
= count
/ 2;
354 if (sample_count
> priv
->samples_avail
)
355 sample_count
= priv
->samples_avail
;
357 /* scale 32-bit samples to 16-bit */
358 samples
= priv
->samples
+ priv
->samples_pos
;
359 for (i
= 0; i
< sample_count
; i
++) {
362 val
= samples
[i
] * float_scale
;
363 if (val
< clip_min
) {
365 } else if (val
> clip_max
) {
369 buffer
[i
* 2 + 0] = val
& 0xff;
370 buffer
[i
* 2 + 1] = val
>> 8;
373 priv
->samples_pos
+= sample_count
;
374 priv
->samples_avail
-= sample_count
;
375 if (priv
->samples_avail
== 0)
376 priv
->samples_pos
= 0;
378 /* number of 16-bit samples to bytes */
379 return sample_count
* 2;
382 static int mpc_read(struct input_plugin_data
*ip_data
, char *buffer
, int count
)
384 struct mpc_private
*priv
= ip_data
->private;
386 if (priv
->samples_avail
== 0) {
387 uint32_t status
= mpc_decoder_decode(&priv
->decoder
, priv
->samples
, NULL
, NULL
);
389 if (status
== (uint32_t)(-1)) {
391 return -IP_ERROR_ERRNO
;
398 /* status seems to be number of _frames_
399 * the api documentation is wrong
401 priv
->samples_avail
= status
* priv
->info
.channels
;
403 return scale(ip_data
, buffer
, count
);
406 static int mpc_seek(struct input_plugin_data
*ip_data
, double offset
)
408 struct mpc_private
*priv
= ip_data
->private;
410 priv
->samples_pos
= 0;
411 priv
->samples_avail
= 0;
413 if (mpc_decoder_seek_seconds(&priv
->decoder
, offset
))
418 static const char *gain_to_str(int gain
)
421 int b
, a
= gain
/ 100;
428 sprintf(buf
, "%d.%02d", a
, b
);
432 static const char *peak_to_str(unsigned int peak
)
435 sprintf(buf
, "%d.%05d", peak
/ 32767, peak
% 32767);
439 static int mpc_read_comments(struct input_plugin_data
*ip_data
, struct keyval
**comments
)
441 struct mpc_private
*priv
= ip_data
->private;
442 int old_pos
, fd
= ip_data
->fd
;
448 old_pos
= lseek(fd
, 0, SEEK_CUR
);
450 if (!find_ape_tag(fd
, &h
))
453 if (AF_IS_FOOTER(h
.flags
)) {
454 off_t file_size
= get_size_impl(ip_data
);
455 /* seek back right after the header */
456 if (lseek(fd
, file_size
- h
.size
, SEEK_SET
) == -1)
460 /* ignore insane tags */
461 if (h
.size
> 1024 * 1024)
464 buf
= xnew(char, h
.size
);
465 if (read_all(fd
, buf
, h
.size
) == h
.size
) {
468 while (pos
< h
.size
) {
470 rc
= ape_parse_one(buf
+ pos
, h
.size
- pos
, &k
, &v
);
474 comments_add(&c
, k
, v
);
482 if (priv
->info
.gain_title
&& priv
->info
.peak_title
) {
483 comments_add_const(&c
, "replaygain_track_gain", gain_to_str(priv
->info
.gain_title
));
484 comments_add_const(&c
, "replaygain_track_peak", peak_to_str(priv
->info
.peak_title
));
486 if (priv
->info
.gain_album
&& priv
->info
.peak_album
) {
487 comments_add_const(&c
, "replaygain_album_gain", gain_to_str(priv
->info
.gain_album
));
488 comments_add_const(&c
, "replaygain_album_peak", peak_to_str(priv
->info
.peak_album
));
490 comments_terminate(&c
);
492 lseek(fd
, old_pos
, SEEK_SET
);
493 *comments
= c
.comments
;
497 static int mpc_duration(struct input_plugin_data
*ip_data
)
499 struct mpc_private
*priv
= ip_data
->private;
501 /* priv->info.pcm_samples seems to be number of frames
502 * priv->info.frames is _not_ pcm frames
504 return priv
->info
.pcm_samples
/ priv
->info
.sample_freq
;
507 const struct input_plugin_ops ip_ops
= {
512 .read_comments
= mpc_read_comments
,
513 .duration
= mpc_duration
516 const char *const ip_extensions
[] = { "mpc", "mpp", "mp+", NULL
};
517 const char *const ip_mime_types
[] = { "audio/x-musepack", NULL
};