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