1 /***************************************************************************************
2 * Genesis Plus
3 * CD drive processor & CD-DA fader
4 *
5 * Copyright (C) 2012-2013 Eke-Eke (Genesis Plus GX)
6 *
7 * Redistribution and use of this code or any derivative works are permitted
8 * provided that the following conditions are met:
9 *
10 * - Redistributions may not be sold, nor may they be used in a commercial
11 * product or activity.
12 *
13 * - Redistributions that are modified from the original source must include the
14 * complete source code, including the source code for all components used by a
15 * binary built from the modified sources. However, as a special exception, the
16 * source code distributed need not include anything that is normally distributed
17 * (in either source or binary form) with the major components (compiler, kernel,
18 * and so on) of the operating system on which the executable runs, unless that
19 * component itself accompanies the executable.
20 *
21 * - Redistributions must reproduce the above copyright notice, this list of
22 * conditions and the following disclaimer in the documentation and/or other
23 * materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 *
37 ****************************************************************************************/
38
39 #include "../pico_int.h"
40 #include "genplus_macros.h"
41 #include "cue.h"
42 #include "cdd.h"
43
44 #ifdef USE_LIBTREMOR
45 #define SUPPORTED_EXT 20
46 #else
47 #define SUPPORTED_EXT 10
48 #endif
49
50 cdd_t cdd;
51
52 /* BCD conversion lookup tables */
53 static const uint8 lut_BCD_8[100] =
54 {
55 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
56 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
57 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
58 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
59 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
60 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
61 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
62 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
63 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
64 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
65 };
66
67 static const uint16 lut_BCD_16[100] =
68 {
69 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009,
70 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109,
71 0x0200, 0x0201, 0x0202, 0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0209,
72 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309,
73 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409,
74 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509,
75 0x0600, 0x0601, 0x0602, 0x0603, 0x0604, 0x0605, 0x0606, 0x0607, 0x0608, 0x0609,
76 0x0700, 0x0701, 0x0702, 0x0703, 0x0704, 0x0705, 0x0706, 0x0707, 0x0708, 0x0709,
77 0x0800, 0x0801, 0x0802, 0x0803, 0x0804, 0x0805, 0x0806, 0x0807, 0x0808, 0x0809,
78 0x0900, 0x0901, 0x0902, 0x0903, 0x0904, 0x0905, 0x0906, 0x0907, 0x0908, 0x0909,
79 };
80
81 /* pre-build TOC */
82 static const uint16 toc_snatcher[21] =
83 {
84 56014, 495, 10120, 20555, 1580, 5417, 12502, 16090, 6553, 9681,
85 8148, 20228, 8622, 6142, 5858, 1287, 7424, 3535, 31697, 2485,
86 31380
87 };
88
89 static const uint16 toc_lunar[52] =
90 {
91 5422, 1057, 7932, 5401, 6380, 6592, 5862, 5937, 5478, 5870,
92 6673, 6613, 6429, 4996, 4977, 5657, 3720, 5892, 3140, 3263,
93 6351, 5187, 3249, 1464, 1596, 1750, 1751, 6599, 4578, 5205,
94 1550, 1827, 2328, 1346, 1569, 1613, 7199, 4928, 1656, 2549,
95 1875, 3901, 1850, 2399, 2028, 1724, 4889, 14551, 1184, 2132,
96 685, 3167
97 };
98
99 static const uint32 toc_shadow[15] =
100 {
101 10226, 70054, 11100, 12532, 12444, 11923, 10059, 10167, 10138, 13792,
102 11637, 2547, 2521, 3856, 900
103 };
104
105 static const uint32 toc_dungeon[13] =
106 {
107 2250, 22950, 16350, 24900, 13875, 19950, 13800, 15375, 17400, 17100,
108 3325, 6825, 25275
109 };
110
111 static const uint32 toc_ffight[26] =
112 {
113 11994, 9742, 10136, 9685, 9553, 14588, 9430, 8721, 9975, 9764,
114 9704, 12796, 585, 754, 951, 624, 9047, 1068, 817, 9191, 1024,
115 14562, 10320, 8627, 3795, 3047
116 };
117
118 static const uint32 toc_ffightj[29] =
119 {
120 11994, 9752, 10119, 9690, 9567, 14575, 9431, 8731, 9965, 9763,
121 9716, 12791, 579, 751, 958, 630, 9050, 1052, 825, 9193, 1026,
122 14553, 9834, 10542, 1699, 1792, 1781, 3783, 3052
123 };
124
125 #if 0
126 /* supported WAVE file header (16-bit stereo samples @44.1kHz) */
127 static const unsigned char waveHeader[32] =
128 {
129 0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
130 0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61
131 };
132 #endif
133
134 #ifdef USE_LIBTREMOR
135 #ifdef DISABLE_MANY_OGG_OPEN_FILES
ogg_free(int i)136 static void ogg_free(int i)
137 {
138 /* clear OGG file descriptor to prevent file from being closed */
139 cdd.toc.tracks[i].vf.datasource = NULL;
140
141 /* close VORBIS file structure */
142 ov_clear(&cdd.toc.tracks[i].vf);
143
144 /* indicates that the track is a seekable VORBIS file */
145 cdd.toc.tracks[i].vf.seekable = 1;
146
147 /* reset file reading position */
148 fseek(cdd.toc.tracks[i].fd, 0, SEEK_SET);
149 }
150 #endif
151 #endif
152
cdd_reset(void)153 void cdd_reset(void)
154 {
155 /* reset cycle counter */
156 cdd.cycles = 0;
157
158 /* reset drive access latency */
159 cdd.latency = 0;
160
161 /* reset track index */
162 cdd.index = 0;
163
164 /* reset logical block address */
165 cdd.lba = 0;
166
167 /* reset status */
168 cdd.status = NO_DISC;
169
170 /* reset CD-DA fader (full volume) */
171 cdd.volume = 0x400;
172
173 /* clear CD-DA output */
174 cdd.audio[0] = cdd.audio[1] = 0;
175 }
176
177 /* FIXME: use cdd_read_audio() instead */
cdd_change_track(int index,int lba)178 static void cdd_change_track(int index, int lba)
179 {
180 int i, base, lba_offset, lb_len;
181
182 for (i = index; i > 0; i--)
183 if (cdd.toc.tracks[i].fd != NULL)
184 break;
185
186 Pico_mcd->cdda_stream = cdd.toc.tracks[i].fd;
187 base = cdd.toc.tracks[index].offset;
188 lba_offset = lba - cdd.toc.tracks[index].start;
189 lb_len = cdd.toc.tracks[index].end - cdd.toc.tracks[index].start;
190
191 elprintf(EL_CD, "play #%d lba %d base %d", index, lba, base);
192
193 cdda_start_play(base, lba_offset, lb_len);
194 }
195
cdd_context_save(uint8 * state)196 int cdd_context_save(uint8 *state)
197 {
198 int bufferptr = 0;
199
200 save_param(&cdd.cycles, sizeof(cdd.cycles));
201 save_param(&cdd.latency, sizeof(cdd.latency));
202 save_param(&cdd.index, sizeof(cdd.index));
203 save_param(&cdd.lba, sizeof(cdd.lba));
204 save_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
205 save_param(&cdd.volume, sizeof(cdd.volume));
206 save_param(&cdd.status, sizeof(cdd.status));
207
208 return bufferptr;
209 }
210
cdd_context_load(uint8 * state)211 int cdd_context_load(uint8 *state)
212 {
213 int lba;
214 int bufferptr = 0;
215
216 #ifdef USE_LIBTREMOR
217 #ifdef DISABLE_MANY_OGG_OPEN_FILES
218 /* close previous track VORBIS file structure to save memory */
219 if (cdd.toc.tracks[cdd.index].vf.datasource)
220 {
221 ogg_free(cdd.index);
222 }
223 #endif
224 #endif
225
226 load_param(&cdd.cycles, sizeof(cdd.cycles));
227 load_param(&cdd.latency, sizeof(cdd.latency));
228 load_param(&cdd.index, sizeof(cdd.index));
229 load_param(&cdd.lba, sizeof(cdd.lba));
230 load_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
231 load_param(&cdd.volume, sizeof(cdd.volume));
232 load_param(&cdd.status, sizeof(cdd.status));
233
234 /* adjust current LBA within track limit */
235 lba = cdd.lba;
236 if (lba < cdd.toc.tracks[cdd.index].start)
237 {
238 lba = cdd.toc.tracks[cdd.index].start;
239 }
240
241 /* seek to current track position */
242 if (!cdd.index)
243 {
244 /* DATA track */
245 if (cdd.toc.tracks[0].fd)
246 {
247 pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
248 }
249 }
250 #ifdef USE_LIBTREMOR
251 else if (cdd.toc.tracks[cdd.index].vf.seekable)
252 {
253 #ifdef DISABLE_MANY_OGG_OPEN_FILES
254 /* VORBIS file need to be opened first */
255 ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
256 #endif
257 /* VORBIS AUDIO track */
258 ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
259 }
260 #endif
261 #if 0
262 else if (cdd.toc.tracks[cdd.index].fd)
263 {
264 /* PCM AUDIO track */
265 fseek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
266 }
267 #else
268 else
269 {
270 cdd_change_track(cdd.index, lba);
271 }
272 #endif
273
274 return bufferptr;
275 }
276
cdd_context_load_old(uint8 * state)277 int cdd_context_load_old(uint8 *state)
278 {
279 memcpy(&cdd.lba, state + 8, sizeof(cdd.lba));
280 return 12 * 4;
281 }
282
cdd_load(const char * filename,int type)283 int cdd_load(const char *filename, int type)
284 {
285 char header[0x210];
286 int ret;
287
288 /* first unmount any loaded disc */
289 cdd_unload();
290
291 /* genplus parses cue here, in PD we use our own parser */
292 ret = load_cd_image(filename, &type);
293 if (ret != 0)
294 return ret;
295
296 /* read first 16 bytes */
297 pm_read(header, 0x10, cdd.toc.tracks[0].fd);
298
299 /* look for valid CD image ID string */
300 if (memcmp("SEGADISCSYSTEM", header, 14))
301 {
302 /* if not found, read next 16 bytes */
303 pm_read(header, 0x10, cdd.toc.tracks[0].fd);
304
305 /* look again for valid CD image ID string */
306 if (memcmp("SEGADISCSYSTEM", header, 14))
307 {
308 elprintf(EL_STATUS|EL_ANOMALY, "cd: bad cd image?");
309 /* assume bin without security code */
310 }
311
312 /* BIN format (2352 bytes data blocks) */
313 cdd.sectorSize = 2352;
314 }
315 else
316 {
317 /* ISO format (2048 bytes data blocks) */
318 cdd.sectorSize = 2048;
319 }
320
321 ret = (type == CT_BIN) ? 2352 : 2048;
322 if (ret != cdd.sectorSize)
323 elprintf(EL_STATUS|EL_ANOMALY, "cd: type detection mismatch");
324
325 /* read CD image header + security code */
326 pm_read(header + 0x10, 0x200, cdd.toc.tracks[0].fd);
327
328 /* Simulate audio tracks if none found */
329 if (cdd.toc.last == 1)
330 {
331 /* Some games require exact TOC infos */
332 if (strstr(header + 0x180,"T-95035") != NULL)
333 {
334 /* Snatcher */
335 cdd.toc.last = cdd.toc.end = 0;
336 do
337 {
338 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
339 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_snatcher[cdd.toc.last];
340 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
341 cdd.toc.last++;
342 }
343 while (cdd.toc.last < 21);
344 }
345 else if (strstr(header + 0x180,"T-127015") != NULL)
346 {
347 /* Lunar - The Silver Star */
348 cdd.toc.last = cdd.toc.end = 0;
349 do
350 {
351 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
352 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_lunar[cdd.toc.last];
353 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
354 cdd.toc.last++;
355 }
356 while (cdd.toc.last < 52);
357 }
358 else if (strstr(header + 0x180,"T-113045") != NULL)
359 {
360 /* Shadow of the Beast II */
361 cdd.toc.last = cdd.toc.end = 0;
362 do
363 {
364 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
365 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_shadow[cdd.toc.last];
366 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
367 cdd.toc.last++;
368 }
369 while (cdd.toc.last < 15);
370 }
371 else if (strstr(header + 0x180,"T-143025") != NULL)
372 {
373 /* Dungeon Explorer */
374 cdd.toc.last = cdd.toc.end = 0;
375 do
376 {
377 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
378 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_dungeon[cdd.toc.last];
379 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
380 cdd.toc.last++;
381 }
382 while (cdd.toc.last < 13);
383 }
384 else if (strstr(header + 0x180,"MK-4410") != NULL)
385 {
386 /* Final Fight CD (USA, Europe) */
387 cdd.toc.last = cdd.toc.end = 0;
388 do
389 {
390 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
391 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffight[cdd.toc.last];
392 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
393 cdd.toc.last++;
394 }
395 while (cdd.toc.last < 26);
396 }
397 else if (strstr(header + 0x180,"G-6013") != NULL)
398 {
399 /* Final Fight CD (Japan) */
400 cdd.toc.last = cdd.toc.end = 0;
401 do
402 {
403 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
404 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffightj[cdd.toc.last];
405 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
406 cdd.toc.last++;
407 }
408 while (cdd.toc.last < 29);
409 }
410 #if 0
411 else
412 {
413 /* default TOC (99 tracks & 2s per audio tracks) */
414 do
415 {
416 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end + 2*75;
417 cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + 2*75;
418 cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
419 cdd.toc.last++;
420 }
421 while ((cdd.toc.last < 99) && (cdd.toc.end < 56*60*75));
422 }
423 #endif
424 }
425
426 /* Lead-out */
427 cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
428
429 /* CD loaded */
430 cdd.loaded = 1;
431
432 /* disc not scanned yet */
433 cdd.status = NO_DISC;
434
435 return 0;
436 }
437
cdd_unload(void)438 int cdd_unload(void)
439 {
440 int was_loaded = cdd.loaded;
441
442 if (cdd.loaded)
443 {
444 int i;
445
446 /* close CD tracks */
447 if (cdd.toc.tracks[0].fd)
448 {
449 pm_close(cdd.toc.tracks[0].fd);
450 cdd.toc.tracks[0].fd = NULL;
451 }
452
453 for (i = 1; i < cdd.toc.last; i++)
454 {
455 #ifdef USE_LIBTREMOR
456 if (cdd.toc.tracks[i].vf.datasource)
457 {
458 /* close VORBIS file (if still opened) */
459 ov_clear(&cdd.toc.tracks[i].vf);
460 }
461 else
462 #endif
463 if (cdd.toc.tracks[i].fd)
464 {
465 /* close file */
466 if (Pico_mcd->cdda_type == CT_MP3)
467 fclose(cdd.toc.tracks[i].fd);
468 else
469 pm_close(cdd.toc.tracks[0].fd);
470
471 /* detect single file images */
472 if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)
473 {
474 /* exit loop */
475 i = cdd.toc.last;
476 }
477 }
478 }
479
480 /* CD unloaded */
481 cdd.loaded = 0;
482
483 if (cdd.status != CD_OPEN)
484 cdd.status = NO_DISC;
485 }
486
487 /* reset TOC */
488 memset(&cdd.toc, 0x00, sizeof(cdd.toc));
489
490 /* unknown CD image file format */
491 cdd.sectorSize = 0;
492
493 return was_loaded;
494 }
495
cdd_read_data(uint8 * dst)496 void cdd_read_data(uint8 *dst)
497 {
498 /* only read DATA track sectors */
499 if ((cdd.lba >= 0) && (cdd.lba < cdd.toc.tracks[0].end))
500 {
501 /* BIN format ? */
502 if (cdd.sectorSize == 2352)
503 {
504 /* skip 16-byte header */
505 pm_seek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET);
506 }
507
508 /* read sector data (Mode 1 = 2048 bytes) */
509 pm_read(dst, 2048, cdd.toc.tracks[0].fd);
510 }
511 }
512
513 #if 0
514 void cdd_read_audio(unsigned int samples)
515 {
516 /* previous audio outputs */
517 int16 l = cdd.audio[0];
518 int16 r = cdd.audio[1];
519
520 /* get number of internal clocks (samples) needed */
521 samples = blip_clocks_needed(blip[0], samples);
522
523 /* audio track playing ? */
524 if (!Pico_mcd->s68k_regs[0x36+0] && cdd.toc.tracks[cdd.index].fd)
525 {
526 int i, mul, delta;
527
528 /* current CD-DA fader volume */
529 int curVol = cdd.volume;
530
531 /* CD-DA fader volume setup (0-1024) */
532 int endVol = Pico_mcd->regs[0x34>>1].w >> 4;
533
534 /* read samples from current block */
535 #ifdef USE_LIBTREMOR
536 if (cdd.toc.tracks[cdd.index].vf.datasource)
537 {
538 int len, done = 0;
539 int16 *ptr = (int16 *) (cdc.ram);
540 samples = samples * 4;
541 while (done < samples)
542 {
543 len = ov_read(&cdd.toc.tracks[cdd.index].vf, (char *)(cdc.ram + done), samples - done, 0);
544 if (len <= 0)
545 {
546 done = samples;
547 break;
548 }
549 done += len;
550 }
551 samples = done / 4;
552
553 /* process 16-bit (host-endian) stereo samples */
554 for (i=0; i<samples; i++)
555 {
556 /* CD-DA fader multiplier (cf. LC7883 datasheet) */
557 /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
558 mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
559
560 /* left channel */
561 delta = ((ptr[0] * mul) / 1024) - l;
562 ptr++;
563 l += delta;
564 blip_add_delta_fast(blip[0], i, delta);
565
566 /* right channel */
567 delta = ((ptr[0] * mul) / 1024) - r;
568 ptr++;
569 r += delta;
570 blip_add_delta_fast(blip[1], i, delta);
571
572 /* update CD-DA fader volume (one step/sample) */
573 if (curVol < endVol)
574 {
575 /* fade-in */
576 curVol++;
577 }
578 else if (curVol > endVol)
579 {
580 /* fade-out */
581 curVol--;
582 }
583 else if (!curVol)
584 {
585 /* audio will remain muted until next setup */
586 break;
587 }
588 }
589 }
590 else
591 #endif
592 {
593 #ifdef LSB_FIRST
594 int16 *ptr = (int16 *) (cdc.ram);
595 #else
596 uint8 *ptr = cdc.ram;
597 #endif
598 fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd);
599
600 /* process 16-bit (little-endian) stereo samples */
601 for (i=0; i<samples; i++)
602 {
603 /* CD-DA fader multiplier (cf. LC7883 datasheet) */
604 /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
605 mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
606
607 /* left channel */
608 #ifdef LSB_FIRST
609 delta = ((ptr[0] * mul) / 1024) - l;
610 ptr++;
611 #else
612 delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
613 ptr += 2;
614 #endif
615 l += delta;
616 blip_add_delta_fast(blip[0], i, delta);
617
618 /* right channel */
619 #ifdef LSB_FIRST
620 delta = ((ptr[0] * mul) / 1024) - r;
621 ptr++;
622 #else
623 delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r;
624 ptr += 2;
625 #endif
626 r += delta;
627 blip_add_delta_fast(blip[1], i, delta);
628
629 /* update CD-DA fader volume (one step/sample) */
630 if (curVol < endVol)
631 {
632 /* fade-in */
633 curVol++;
634 }
635 else if (curVol > endVol)
636 {
637 /* fade-out */
638 curVol--;
639 }
640 else if (!curVol)
641 {
642 /* audio will remain muted until next setup */
643 break;
644 }
645 }
646 }
647
648 /* save current CD-DA fader volume */
649 cdd.volume = curVol;
650
651 /* save last audio output for next frame */
652 cdd.audio[0] = l;
653 cdd.audio[1] = r;
654 }
655 else
656 {
657 /* no audio output */
658 if (l) blip_add_delta_fast(blip[0], 0, -l);
659 if (r) blip_add_delta_fast(blip[1], 0, -r);
660
661 /* save audio output for next frame */
662 cdd.audio[0] = 0;
663 cdd.audio[1] = 0;
664 }
665
666 /* end of Blip Buffer timeframe */
667 blip_end_frame(blip[0], samples);
668 blip_end_frame(blip[1], samples);
669 }
670 #endif
671
672
cdd_update(void)673 void cdd_update(void)
674 {
675 #ifdef LOG_CDD
676 error("LBA = %d (track n�%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
677 #endif
678
679 /* seeking disc */
680 if (cdd.status == CD_SEEK)
681 {
682 /* drive latency */
683 if (cdd.latency > 0)
684 {
685 cdd.latency--;
686 return;
687 }
688
689 /* drive is ready */
690 cdd.status = CD_READY;
691 }
692
693 /* reading disc */
694 else if (cdd.status == CD_PLAY)
695 {
696 /* drive latency */
697 if (cdd.latency > 0)
698 {
699 cdd.latency--;
700 return;
701 }
702
703 /* track type */
704 if (!cdd.index)
705 {
706 /* DATA sector header (CD-ROM Mode 1) */
707 uint8 header[4];
708 uint32 msf = cdd.lba + 150;
709 header[0] = lut_BCD_8[(msf / 75) / 60];
710 header[1] = lut_BCD_8[(msf / 75) % 60];
711 header[2] = lut_BCD_8[(msf % 75)];
712 header[3] = 0x01;
713
714 /* data track sector read is controlled by CDC */
715 cdd.lba += cdc_decoder_update(header);
716 }
717 else if (cdd.index < cdd.toc.last)
718 {
719 uint8 header[4] = { 0, };
720
721 /* check against audio track start index */
722 if (cdd.lba >= cdd.toc.tracks[cdd.index].start)
723 {
724 /* audio track playing */
725 Pico_mcd->s68k_regs[0x36+0] = 0x00;
726 }
727
728 /* audio blocks are still sent to CDC as well as CD DAC/Fader */
729 cdc_decoder_update(header);
730
731 /* next audio block is automatically read */
732 cdd.lba++;
733 }
734 else
735 {
736 /* end of disc */
737 cdd.status = CD_END;
738 return;
739 }
740
741 /* check end of current track */
742 if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
743 {
744 #ifdef USE_LIBTREMOR
745 #ifdef DISABLE_MANY_OGG_OPEN_FILES
746 /* close previous track VORBIS file structure to save memory */
747 if (cdd.toc.tracks[cdd.index].vf.datasource)
748 {
749 ogg_free(cdd.index);
750 }
751 #endif
752 #endif
753 /* play next track */
754 cdd.index++;
755
756 /* PAUSE between tracks */
757 Pico_mcd->s68k_regs[0x36+0] = 0x01;
758
759 /* seek to next audio track start */
760 #ifdef USE_LIBTREMOR
761 if (cdd.toc.tracks[cdd.index].vf.seekable)
762 {
763 #ifdef DISABLE_MANY_OGG_OPEN_FILES
764 /* VORBIS file need to be opened first */
765 ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
766 #endif
767 ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, -cdd.toc.tracks[cdd.index].offset);
768 }
769 else
770 #endif
771 #if 0
772 if (cdd.toc.tracks[cdd.index].fd)
773 {
774 fseek(cdd.toc.tracks[cdd.index].fd, (cdd.toc.tracks[cdd.index].start * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
775 }
776 #else
777 {
778 cdd_change_track(cdd.index, cdd.lba);
779 }
780 #endif
781 }
782 }
783
784 /* scanning disc */
785 else if (cdd.status == CD_SCAN)
786 {
787 /* fast-forward or fast-rewind */
788 cdd.lba += cdd.scanOffset;
789
790 /* check current track limits */
791 if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
792 {
793 #ifdef USE_LIBTREMOR
794 #ifdef DISABLE_MANY_OGG_OPEN_FILES
795 /* close previous track VORBIS file structure to save memory */
796 if (cdd.toc.tracks[cdd.index].vf.datasource)
797 {
798 ogg_free(cdd.index);
799 }
800 #endif
801 #endif
802 /* next track */
803 cdd.index++;
804
805 /* skip directly to track start position */
806 cdd.lba = cdd.toc.tracks[cdd.index].start;
807
808 /* AUDIO track playing ? */
809 if (cdd.status == CD_PLAY)
810 {
811 Pico_mcd->s68k_regs[0x36+0] = 0x00;
812 }
813 }
814 else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
815 {
816 #ifdef USE_LIBTREMOR
817 #ifdef DISABLE_MANY_OGG_OPEN_FILES
818 /* close previous track VORBIS file structure to save memory */
819 if (cdd.toc.tracks[cdd.index].vf.datasource)
820 {
821 ogg_free(cdd.index);
822 }
823 #endif
824 #endif
825
826 /* previous track */
827 cdd.index--;
828
829 /* skip directly to track end position */
830 cdd.lba = cdd.toc.tracks[cdd.index].end;
831 }
832
833 /* check disc limits */
834 if (cdd.index < 0)
835 {
836 cdd.index = 0;
837 cdd.lba = 0;
838 }
839 else if (cdd.index >= cdd.toc.last)
840 {
841 /* no AUDIO track playing */
842 Pico_mcd->s68k_regs[0x36+0] = 0x01;
843
844 /* end of disc */
845 cdd.index = cdd.toc.last;
846 cdd.lba = cdd.toc.end;
847 cdd.status = CD_END;
848 return;
849 }
850
851 /* seek to current block */
852 if (!cdd.index)
853 {
854 /* no AUDIO track playing */
855 Pico_mcd->s68k_regs[0x36+0] = 0x01;
856
857 /* DATA track */
858 pm_seek(cdd.toc.tracks[0].fd, cdd.lba * cdd.sectorSize, SEEK_SET);
859 }
860 #ifdef USE_LIBTREMOR
861 else if (cdd.toc.tracks[cdd.index].vf.seekable)
862 {
863 #ifdef DISABLE_MANY_OGG_OPEN_FILES
864 /* check if a new track is being played */
865 if (!cdd.toc.tracks[cdd.index].vf.datasource)
866 {
867 /* VORBIS file need to be opened first */
868 ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
869 }
870 #endif
871 /* VORBIS AUDIO track */
872 ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (cdd.lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
873 }
874 #endif
875 #if 0
876 else if (cdd.toc.tracks[cdd.index].fd)
877 {
878 /* PCM AUDIO track */
879 fseek(cdd.toc.tracks[cdd.index].fd, (cdd.lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
880 }
881 #else
882 else
883 {
884 cdd_change_track(cdd.index, cdd.lba);
885 }
886 #endif
887 }
888 }
889
890 #define set_reg16(r, v) { \
891 uint16 _v = v; \
892 Pico_mcd->s68k_regs[(r)] = _v >> 8; \
893 Pico_mcd->s68k_regs[(r)+1] = _v; \
894 }
895
cdd_process(void)896 void cdd_process(void)
897 {
898 /* Process CDD command */
899 switch (Pico_mcd->s68k_regs[0x42+0] & 0x0f)
900 {
901 case 0x00: /* Drive Status */
902 {
903 /* RS1-RS8 normally unchanged */
904 Pico_mcd->s68k_regs[0x38+0] = cdd.status;
905
906 /* unless RS1 indicated invalid track infos */
907 if (Pico_mcd->s68k_regs[0x38+1] == 0x0f)
908 {
909 /* and SEEK has ended */
910 if (cdd.status != CD_SEEK)
911 {
912 /* then return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */
913 Pico_mcd->s68k_regs[0x38+1] = 0x02;
914 set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
915 }
916 }
917 break;
918 }
919
920 case 0x01: /* Stop Drive */
921 {
922 /* update status */
923 cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
924
925 /* no audio track playing */
926 Pico_mcd->s68k_regs[0x36+0] = 0x01;
927
928 /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
929 set_reg16(0x38, 0x0000);
930 set_reg16(0x3a, 0x0000);
931 set_reg16(0x3c, 0x0000);
932 set_reg16(0x3e, 0x0000);
933 set_reg16(0x40, 0x000f);
934 return;
935 }
936
937 case 0x02: /* Read TOC */
938 {
939 if (cdd.status == NO_DISC)
940 cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
941
942 /* Infos automatically retrieved by CDD processor from Q-Channel */
943 /* commands 0x00-0x02 (current block) and 0x03-0x05 (Lead-In) */
944 switch (Pico_mcd->s68k_regs[0x44+1])
945 {
946 case 0x00: /* Current Absolute Time (MM:SS:FF) */
947 {
948 int lba = cdd.lba + 150;
949 set_reg16(0x38, cdd.status << 8);
950 set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
951 set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
952 set_reg16(0x3e, lut_BCD_16[(lba%75)]);
953 Pico_mcd->s68k_regs[0x40+0] = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
954 break;
955 }
956
957 case 0x01: /* Current Track Relative Time (MM:SS:FF) */
958 {
959 int lba = cdd.lba - cdd.toc.tracks[cdd.index].start;
960 set_reg16(0x38, (cdd.status << 8) | 0x01);
961 set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
962 set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
963 set_reg16(0x3e, lut_BCD_16[(lba%75)]);
964 Pico_mcd->s68k_regs[0x40+0] = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
965 break;
966 }
967
968 case 0x02: /* Current Track Number */
969 {
970 set_reg16(0x38, (cdd.status << 8) | 0x02);
971 set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
972 set_reg16(0x3c, 0x0000);
973 set_reg16(0x3e, 0x0000); /* Disk Control Code (?) in RS6 */
974 Pico_mcd->s68k_regs[0x40+0] = 0x00;
975 break;
976 }
977
978 case 0x03: /* Total length (MM:SS:FF) */
979 {
980 int lba = cdd.toc.end + 150;
981 set_reg16(0x38, (cdd.status << 8) | 0x03);
982 set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
983 set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
984 set_reg16(0x3e, lut_BCD_16[(lba%75)]);
985 Pico_mcd->s68k_regs[0x40+0] = 0x00;
986 break;
987 }
988
989 case 0x04: /* First & Last Track Numbers */
990 {
991 set_reg16(0x38, (cdd.status << 8) | 0x04);
992 set_reg16(0x3a, 0x0001);
993 set_reg16(0x3c, lut_BCD_16[cdd.toc.last]);
994 set_reg16(0x3e, 0x0000); /* Drive Version (?) in RS6-RS7 */
995 Pico_mcd->s68k_regs[0x40+0] = 0x00; /* Lead-In flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
996 break;
997 }
998
999 case 0x05: /* Track Start Time (MM:SS:FF) */
1000 {
1001 int track = Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1];
1002 int lba = cdd.toc.tracks[track-1].start + 150;
1003 set_reg16(0x38, (cdd.status << 8) | 0x05);
1004 set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
1005 set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
1006 set_reg16(0x3e, lut_BCD_16[(lba%75)]);
1007 Pico_mcd->s68k_regs[0x40+0] = track % 10; /* Track Number (low digit) */
1008 if (track == 1)
1009 {
1010 /* RS6 bit 3 is set for the first (DATA) track */
1011 Pico_mcd->s68k_regs[0x3e + 0] |= 0x08;
1012 }
1013 break;
1014 }
1015
1016 default:
1017 {
1018 #ifdef LOG_ERROR
1019 error("Unknown CDD Command %02X (%X)\n", Pico_mcd->s68k_regs[0x44+1], s68k.pc);
1020 #endif
1021 return;
1022 }
1023 }
1024 break;
1025 }
1026
1027 case 0x03: /* Play */
1028 {
1029 /* reset track index */
1030 int index = 0;
1031
1032 /* new LBA position */
1033 int lba = ((Pico_mcd->s68k_regs[0x44+0] * 10 + Pico_mcd->s68k_regs[0x44+1]) * 60 +
1034 (Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 +
1035 (Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150;
1036
1037 /* CD drive latency */
1038 if (!cdd.latency)
1039 {
1040 /* Fixes a few games hanging during intro because they expect data to be read with some delay */
1041 /* Radical Rex needs at least one interrupt delay */
1042 /* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal) need at least 6 interrupts delay */
1043 /* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 6 is OK) */
1044 /* Jeopardy & ESPN Sunday Night NFL are picky about this as well: 10 interrupts delay (+ seek time) seems OK */
1045 cdd.latency = 10;
1046 }
1047
1048 /* CD drive seek time */
1049 /* max. seek time = 1.5 s = 1.5 x 75 = 112.5 CDD interrupts (rounded to 120) for 270000 sectors max on disc. */
1050 /* Note: This is only a rough approximation since, on real hardware, seek time is much likely not linear and */
1051 /* latency much larger than above value, but this model works fine for Sonic CD (track 26 playback needs to */
1052 /* be enough delayed to start in sync with intro sequence, as compared with real hardware recording). */
1053 if (lba > cdd.lba)
1054 {
1055 cdd.latency += (((lba - cdd.lba) * 120) / 270000);
1056 }
1057 else
1058 {
1059 cdd.latency += (((cdd.lba - lba) * 120) / 270000);
1060 }
1061
1062 /* update current LBA */
1063 cdd.lba = lba;
1064
1065 /* get track index */
1066 while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
1067
1068 #ifdef USE_LIBTREMOR
1069 #ifdef DISABLE_MANY_OGG_OPEN_FILES
1070 /* check if track index has changed */
1071 if (index != cdd.index)
1072 {
1073 /* close previous track VORBIS file structure to save memory */
1074 if (cdd.toc.tracks[cdd.index].vf.datasource)
1075 {
1076 ogg_free(cdd.index);
1077 }
1078
1079 /* open current track VORBIS file */
1080 if (cdd.toc.tracks[index].vf.seekable)
1081 {
1082 ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
1083 }
1084 }
1085 #endif
1086 #endif
1087
1088 /* update current track index */
1089 cdd.index = index;
1090
1091 /* stay within track limits when seeking files */
1092 if (lba < cdd.toc.tracks[index].start)
1093 {
1094 lba = cdd.toc.tracks[index].start;
1095 }
1096
1097 /* seek to current block */
1098 if (!index)
1099 {
1100 /* DATA track */
1101 pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
1102 }
1103 #ifdef USE_LIBTREMOR
1104 else if (cdd.toc.tracks[index].vf.seekable)
1105 {
1106 /* VORBIS AUDIO track */
1107 ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
1108 }
1109 #endif
1110 #if 0
1111 else if (cdd.toc.tracks[index].fd)
1112 {
1113 /* PCM AUDIO track */
1114 fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
1115 }
1116 #else
1117 else
1118 {
1119 cdd_change_track(index, lba);
1120 }
1121 #endif
1122
1123 /* no audio track playing (yet) */
1124 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1125
1126 /* update status */
1127 cdd.status = CD_PLAY;
1128
1129 /* return track index in RS2-RS3 */
1130 set_reg16(0x38, (CD_PLAY << 8) | 0x02);
1131 set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[index + 1] : 0x0A0A);
1132 set_reg16(0x3c, 0x0000);
1133 set_reg16(0x3e, 0x0000);
1134 Pico_mcd->s68k_regs[0x40+0] = 0x00;
1135 break;
1136 }
1137
1138 case 0x04: /* Seek */
1139 {
1140 /* reset track index */
1141 int index = 0;
1142
1143 /* new LBA position */
1144 int lba = ((Pico_mcd->s68k_regs[0x44+0] * 10 + Pico_mcd->s68k_regs[0x44+1]) * 60 +
1145 (Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 +
1146 (Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150;
1147
1148 /* CD drive seek time */
1149 /* We are using similar linear model as above, although still not exactly accurate, */
1150 /* it works fine for Switch/Panic! intro (Switch needs at least 30 interrupts while */
1151 /* seeking from 00:05:63 to 24:03:19, Panic! when seeking from 00:05:60 to 24:06:07) */
1152 if (lba > cdd.lba)
1153 {
1154 cdd.latency = ((lba - cdd.lba) * 120) / 270000;
1155 }
1156 else
1157 {
1158 cdd.latency = ((cdd.lba - lba) * 120) / 270000;
1159 }
1160
1161 /* update current LBA */
1162 cdd.lba = lba;
1163
1164 /* get current track index */
1165 while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
1166
1167 #ifdef USE_LIBTREMOR
1168 #ifdef DISABLE_MANY_OGG_OPEN_FILES
1169 /* check if track index has changed */
1170 if (index != cdd.index)
1171 {
1172 /* close previous track VORBIS file structure to save memory */
1173 if (cdd.toc.tracks[cdd.index].vf.datasource)
1174 {
1175 ogg_free(cdd.index);
1176 }
1177
1178 /* open current track VORBIS file */
1179 if (cdd.toc.tracks[index].vf.seekable)
1180 {
1181 ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
1182 }
1183 }
1184 #endif
1185 #endif
1186
1187 /* update current track index */
1188 cdd.index = index;
1189
1190 /* stay within track limits */
1191 if (lba < cdd.toc.tracks[index].start)
1192 {
1193 lba = cdd.toc.tracks[index].start;
1194 }
1195
1196 /* seek to current block */
1197 if (!index)
1198 {
1199 /* DATA track */
1200 pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
1201 }
1202 #ifdef USE_LIBTREMOR
1203 else if (cdd.toc.tracks[index].vf.seekable)
1204 {
1205 /* VORBIS AUDIO track */
1206 ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
1207 }
1208 #endif
1209 #if 0
1210 else if (cdd.toc.tracks[index].fd)
1211 {
1212 /* PCM AUDIO track */
1213 fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
1214 }
1215 #endif
1216
1217 /* no audio track playing */
1218 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1219
1220 /* update status */
1221 cdd.status = CD_SEEK;
1222
1223 /* unknown RS1-RS8 values (returning 0xF in RS1 invalidates track infos in RS2-RS8 and fixes Final Fight CD intro when seek time is emulated) */
1224 set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
1225 set_reg16(0x3a, 0x0000);
1226 set_reg16(0x3c, 0x0000);
1227 set_reg16(0x3e, 0x0000);
1228 set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
1229 return;
1230 }
1231
1232 case 0x06: /* Pause */
1233 {
1234 /* no audio track playing */
1235 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1236
1237 /* update status (RS1-RS8 unchanged) */
1238 cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY;
1239 break;
1240 }
1241
1242 case 0x07: /* Resume */
1243 {
1244 /* update status (RS1-RS8 unchanged) */
1245 cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_PLAY;
1246 break;
1247 }
1248
1249 case 0x08: /* Forward Scan */
1250 {
1251 /* reset scanning direction / speed */
1252 cdd.scanOffset = CD_SCAN_SPEED;
1253
1254 /* update status (RS1-RS8 unchanged) */
1255 cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_SCAN;
1256 break;
1257 }
1258
1259 case 0x09: /* Rewind Scan */
1260 {
1261 /* reset scanning direction / speed */
1262 cdd.scanOffset = -CD_SCAN_SPEED;
1263
1264 /* update status (RS1-RS8 unchanged) */
1265 cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_SCAN;
1266 break;
1267 }
1268
1269
1270 case 0x0a: /* N-Track Jump Control ? (usually sent before CD_SEEK or CD_PLAY commands) */
1271 {
1272 /* TC3 corresponds to seek direction (00=forward, FF=reverse) */
1273 /* TC4-TC7 are related to seek length (4x4 bits i.e parameter values are between -65535 and +65535) */
1274 /* Maybe related to number of auto-sequenced track jumps/moves for CD DSP (cf. CXD2500BQ datasheet) */
1275 /* also see US Patent nr. 5222054 for a detailled description of seeking operation using Track Jump */
1276
1277 /* no audio track playing */
1278 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1279
1280 /* update status (RS1-RS8 unchanged) */
1281 cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY;
1282 break;
1283 }
1284
1285 case 0x0c: /* Close Tray */
1286 {
1287 /* no audio track playing */
1288 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1289
1290 /* update status */
1291 cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
1292
1293 /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
1294 set_reg16(0x38, 0x0000);
1295 set_reg16(0x3a, 0x0000);
1296 set_reg16(0x3c, 0x0000);
1297 set_reg16(0x3e, 0x0000);
1298 set_reg16(0x40, 0x000f);
1299
1300 if (PicoIn.mcdTrayClose)
1301 PicoIn.mcdTrayClose();
1302
1303 return;
1304 }
1305
1306 case 0x0d: /* Open Tray */
1307 {
1308 /* no audio track playing */
1309 Pico_mcd->s68k_regs[0x36+0] = 0x01;
1310
1311 /* update status (RS1-RS8 ignored) */
1312 cdd.status = CD_OPEN;
1313 set_reg16(0x38, CD_OPEN << 8);
1314 set_reg16(0x3a, 0x0000);
1315 set_reg16(0x3c, 0x0000);
1316 set_reg16(0x3e, 0x0000);
1317 set_reg16(0x40, ~CD_OPEN & 0x0f);
1318
1319 if (PicoIn.mcdTrayOpen)
1320 PicoIn.mcdTrayOpen();
1321 return;
1322 }
1323
1324 default: /* Unknown command */
1325 #ifdef LOG_CDD
1326 error("Unknown CDD Command !!!\n");
1327 #endif
1328 Pico_mcd->s68k_regs[0x38+0] = cdd.status;
1329 break;
1330 }
1331
1332 /* only compute checksum when necessary */
1333 Pico_mcd->s68k_regs[0x40 + 1] =
1334 ~(Pico_mcd->s68k_regs[0x38 + 0] + Pico_mcd->s68k_regs[0x38 + 1] +
1335 Pico_mcd->s68k_regs[0x3a + 0] + Pico_mcd->s68k_regs[0x3a + 1] +
1336 Pico_mcd->s68k_regs[0x3c + 0] + Pico_mcd->s68k_regs[0x3c + 1] +
1337 Pico_mcd->s68k_regs[0x3e + 0] + Pico_mcd->s68k_regs[0x3e + 1] +
1338 Pico_mcd->s68k_regs[0x40 + 0]) & 0x0f;
1339 }
1340
1341 // vim:shiftwidth=2:ts=2:expandtab
1342