1 /*
2 * UAE
3 *
4 * CD image file support
5 *
6 * - iso (2048/2352 block size)
7 * - cue/bin, cue/bin/wav, cue/bin/mp3, cue/bin/flac
8 * - ccd/img and ccd/img/sub
9 * - chd cd
10 *
11 * Copyright 2010-2013 Toni Wilen
12 *
13 */
14 #include "sysconfig.h"
15 #include "sysdeps.h"
16
17 #ifdef HAVE_SYS_TIMEB_H
18 #include <sys/timeb.h>
19 #else
20
21 #endif
22
23 #include "options.h"
24 #include "blkdev.h"
25 #include "zfile.h"
26 #include "gui.h"
27 #include "fsdb.h"
28 #include "threaddep/thread.h"
29 #include "scsidev.h"
30 #include "mp3decoder.h"
31 #include "cda_play.h"
32 #include "uae/memory.h"
33 #include "audio.h"
34 #include "uae.h"
35 #include "uae/cdrom.h"
36 #ifdef RETROPLATFORM
37 #include "rp.h"
38 #endif
39
40 #ifdef FSUAE
41 #else
42 #define FLAC__NO_DLL
43 #endif // NL
44
45 #include "FLAC/stream_decoder.h"
46
47 #ifdef WITH_CHD
48 #include "archivers/chd/chdtypes.h"
49 #include "archivers/chd/chd.h"
50 #include "archivers/chd/chdcd.h"
51 #endif
52
53 #define scsi_log write_log
54
55 #define CDDA_BUFFERS 12
56
57 enum audenc { AUDENC_NONE, AUDENC_PCM, AUDENC_MP3, AUDENC_FLAC, ENC_CHD };
58
59 struct cdtoc
60 {
61 struct zfile *handle;
62 uae_s64 offset;
63 uae_u8 *data;
64 struct zfile *subhandle;
65 int suboffset;
66 uae_u8 *subdata;
67
68 uae_s64 filesize;
69 TCHAR *fname;
70 TCHAR *extrainfo;
71 int address;
72 uae_u8 adr, ctrl;
73 int track;
74 int size;
75 int skipsize; // bytes to skip after each block
76 int index1; // distance between index0 and index1
77 int pregap; // sectors of silence
78 int postgap; // sectors of silence
79 audenc enctype;
80 int writeoffset;
81 int subcode;
82 #ifdef WITH_CHD
83 const cdrom_track_info *chdtrack;
84 #endif
85 };
86
87 struct cdunit {
88 bool enabled;
89 bool open;
90 uae_u8 buffer[2352];
91 struct cdtoc toc[102];
92 int tracks;
93 uae_u64 cdsize;
94 int blocksize;
95
96 int cdda_play_state;
97 int cdda_play;
98 int cdda_paused;
99 int cdda_volume[2];
100 int cdda_scan;
101 int cd_last_pos;
102 int cdda_start, cdda_end;
103 play_subchannel_callback cdda_subfunc;
104 play_status_callback cdda_statusfunc;
105 int cdda_delay, cdda_delay_frames;
106 bool thread_active;
107
108 TCHAR imgname[MAX_DPATH];
109 uae_sem_t sub_sem;
110 struct device_info di;
111 #ifdef WITH_CHD
112 chd_file *chd_f;
113 cdrom_file *chd_cdf;
114 #endif
115 };
116
117 static struct cdunit cdunits[MAX_TOTAL_SCSI_DEVICES];
118 static int bus_open;
119
120 static volatile int cdimage_unpack_thread, cdimage_unpack_active;
121 static smp_comm_pipe unpack_pipe;
122 static uae_sem_t play_sem;
123
unitisopen(int unitnum)124 static struct cdunit *unitisopen (int unitnum)
125 {
126 struct cdunit *cdu = &cdunits[unitnum];
127 if (cdu->open)
128 return cdu;
129 return NULL;
130 }
131
132
findtoc(struct cdunit * cdu,int * sectorp,bool data)133 static struct cdtoc *findtoc (struct cdunit *cdu, int *sectorp, bool data)
134 {
135 int i;
136 int sector;
137
138 if (*sectorp < 0)
139 return NULL;
140 sector = *sectorp;
141 for (i = 0; i <= cdu->tracks; i++) {
142 struct cdtoc *t = &cdu->toc[i];
143 if (t->address - t->index1 > sector) {
144 if (i == 0) {
145 *sectorp = 0;
146 return t;
147 }
148 t--;
149 sector -= t->address - t->index1;
150 if (!data && sector < t->pregap)
151 return NULL; // pregap silence
152 *sectorp = sector;
153 return t;
154 }
155 }
156 return NULL;
157 }
158
do_read(struct cdunit * cdu,struct cdtoc * t,uae_u8 * data,int sector,int offset,int size,bool audio)159 static int do_read (struct cdunit *cdu, struct cdtoc *t, uae_u8 *data, int sector, int offset, int size, bool audio)
160 {
161 if (t->enctype == ENC_CHD) {
162 #ifdef WITH_CHD
163 int type = CD_TRACK_MODE1_RAW;
164 uae_u8 tmpbuf[2352];
165 if (size > 2352)
166 return 0;
167 switch (size)
168 {
169 case 2352:
170 type = CD_TRACK_MODE1_RAW;
171 break;
172 case 2336:
173 type = CD_TRACK_MODE2;
174 break;
175 case 2048:
176 type = CD_TRACK_MODE1;
177 break;
178 }
179 if (audio && size == 2352)
180 type = CD_TRACK_AUDIO;
181 if (cdrom_read_data(cdu->chd_cdf, sector + t->offset, tmpbuf, type, true)) {
182 memcpy(data, tmpbuf + offset, size);
183 return 1;
184 }
185 return 0;
186 #endif
187 } else if (t->handle) {
188 int ssize = t->size + t->skipsize;
189 zfile_fseek (t->handle, t->offset + (uae_u64)sector * ssize + offset, SEEK_SET);
190 return zfile_fread (data, 1, size, t->handle) == size;
191 }
192 return 0;
193 }
194
195 // WOHOO, library that supports virtual file access functions. Perfect!
flac_metadata_callback(const FLAC__StreamDecoder * decoder,const FLAC__StreamMetadata * metadata,void * client_data)196 static void flac_metadata_callback (const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
197 {
198 struct cdtoc *t = (struct cdtoc*)client_data;
199 if (t->data)
200 return;
201 if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
202 t->filesize = metadata->data.stream_info.total_samples * (metadata->data.stream_info.bits_per_sample / 8) * metadata->data.stream_info.channels;
203 }
204 }
flac_error_callback(const FLAC__StreamDecoder * decoder,FLAC__StreamDecoderErrorStatus status,void * client_data)205 static void flac_error_callback (const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
206 {
207 return;
208 }
flac_write_callback(const FLAC__StreamDecoder * decoder,const FLAC__Frame * frame,const FLAC__int32 * const buffer[],void * client_data)209 static FLAC__StreamDecoderWriteStatus flac_write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
210 {
211 struct cdtoc *t = (struct cdtoc*)client_data;
212 uae_u16 *p = (uae_u16*)(t->data + t->writeoffset);
213 int size = 4;
214 for (int i = 0; i < frame->header.blocksize && t->writeoffset < t->filesize - size; i++, t->writeoffset += size) {
215 *p++ = (FLAC__int16)buffer[0][i];
216 *p++ = (FLAC__int16)buffer[1][i];
217 }
218 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
219 }
file_read_callback(const FLAC__StreamDecoder * decoder,FLAC__byte buffer[],size_t * bytes,void * client_data)220 static FLAC__StreamDecoderReadStatus file_read_callback (const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
221 {
222 struct cdtoc *t = (struct cdtoc*)client_data;
223 if (zfile_ftell (t->handle) >= zfile_size (t->handle))
224 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
225 return zfile_fread (buffer, *bytes, 1, t->handle) ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_ABORT;
226 }
file_seek_callback(const FLAC__StreamDecoder * decoder,FLAC__uint64 absolute_byte_offset,void * client_data)227 static FLAC__StreamDecoderSeekStatus file_seek_callback (const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
228 {
229 struct cdtoc *t = (struct cdtoc*)client_data;
230 zfile_fseek (t->handle, absolute_byte_offset, SEEK_SET);
231 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
232 }
file_tell_callback(const FLAC__StreamDecoder * decoder,FLAC__uint64 * absolute_byte_offset,void * client_data)233 static FLAC__StreamDecoderTellStatus file_tell_callback (const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
234 {
235 struct cdtoc *t = (struct cdtoc*)client_data;
236 *absolute_byte_offset = zfile_ftell (t->handle);
237 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
238 }
file_len_callback(const FLAC__StreamDecoder * decoder,FLAC__uint64 * stream_length,void * client_data)239 static FLAC__StreamDecoderLengthStatus file_len_callback (const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
240 {
241 struct cdtoc *t = (struct cdtoc*)client_data;
242 *stream_length = zfile_size (t->handle);
243 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
244 }
file_eof_callback(const FLAC__StreamDecoder * decoder,void * client_data)245 static FLAC__bool file_eof_callback (const FLAC__StreamDecoder *decoder, void *client_data)
246 {
247 struct cdtoc *t = (struct cdtoc*)client_data;
248 return zfile_ftell (t->handle) >= zfile_size (t->handle);
249 }
250
flac_get_size(struct cdtoc * t)251 static void flac_get_size (struct cdtoc *t)
252 {
253 FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new ();
254 if (decoder) {
255 FLAC__stream_decoder_set_md5_checking (decoder, false);
256 int init_status = FLAC__stream_decoder_init_stream (decoder,
257 &file_read_callback, &file_seek_callback, &file_tell_callback,
258 &file_len_callback, &file_eof_callback,
259 &flac_write_callback, &flac_metadata_callback, &flac_error_callback, t);
260 FLAC__stream_decoder_process_until_end_of_metadata (decoder);
261 FLAC__stream_decoder_delete (decoder);
262 }
263 }
flac_get_data(struct cdtoc * t)264 static uae_u8 *flac_get_data (struct cdtoc *t)
265 {
266 write_log (_T("FLAC: unpacking '%s'..\n"), zfile_getname (t->handle));
267 t->writeoffset = 0;
268 FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new ();
269 if (decoder) {
270 FLAC__stream_decoder_set_md5_checking (decoder, false);
271 int init_status = FLAC__stream_decoder_init_stream (decoder,
272 &file_read_callback, &file_seek_callback, &file_tell_callback,
273 &file_len_callback, &file_eof_callback,
274 &flac_write_callback, &flac_metadata_callback, &flac_error_callback, t);
275 FLAC__stream_decoder_process_until_end_of_stream (decoder);
276 FLAC__stream_decoder_delete (decoder);
277 write_log (_T("FLAC: %s unpacked\n"), zfile_getname (t->handle));
278 }
279 return t->data;
280 }
281
sub_to_interleaved(const uae_u8 * s,uae_u8 * d)282 void sub_to_interleaved (const uae_u8 *s, uae_u8 *d)
283 {
284 for (int i = 0; i < 8 * SUB_ENTRY_SIZE; i ++) {
285 int dmask = 0x80;
286 int smask = 1 << (7 - (i & 7));
287 (*d) = 0;
288 for (int j = 0; j < 8; j++) {
289 (*d) |= (s[(i / 8) + j * SUB_ENTRY_SIZE] & smask) ? dmask : 0;
290 dmask >>= 1;
291 }
292 d++;
293 }
294 }
sub_to_deinterleaved(const uae_u8 * s,uae_u8 * d)295 void sub_to_deinterleaved (const uae_u8 *s, uae_u8 *d)
296 {
297 for (int i = 0; i < 8 * SUB_ENTRY_SIZE; i ++) {
298 int dmask = 0x80;
299 int smask = 1 << (7 - (i / SUB_ENTRY_SIZE));
300 (*d) = 0;
301 for (int j = 0; j < 8; j++) {
302 (*d) |= (s[(i % SUB_ENTRY_SIZE) * 8 + j] & smask) ? dmask : 0;
303 dmask >>= 1;
304 }
305 d++;
306 }
307 }
308
getsub_deinterleaved(uae_u8 * dst,struct cdunit * cdu,struct cdtoc * t,int sector)309 static int getsub_deinterleaved (uae_u8 *dst, struct cdunit *cdu, struct cdtoc *t, int sector)
310 {
311 int ret = 0;
312 uae_sem_wait (&cdu->sub_sem);
313 if (t->subcode) {
314 if (t->enctype == ENC_CHD) {
315 #ifdef WITH_CHD
316 const cdrom_track_info *cti = t->chdtrack;
317 if (cdrom_read_subcode(cdu->chd_cdf, sector, dst, false))
318 ret = t->subcode;
319 #endif
320 } else if (t->subhandle) {
321 int offset = 0;
322 int totalsize = SUB_CHANNEL_SIZE;
323 if (t->skipsize) {
324 totalsize += t->size;
325 offset = t->size;
326 }
327 zfile_fseek (t->subhandle, (uae_u64)sector * totalsize + t->suboffset + offset, SEEK_SET);
328 if (zfile_fread (dst, SUB_CHANNEL_SIZE, 1, t->subhandle) > 0)
329 ret = t->subcode;
330 } else {
331 memcpy (dst, t->subdata + sector * SUB_CHANNEL_SIZE + t->suboffset, SUB_CHANNEL_SIZE);
332 ret = t->subcode;
333 }
334 }
335 if (!ret) {
336 memset (dst, 0, SUB_CHANNEL_SIZE);
337 // regenerate Q-subchannel
338 uae_u8 *s = dst + SUB_ENTRY_SIZE;
339 s[0] = (t->ctrl << 4) | (t->adr << 0);
340 s[1] = tobcd (t - &cdu->toc[0] + 1);
341 s[2] = tobcd (1);
342 int msf = lsn2msf (sector);
343 tolongbcd (s + 7, msf);
344 msf = lsn2msf (sector - t->address - 150);
345 tolongbcd (s + 3, msf);
346 ret = 2;
347 }
348 if (ret == 1) {
349 uae_u8 tmp[SUB_CHANNEL_SIZE];
350 memcpy (tmp, dst, SUB_CHANNEL_SIZE);
351 sub_to_deinterleaved (tmp, dst);
352 ret = 2;
353 }
354 uae_sem_post (&cdu->sub_sem);
355 return ret;
356 }
357
dosub(struct cdunit * cdu,uae_u8 * subbuf)358 static void dosub (struct cdunit *cdu, uae_u8 *subbuf)
359 {
360 uae_u8 subbuf2[SUB_CHANNEL_SIZE];
361
362 if (!cdu->cdda_subfunc)
363 return;
364
365 if (!subbuf) {
366 memset (subbuf2, 0, sizeof subbuf2);
367 cdu->cdda_subfunc (subbuf2, 1);
368 return;
369 }
370 sub_to_interleaved (subbuf, subbuf2);
371 cdu->cdda_subfunc (subbuf2, 1);
372 }
373
setstate(struct cdunit * cdu,int state)374 static int setstate (struct cdunit *cdu, int state)
375 {
376 cdu->cdda_play_state = state;
377 if (cdu->cdda_statusfunc)
378 return cdu->cdda_statusfunc (cdu->cdda_play_state);
379 return 0;
380 }
381
cdda_unpack_func(void * v)382 static void *cdda_unpack_func (void *v)
383 {
384 cdimage_unpack_thread = 1;
385 mp3decoder *mp3dec = NULL;
386
387 for (;;) {
388 uae_u32 cduidx = read_comm_pipe_u32_blocking (&unpack_pipe);
389 if (cdimage_unpack_thread == 0)
390 break;
391 uae_u32 tocidx = read_comm_pipe_u32_blocking (&unpack_pipe);
392 struct cdunit *cdu = &cdunits[cduidx];
393 struct cdtoc *t = &cdu->toc[tocidx];
394 if (t->handle) {
395 // force unpack if handle points to delayed zipped file
396 uae_s64 pos = zfile_ftell (t->handle);
397 zfile_fseek (t->handle, -1, SEEK_END);
398 uae_u8 b;
399 zfile_fread (&b, 1, 1, t->handle);
400 zfile_fseek (t->handle, pos, SEEK_SET);
401 if (!t->data && (t->enctype == AUDENC_MP3 || t->enctype == AUDENC_FLAC)) {
402 t->data = xcalloc (uae_u8, t->filesize + 2352);
403 cdimage_unpack_active = 1;
404 if (t->data) {
405 if (t->enctype == AUDENC_MP3) {
406 if (!mp3dec) {
407 try {
408 mp3dec = new mp3decoder();
409 } catch (exception) { };
410 }
411 if (mp3dec)
412 t->data = mp3dec->get (t->handle, t->data, t->filesize);
413 } else if (t->enctype == AUDENC_FLAC) {
414 flac_get_data (t);
415 }
416 }
417 }
418 }
419 cdimage_unpack_active = 2;
420 }
421 delete mp3dec;
422 cdimage_unpack_thread = -1;
423 return 0;
424 }
425
audio_unpack(struct cdunit * cdu,struct cdtoc * t)426 static void audio_unpack (struct cdunit *cdu, struct cdtoc *t)
427 {
428 // do this even if audio is not compressed, t->handle also could be
429 // compressed and we want to unpack it in background too
430 while (cdimage_unpack_active == 1)
431 sleep_millis(10);
432 cdimage_unpack_active = 0;
433 write_comm_pipe_u32 (&unpack_pipe, cdu - &cdunits[0], 0);
434 write_comm_pipe_u32 (&unpack_pipe, t - &cdu->toc[0], 1);
435 while (cdimage_unpack_active == 0)
436 sleep_millis(10);
437 }
438
439 static volatile int cda_bufon[2];
440 static cda_audio *cda;
441
next_cd_audio_buffer_callback(int bufnum)442 static void next_cd_audio_buffer_callback(int bufnum)
443 {
444 uae_sem_wait(&play_sem);
445 if (bufnum >= 0) {
446 cda_bufon[bufnum] = 0;
447 bufnum = 1 - bufnum;
448 if (cda_bufon[bufnum])
449 audio_cda_new_buffer((uae_s16*)cda->buffers[bufnum], CDDA_BUFFERS * 2352 / 4, bufnum, next_cd_audio_buffer_callback);
450 else
451 bufnum = -1;
452 }
453 if (bufnum < 0) {
454 audio_cda_new_buffer(NULL, 0, -1, NULL);
455 }
456 uae_sem_post(&play_sem);
457 }
458
cdda_play_func(void * v)459 static void *cdda_play_func (void *v)
460 {
461 int cdda_pos;
462 int bufnum;
463 int oldplay;
464 int idleframes = 0;
465 int silentframes = 0;
466 bool foundsub;
467 struct cdunit *cdu = (struct cdunit*)v;
468 int oldtrack = -1;
469 int mode = currprefs.sound_cdaudio;
470
471 cdu->thread_active = true;
472
473 while (cdu->cdda_play == 0)
474 sleep_millis(10);
475 oldplay = -1;
476
477 cda_bufon[0] = cda_bufon[1] = 0;
478 bufnum = 0;
479
480 cda = new cda_audio (CDDA_BUFFERS, 2352, 44100);
481
482 while (cdu->cdda_play > 0) {
483
484 if (oldplay != cdu->cdda_play) {
485 struct cdtoc *t;
486 int sector, diff;
487 #ifdef HAVE_SYS_TIMEB_H
488 struct _timeb tb1, tb2;
489 #else
490 #warning Missing timing functions
491 #endif
492
493 idleframes = 0;
494 silentframes = 0;
495 foundsub = false;
496 #ifdef HAVE_SYS_TIMEB_H
497 _ftime (&tb1);
498 #endif
499 cdda_pos = cdu->cdda_start;
500 oldplay = cdu->cdda_play;
501 sector = cdu->cd_last_pos = cdda_pos;
502 t = findtoc (cdu, §or, false);
503 if (!t) {
504 sector = cdu->cd_last_pos = cdda_pos + 2 * 75;
505 t = findtoc (cdu, §or, false);
506 if (!t) {
507 write_log (_T("IMAGE CDDA: illegal sector number %d\n"), cdu->cdda_start);
508 setstate (cdu, AUDIO_STATUS_PLAY_ERROR);
509 } else {
510 audio_unpack (cdu, t);
511 }
512 } else {
513 write_log (_T("IMAGE CDDA: playing from %d to %d, track %d ('%s', offset %lld, secoffset %d (%d))\n"),
514 cdu->cdda_start, cdu->cdda_end, t->track, t->fname, t->offset, sector, t->index1);
515 oldtrack = t->track;
516 audio_unpack (cdu, t);
517 }
518 idleframes = cdu->cdda_delay_frames;
519 while (cdu->cdda_paused && cdu->cdda_play > 0) {
520 sleep_millis(10);
521 idleframes = -1;
522 }
523
524 if (cdu->cdda_scan == 0) {
525 // find possible P-subchannel=1 and fudge starting point so that
526 // buggy CD32/CDTV software CD+G handling does not miss any frames
527 bool seenindex = false;
528 for (sector = cdda_pos - 200; sector < cdda_pos; sector++) {
529 int sec = sector;
530 t = findtoc (cdu, &sec, false);
531 if (t) {
532 uae_u8 subbuf[SUB_CHANNEL_SIZE];
533 getsub_deinterleaved (subbuf, cdu, t, sector);
534 if (seenindex) {
535 for (int i = 2 * SUB_ENTRY_SIZE; i < SUB_CHANNEL_SIZE; i++) {
536 if (subbuf[i]) { // non-zero R-W subchannels
537 int diff = cdda_pos - sector + 2;
538 write_log (_T("-> CD+G start pos fudge -> %d (%d)\n"), sector, -diff);
539 idleframes -= diff;
540 cdda_pos = sector;
541 break;
542 }
543 }
544 } else if (subbuf[0] == 0xff) { // P == 1?
545 seenindex = true;
546 }
547 }
548 }
549 }
550 cdda_pos -= idleframes;
551
552 #ifdef HAVE_SYS_TIMEB_H
553 _ftime (&tb2);
554 diff = (tb2.time * (uae_s64)1000 + tb2.millitm) - (tb1.time * (uae_s64)1000 + tb1.millitm);
555 diff -= cdu->cdda_delay;
556 #else
557 diff = 0;
558 #endif
559 if (idleframes >= 0 && diff < 0 && cdu->cdda_play > 0)
560 sleep_millis(-diff);
561 setstate (cdu, AUDIO_STATUS_IN_PROGRESS);
562
563 sector = cdda_pos;
564 struct cdtoc *t1 = findtoc (cdu, §or, false);
565 int tsector = cdda_pos + 2 * 75;
566 struct cdtoc *t2 = findtoc (cdu, &tsector, false);
567 if (t1 != t2) {
568 for (sector = cdda_pos; sector < cdda_pos + 2 * 75; sector++) {
569 int sec = sector;
570 t = findtoc (cdu, &sec, false);
571 if (t == t2)
572 break;
573 silentframes++;
574 }
575 }
576 }
577
578 if (mode) {
579 while (cda_bufon[bufnum] && cdu->cdda_play > 0)
580 sleep_millis(10);
581 } else {
582 cda->wait(bufnum);
583 }
584
585 cda_bufon[bufnum] = 0;
586 if (cdu->cdda_play <= 0)
587 goto end;
588
589 if (idleframes <= 0 && cdda_pos >= cdu->cdda_start && !isaudiotrack (&cdu->di.toc, cdda_pos)) {
590 setstate (cdu, AUDIO_STATUS_PLAY_ERROR);
591 write_log (_T("IMAGE CDDA: attempted to play data track %d\n"), cdda_pos);
592 goto end; // data track?
593 }
594
595 if ((cdda_pos < cdu->cdda_end || cdu->cdda_end == 0xffffffff) && !cdu->cdda_paused && cdu->cdda_play > 0) {
596 struct cdtoc *t;
597 int sector, cnt;
598 int dofinish = 0;
599
600 gui_flicker_led (LED_CD, cdu->di.unitnum - 1, LED_CD_AUDIO);
601
602 memset (cda->buffers[bufnum], 0, CDDA_BUFFERS * 2352);
603
604 for (cnt = 0; cnt < CDDA_BUFFERS && cdu->cdda_play > 0; cnt++) {
605 uae_u8 *dst = cda->buffers[bufnum] + cnt * 2352;
606 uae_u8 subbuf[SUB_CHANNEL_SIZE];
607 sector = cdda_pos;
608
609 memset (subbuf, 0, SUB_CHANNEL_SIZE);
610
611 t = findtoc (cdu, §or, false);
612 if (t) {
613 if (t->track != oldtrack) {
614 oldtrack = t->track;
615 write_log (_T("IMAGE CDDA: track %d ('%s', offset %lld, secoffset %d (%d))\n"),
616 t->track, t->fname, t->offset, sector, t->index1);
617 audio_unpack (cdu, t);
618 }
619 if (!(t->ctrl & 4)) {
620 if (t->enctype == ENC_CHD) {
621 #ifdef WITH_CHD
622 do_read (cdu, t, dst, sector, 0, t->size, true);
623 for (int i = 0; i < 2352; i+=2) {
624 uae_u8 p;
625 p = dst[i + 0];
626 dst[i + 0] = dst[i + 1];
627 dst[i +1] = p;
628 }
629 #endif
630 } else if (t->handle) {
631 int totalsize = t->size + t->skipsize;
632 int offset = t->offset;
633 if (offset >= 0) {
634 if ((t->enctype == AUDENC_MP3 || t->enctype == AUDENC_FLAC) && t->data) {
635 if (t->filesize >= sector * totalsize + offset + t->size)
636 memcpy (dst, t->data + sector * totalsize + offset, t->size);
637 } else if (t->enctype == AUDENC_PCM) {
638 if (sector * totalsize + offset + totalsize < t->filesize) {
639 zfile_fseek (t->handle, (uae_u64)sector * totalsize + offset, SEEK_SET);
640 zfile_fread (dst, t->size, 1, t->handle);
641 }
642 }
643 }
644 }
645 }
646 getsub_deinterleaved (subbuf, cdu, t, cdda_pos);
647 }
648
649 if (idleframes > 0 || silentframes > 0) {
650 if (idleframes > 0) {
651 idleframes--;
652 memset (subbuf, 0, SUB_CHANNEL_SIZE);
653 }
654 if (silentframes > 0)
655 silentframes--;
656 memset (dst, 0, 2352);
657 }
658
659 if (cdda_pos < cdu->cdda_start && cdu->cdda_scan == 0)
660 memset (dst, 0, 2352);
661
662 dosub (cdu, subbuf);
663
664 if (cdu->cdda_scan) {
665 cdda_pos += cdu->cdda_scan;
666 if (cdda_pos < 0)
667 cdda_pos = 0;
668 } else {
669 cdda_pos++;
670 }
671
672 if (cdda_pos - CDDA_BUFFERS < cdu->cdda_end && cdda_pos >= cdu->cdda_end)
673 dofinish = 1;
674
675 }
676
677 if (idleframes <= 0)
678 cdu->cd_last_pos = cdda_pos;
679
680 if (mode) {
681 if (cda_bufon[0] == 0 && cda_bufon[1] == 0) {
682 cda_bufon[bufnum] = 1;
683 next_cd_audio_buffer_callback(1 - bufnum);
684 }
685 audio_cda_volume(cdu->cdda_volume[0], cdu->cdda_volume[1]);
686 cda_bufon[bufnum] = 1;
687 } else {
688 cda_bufon[bufnum] = 1;
689 cda->setvolume (cdu->cdda_volume[0], cdu->cdda_volume[1]);
690 if (!cda->play (bufnum)) {
691 if (cdu->cdda_play > 0)
692 setstate (cdu, AUDIO_STATUS_PLAY_ERROR);
693 goto end;
694 }
695 }
696
697 if (dofinish) {
698 if (cdu->cdda_play >= 0)
699 setstate (cdu, AUDIO_STATUS_PLAY_COMPLETE);
700 cdu->cdda_play = -1;
701 cdda_pos = cdu->cdda_end + 1;
702 }
703
704 }
705
706 if (cda_bufon[0] == 0 && cda_bufon[1] == 0) {
707 while (cdu->cdda_paused && cdu->cdda_play == oldplay)
708 sleep_millis(10);
709 }
710
711 bufnum = 1 - bufnum;
712 }
713
714 end:
715 if (mode) {
716 next_cd_audio_buffer_callback(-1);
717 } else {
718 cda->wait (0);
719 cda->wait (1);
720 }
721
722 while (cdimage_unpack_active == 1)
723 sleep_millis(10);
724
725 delete cda;
726
727 cdu->cdda_play = 0;
728 write_log (_T("IMAGE CDDA: thread killed\n"));
729 cdu->thread_active = false;
730 return NULL;
731 }
732
733
cdda_stop(struct cdunit * cdu)734 static void cdda_stop (struct cdunit *cdu)
735 {
736 if (cdu->cdda_play != 0) {
737 cdu->cdda_play = -1;
738 while (cdu->cdda_play && cdu->thread_active) {
739 sleep_millis(10);
740 }
741 cdu->cdda_play = 0;
742 }
743 cdu->cdda_paused = 0;
744 cdu->cdda_play_state = 0;
745 }
746
747
command_pause(int unitnum,int paused)748 static int command_pause (int unitnum, int paused)
749 {
750 struct cdunit *cdu = unitisopen (unitnum);
751 if (!cdu)
752 return -1;
753 int old = cdu->cdda_paused;
754 if ((paused && cdu->cdda_play) || !paused)
755 cdu->cdda_paused = paused;
756 return old;
757 }
758
command_stop(int unitnum)759 static int command_stop (int unitnum)
760 {
761 struct cdunit *cdu = unitisopen (unitnum);
762 if (!cdu)
763 return 0;
764 cdda_stop (cdu);
765 return 1;
766 }
767
command_play(int unitnum,int startlsn,int endlsn,int scan,play_status_callback statusfunc,play_subchannel_callback subfunc)768 static int command_play (int unitnum, int startlsn, int endlsn, int scan, play_status_callback statusfunc, play_subchannel_callback subfunc)
769 {
770 struct cdunit *cdu = unitisopen (unitnum);
771 if (!cdu)
772 return 0;
773 if (cdu->cdda_play) {
774 cdu->cdda_play = -1;
775 while (cdu->thread_active)
776 Sleep (10);
777 cdu->cdda_play = 0;
778 }
779 cdu->cd_last_pos = startlsn;
780 cdu->cdda_start = startlsn;
781 cdu->cdda_end = endlsn;
782 cdu->cdda_subfunc = subfunc;
783 cdu->cdda_statusfunc = statusfunc;
784 cdu->cdda_scan = scan > 0 ? 10 : (scan < 0 ? 10 : 0);
785 cdu->cdda_delay = setstate (cdu, -1);
786 cdu->cdda_delay_frames = setstate (cdu, -2);
787 setstate (cdu, AUDIO_STATUS_NOT_SUPPORTED);
788 if (!isaudiotrack (&cdu->di.toc, startlsn)) {
789 setstate (cdu, AUDIO_STATUS_PLAY_ERROR);
790 return 0;
791 }
792 if (!cdu->thread_active) {
793 uae_start_thread (_T("cdimage_cdda_play"), cdda_play_func, cdu, NULL);
794 while (!cdu->thread_active)
795 Sleep (10);
796 }
797 cdu->cdda_play++;
798 return 1;
799 }
800
command_qcode(int unitnum,uae_u8 * buf,int sector)801 static int command_qcode (int unitnum, uae_u8 *buf, int sector)
802 {
803 struct cdunit *cdu = unitisopen (unitnum);
804 if (!cdu)
805 return 0;
806
807 uae_u8 subbuf[SUB_CHANNEL_SIZE];
808 uae_u8 *p;
809 int trk;
810 int pos;
811 int status;
812
813 memset (buf, 0, SUBQ_SIZE);
814 p = buf;
815
816 status = cdu->cdda_play_state;
817 if (cdu->cdda_play > 0 && cdu->cdda_paused)
818 status = AUDIO_STATUS_PAUSED;
819
820 if (sector < 0)
821 pos = cdu->cd_last_pos;
822 else
823 pos = sector;
824
825 p[1] = status;
826 p[3] = 12;
827
828 p = buf + 4;
829
830 struct cdtoc *td = NULL;
831 for (trk = 0; trk <= cdu->tracks; trk++) {
832 td = &cdu->toc[trk];
833 if (pos < td->address) {
834 if (trk > 0)
835 td--;
836 break;
837 }
838 if (pos >= td->address && pos < td[1].address)
839 break;
840 }
841 if (!td)
842 return 0;
843 getsub_deinterleaved (subbuf, cdu, td, pos);
844 memcpy (p, subbuf + 12, 12);
845 // write_log (_T("%6d %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n"),
846 // pos, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11]);
847 return 1;
848 }
849
command_volume(int unitnum,uae_u16 volume_left,uae_u16 volume_right)850 static uae_u32 command_volume (int unitnum, uae_u16 volume_left, uae_u16 volume_right)
851 {
852 struct cdunit *cdu = unitisopen (unitnum);
853 if (!cdu)
854 return -1;
855 uae_u32 old = (cdu->cdda_volume[1] << 16) | (cdu->cdda_volume[0] << 0);
856 cdu->cdda_volume[0] = volume_left;
857 cdu->cdda_volume[1] = volume_right;
858 return old;
859 }
860
861 extern void encode_l2 (uae_u8 *p, int address);
862
command_rawread(int unitnum,uae_u8 * data,int sector,int size,int sectorsize,uae_u32 extra)863 static int command_rawread (int unitnum, uae_u8 *data, int sector, int size, int sectorsize, uae_u32 extra)
864 {
865 int ret = 0;
866 struct cdunit *cdu = unitisopen (unitnum);
867 if (!cdu)
868 return 0;
869 int asector = sector;
870 struct cdtoc *t = findtoc (cdu, §or, true);
871 int ssize;
872
873 if (!t)
874 goto end;
875
876 ssize = t->size + t->skipsize;
877 cdda_stop (cdu);
878 if (sectorsize > 0) {
879 if (sectorsize == 2352 && t->size == 2336) {
880 // 2336 -> 2352
881 while (size-- > 0) {
882 int address = asector + 150;
883 data[0] = 0x00;
884 memset(data + 1, 0xff, 11);
885 data[12] = tobcd((uae_u8)(address / (60 * 75)));
886 data[13] = tobcd((uae_u8)((address / 75) % 60));
887 data[14] = tobcd((uae_u8)(address % 75));
888 data[15] = 2; /* MODE2 */
889 do_read(cdu, t, data + 16, sector, 0, t->size, false);
890 sector++;
891 asector++;
892 data += sectorsize;
893 ret += sectorsize;
894 }
895 } else if (sectorsize == 2352 && t->size == 2048) {
896 // 2048 -> 2352
897 while (size-- > 0) {
898 memset (data, 0, 16);
899 do_read (cdu, t, data + 16, sector, 0, 2048, false);
900 encode_l2 (data, sector + 150);
901 sector++;
902 asector++;
903 data += sectorsize;
904 ret += sectorsize;
905 }
906 } else if (sectorsize == 2048 && t->size == 2352) {
907 // 2352 -> 2048
908 while (size-- > 0) {
909 uae_u8 b = 0;
910 do_read (cdu, t, &b, sector, 15, 1, false);
911 do_read (cdu, t, data, sector, b == 2 ? 24 : 16, sectorsize, false);
912 sector++;
913 asector++;
914 data += sectorsize;
915 ret += sectorsize;
916 }
917 } else if (sectorsize == 2336 && t->size == 2352) {
918 // 2352 -> 2336
919 while (size-- > 0) {
920 uae_u8 b = 0;
921 do_read (cdu, t, &b, sector, 15, 1, false);
922 if (b != 2 && b != 0) // MODE0 or MODE2 only allowed
923 return 0;
924 do_read (cdu, t, data, sector, 16, sectorsize, false);
925 sector++;
926 asector++;
927 data += sectorsize;
928 ret += sectorsize;
929 }
930 } else if (sectorsize == t->size) {
931 // no change
932 while (size -- > 0) {
933 do_read (cdu, t, data, sector, 0, sectorsize, false);
934 sector++;
935 asector++;
936 data += sectorsize;
937 ret++;
938 }
939 }
940 cdu->cd_last_pos = asector;
941
942 } else {
943
944 uae_u8 sectortype = extra >> 16;
945 uae_u8 cmd9 = extra >> 8;
946 int sync = (cmd9 >> 7) & 1;
947 int headercodes = (cmd9 >> 5) & 3;
948 int userdata = (cmd9 >> 4) & 1;
949 int edcecc = (cmd9 >> 3) & 1;
950 int errorfield = (cmd9 >> 1) & 3;
951 uae_u8 subs = extra & 7;
952 if (subs != 0 && subs != 1 && subs != 2 && subs != 4) {
953 ret = -1;
954 goto end;
955 }
956
957 if (sectortype != 0 && sectortype != 1) {
958 ret = -2;
959 goto end;
960 }
961 if (t->size != 2352) {
962 ret = -1;
963 goto end;
964 }
965 for (int i = 0; i < size; i++) {
966 do_read (cdu, t, data, sector, 0, t->size, true);
967 uae_u8 *p = data + t->size;
968 if (subs) {
969 uae_u8 subdata[SUB_CHANNEL_SIZE];
970 getsub_deinterleaved (subdata, cdu, t, sector);
971 if (subs == 4) { // all, de-interleaved
972 memcpy (p, subdata, SUB_CHANNEL_SIZE);
973 p += SUB_CHANNEL_SIZE;
974 } else if (subs == 2) { // q-only
975 memcpy (p, subdata + SUB_ENTRY_SIZE, SUB_ENTRY_SIZE);
976 p += SUB_ENTRY_SIZE;
977 } else if (subs == 1) { // all, interleaved
978 sub_to_interleaved (subdata, p);
979 p += SUB_CHANNEL_SIZE;
980 }
981 }
982 ret += p - data;
983 data = p;
984 sector++;
985 }
986 }
987 end:
988 return ret;
989 }
990
991 // return standard 2048 byte sectors only
command_read(int unitnum,uae_u8 * data,int sector,int numsectors)992 static int command_read (int unitnum, uae_u8 *data, int sector, int numsectors)
993 {
994 struct cdunit *cdu = unitisopen (unitnum);
995 if (!cdu)
996 return 0;
997 struct cdtoc *t = findtoc (cdu, §or, true);
998 if (!t)
999 return 0;
1000 cdda_stop (cdu);
1001 if (t->size == 2048) {
1002 while (numsectors-- > 0) {
1003 do_read (cdu, t, data, sector, 0, 2048, false);
1004 data += 2048;
1005 sector++;
1006 }
1007 } else {
1008 while (numsectors-- > 0) {
1009 if (t->size == 2352) {
1010 uae_u8 b = 0;
1011 do_read (cdu, t, &b, sector, 15, 1, false);
1012 // 2 = MODE2
1013 do_read (cdu, t, data, sector, b == 2 ? 24 : 16, 2048, false);
1014 } else {
1015 // 2336
1016 do_read (cdu, t, data, sector, 8, 2048, false);
1017 }
1018 data += 2048;
1019 sector++;
1020 }
1021 }
1022 cdu->cd_last_pos = sector;
1023 return 1;
1024 }
1025
command_toc(int unitnum,struct cd_toc_head * th)1026 static int command_toc (int unitnum, struct cd_toc_head *th)
1027 {
1028 struct cdunit *cdu = unitisopen (unitnum);
1029 if (!cdu)
1030 return 0;
1031
1032 int i;
1033
1034 memset (&cdu->di.toc, 0, sizeof (struct cd_toc_head));
1035 if (!cdu->tracks)
1036 return 0;
1037
1038 memset (th, 0, sizeof (struct cd_toc_head));
1039 struct cd_toc *toc = &th->toc[0];
1040 th->first_track = 1;
1041 th->last_track = cdu->tracks;
1042 th->points = cdu->tracks + 3;
1043 th->tracks = cdu->tracks;
1044 th->firstaddress = 0;
1045 th->lastaddress = cdu->toc[cdu->tracks].address;
1046
1047 toc->adr = 1;
1048 toc->point = 0xa0;
1049 toc->track = th->first_track;
1050 toc++;
1051
1052 th->first_track_offset = 1;
1053 for (i = 0; i < cdu->tracks; i++) {
1054 toc->adr = cdu->toc[i].adr;
1055 toc->control = cdu->toc[i].ctrl;
1056 toc->track = i + 1;
1057 toc->point = i + 1;
1058 toc->paddress = cdu->toc[i].address;
1059 toc++;
1060 }
1061
1062 th->last_track_offset = cdu->tracks;
1063 toc->adr = 1;
1064 toc->point = 0xa1;
1065 toc->track = th->last_track;
1066 toc->paddress = th->lastaddress;
1067 toc++;
1068
1069 toc->adr = 1;
1070 toc->point = 0xa2;
1071 toc->paddress = th->lastaddress;
1072 toc++;
1073
1074 memcpy (&cdu->di.toc, th, sizeof (struct cd_toc_head));
1075 return 1;
1076 }
1077
skipspace(TCHAR ** s)1078 static void skipspace (TCHAR **s)
1079 {
1080 while (_istspace (**s))
1081 (*s)++;
1082 }
skipnspace(TCHAR ** s)1083 static void skipnspace (TCHAR **s)
1084 {
1085 while (!_istspace (**s))
1086 (*s)++;
1087 }
1088
nextstring(TCHAR ** sp)1089 static TCHAR *nextstring (TCHAR **sp)
1090 {
1091 TCHAR *s;
1092 TCHAR *out = NULL;
1093
1094 skipspace (sp);
1095 s = *sp;
1096 if (*s == '\"') {
1097 s++;
1098 out = s;
1099 while (*s && *s != '\"')
1100 s++;
1101 *s++ = 0;
1102 } else if (*s) {
1103 out = s;
1104 skipnspace (&s);
1105 *s++ = 0;
1106 }
1107 *sp = s;
1108 return out;
1109 }
1110
readval(const TCHAR * s)1111 static int readval (const TCHAR *s)
1112 {
1113 int base = 10;
1114 TCHAR *endptr;
1115 if (s[0] == '0' && _totupper (s[1]) == 'X')
1116 s += 2, base = 16;
1117 return _tcstol (s, &endptr, base);
1118 }
1119
1120 #define MEDIA_DESCRIPTOR "MEDIA DESCRIPTOR"
1121
1122 /* MDS spec structures from cdemu */
1123
1124 #define MDS_MEDIUM_CD 0x00 /* CD-ROM */
1125 #define MDS_MEDIUM_CD_R 0x01 /* CD-R */
1126 #define MDS_MEDIUM_CD_RW 0x02 /* CD-RW */
1127 #define MDS_MEDIUM_DVD 0x10 /* DVD-ROM */
1128 #define MDS_MEDIUM_DVD_MINUS_R 0x12 /* DVD-R */
1129
1130 #define MDS_TRACKMODE_UNKNOWN 0x00
1131 #define MDS_TRACKMODE_AUDIO 0xA9 /* sector size = 2352 */
1132 #define MDS_TRACKMODE_MODE1 0xAA /* sector size = 2048 */
1133 #define MDS_TRACKMODE_MODE2 0xAB /* sector size = 2336 */
1134 #define MDS_TRACKMODE_MODE2_FORM1 0xAC /* sector size = 2048 */
1135 #define MDS_TRACKMODE_MODE2_FORM2 0xAD /* sector size = 2324 (+4) */
1136
1137 #define MDS_SUBCHAN_NONE 0x00 /* no subchannel */
1138 #define MDS_SUBCHAN_PW_INTERLEAVED 0x08 /* 96-byte PW subchannel, interleaved */
1139
1140 #define MDS_POINT_TRACK_FIRST 0xA0 /* info about first track */
1141 #define MDS_POINT_TRACK_LAST 0xA1 /* info about last track */
1142 #define MDS_POINT_TRACK_LEADOUT 0xA2 /* info about lead-out */
1143
1144 #pragma pack(1)
1145
1146 typedef struct {
1147 uae_u8 signature[16]; /* "MEDIA DESCRIPTOR" */
1148 uae_u8 version[2]; /* Version ? */
1149 uae_u16 medium_type; /* Medium type */
1150 uae_u16 num_sessions; /* Number of sessions */
1151 uae_u16 __dummy1__[2]; /* Wish I knew... */
1152 uae_u16 bca_len; /* Length of BCA data (DVD-ROM) */
1153 uae_u32 __dummy2__[2];
1154 uae_u32 bca_data_offset; /* Offset to BCA data (DVD-ROM) */
1155 uae_u32 __dummy3__[6]; /* Probably more offsets */
1156 uae_u32 disc_structures_offset; /* Offset to disc structures */
1157 uae_u32 __dummy4__[3]; /* Probably more offsets */
1158 uae_u32 sessions_blocks_offset; /* Offset to session blocks */
1159 uae_u32 dpm_blocks_offset; /* offset to DPM data blocks */
1160 } MDS_Header; /* length: 88 bytes */
1161
1162 typedef struct {
1163 uae_s32 session_start; /* Session's start address */
1164 uae_s32 session_end; /* Session's end address */
1165 uae_u16 session_number; /* (Unknown) */
1166 uae_u8 num_all_blocks; /* Number of all data blocks. */
1167 uae_u8 num_nontrack_blocks; /* Number of lead-in data blocks */
1168 uae_u16 first_track; /* Total number of sessions in image? */
1169 uae_u16 last_track; /* Number of regular track data blocks. */
1170 uae_u32 __dummy2__; /* (unknown) */
1171 uae_u32 tracks_blocks_offset; /* Offset of lead-in+regular track data blocks. */
1172 } MDS_SessionBlock; /* length: 24 bytes */
1173
1174 typedef struct {
1175 uae_u8 mode; /* Track mode */
1176 uae_u8 subchannel; /* Subchannel mode */
1177 uae_u8 adr_ctl; /* Adr/Ctl */
1178 uae_u8 __dummy2__; /* Track flags? */
1179 uae_u8 point; /* Track number. (>0x99 is lead-in track) */
1180
1181 uae_u32 __dummy3__;
1182 uae_u8 min; /* Min */
1183 uae_u8 sec; /* Sec */
1184 uae_u8 frame; /* Frame */
1185 uae_u32 extra_offset; /* Start offset of this track's extra block. */
1186 uae_u16 sector_size; /* Sector size. */
1187
1188 uae_u8 __dummy4__[18];
1189 uae_u32 start_sector; /* Track start sector (PLBA). */
1190 uae_u64 start_offset; /* Track start offset. */
1191 uae_u8 session; /* Session or index? */
1192 uae_u8 __dummy5__[3];
1193 uae_u32 footer_offset; /* Start offset of footer. */
1194 uae_u8 __dummy6__[24];
1195 } MDS_TrackBlock; /* length: 80 bytes */
1196
1197 typedef struct {
1198 uae_u32 pregap; /* Number of sectors in pregap. */
1199 uae_u32 length; /* Number of sectors in track. */
1200 } MDS_TrackExtraBlock; /* length: 8 bytes */
1201
1202 typedef struct {
1203 uae_u32 filename_offset; /* Start offset of image filename. */
1204 uae_u32 widechar_filename; /* Seems to be set to 1 if widechar filename is used */
1205 uae_u32 __dummy1__;
1206 uae_u32 __dummy2__;
1207 } MDS_Footer; /* length: 16 bytes */
1208
1209 #pragma pack()
1210
parsemds(struct cdunit * cdu,struct zfile * zmds,const TCHAR * img)1211 static int parsemds (struct cdunit *cdu, struct zfile *zmds, const TCHAR *img)
1212 {
1213 MDS_Header *head;
1214 struct cdtoc *t;
1215 uae_u8 *mds = NULL;
1216 uae_u64 size;
1217 MDS_SessionBlock *sb;
1218
1219 write_log (_T("MDS TOC: '%s'\n"), img);
1220 size = zfile_size (zmds);
1221 mds = xmalloc (uae_u8, size);
1222 if (!mds)
1223 goto end;
1224 if (zfile_fread (mds, size, 1, zmds) != 1)
1225 goto end;
1226
1227 head = (MDS_Header*)mds;
1228 if (!memcmp (&head, MEDIA_DESCRIPTOR, strlen (MEDIA_DESCRIPTOR)))
1229 goto end;
1230 if (head->version[0] != 1) {
1231 write_log (_T("unsupported MDS version %d, only v.1 supported\n"), head->version[0]);
1232 goto end;
1233 }
1234
1235 sb = (MDS_SessionBlock*)(mds + head->sessions_blocks_offset);
1236 cdu->tracks = sb->last_track - sb->first_track + 1;
1237 for (int i = 0; i < sb->num_all_blocks; i++) {
1238 MDS_TrackBlock *tb = (MDS_TrackBlock*)(mds + sb->tracks_blocks_offset + i * sizeof (MDS_TrackBlock));
1239 int point = tb->point;
1240 int tracknum = -1;
1241 if (point == 0xa2)
1242 tracknum = cdu->tracks;
1243 else if (point >= 1 && point <= 99)
1244 tracknum = point - 1;
1245 if (tracknum >= 0) {
1246 MDS_Footer *footer = tb->footer_offset == 0 ? NULL : (MDS_Footer*)(mds + tb->footer_offset);
1247 MDS_TrackExtraBlock *teb = tb->extra_offset == 0 ? NULL : (MDS_TrackExtraBlock*)(mds + tb->extra_offset);
1248 t = &cdu->toc[tracknum];
1249 t->adr = tb->adr_ctl >> 4;
1250 t->ctrl = tb->adr_ctl & 15;
1251 if (point == 0xa2)
1252 t->address = sb->session_end;
1253 else
1254 t->address = tb->start_sector;
1255 t->track = point;
1256 t->offset = tb->start_offset;
1257 t->size = tb->sector_size;
1258
1259 if (point >= 100)
1260 continue;
1261
1262 if (footer) {
1263 TCHAR *fname = NULL;
1264 if (footer->widechar_filename == 0)
1265 fname = au ((char*)(mds + footer->filename_offset));
1266 else
1267 fname = my_strdup ((TCHAR*)(mds + footer->filename_offset));
1268 if (fname[0] == '*' && fname[1] == '.') {
1269 TCHAR newname[MAX_DPATH];
1270 _tcscpy (newname, img);
1271 TCHAR *ext = _tcsrchr (newname, '.');
1272 if (ext)
1273 _tcscpy (ext, fname + 1);
1274 xfree (fname);
1275 fname = my_strdup (newname);
1276 }
1277
1278 t->handle = zfile_fopen (fname, _T("rb"), ZFD_NORMAL);
1279 t->fname = my_strdup (fname);
1280 if (t->handle)
1281 t->filesize = zfile_size (t->handle);
1282 }
1283
1284 if (tb->subchannel && t->handle) {
1285 t->suboffset = t->size;
1286 t->subcode = 1; // interleaved
1287 t->subhandle = zfile_dup (t->handle);
1288 t->skipsize = SUB_CHANNEL_SIZE;
1289 t->size -= SUB_CHANNEL_SIZE;
1290 }
1291 if ((t->ctrl & 0x0c) != 4)
1292 t->enctype = AUDENC_PCM;
1293 }
1294 }
1295
1296 end:
1297 xfree (mds);
1298
1299 return cdu->tracks;
1300 }
1301
1302 #ifdef WITH_CHD
parsechd(struct cdunit * cdu,struct zfile * zcue,const TCHAR * img)1303 static int parsechd (struct cdunit *cdu, struct zfile *zcue, const TCHAR *img)
1304 {
1305 chd_error err;
1306 struct cdrom_file *cdf;
1307 struct zfile *f = zfile_dup (zcue);
1308 if (!f)
1309 return 0;
1310 chd_file *cf = new chd_file();
1311 err = cf->open(*f, false, NULL);
1312 if (err != CHDERR_NONE) {
1313 write_log (_T("CHD '%s' err=%d\n"), zfile_getname (zcue), err);
1314 zfile_fclose (f);
1315 return 0;
1316 }
1317 if (!(cdf = cdrom_open (cf))) {
1318 write_log (_T("Couldn't open CHD '%s' as CD\n"), zfile_getname (zcue));
1319 cf->close ();
1320 zfile_fclose (f);
1321 return 0;
1322 }
1323 cdu->chd_f = cf;
1324 cdu->chd_cdf = cdf;
1325
1326 const cdrom_toc *stoc = cdrom_get_toc (cdf);
1327 cdu->tracks = stoc->numtrks;
1328 uae_u32 hunkcnt = cf->hunk_count ();
1329 uae_u32 hunksize = cf->hunk_bytes ();
1330 uae_u32 cbytes;
1331 chd_codec_type compr;
1332
1333 for (int i = 0; i <cdu->tracks; i++) {
1334 int size;
1335 const cdrom_track_info *strack = &stoc->tracks[i];
1336 struct cdtoc *dtrack = &cdu->toc[i];
1337 dtrack->address = strack->physframeofs;
1338 dtrack->offset = strack->chdframeofs;
1339 dtrack->adr = cdrom_get_adr_control (cdf, i) >> 4;
1340 dtrack->ctrl = cdrom_get_adr_control (cdf, i) & 15;
1341 switch (strack->trktype)
1342 {
1343 case CD_TRACK_MODE1:
1344 case CD_TRACK_MODE2_FORM1:
1345 size = 2048;
1346 break;
1347 case CD_TRACK_MODE1_RAW:
1348 case CD_TRACK_MODE2_RAW:
1349 case CD_TRACK_AUDIO:
1350 default:
1351 size = 2352;
1352 break;
1353 case CD_TRACK_MODE2:
1354 case CD_TRACK_MODE2_FORM_MIX:
1355 size = 2336;
1356 break;
1357 case CD_TRACK_MODE2_FORM2:
1358 size = 2324;
1359 break;
1360 }
1361 dtrack->suboffset = size;
1362 dtrack->subcode = strack->subtype == CD_SUB_NONE ? 0 : strack->subtype == CD_SUB_RAW ? 1 : 2;
1363 dtrack->chdtrack = strack;
1364 dtrack->size = size;
1365 dtrack->enctype = ENC_CHD;
1366 dtrack->fname = my_strdup (zfile_getname (zcue));
1367 dtrack->filesize = cf->logical_bytes ();
1368 dtrack->track = i + 1;
1369 dtrack[1].address = dtrack->address + strack->frames;
1370 if (cf->hunk_info(dtrack->offset * CD_FRAME_SIZE / hunksize, compr, cbytes) == CHDERR_NONE) {
1371 TCHAR tmp[100];
1372 uae_u32 c = (uae_u32)compr;
1373 for (int j = 0; j < 4; j++) {
1374 uae_u8 b = c >> ((3 - j) * 8);
1375 if (c < 10) {
1376 b += '0';
1377 }
1378 if (b < ' ' || b >= 127)
1379 b = '.';
1380 tmp[j] = b;
1381 }
1382 tmp[4] = 0;
1383 dtrack->extrainfo = my_strdup (tmp);
1384 }
1385
1386 }
1387 return cdu->tracks;
1388 }
1389 #endif
1390
parseccd(struct cdunit * cdu,struct zfile * zcue,const TCHAR * img)1391 static int parseccd (struct cdunit *cdu, struct zfile *zcue, const TCHAR *img)
1392 {
1393 int mode;
1394 int num, tracknum, trackmode;
1395 int adr, control, lba;
1396 bool gotlba;
1397 struct cdtoc *t;
1398 struct zfile *zimg, *zsub;
1399 TCHAR fname[MAX_DPATH];
1400
1401 write_log (_T("CCD TOC: '%s'\n"), img);
1402 _tcscpy (fname, zfile_getname(zcue));
1403 TCHAR *ext = _tcsrchr (fname, '.');
1404 if (ext)
1405 *ext = 0;
1406 _tcscat (fname, _T(".img"));
1407 zimg = zfile_fopen (fname, _T("rb"), ZFD_NORMAL);
1408 if (!zimg) {
1409 write_log (_T("CCD: can't open '%s'\n"), fname);
1410 return 0;
1411 }
1412 ext = _tcsrchr (fname, '.');
1413 if (ext)
1414 *ext = 0;
1415 _tcscat (fname, _T(".sub"));
1416 zsub = zfile_fopen (fname, _T("rb"), ZFD_NORMAL);
1417 if (zsub)
1418 write_log (_T("CCD: '%s' detected\n"), fname);
1419
1420 num = -1;
1421 mode = -1;
1422 for (;;) {
1423 TCHAR buf[MAX_DPATH], *p;
1424 if (!zfile_fgets (buf, sizeof buf / sizeof (TCHAR), zcue))
1425 break;
1426 p = buf;
1427 skipspace (&p);
1428 if (!_tcsnicmp (p, _T("[DISC]"), 6)) {
1429 mode = 1;
1430 } else if (!_tcsnicmp (p, _T("[ENTRY "), 7)) {
1431 t = NULL;
1432 mode = 2;
1433 num = readval (p + 7);
1434 if (num < 0)
1435 break;
1436 adr = control = -1;
1437 gotlba = false;
1438 } else if (!_tcsnicmp (p, _T("[TRACK "), 7)) {
1439 mode = 3;
1440 tracknum = readval (p + 7);
1441 trackmode = -1;
1442 if (tracknum <= 0 || tracknum > 99)
1443 break;
1444 t = &cdu->toc[tracknum - 1];
1445 }
1446 if (mode < 0)
1447 continue;
1448 if (mode == 1) {
1449 if (!_tcsnicmp (p, _T("TocEntries="), 11)) {
1450 cdu->tracks = readval (p + 11) - 3;
1451 if (cdu->tracks <= 0 || cdu->tracks > 99)
1452 break;
1453 }
1454 continue;
1455 }
1456 if (cdu->tracks <= 0)
1457 break;
1458
1459 if (mode == 2) {
1460
1461 if (!_tcsnicmp (p, _T("SESSION="), 8)) {
1462 if (readval (p + 8) != 1)
1463 mode = -1;
1464 continue;
1465 } else if (!_tcsnicmp (p, _T("POINT="), 6)) {
1466 tracknum = readval (p + 6);
1467 if (tracknum <= 0)
1468 break;
1469 if (tracknum >= 0xa0 && tracknum != 0xa2) {
1470 mode = -1;
1471 continue;
1472 }
1473 if (tracknum == 0xa2)
1474 tracknum = cdu->tracks + 1;
1475 t = &cdu->toc[tracknum - 1];
1476 continue;
1477 }
1478 if (!_tcsnicmp (p, _T("ADR="), 4))
1479 adr = readval (p + 4);
1480 if (!_tcsnicmp (p, _T("CONTROL="), 8))
1481 control = readval (p + 8);
1482 if (!_tcsnicmp (p, _T("PLBA="), 5)) {
1483 lba = readval (p + 5);
1484 gotlba = true;
1485 }
1486 if (gotlba && adr >= 0 && control >= 0) {
1487 t->adr = adr;
1488 t->ctrl = control;
1489 t->address = lba;
1490 t->offset = 0;
1491 t->size = 2352;
1492 t->offset = lba * t->size;
1493 t->track = tracknum;
1494 if ((control & 0x0c) != 4)
1495 t->enctype = AUDENC_PCM;
1496 if (zsub) {
1497 t->subcode = 2;
1498 t->subhandle = zfile_dup (zsub);
1499 t->suboffset = 0;
1500 }
1501 if (zimg) {
1502 t->handle = zfile_dup (zimg);
1503 t->fname = my_strdup (zfile_getname (zimg));
1504 }
1505 mode = -1;
1506 }
1507
1508 } else if (mode == 3) {
1509
1510 if (!_tcsnicmp (p, _T("MODE="), 5))
1511 trackmode = _tstol (p + 5);
1512 if (trackmode < 0 || trackmode > 2)
1513 continue;
1514
1515 }
1516
1517 }
1518 zfile_fclose (zimg);
1519 zfile_fclose (zsub);
1520 return cdu->tracks;
1521 }
1522
parsecue(struct cdunit * cdu,struct zfile * zcue,const TCHAR * img)1523 static int parsecue (struct cdunit *cdu, struct zfile *zcue, const TCHAR *img)
1524 {
1525 int tracknum, pregap, postgap, lastpregap, lastpostgap;
1526 int newfile, secoffset;
1527 uae_s64 fileoffset;
1528 int index0;
1529 TCHAR *fname, *fnametype;
1530 audenc fnametypeid;
1531 int ctrl;
1532 mp3decoder *mp3dec = NULL;
1533
1534 fname = NULL;
1535 fnametype = NULL;
1536 tracknum = 0;
1537 fileoffset = 0;
1538 secoffset = 0;
1539 newfile = 0;
1540 ctrl = 0;
1541 index0 = -1;
1542 pregap = 0;
1543 postgap = 0;
1544 lastpregap = 0;
1545 lastpostgap = 0;
1546 fnametypeid = AUDENC_NONE;
1547
1548 write_log (_T("CUE TOC: '%s'\n"), img);
1549 for (;;) {
1550 TCHAR buf[MAX_DPATH], *p;
1551 if (!zfile_fgets (buf, sizeof buf / sizeof (TCHAR), zcue))
1552 break;
1553
1554 p = buf;
1555 skipspace (&p);
1556
1557 if (!_tcsnicmp (p, _T("FILE"), 4)) {
1558 p += 4;
1559 xfree (fname);
1560 fname = my_strdup (nextstring (&p));
1561 fnametype = nextstring (&p);
1562 fnametypeid = AUDENC_NONE;
1563 if (!fnametype)
1564 break;
1565 if (_tcsicmp (fnametype, _T("BINARY")) && _tcsicmp (fnametype, _T("WAVE")) && _tcsicmp (fnametype, _T("MP3")) && _tcsicmp (fnametype, _T("FLAC"))) {
1566 write_log (_T("CUE: unknown file type '%s' ('%s')\n"), fnametype, fname);
1567 }
1568 fnametypeid = AUDENC_PCM;
1569 if (!_tcsicmp (fnametype, _T("MP3")))
1570 fnametypeid = AUDENC_MP3;
1571 else if (!_tcsicmp (fnametype, _T("FLAC")))
1572 fnametypeid = AUDENC_FLAC;
1573 fileoffset = 0;
1574 newfile = 1;
1575 ctrl = 0;
1576 } else if (!_tcsnicmp (p, _T("FLAGS"), 5)) {
1577 ctrl &= ~(1 | 2 | 8);
1578 for (;;) {
1579 TCHAR *f = nextstring (&p);
1580 if (!f)
1581 break;
1582 if (!_tcsicmp (f, _T("PRE")))
1583 ctrl |= 1;
1584 if (!_tcsicmp (f, _T("DCP")))
1585 ctrl |= 2;
1586 if (!_tcsicmp (f, _T("4CH")))
1587 ctrl |= 8;
1588 }
1589 } else if (!_tcsnicmp (p, _T("TRACK"), 5)) {
1590 int size;
1591 TCHAR *tracktype;
1592
1593 p += 5;
1594 index0 = -1;
1595 lastpregap = 0;
1596 lastpostgap = 0;
1597 tracknum = _tstoi (nextstring (&p));
1598 tracktype = nextstring (&p);
1599 if (!tracktype)
1600 break;
1601 size = 2352;
1602 if (!_tcsicmp (tracktype, _T("AUDIO"))) {
1603 ctrl &= ~4;
1604 } else {
1605 ctrl |= 4;
1606 if (!_tcsicmp (tracktype, _T("MODE1/2048")))
1607 size = 2048;
1608 else if (!_tcsicmp (tracktype, _T("MODE1/2352")))
1609 size = 2352;
1610 else if (!_tcsicmp (tracktype, _T("MODE2/2336")) || !_tcsicmp (tracktype, _T("CDI/2336")))
1611 size = 2336;
1612 else if (!_tcsicmp (tracktype, _T("MODE2/2352")) || !_tcsicmp (tracktype, _T("CDI/2352")))
1613 size = 2352;
1614 else {
1615 write_log (_T("CUE: unknown tracktype '%s' ('%s')\n"), tracktype, fname);
1616 }
1617 }
1618 if (tracknum >= 1 && tracknum <= 99) {
1619 struct cdtoc *t = &cdu->toc[tracknum - 1];
1620 struct zfile *ztrack;
1621
1622 if (tracknum > 1 && newfile) {
1623 t--;
1624 secoffset += (int)(t->filesize / t->size);
1625 t++;
1626 }
1627
1628 newfile = 0;
1629 ztrack = zfile_fopen (fname, _T("rb"), ZFD_ARCHIVE | ZFD_DELAYEDOPEN);
1630 if (!ztrack) {
1631 TCHAR tmp[MAX_DPATH];
1632 _tcscpy (tmp, fname);
1633 p = tmp + _tcslen (tmp);
1634 while (p > tmp) {
1635 if (*p == '/' || *p == '\\') {
1636 ztrack = zfile_fopen (p + 1, _T("rb"), ZFD_ARCHIVE | ZFD_DELAYEDOPEN);
1637 if (ztrack) {
1638 xfree (fname);
1639 fname = my_strdup (p + 1);
1640 }
1641 break;
1642 }
1643 p--;
1644 }
1645 }
1646 if (!ztrack) {
1647 TCHAR tmp[MAX_DPATH];
1648 TCHAR *s2;
1649 _tcscpy (tmp, zfile_getname (zcue));
1650 s2 = _tcsrchr (tmp, '\\');
1651 if (!s2)
1652 s2 = _tcsrchr (tmp, '/');
1653 if (s2) {
1654 s2[0] = 0;
1655 _tcscat (tmp, FSDB_DIR_SEPARATOR_S);
1656 _tcscat (tmp, fname);
1657 ztrack = zfile_fopen (tmp, _T("rb"), ZFD_ARCHIVE | ZFD_DELAYEDOPEN);
1658 }
1659 }
1660 t->track = tracknum;
1661 t->ctrl = ctrl;
1662 t->adr = 1;
1663 t->handle = ztrack;
1664 t->size = size;
1665 t->fname = my_strdup (fname);
1666 if (tracknum > cdu->tracks)
1667 cdu->tracks = tracknum;
1668 if (t->handle)
1669 t->filesize = zfile_size (t->handle);
1670 }
1671 } else if (!_tcsnicmp (p, _T("PREGAP"), 6)) {
1672 TCHAR *tt;
1673 int tn;
1674 p += 6;
1675 tt = nextstring (&p);
1676 tn = _tstoi (tt) * 60 * 75;
1677 tn += _tstoi (tt + 3) * 75;
1678 tn += _tstoi (tt + 6);
1679 pregap += tn;
1680 lastpregap = tn;
1681 } else if (!_tcsnicmp (p, _T("POSTGAP"), 7)) {
1682 struct cdtoc *t = &cdu->toc[tracknum - 1];
1683 TCHAR *tt;
1684 int tn;
1685 p += 7;
1686 tt = nextstring (&p);
1687 tn = _tstoi (tt) * 60 * 75;
1688 tn += _tstoi (tt + 3) * 75;
1689 tn += _tstoi (tt + 6);
1690 postgap += tn;
1691 lastpostgap = tn;
1692 } else if (!_tcsnicmp (p, _T("INDEX"), 5)) {
1693 int idxnum;
1694 int tn = 0;
1695 TCHAR *tt;
1696 p += 5;
1697 idxnum = _tstoi (nextstring (&p));
1698 tt = nextstring (&p);
1699 tn = _tstoi (tt) * 60 * 75;
1700 tn += _tstoi (tt + 3) * 75;
1701 tn += _tstoi (tt + 6);
1702 if (idxnum == 0) {
1703 index0 = tn;
1704 } else if (idxnum == 1 && tracknum >= 1 && tracknum <= 99) {
1705 struct cdtoc *t = &cdu->toc[tracknum - 1];
1706 if (!t->address) {
1707 t->address = tn + secoffset;
1708 t->address += pregap;
1709 t->pregap = lastpregap;
1710 t->postgap = lastpostgap;
1711 if (index0 >= 0) {
1712 t->index1 = tn - index0;
1713 }
1714 if (lastpregap && !secoffset) {
1715 t->index1 = lastpregap;
1716 }
1717 int blockoffset = t->address - t->index1;
1718 if (tracknum > 1)
1719 blockoffset -= t[-1].address - t[-1].index1;
1720 fileoffset += blockoffset * t[-1].size;
1721 if (!secoffset) {
1722 // secoffset == 0: same file contained also previous track
1723 t->offset = fileoffset - pregap * t->size;
1724 }
1725 t->address += postgap;
1726 if (fnametypeid == AUDENC_PCM && t->handle) {
1727 struct zfile *zf = t->handle;
1728 uae_u8 buf[16] = { 0 };
1729 zfile_fread (buf, 12, 1, zf);
1730 if (!memcmp (buf, "RIFF", 4) && !memcmp (buf + 8, "WAVE", 4)) {
1731 int size;
1732 for (;;) {
1733 memset (buf, 0, sizeof buf);
1734 if (zfile_fread (buf, 8, 1, zf) != 1)
1735 break;
1736 size = (buf[4] << 0) | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24);
1737 if (!memcmp (buf, "data", 4))
1738 break;
1739 if (size <= 0)
1740 break;
1741 zfile_fseek (zf, size, SEEK_CUR);
1742 }
1743 t->offset += zfile_ftell (zf);
1744 t->filesize = size;
1745 }
1746 t->enctype = fnametypeid;
1747 } else if (fnametypeid == AUDENC_MP3 && t->handle) {
1748 if (!mp3dec) {
1749 try {
1750 mp3dec = new mp3decoder();
1751 } catch (exception) { }
1752 }
1753 if (mp3dec) {
1754 t->offset = 0;
1755 t->filesize = mp3dec->getsize (t->handle);
1756 if (t->filesize)
1757 t->enctype = fnametypeid;
1758 }
1759 } else if (fnametypeid == AUDENC_FLAC && t->handle) {
1760 flac_get_size (t);
1761 if (t->filesize)
1762 t->enctype = fnametypeid;
1763 }
1764 }
1765 }
1766 }
1767 }
1768
1769 struct cdtoc *t = &cdu->toc[cdu->tracks - 1];
1770 uae_s64 size = t->filesize;
1771 if (!secoffset)
1772 size -= fileoffset;
1773 if (size < 0)
1774 size = 0;
1775 size /= t->size;
1776 cdu->toc[cdu->tracks].address = t->address + (int)size;
1777
1778 xfree (fname);
1779
1780 delete mp3dec;
1781
1782 return cdu->tracks;
1783 }
1784
parse_image(struct cdunit * cdu,const TCHAR * img)1785 static int parse_image (struct cdunit *cdu, const TCHAR *img)
1786 {
1787 struct zfile *zcue;
1788 int i;
1789 const TCHAR *ext;
1790 int secoffset;
1791
1792 secoffset = 0;
1793 cdu->tracks = 0;
1794 if (!img)
1795 return 0;
1796 zcue = zfile_fopen (img, _T("rb"), ZFD_ARCHIVE | ZFD_CD | ZFD_DELAYEDOPEN);
1797 if (!zcue)
1798 return 0;
1799
1800 ext = _tcsrchr (zfile_getname (zcue), '.');
1801 if (ext) {
1802 TCHAR curdir[MAX_DPATH];
1803 TCHAR oldcurdir[MAX_DPATH], *p;
1804
1805 ext++;
1806 oldcurdir[0] = 0;
1807 _tcscpy (curdir, img);
1808 p = curdir + _tcslen (curdir);
1809 while (p > curdir) {
1810 if (*p == '/' || *p == '\\')
1811 break;
1812 p--;
1813 }
1814 *p = 0;
1815 if (p > curdir)
1816 my_setcurrentdir (curdir, oldcurdir);
1817
1818 if (!_tcsicmp (ext, _T("cue"))) {
1819 parsecue (cdu, zcue, img);
1820 } else if (!_tcsicmp (ext, _T("ccd"))) {
1821 parseccd (cdu, zcue, img);
1822 } else if (!_tcsicmp (ext, _T("mds"))) {
1823 parsemds (cdu, zcue, img);
1824 #ifdef WITH_CHD
1825 } else if (!_tcsicmp (ext, _T("chd"))) {
1826 if (oldcurdir[0])
1827 my_setcurrentdir (oldcurdir, NULL);
1828 parsechd (cdu, zcue, img);
1829 #endif
1830 }
1831
1832 if (oldcurdir[0])
1833 my_setcurrentdir (oldcurdir, NULL);
1834 }
1835 if (!cdu->tracks) {
1836 uae_u64 siz = zfile_size (zcue);
1837 if (siz >= 16384 && ((siz % 2048) == 0 || (siz % 2352) == 0)) {
1838 struct cdtoc *t = &cdu->toc[0];
1839 cdu->tracks = 1;
1840 t->ctrl = 4;
1841 t->adr = 1;
1842 t->fname = my_strdup (img);
1843 t->handle = zcue;
1844 t->size = (siz % 2048) == 0 ? 2048 : 2352;
1845 t->filesize = siz;
1846 t->track = 1;
1847 write_log (_T("CD: plain CD image mounted!\n"));
1848 cdu->toc[1].address = t->address + (int)(t->filesize / t->size);
1849 zcue = NULL;
1850 }
1851 }
1852
1853 if (!cdu->tracks)
1854 write_log (_T("CD: couldn't mount '%s'!\n"), img);
1855
1856 for (i = 0; i <= cdu->tracks; i++) {
1857 struct cdtoc *t = &cdu->toc[i];
1858 uae_u32 msf;
1859 if (t->pregap) {
1860 msf = lsn2msf (t->pregap - 150);
1861 write_log (_T(" PREGAP : %02d:%02d:%02d\n"), (msf >> 16) & 0x7fff, (msf >> 8) & 0xff, (msf >> 0) & 0xff);
1862 }
1863 if (t->index1) {
1864 msf = lsn2msf (t->index1 - 150);
1865 write_log (_T(" INDEX1 : %02d:%02d:%02d\n"), (msf >> 16) & 0x7fff, (msf >> 8) & 0xff, (msf >> 0) & 0xff);
1866 }
1867 if (i < cdu->tracks)
1868 write_log (_T("%2d: "), i + 1);
1869 else
1870 write_log (_T(" "));
1871 msf = lsn2msf (t->address);
1872 write_log (_T("%7d %02d:%02d:%02d"),
1873 t->address, (msf >> 16) & 0x7fff, (msf >> 8) & 0xff, (msf >> 0) & 0xff);
1874 if (i < cdu->tracks) {
1875 write_log (_T(" %s %x %10lld %10lld %s%s"),
1876 (t->ctrl & 4) ? _T("DATA ") : (t->subcode ? _T("CDA+SUB") : _T("CDA ")),
1877 t->ctrl, t->offset, t->filesize,
1878 t->extrainfo ? t->extrainfo : _T(""),
1879 t->handle == NULL && t->enctype != ENC_CHD ? _T("[FILE ERROR]") : _T(""));
1880 }
1881 write_log (_T("\n"));
1882 if (i < cdu->tracks)
1883 write_log (_T(" - %s\n"), t->fname);
1884 if (t->handle && !t->filesize)
1885 t->filesize = zfile_size (t->handle);
1886 if (t->postgap) {
1887 msf = lsn2msf (t->postgap - 150);
1888 write_log (_T(" POSTGAP: %02d:%02d:%02d\n"), (msf >> 16) & 0x7fff, (msf >> 8) & 0xff, (msf >> 0) & 0xff);
1889 }
1890 }
1891
1892 cdu->blocksize = 2048;
1893 cdu->cdsize = (uae_u64)cdu->toc[cdu->tracks].address * cdu->blocksize;
1894
1895
1896 zfile_fclose (zcue);
1897 return 1;
1898 }
1899
ismedia(int unitnum,int quick)1900 static int ismedia (int unitnum, int quick)
1901 {
1902 struct cdunit *cdu = &cdunits[unitnum];
1903 if (!cdu->enabled)
1904 return -1;
1905 return cdu->tracks > 0 ? 1 : 0;
1906 }
1907
info_device(int unitnum,struct device_info * di,int quick,int session)1908 static struct device_info *info_device (int unitnum, struct device_info *di, int quick, int session)
1909 {
1910 struct cdunit *cdu = &cdunits[unitnum];
1911 memset (di, 0, sizeof (struct device_info));
1912 if (!cdu->enabled)
1913 return NULL;
1914 di->open = cdu->open;
1915 di->removable = 1;
1916 di->bus = unitnum;
1917 di->target = 0;
1918 di->lun = 0;
1919 di->media_inserted = 0;
1920 di->bytespersector = 2048;
1921 di->mediapath[0] = 0;
1922 di->cylinders = 1;
1923 di->trackspercylinder = 1;
1924 di->sectorspertrack = (int)(cdu->cdsize / di->bytespersector);
1925 if (ismedia (unitnum, 1)) {
1926 di->media_inserted = 1;
1927 _tcscpy (di->mediapath, cdu->imgname);
1928 }
1929 memset (&di->toc, 0, sizeof (struct cd_toc_head));
1930 command_toc (unitnum, &di->toc);
1931 di->write_protected = 1;
1932 di->type = INQ_ROMD;
1933 di->unitnum = unitnum + 1;
1934 if (di->mediapath[0]) {
1935 _tcscpy (di->label, _T("IMG:"));
1936 _tcscat (di->label, di->mediapath);
1937 } else {
1938 _tcscpy (di->label, _T("IMG:<EMPTY>"));
1939 }
1940 _tcscpy (di->vendorid, _T("UAE"));
1941 _stprintf (di->productid, _T("SCSICD%d"), unitnum);
1942 _tcscpy (di->revision, _T("1.0"));
1943 di->backend = _T("IMAGE");
1944 return di;
1945 }
1946
unload_image(struct cdunit * cdu)1947 static void unload_image (struct cdunit *cdu)
1948 {
1949 int i;
1950
1951 for (i = 0; i < sizeof cdu->toc / sizeof (struct cdtoc); i++) {
1952 struct cdtoc *t = &cdu->toc[i];
1953 zfile_fclose (t->handle);
1954 if (t->handle != t->subhandle)
1955 zfile_fclose (t->subhandle);
1956 xfree (t->fname);
1957 xfree (t->data);
1958 xfree (t->subdata);
1959 xfree (t->extrainfo);
1960 }
1961 #ifdef WITH_CHD
1962 cdrom_close (cdu->chd_cdf);
1963 cdu->chd_cdf = NULL;
1964 if (cdu->chd_f)
1965 cdu->chd_f->close();
1966 cdu->chd_f = NULL;
1967 #endif
1968 memset (cdu->toc, 0, sizeof cdu->toc);
1969 cdu->tracks = 0;
1970 cdu->cdsize = 0;
1971 }
1972
1973
open_device(int unitnum,const TCHAR * ident,int flags)1974 static int open_device (int unitnum, const TCHAR *ident, int flags)
1975 {
1976 struct cdunit *cdu = &cdunits[unitnum];
1977 int ret = 0;
1978
1979 if (!cdu->open) {
1980 uae_sem_init (&cdu->sub_sem, 0, 1);
1981 cdu->imgname[0] = 0;
1982 if (ident)
1983 _tcscpy (cdu->imgname, ident);
1984 parse_image (cdu, ident);
1985 cdu->open = true;
1986 cdu->enabled = true;
1987 cdu->cdda_volume[0] = 0x7fff;
1988 cdu->cdda_volume[1] = 0x7fff;
1989 if (cdimage_unpack_thread == 0) {
1990 init_comm_pipe (&unpack_pipe, 10, 1);
1991 uae_start_thread (_T("cdimage_unpack"), cdda_unpack_func, NULL, NULL);
1992 while (cdimage_unpack_thread == 0)
1993 Sleep (10);
1994 }
1995 ret = 1;
1996 }
1997 blkdev_cd_change (unitnum, cdu->imgname);
1998 return ret;
1999 }
2000
close_device(int unitnum)2001 static void close_device (int unitnum)
2002 {
2003 struct cdunit *cdu = &cdunits[unitnum];
2004 if (cdu->open) {
2005 cdda_stop (cdu);
2006 cdu->open = false;
2007 if (cdimage_unpack_thread) {
2008 cdimage_unpack_thread = 0;
2009 write_comm_pipe_u32 (&unpack_pipe, -1, 0);
2010 write_comm_pipe_u32 (&unpack_pipe, -1, 1);
2011 while (cdimage_unpack_thread == 0)
2012 Sleep (10);
2013 cdimage_unpack_thread = 0;
2014 destroy_comm_pipe (&unpack_pipe);
2015 }
2016 unload_image (cdu);
2017 uae_sem_destroy (&cdu->sub_sem);
2018 }
2019 blkdev_cd_change (unitnum, cdu->imgname);
2020 }
2021
close_bus(void)2022 static void close_bus (void)
2023 {
2024 if (!bus_open) {
2025 write_log (_T("IMAGE close_bus() when already closed!\n"));
2026 return;
2027 }
2028 for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
2029 struct cdunit *cdu = &cdunits[i];
2030 if (cdu->open)
2031 close_device (i);
2032 cdu->enabled = false;
2033 }
2034 bus_open = 0;
2035 uae_sem_destroy(&play_sem);
2036 write_log (_T("IMAGE driver closed.\n"));
2037 }
2038
open_bus(int flags)2039 static int open_bus (int flags)
2040 {
2041 if (bus_open) {
2042 write_log (_T("IOCTL open_bus() more than once!\n"));
2043 return 1;
2044 }
2045 bus_open = 1;
2046 uae_sem_init(&play_sem, 0, 1);
2047 write_log (_T("Image driver open.\n"));
2048 return 1;
2049 }
2050
2051 struct device_functions devicefunc_cdimage = {
2052 _T("IMAGE"),
2053 open_bus, close_bus, open_device, close_device, info_device,
2054 0, 0, 0,
2055 command_pause, command_stop, command_play, command_volume, command_qcode,
2056 command_toc, command_read, command_rawread, 0,
2057 0, ismedia
2058 };
2059