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 | |
02ff0254 |
52 | track->type = CT_AUDIO; |
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 | |
96 | Pico_mcd->cdda_type = CT_UNKNOWN; |
97 | |
98 | /* is this a .cue? */ |
99 | cue_data = cue_parse(cd_img_name); |
100 | if (cue_data != NULL) { |
101 | cd_img_name = cue_data->tracks[1].fname; |
102 | *type = cue_data->tracks[1].type; |
15ca7152 |
103 | } else { |
104 | cue_data = chd_parse(cd_img_name); |
105 | if (cue_data != NULL) |
106 | *type = cue_data->tracks[1].type; |
274fcc35 |
107 | } |
108 | |
109 | pmf = pm_open(cd_img_name); |
110 | if (pmf == NULL) |
111 | { |
112 | if (cue_data != NULL) |
15ca7152 |
113 | cdparse_destroy(cue_data); |
274fcc35 |
114 | return -1; |
115 | } |
116 | tracks[0].fd = pmf; |
15ca7152 |
117 | tracks[0].fname = strdup(cd_img_name); |
02ff0254 |
118 | tracks[0].type = *type & CT_AUDIO; |
274fcc35 |
119 | |
120 | if (*type == CT_ISO) |
02ff0254 |
121 | cd_img_sectors = pmf->size >> 11; // size in sectors |
122 | else cd_img_sectors = pmf->size / 2352; |
274fcc35 |
123 | |
124 | // cdd.c operates with lba - 150 |
125 | tracks[0].start = 0; |
126 | tracks[0].end = cd_img_sectors; |
127 | tracks[0].offset = 0; |
128 | |
129 | sprintf_lba(tmp_ext, sizeof(tmp_ext), 0); |
02ff0254 |
130 | elprintf(EL_STATUS, "Track 1: %s %9i %s %s", |
131 | tmp_ext, tracks[0].end, tracks[0].type ? "AUDIO" : "DATA ", cd_img_name); |
274fcc35 |
132 | |
133 | lba = cd_img_sectors; |
134 | |
135 | if (cue_data != NULL) |
136 | { |
15ca7152 |
137 | if (cue_data->track_count > 1 && cue_data->tracks[2].fname == NULL) { |
274fcc35 |
138 | // NULL fname means track2 is in same file as track1 |
139 | lba = tracks[0].end = cue_data->tracks[2].sector_offset; |
140 | } |
141 | i = 100 / cue_data->track_count + 1; // progress display |
142 | |
143 | for (n = 2; n <= cue_data->track_count; n++) |
144 | { |
145 | if (PicoCDLoadProgressCB != NULL) |
146 | PicoCDLoadProgressCB(cd_img_name, i * n); |
147 | |
148 | index = n - 1; |
149 | lba += cue_data->tracks[n].pregap; |
150 | if (cue_data->tracks[n].type == CT_MP3) { |
151 | ret = handle_mp3(cue_data->tracks[n].fname, index); |
152 | if (ret < 0) |
153 | break; |
154 | length = ret; |
155 | } |
156 | else if (cue_data->tracks[n].fname != NULL) |
157 | { |
158 | pm_file *f = pm_open(cue_data->tracks[n].fname); |
159 | if (f != NULL) |
160 | { |
161 | // assume raw, ignore header for wav.. |
162 | tracks[index].fd = f; |
15ca7152 |
163 | tracks[index].fname = strdup(cue_data->tracks[n].fname); |
274fcc35 |
164 | tracks[index].offset = cue_data->tracks[n].sector_offset; |
165 | length = f->size / 2352; |
166 | } |
167 | else |
168 | { |
169 | elprintf(EL_STATUS, "track %2i (%s): can't determine length", |
170 | n, cue_data->tracks[n].fname); |
171 | tracks[index].offset = 0; |
172 | length = 2*75; |
173 | } |
174 | } |
175 | else |
176 | { |
177 | if (n < cue_data->track_count) |
178 | length = cue_data->tracks[n+1].sector_offset - |
179 | cue_data->tracks[n].sector_offset; |
180 | else |
181 | length = cd_img_sectors - cue_data->tracks[n].sector_offset; |
182 | tracks[index].offset = cue_data->tracks[n].sector_offset; |
183 | } |
184 | |
185 | if (cue_data->tracks[n].sector_xlength != 0) |
186 | // overriden by custom cue command |
187 | length = cue_data->tracks[n].sector_xlength; |
188 | |
189 | Pico_mcd->cdda_type = cue_data->tracks[n].type; |
02ff0254 |
190 | tracks[index].type = cue_data->tracks[n].type & CT_AUDIO; |
274fcc35 |
191 | |
192 | tracks[index].start = lba; |
193 | lba += length; |
194 | tracks[index].end = lba; |
195 | |
196 | sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start); |
02ff0254 |
197 | elprintf(EL_STATUS, "Track %2i: %s %9i %s %s", n, tmp_ext, length, |
198 | tracks[index].type ? "AUDIO" : "DATA ", |
15ca7152 |
199 | cue_data->tracks[n].fname ? cue_data->tracks[n].fname : ""); |
274fcc35 |
200 | } |
274fcc35 |
201 | goto finish; |
202 | } |
203 | |
204 | /* mp3 track autosearch, Gens-like */ |
205 | iso_name_len = strlen(cd_img_name); |
206 | if (iso_name_len >= sizeof(tmp_name)) |
207 | iso_name_len = sizeof(tmp_name) - 1; |
208 | |
209 | for (n = 2, i = 0, missed = 0; i < 100 && missed < 4; i++) |
210 | { |
211 | if (PicoCDLoadProgressCB != NULL && i > 1) |
212 | PicoCDLoadProgressCB(cd_img_name, i + (100-i)*missed/4); |
213 | |
214 | for (j = 0; j < sizeof(exts)/sizeof(char *); j++) |
215 | { |
216 | int ext_len; |
217 | char *p; |
218 | |
219 | index = n - 1; |
220 | |
221 | snprintf(tmp_ext, sizeof(tmp_ext), exts[j], i); |
222 | ext_len = strlen(tmp_ext); |
223 | to_upper(tmp_ext_u, tmp_ext); |
224 | |
225 | memcpy(tmp_name, cd_img_name, iso_name_len + 1); |
226 | p = tmp_name + iso_name_len - 4; |
227 | |
228 | strcpy(p, tmp_ext); |
229 | ret = handle_mp3(tmp_name, index); |
230 | if (ret <= 0) { |
231 | strcpy(p, tmp_ext_u); |
232 | ret = handle_mp3(tmp_name, index); |
233 | } |
234 | |
235 | if (ret <= 0 && i > 1 && iso_name_len > ext_len) { |
236 | p = tmp_name + iso_name_len - ext_len; |
237 | strcpy(p, tmp_ext); |
238 | ret = handle_mp3(tmp_name, index); |
239 | if (ret <= 0) { |
240 | strcpy(p, tmp_ext_u); |
241 | ret = handle_mp3(tmp_name, index); |
242 | } |
243 | } |
244 | |
245 | if (ret > 0) |
246 | { |
247 | length = ret; |
248 | tracks[index].start = lba; |
249 | lba += length; |
250 | tracks[index].end = lba; |
251 | |
252 | Pico_mcd->cdda_type = CT_MP3; |
02ff0254 |
253 | tracks[index].type = CT_AUDIO; |
274fcc35 |
254 | |
255 | sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start); |
256 | elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO - %s", |
257 | n, tmp_ext, length, tmp_name); |
258 | |
259 | n++; |
260 | missed = 0; |
261 | break; |
262 | } |
263 | } |
264 | if (ret <= 0 && i > 1) |
265 | missed++; |
266 | } |
267 | |
268 | finish: |
269 | cdd.toc.last = n - 1; |
270 | cdd.toc.end = lba; |
d4a08748 |
271 | tracks[n].start = cdd.toc.end; |
274fcc35 |
272 | |
273 | sprintf_lba(tmp_ext, sizeof(tmp_ext), cdd.toc.end); |
274 | elprintf(EL_STATUS, "End CD - %s\n", tmp_ext); |
275 | |
276 | if (PicoCDLoadProgressCB != NULL) |
277 | PicoCDLoadProgressCB(cd_img_name, 100); |
278 | |
9993e0d6 |
279 | if (cue_data != NULL) |
15ca7152 |
280 | cdparse_destroy(cue_data); |
9993e0d6 |
281 | |
274fcc35 |
282 | return 0; |
283 | } |
284 | |
285 | // vim:shiftwidth=2:ts=2:expandtab |