diff options
Diffstat (limited to 'lib/rbcodec/metadata/adx.c')
-rw-r--r-- | lib/rbcodec/metadata/adx.c | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/lib/rbcodec/metadata/adx.c b/lib/rbcodec/metadata/adx.c new file mode 100644 index 0000000000..7c341b4835 --- /dev/null +++ b/lib/rbcodec/metadata/adx.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 Dave Chapman | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <stdio.h> | ||
22 | #include <string.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <ctype.h> | ||
25 | #include <inttypes.h> | ||
26 | |||
27 | #include "system.h" | ||
28 | #include "metadata.h" | ||
29 | #include "metadata_common.h" | ||
30 | #include "metadata_parsers.h" | ||
31 | #include "debug.h" | ||
32 | |||
33 | bool get_adx_metadata(int fd, struct mp3entry* id3) | ||
34 | { | ||
35 | /* Use the trackname part of the id3 structure as a temporary buffer */ | ||
36 | unsigned char * buf = (unsigned char *)id3->path; | ||
37 | int chanstart, channels; | ||
38 | int looping = 0, start_adr = 0, end_adr = 0; | ||
39 | |||
40 | /* try to get the basic header */ | ||
41 | if ((lseek(fd, 0, SEEK_SET) < 0) | ||
42 | || (read(fd, buf, 0x38) < 0x38)) | ||
43 | { | ||
44 | DEBUGF("lseek or read failed\n"); | ||
45 | return false; | ||
46 | } | ||
47 | |||
48 | /* ADX starts with 0x80 */ | ||
49 | if (buf[0] != 0x80) { | ||
50 | DEBUGF("get_adx_metadata: wrong first byte %c\n",buf[0]); | ||
51 | return false; | ||
52 | } | ||
53 | |||
54 | /* check for a reasonable offset */ | ||
55 | chanstart = ((buf[2] << 8) | buf[3]) + 4; | ||
56 | if (chanstart > 4096) { | ||
57 | DEBUGF("get_adx_metadata: bad chanstart %i\n", chanstart); | ||
58 | return false; | ||
59 | } | ||
60 | |||
61 | /* check for a workable number of channels */ | ||
62 | channels = buf[7]; | ||
63 | if (channels != 1 && channels != 2) { | ||
64 | DEBUGF("get_adx_metadata: bad channel count %i\n",channels); | ||
65 | return false; | ||
66 | } | ||
67 | |||
68 | id3->frequency = get_long_be(&buf[8]); | ||
69 | /* 32 samples per 18 bytes */ | ||
70 | id3->bitrate = id3->frequency * channels * 18 * 8 / 32 / 1000; | ||
71 | id3->length = get_long_be(&buf[12]) / id3->frequency * 1000; | ||
72 | id3->vbr = false; | ||
73 | id3->filesize = filesize(fd); | ||
74 | |||
75 | /* get loop info */ | ||
76 | if (!memcmp(buf+0x10,"\x01\xF4\x03",3)) { | ||
77 | /* Soul Calibur 2 style (type 03) */ | ||
78 | DEBUGF("get_adx_metadata: type 03 found\n"); | ||
79 | /* check if header is too small for loop data */ | ||
80 | if (chanstart-6 < 0x2c) looping=0; | ||
81 | else { | ||
82 | looping = get_long_be(&buf[0x18]); | ||
83 | end_adr = get_long_be(&buf[0x28]); | ||
84 | start_adr = get_long_be(&buf[0x1c])/32*channels*18+chanstart; | ||
85 | } | ||
86 | } else if (!memcmp(buf+0x10,"\x01\xF4\x04",3)) { | ||
87 | /* Standard (type 04) */ | ||
88 | DEBUGF("get_adx_metadata: type 04 found\n"); | ||
89 | /* check if header is too small for loop data */ | ||
90 | if (chanstart-6 < 0x38) looping=0; | ||
91 | else { | ||
92 | looping = get_long_be(&buf[0x24]); | ||
93 | end_adr = get_long_be(&buf[0x34]); | ||
94 | start_adr = get_long_be(&buf[0x28])/32*channels*18+chanstart; | ||
95 | } | ||
96 | } else { | ||
97 | DEBUGF("get_adx_metadata: error, couldn't determine ADX type\n"); | ||
98 | return false; | ||
99 | } | ||
100 | |||
101 | /* is file using encryption */ | ||
102 | if (buf[0x13]==0x08) { | ||
103 | DEBUGF("get_adx_metadata: error, encrypted ADX not supported\n"); | ||
104 | return false; | ||
105 | } | ||
106 | |||
107 | if (looping) { | ||
108 | /* 2 loops, 10 second fade */ | ||
109 | id3->length = (start_adr-chanstart + 2*(end_adr-start_adr)) | ||
110 | *8 / id3->bitrate + 10000; | ||
111 | } | ||
112 | |||
113 | /* try to get the channel header */ | ||
114 | if ((lseek(fd, chanstart-6, SEEK_SET) < 0) | ||
115 | || (read(fd, buf, 6) < 6)) | ||
116 | { | ||
117 | return false; | ||
118 | } | ||
119 | |||
120 | /* check channel header */ | ||
121 | if (memcmp(buf, "(c)CRI", 6) != 0) return false; | ||
122 | |||
123 | return true; | ||
124 | } | ||