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