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