274fcc35 |
1 | /* |
2 | * CD image handler |
3 | * (C) notaz, 2007,2013 |
4 | * |
5 | * This work is licensed under the terms of MAME license. |
6 | * See COPYING file in the top-level directory. |
7 | */ |
8 | |
9 | #include "../pico_int.h" |
10 | #include "genplus_macros.h" |
11 | #include "cdd.h" |
12 | #include "cue.h" |
13 | |
14 | static int handle_mp3(const char *fname, int index) |
15 | { |
16 | track_t *track = &cdd.toc.tracks[index]; |
17 | FILE *tmp_file; |
18 | int kBps; |
19 | int fs, ret; |
20 | |
21 | tmp_file = fopen(fname, "rb"); |
22 | if (tmp_file == NULL) |
23 | return -1; |
24 | |
25 | ret = fseek(tmp_file, 0, SEEK_END); |
26 | fs = ftell(tmp_file); |
27 | fseek(tmp_file, 0, SEEK_SET); |
28 | |
29 | #ifdef _PSP_FW_VERSION |
30 | // some systems (like PSP) can't have many open files at a time, |
31 | // so we work with their names instead. |
32 | fclose(tmp_file); |
33 | tmp_file = (void *) strdup(fname); |
34 | #endif |
35 | |
36 | kBps = mp3_get_bitrate(tmp_file, fs) / 8; |
37 | if (ret != 0 || kBps <= 0) |
38 | { |
39 | elprintf(EL_STATUS, "track %2i: mp3 bitrate %i", index+1, kBps); |
40 | #ifdef _PSP_FW_VERSION |
41 | free(tmp_file); |
42 | #else |
43 | fclose(tmp_file); |
44 | #endif |
45 | return -1; |
46 | } |
47 | |
48 | track->fd = tmp_file; |
49 | track->offset = 0; |
50 | |
51 | fs *= 75; |
52 | fs /= kBps * 1000; |
53 | return fs; |
54 | } |
55 | |
56 | static void to_upper(char *d, const char *s) |
57 | { |
58 | for (; *s != 0; d++, s++) { |
59 | if ('a' <= *s && *s <= 'z') |
60 | *d = *s - 'a' + 'A'; |
61 | else |
62 | *d = *s; |
63 | } |
8a601d66 |
64 | *d = 0; |
274fcc35 |
65 | } |
66 | |
67 | // cdd.c uses lba - 150 |
68 | static void sprintf_lba(char *buf, size_t size, int lba) |
69 | { |
70 | lba += 150; |
71 | snprintf(buf, size, "%02d:%02d:%02d", lba / 60 / 75, |
72 | (lba / 75) % 60, lba % 75); |
73 | } |
74 | |
75 | int load_cd_image(const char *cd_img_name, int *type) |
76 | { |
77 | static const char *exts[] = { |
78 | "%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3", |
79 | "%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3", |
80 | }; |
81 | int i, j, n, lba, index, length, ret; |
82 | int iso_name_len, missed, cd_img_sectors; |
83 | char tmp_name[256], tmp_ext[10], tmp_ext_u[10]; |
84 | track_t *tracks = cdd.toc.tracks; |
85 | cue_data_t *cue_data = NULL; |
86 | pm_file *pmf; |
87 | |
88 | if (PicoCDLoadProgressCB != NULL) |
89 | PicoCDLoadProgressCB(cd_img_name, 1); |
90 | |
91 | Pico_mcd->cdda_type = CT_UNKNOWN; |
92 | |
93 | /* is this a .cue? */ |
94 | cue_data = cue_parse(cd_img_name); |
95 | if (cue_data != NULL) { |
96 | cd_img_name = cue_data->tracks[1].fname; |
97 | *type = cue_data->tracks[1].type; |
98 | } |
99 | |
100 | pmf = pm_open(cd_img_name); |
101 | if (pmf == NULL) |
102 | { |
103 | if (cue_data != NULL) |
104 | cue_destroy(cue_data); |
105 | return -1; |
106 | } |
107 | tracks[0].fd = pmf; |
108 | |
109 | if (*type == CT_ISO) |
110 | cd_img_sectors = pmf->size >>= 11; // size in sectors |
111 | else cd_img_sectors = pmf->size /= 2352; |
112 | |
113 | // cdd.c operates with lba - 150 |
114 | tracks[0].start = 0; |
115 | tracks[0].end = cd_img_sectors; |
116 | tracks[0].offset = 0; |
117 | |
118 | sprintf_lba(tmp_ext, sizeof(tmp_ext), 0); |
119 | elprintf(EL_STATUS, "Track 1: %s %9i DATA %s", |
120 | tmp_ext, tracks[0].end, cd_img_name); |
121 | |
122 | lba = cd_img_sectors; |
123 | |
124 | if (cue_data != NULL) |
125 | { |
126 | if (cue_data->tracks[2].fname == NULL) { |
127 | // NULL fname means track2 is in same file as track1 |
128 | lba = tracks[0].end = cue_data->tracks[2].sector_offset; |
129 | } |
130 | i = 100 / cue_data->track_count + 1; // progress display |
131 | |
132 | for (n = 2; n <= cue_data->track_count; n++) |
133 | { |
134 | if (PicoCDLoadProgressCB != NULL) |
135 | PicoCDLoadProgressCB(cd_img_name, i * n); |
136 | |
137 | index = n - 1; |
138 | lba += cue_data->tracks[n].pregap; |
139 | if (cue_data->tracks[n].type == CT_MP3) { |
140 | ret = handle_mp3(cue_data->tracks[n].fname, index); |
141 | if (ret < 0) |
142 | break; |
143 | length = ret; |
144 | } |
145 | else if (cue_data->tracks[n].fname != NULL) |
146 | { |
147 | pm_file *f = pm_open(cue_data->tracks[n].fname); |
148 | if (f != NULL) |
149 | { |
150 | // assume raw, ignore header for wav.. |
151 | tracks[index].fd = f; |
152 | tracks[index].offset = cue_data->tracks[n].sector_offset; |
153 | length = f->size / 2352; |
154 | } |
155 | else |
156 | { |
157 | elprintf(EL_STATUS, "track %2i (%s): can't determine length", |
158 | n, cue_data->tracks[n].fname); |
159 | tracks[index].offset = 0; |
160 | length = 2*75; |
161 | } |
162 | } |
163 | else |
164 | { |
165 | if (n < cue_data->track_count) |
166 | length = cue_data->tracks[n+1].sector_offset - |
167 | cue_data->tracks[n].sector_offset; |
168 | else |
169 | length = cd_img_sectors - cue_data->tracks[n].sector_offset; |
170 | tracks[index].offset = cue_data->tracks[n].sector_offset; |
171 | } |
172 | |
173 | if (cue_data->tracks[n].sector_xlength != 0) |
174 | // overriden by custom cue command |
175 | length = cue_data->tracks[n].sector_xlength; |
176 | |
177 | Pico_mcd->cdda_type = cue_data->tracks[n].type; |
178 | |
179 | tracks[index].start = lba; |
180 | lba += length; |
181 | tracks[index].end = lba; |
182 | |
183 | sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start); |
184 | elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s", |
185 | n, tmp_ext, length, cue_data->tracks[n].fname); |
186 | } |
274fcc35 |
187 | goto finish; |
188 | } |
189 | |
190 | /* mp3 track autosearch, Gens-like */ |
191 | iso_name_len = strlen(cd_img_name); |
192 | if (iso_name_len >= sizeof(tmp_name)) |
193 | iso_name_len = sizeof(tmp_name) - 1; |
194 | |
195 | for (n = 2, i = 0, missed = 0; i < 100 && missed < 4; i++) |
196 | { |
197 | if (PicoCDLoadProgressCB != NULL && i > 1) |
198 | PicoCDLoadProgressCB(cd_img_name, i + (100-i)*missed/4); |
199 | |
200 | for (j = 0; j < sizeof(exts)/sizeof(char *); j++) |
201 | { |
202 | int ext_len; |
203 | char *p; |
204 | |
205 | index = n - 1; |
206 | |
207 | snprintf(tmp_ext, sizeof(tmp_ext), exts[j], i); |
208 | ext_len = strlen(tmp_ext); |
209 | to_upper(tmp_ext_u, tmp_ext); |
210 | |
211 | memcpy(tmp_name, cd_img_name, iso_name_len + 1); |
212 | p = tmp_name + iso_name_len - 4; |
213 | |
214 | strcpy(p, tmp_ext); |
215 | ret = handle_mp3(tmp_name, index); |
216 | if (ret <= 0) { |
217 | strcpy(p, tmp_ext_u); |
218 | ret = handle_mp3(tmp_name, index); |
219 | } |
220 | |
221 | if (ret <= 0 && i > 1 && iso_name_len > ext_len) { |
222 | p = tmp_name + iso_name_len - ext_len; |
223 | strcpy(p, tmp_ext); |
224 | ret = handle_mp3(tmp_name, index); |
225 | if (ret <= 0) { |
226 | strcpy(p, tmp_ext_u); |
227 | ret = handle_mp3(tmp_name, index); |
228 | } |
229 | } |
230 | |
231 | if (ret > 0) |
232 | { |
233 | length = ret; |
234 | tracks[index].start = lba; |
235 | lba += length; |
236 | tracks[index].end = lba; |
237 | |
238 | Pico_mcd->cdda_type = CT_MP3; |
239 | |
240 | sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start); |
241 | elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO - %s", |
242 | n, tmp_ext, length, tmp_name); |
243 | |
244 | n++; |
245 | missed = 0; |
246 | break; |
247 | } |
248 | } |
249 | if (ret <= 0 && i > 1) |
250 | missed++; |
251 | } |
252 | |
253 | finish: |
254 | cdd.toc.last = n - 1; |
255 | cdd.toc.end = lba; |
256 | |
257 | sprintf_lba(tmp_ext, sizeof(tmp_ext), cdd.toc.end); |
258 | elprintf(EL_STATUS, "End CD - %s\n", tmp_ext); |
259 | |
260 | if (PicoCDLoadProgressCB != NULL) |
261 | PicoCDLoadProgressCB(cd_img_name, 100); |
262 | |
9993e0d6 |
263 | if (cue_data != NULL) |
264 | cue_destroy(cue_data); |
265 | |
274fcc35 |
266 | return 0; |
267 | } |
268 | |
269 | // vim:shiftwidth=2:ts=2:expandtab |