c6b24b8219a1f1bc776bdcbaad17e4c70042a518
[picodrive.git] / pico / cd / cdd.c
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 /* supported WAVE file header (16-bit stereo samples @44.1kHz) */
126 static const unsigned char waveHeader[32] =
127 {
128   0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
129   0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61
130 };
131
132 #ifdef USE_LIBTREMOR
133 #ifdef DISABLE_MANY_OGG_OPEN_FILES
134 static void ogg_free(int i)
135 {
136   /* clear OGG file descriptor to prevent file from being closed */
137   cdd.toc.tracks[i].vf.datasource = NULL;
138
139   /* close VORBIS file structure */
140   ov_clear(&cdd.toc.tracks[i].vf);
141
142   /* indicates that the track is a seekable VORBIS file */
143   cdd.toc.tracks[i].vf.seekable = 1;
144
145   /* reset file reading position */
146   fseek(cdd.toc.tracks[i].fd, 0, SEEK_SET);
147 }
148 #endif
149 #endif
150
151 void cdd_reset(void)
152 {
153   /* reset cycle counter */
154   cdd.cycles = 0;
155   
156   /* reset drive access latency */
157   cdd.latency = 0;
158   
159   /* reset track index */
160   cdd.index = 0;
161   
162   /* reset logical block address */
163   cdd.lba = 0;
164
165   /* reset status */
166   cdd.status = NO_DISC;
167
168   /* reset CD-DA fader (full volume) */
169   cdd.volume = 0x400;
170
171   /* clear CD-DA output */
172   cdd.audio[0] = cdd.audio[1] = 0;
173 }
174
175 /* FIXME: use cdd_read_audio() instead */
176 static void cdd_change_track(int index, int lba)
177 {
178   int i, base, lba_offset, lb_len;
179
180   for (i = index; i > 0; i--)
181     if (cdd.toc.tracks[i].fd != NULL)
182       break;
183
184   Pico_mcd->cdda_stream = cdd.toc.tracks[i].fd;
185   base = cdd.toc.tracks[index].offset;
186   lba_offset = lba - cdd.toc.tracks[index].start;
187   lb_len = cdd.toc.tracks[index].end - cdd.toc.tracks[index].start;
188
189   elprintf(EL_CD, "play #%d lba %d base %d", index, lba, base);
190
191   cdda_start_play(base, lba_offset, lb_len);
192 }
193
194 int cdd_context_save(uint8 *state)
195 {
196   int bufferptr = 0;
197
198   save_param(&cdd.cycles, sizeof(cdd.cycles));
199   save_param(&cdd.latency, sizeof(cdd.latency));
200   save_param(&cdd.index, sizeof(cdd.index));
201   save_param(&cdd.lba, sizeof(cdd.lba));
202   save_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
203   save_param(&cdd.volume, sizeof(cdd.volume));
204   save_param(&cdd.status, sizeof(cdd.status));
205
206   return bufferptr;
207 }
208
209 int cdd_context_load(uint8 *state)
210 {
211   int lba;
212   int bufferptr = 0;
213
214 #ifdef USE_LIBTREMOR
215 #ifdef DISABLE_MANY_OGG_OPEN_FILES
216   /* close previous track VORBIS file structure to save memory */
217   if (cdd.toc.tracks[cdd.index].vf.datasource)
218   {
219     ogg_free(cdd.index);
220   }
221 #endif
222 #endif
223
224   load_param(&cdd.cycles, sizeof(cdd.cycles));
225   load_param(&cdd.latency, sizeof(cdd.latency));
226   load_param(&cdd.index, sizeof(cdd.index));
227   load_param(&cdd.lba, sizeof(cdd.lba));
228   load_param(&cdd.scanOffset, sizeof(cdd.scanOffset));
229   load_param(&cdd.volume, sizeof(cdd.volume));
230   load_param(&cdd.status, sizeof(cdd.status));
231
232   /* adjust current LBA within track limit */
233   lba = cdd.lba;
234   if (lba < cdd.toc.tracks[cdd.index].start)
235   {
236     lba = cdd.toc.tracks[cdd.index].start;
237   }
238
239   /* seek to current track position */
240   if (!cdd.index)
241   {
242     /* DATA track */
243     if (cdd.toc.tracks[0].fd)
244     {
245       pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
246     }
247   }
248 #ifdef USE_LIBTREMOR
249   else if (cdd.toc.tracks[cdd.index].vf.seekable)
250   {
251 #ifdef DISABLE_MANY_OGG_OPEN_FILES
252     /* VORBIS file need to be opened first */
253     ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
254 #endif
255     /* VORBIS AUDIO track */
256     ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
257   }
258 #endif
259 #if 0
260   else if (cdd.toc.tracks[cdd.index].fd)
261   {
262     /* PCM AUDIO track */
263     fseek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
264   }
265 #else
266   else
267   {
268     cdd_change_track(cdd.index, lba);
269   }
270 #endif
271
272   return bufferptr;
273 }
274
275 int cdd_context_load_old(uint8 *state)
276 {
277   memcpy(&cdd.lba, state + 8, sizeof(cdd.lba));
278   return 12 * 4;
279 }
280
281 int cdd_load(const char *filename, int type)
282 {
283   char header[0x210];
284   int ret;
285
286   /* first unmount any loaded disc */
287   cdd_unload();
288
289   /* genplus parses cue here, in PD we use our own parser */
290   ret = load_cd_image(filename, &type);
291   if (ret != 0)
292     return ret;
293
294   /* read first 16 bytes */
295   pm_read(header, 0x10, cdd.toc.tracks[0].fd);
296
297   /* look for valid CD image ID string */
298   if (memcmp("SEGADISCSYSTEM", header, 14))
299   {    
300     /* if not found, read next 16 bytes */
301     pm_read(header, 0x10, cdd.toc.tracks[0].fd);
302
303     /* look again for valid CD image ID string */
304     if (memcmp("SEGADISCSYSTEM", header, 14))
305     {
306       elprintf(EL_STATUS|EL_ANOMALY, "cd: bad cd image?");
307       /* assume bin without security code */
308     }
309
310     /* BIN format (2352 bytes data blocks) */
311     cdd.sectorSize = 2352;
312   }
313   else
314   {
315     /* ISO format (2048 bytes data blocks) */
316     cdd.sectorSize = 2048;
317   }
318
319   ret = (type == CT_BIN) ? 2352 : 2048;
320   if (ret != cdd.sectorSize)
321     elprintf(EL_STATUS|EL_ANOMALY, "cd: type detection mismatch");
322
323   /* read CD image header + security code */
324   pm_read(header + 0x10, 0x200, cdd.toc.tracks[0].fd);
325
326   /* Simulate audio tracks if none found */
327   if (cdd.toc.last == 1)
328   {
329     /* Some games require exact TOC infos */
330     if (strstr(header + 0x180,"T-95035") != NULL)
331     {
332       /* Snatcher */
333       cdd.toc.last = cdd.toc.end = 0;
334       do
335       {
336         cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
337         cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_snatcher[cdd.toc.last];
338         cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
339         cdd.toc.last++;
340       }
341       while (cdd.toc.last < 21);
342     }
343     else if (strstr(header + 0x180,"T-127015") != NULL)
344     {
345       /* Lunar - The Silver Star */
346       cdd.toc.last = cdd.toc.end = 0;
347       do
348       {
349         cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
350         cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_lunar[cdd.toc.last];
351         cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
352         cdd.toc.last++;
353       }
354       while (cdd.toc.last < 52);
355     }
356     else if (strstr(header + 0x180,"T-113045") != NULL)
357     {
358       /* Shadow of the Beast II */
359       cdd.toc.last = cdd.toc.end = 0;
360       do
361       {
362         cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
363         cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_shadow[cdd.toc.last];
364         cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
365         cdd.toc.last++;
366       }
367       while (cdd.toc.last < 15);
368     }
369     else if (strstr(header + 0x180,"T-143025") != NULL)
370     {
371       /* Dungeon Explorer */
372       cdd.toc.last = cdd.toc.end = 0;
373       do
374       {
375         cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
376         cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_dungeon[cdd.toc.last];
377         cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
378         cdd.toc.last++;
379       }
380       while (cdd.toc.last < 13);
381     }
382     else if (strstr(header + 0x180,"MK-4410") != NULL)
383     {
384       /* Final Fight CD (USA, Europe) */
385       cdd.toc.last = cdd.toc.end = 0;
386       do
387       {
388         cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
389         cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffight[cdd.toc.last];
390         cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
391         cdd.toc.last++;
392       }
393       while (cdd.toc.last < 26);
394     }
395     else if (strstr(header + 0x180,"G-6013") != NULL)
396     {
397       /* Final Fight CD (Japan) */
398       cdd.toc.last = cdd.toc.end = 0;
399       do
400       {
401         cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
402         cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + toc_ffightj[cdd.toc.last];
403         cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
404         cdd.toc.last++;
405       }
406       while (cdd.toc.last < 29);
407     }
408 #if 0
409     else
410     {
411       /* default TOC (99 tracks & 2s per audio tracks) */
412       do
413       {
414         cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end + 2*75;
415         cdd.toc.tracks[cdd.toc.last].end = cdd.toc.tracks[cdd.toc.last].start + 2*75;
416         cdd.toc.end = cdd.toc.tracks[cdd.toc.last].end;
417         cdd.toc.last++;
418       }
419       while ((cdd.toc.last < 99) && (cdd.toc.end < 56*60*75));
420     }
421 #endif
422   }
423
424   /* Lead-out */
425   cdd.toc.tracks[cdd.toc.last].start = cdd.toc.end;
426
427   /* CD loaded */
428   cdd.loaded = 1;
429
430   /* disc not scanned yet */
431   cdd.status = NO_DISC;
432
433   return 0;
434 }
435
436 int cdd_unload(void)
437 {
438   int was_loaded = cdd.loaded;
439
440   if (cdd.loaded)
441   {
442     int i;
443
444     /* close CD tracks */
445     if (cdd.toc.tracks[0].fd)
446     {
447       pm_close(cdd.toc.tracks[0].fd);
448       cdd.toc.tracks[0].fd = NULL;
449     }
450
451     for (i = 1; i < cdd.toc.last; i++)
452     {
453 #ifdef USE_LIBTREMOR
454       if (cdd.toc.tracks[i].vf.datasource)
455       {
456         /* close VORBIS file (if still opened) */
457         ov_clear(&cdd.toc.tracks[i].vf);
458       }
459       else
460 #endif
461       if (cdd.toc.tracks[i].fd)
462       {
463         /* close file */
464         if (Pico_mcd->cdda_type == CT_MP3)
465           fclose(cdd.toc.tracks[i].fd);
466         else
467           pm_close(cdd.toc.tracks[0].fd);
468
469         /* detect single file images */
470         if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)
471         {
472           /* exit loop */
473           i = cdd.toc.last;
474         }
475       }
476     }
477
478     /* CD unloaded */
479     cdd.loaded = 0;
480
481     if (cdd.status != CD_OPEN)
482       cdd.status = NO_DISC;
483   }
484
485   /* reset TOC */
486   memset(&cdd.toc, 0x00, sizeof(cdd.toc));
487     
488   /* unknown CD image file format */
489   cdd.sectorSize = 0;
490
491   return was_loaded;
492 }
493
494 void cdd_read_data(uint8 *dst)
495 {
496   /* only read DATA track sectors */
497   if ((cdd.lba >= 0) && (cdd.lba < cdd.toc.tracks[0].end))
498   {
499     /* BIN format ? */
500     if (cdd.sectorSize == 2352)
501     {
502       /* skip 16-byte header */
503       pm_seek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET);
504     }
505
506     /* read sector data (Mode 1 = 2048 bytes) */
507     pm_read(dst, 2048, cdd.toc.tracks[0].fd);
508   }
509 }
510
511 #if 0
512 void cdd_read_audio(unsigned int samples)
513 {
514   /* previous audio outputs */
515   int16 l = cdd.audio[0];
516   int16 r = cdd.audio[1];
517
518   /* get number of internal clocks (samples) needed */
519   samples = blip_clocks_needed(blip[0], samples);
520
521   /* audio track playing ? */
522   if (!Pico_mcd->s68k_regs[0x36+0] && cdd.toc.tracks[cdd.index].fd)
523   {
524     int i, mul, delta;
525
526     /* current CD-DA fader volume */
527     int curVol = cdd.volume;
528
529     /* CD-DA fader volume setup (0-1024) */
530     int endVol = Pico_mcd->regs[0x34>>1].w >> 4;
531
532     /* read samples from current block */
533 #ifdef USE_LIBTREMOR
534     if (cdd.toc.tracks[cdd.index].vf.datasource)
535     {
536       int len, done = 0;
537       int16 *ptr = (int16 *) (cdc.ram);
538       samples = samples * 4;
539       while (done < samples)
540       {
541         len = ov_read(&cdd.toc.tracks[cdd.index].vf, (char *)(cdc.ram + done), samples - done, 0);
542         if (len <= 0) 
543         {
544           done = samples;
545           break;
546         }
547         done += len;
548       }
549       samples = done / 4;
550
551       /* process 16-bit (host-endian) stereo samples */
552       for (i=0; i<samples; i++)
553       {
554         /* CD-DA fader multiplier (cf. LC7883 datasheet) */
555         /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
556         mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
557
558         /* left channel */
559         delta = ((ptr[0] * mul) / 1024) - l;
560         ptr++;
561         l += delta;
562         blip_add_delta_fast(blip[0], i, delta);
563
564         /* right channel */
565         delta = ((ptr[0] * mul) / 1024) - r;
566         ptr++;
567         r += delta;
568         blip_add_delta_fast(blip[1], i, delta);
569
570         /* update CD-DA fader volume (one step/sample) */
571         if (curVol < endVol)
572         {
573           /* fade-in */
574           curVol++;
575         }
576         else if (curVol > endVol)
577         {
578           /* fade-out */
579           curVol--;
580         }
581         else if (!curVol)
582         {
583           /* audio will remain muted until next setup */
584           break;
585         }
586       }
587     }
588     else
589 #endif
590     {
591 #ifdef LSB_FIRST
592       int16 *ptr = (int16 *) (cdc.ram);
593 #else
594       uint8 *ptr = cdc.ram;
595 #endif
596       fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd);
597
598       /* process 16-bit (little-endian) stereo samples */
599       for (i=0; i<samples; i++)
600       {
601         /* CD-DA fader multiplier (cf. LC7883 datasheet) */
602         /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
603         mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
604
605         /* left channel */
606   #ifdef LSB_FIRST
607         delta = ((ptr[0] * mul) / 1024) - l;
608         ptr++;
609   #else
610         delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
611         ptr += 2;
612   #endif
613         l += delta;
614         blip_add_delta_fast(blip[0], i, delta);
615
616         /* right channel */
617   #ifdef LSB_FIRST
618         delta = ((ptr[0] * mul) / 1024) - r;
619         ptr++;
620   #else
621         delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r;
622         ptr += 2;
623   #endif
624         r += delta;
625         blip_add_delta_fast(blip[1], i, delta);
626
627         /* update CD-DA fader volume (one step/sample) */
628         if (curVol < endVol)
629         {
630           /* fade-in */
631           curVol++;
632         }
633         else if (curVol > endVol)
634         {
635           /* fade-out */
636           curVol--;
637         }
638         else if (!curVol)
639         {
640           /* audio will remain muted until next setup */
641           break;
642         }
643       }
644     }
645
646     /* save current CD-DA fader volume */
647     cdd.volume = curVol;
648
649     /* save last audio output for next frame */
650     cdd.audio[0] = l;
651     cdd.audio[1] = r;
652   }
653   else
654   {
655     /* no audio output */
656     if (l) blip_add_delta_fast(blip[0], 0, -l);
657     if (r) blip_add_delta_fast(blip[1], 0, -r);
658
659     /* save audio output for next frame */
660     cdd.audio[0] = 0;
661     cdd.audio[1] = 0;
662   }
663
664   /* end of Blip Buffer timeframe */
665   blip_end_frame(blip[0], samples);
666   blip_end_frame(blip[1], samples);
667 }
668 #endif
669
670
671 void cdd_update(void)
672 {  
673 #ifdef LOG_CDD
674   error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
675 #endif
676   
677   /* seeking disc */
678   if (cdd.status == CD_SEEK)
679   {
680     /* drive latency */
681     if (cdd.latency > 0)
682     {
683       cdd.latency--;
684       return;
685     }
686
687     /* drive is ready */
688     cdd.status = CD_READY;
689   }
690
691   /* reading disc */
692   else if (cdd.status == CD_PLAY)
693   {
694     /* drive latency */
695     if (cdd.latency > 0)
696     {
697       cdd.latency--;
698       return;
699     }
700
701     /* track type */
702     if (!cdd.index)
703     {
704       /* DATA sector header (CD-ROM Mode 1) */
705       uint8 header[4];
706       uint32 msf = cdd.lba + 150;
707       header[0] = lut_BCD_8[(msf / 75) / 60];
708       header[1] = lut_BCD_8[(msf / 75) % 60];
709       header[2] = lut_BCD_8[(msf % 75)];
710       header[3] = 0x01;
711
712       /* data track sector read is controlled by CDC */
713       cdd.lba += cdc_decoder_update(header);
714     }
715     else if (cdd.index < cdd.toc.last)
716     {
717       uint8 header[4] = { 0, };
718
719       /* check against audio track start index */
720       if (cdd.lba >= cdd.toc.tracks[cdd.index].start)
721       {
722         /* audio track playing */
723         Pico_mcd->s68k_regs[0x36+0] = 0x00;
724       }
725
726       /* audio blocks are still sent to CDC as well as CD DAC/Fader */
727       cdc_decoder_update(header);
728  
729       /* next audio block is automatically read */
730       cdd.lba++;
731     }
732     else
733     {
734       /* end of disc */
735       cdd.status = CD_END;
736       return;
737     }
738
739     /* check end of current track */
740     if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
741     {
742 #ifdef USE_LIBTREMOR
743 #ifdef DISABLE_MANY_OGG_OPEN_FILES
744       /* close previous track VORBIS file structure to save memory */
745       if (cdd.toc.tracks[cdd.index].vf.datasource)
746       {
747         ogg_free(cdd.index);
748       }
749 #endif
750 #endif
751       /* play next track */
752       cdd.index++;
753
754       /* PAUSE between tracks */
755       Pico_mcd->s68k_regs[0x36+0] = 0x01;
756
757       /* seek to next audio track start */
758 #ifdef USE_LIBTREMOR
759       if (cdd.toc.tracks[cdd.index].vf.seekable)
760       {
761 #ifdef DISABLE_MANY_OGG_OPEN_FILES
762         /* VORBIS file need to be opened first */
763         ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
764 #endif
765         ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, -cdd.toc.tracks[cdd.index].offset);
766       }
767       else
768 #endif 
769 #if 0
770       if (cdd.toc.tracks[cdd.index].fd)
771       {
772         fseek(cdd.toc.tracks[cdd.index].fd, (cdd.toc.tracks[cdd.index].start * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
773       }
774 #else
775       {
776         cdd_change_track(cdd.index, cdd.lba);
777       }
778 #endif
779     }
780   }
781
782   /* scanning disc */
783   else if (cdd.status == CD_SCAN)
784   {
785     /* fast-forward or fast-rewind */
786     cdd.lba += cdd.scanOffset;
787
788     /* check current track limits */
789     if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
790     {
791 #ifdef USE_LIBTREMOR
792 #ifdef DISABLE_MANY_OGG_OPEN_FILES
793       /* close previous track VORBIS file structure to save memory */
794       if (cdd.toc.tracks[cdd.index].vf.datasource)
795       {
796         ogg_free(cdd.index);
797       }
798 #endif
799 #endif
800       /* next track */
801       cdd.index++;
802
803       /* skip directly to track start position */
804       cdd.lba = cdd.toc.tracks[cdd.index].start;
805       
806       /* AUDIO track playing ? */
807       if (cdd.status == CD_PLAY)
808       {
809         Pico_mcd->s68k_regs[0x36+0] = 0x00;
810       }
811     }
812     else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
813     {
814 #ifdef USE_LIBTREMOR
815 #ifdef DISABLE_MANY_OGG_OPEN_FILES
816       /* close previous track VORBIS file structure to save memory */
817       if (cdd.toc.tracks[cdd.index].vf.datasource)
818       {
819         ogg_free(cdd.index);
820       }
821 #endif
822 #endif
823
824       /* previous track */
825       cdd.index--;
826
827       /* skip directly to track end position */
828       cdd.lba = cdd.toc.tracks[cdd.index].end;
829     }
830
831     /* check disc limits */
832     if (cdd.index < 0)
833     {
834       cdd.index = 0;
835       cdd.lba = 0;
836     }
837     else if (cdd.index >= cdd.toc.last)
838     {
839       /* no AUDIO track playing */
840       Pico_mcd->s68k_regs[0x36+0] = 0x01;
841
842       /* end of disc */
843       cdd.index = cdd.toc.last;
844       cdd.lba = cdd.toc.end;
845       cdd.status = CD_END;
846       return;
847     }
848
849     /* seek to current block */
850     if (!cdd.index)
851     {
852       /* no AUDIO track playing */
853       Pico_mcd->s68k_regs[0x36+0] = 0x01;
854
855       /* DATA track */
856       pm_seek(cdd.toc.tracks[0].fd, cdd.lba * cdd.sectorSize, SEEK_SET);
857     }
858 #ifdef USE_LIBTREMOR
859     else if (cdd.toc.tracks[cdd.index].vf.seekable)
860     {
861 #ifdef DISABLE_MANY_OGG_OPEN_FILES
862       /* check if a new track is being played */
863       if (!cdd.toc.tracks[cdd.index].vf.datasource)
864       {
865         /* VORBIS file need to be opened first */
866         ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
867       }
868 #endif
869       /* VORBIS AUDIO track */
870       ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (cdd.lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
871     }
872 #endif 
873 #if 0
874     else if (cdd.toc.tracks[cdd.index].fd)
875     {
876       /* PCM AUDIO track */
877       fseek(cdd.toc.tracks[cdd.index].fd, (cdd.lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
878     }
879 #else
880     else
881     {
882       cdd_change_track(cdd.index, cdd.lba);
883     }
884 #endif
885   }
886 }
887
888 #define set_reg16(r, v) { \
889   uint16 _v = v; \
890   Pico_mcd->s68k_regs[(r)] = _v >> 8; \
891   Pico_mcd->s68k_regs[(r)+1] = _v; \
892 }
893
894 void cdd_process(void)
895 {
896   /* Process CDD command */
897   switch (Pico_mcd->s68k_regs[0x42+0] & 0x0f)
898   {
899     case 0x00:  /* Drive Status */
900     {
901       /* RS1-RS8 normally unchanged */
902       Pico_mcd->s68k_regs[0x38+0] = cdd.status;
903
904       /* unless RS1 indicated invalid track infos */
905       if (Pico_mcd->s68k_regs[0x38+1] == 0x0f)
906       {
907         /* and SEEK has ended */
908         if (cdd.status != CD_SEEK)
909         {
910           /* then return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */
911           Pico_mcd->s68k_regs[0x38+1] = 0x02;
912           set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
913         }
914       }
915       break;
916     }
917
918     case 0x01:  /* Stop Drive */
919     {
920       /* update status */
921       cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
922
923       /* no audio track playing */
924       Pico_mcd->s68k_regs[0x36+0] = 0x01;
925
926       /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
927       set_reg16(0x38, 0x0000);
928       set_reg16(0x3a, 0x0000);
929       set_reg16(0x3c, 0x0000);
930       set_reg16(0x3e, 0x0000);
931       set_reg16(0x40, 0x000f);
932       return;
933     }
934
935     case 0x02:  /* Read TOC */
936     {
937       if (cdd.status == NO_DISC)
938         cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
939
940       /* Infos automatically retrieved by CDD processor from Q-Channel */
941       /* commands 0x00-0x02 (current block) and 0x03-0x05 (Lead-In) */
942       switch (Pico_mcd->s68k_regs[0x44+1])
943       {
944         case 0x00:  /* Current Absolute Time (MM:SS:FF) */
945         {
946           int lba = cdd.lba + 150;
947           set_reg16(0x38, cdd.status << 8);
948           set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
949           set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
950           set_reg16(0x3e, lut_BCD_16[(lba%75)]);
951           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) */
952           break;
953         }
954
955         case 0x01:  /* Current Track Relative Time (MM:SS:FF) */
956         {
957           int lba = cdd.lba - cdd.toc.tracks[cdd.index].start;
958           set_reg16(0x38, (cdd.status << 8) | 0x01);
959           set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
960           set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
961           set_reg16(0x3e, lut_BCD_16[(lba%75)]);
962           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) */
963           break;
964         }
965
966         case 0x02:  /* Current Track Number */
967         {
968           set_reg16(0x38, (cdd.status << 8) | 0x02);
969           set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
970           set_reg16(0x3c, 0x0000);
971           set_reg16(0x3e, 0x0000); /* Disk Control Code (?) in RS6 */
972           Pico_mcd->s68k_regs[0x40+0] = 0x00;
973           break;
974         }
975
976         case 0x03:  /* Total length (MM:SS:FF) */
977         {
978           int lba = cdd.toc.end + 150;
979           set_reg16(0x38, (cdd.status << 8) | 0x03);
980           set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
981           set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
982           set_reg16(0x3e, lut_BCD_16[(lba%75)]);
983           Pico_mcd->s68k_regs[0x40+0] = 0x00;
984           break;
985         }
986
987         case 0x04:  /* First & Last Track Numbers */
988         {
989           set_reg16(0x38, (cdd.status << 8) | 0x04);
990           set_reg16(0x3a, 0x0001);
991           set_reg16(0x3c, lut_BCD_16[cdd.toc.last]);
992           set_reg16(0x3e, 0x0000); /* Drive Version (?) in RS6-RS7 */
993           Pico_mcd->s68k_regs[0x40+0] = 0x00;  /* Lead-In flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
994           break;
995         }
996
997         case 0x05:  /* Track Start Time (MM:SS:FF) */
998         {
999           int track = Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1];
1000           int lba = cdd.toc.tracks[track-1].start + 150;
1001           set_reg16(0x38, (cdd.status << 8) | 0x05);
1002           set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
1003           set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
1004           set_reg16(0x3e, lut_BCD_16[(lba%75)]);
1005           Pico_mcd->s68k_regs[0x40+0] = track % 10;  /* Track Number (low digit) */
1006           if (track == 1)
1007           {
1008             /* RS6 bit 3 is set for the first (DATA) track */
1009             Pico_mcd->s68k_regs[0x3e + 0] |= 0x08;
1010           }
1011           break;
1012         }
1013
1014         default:
1015         {
1016 #ifdef LOG_ERROR
1017           error("Unknown CDD Command %02X (%X)\n", Pico_mcd->s68k_regs[0x44+1], s68k.pc);
1018 #endif
1019           return;
1020         }
1021       }
1022       break;
1023     }
1024
1025     case 0x03:  /* Play  */
1026     {
1027       /* reset track index */
1028       int index = 0;
1029
1030       /* new LBA position */
1031       int lba = ((Pico_mcd->s68k_regs[0x44+0] * 10 + Pico_mcd->s68k_regs[0x44+1]) * 60 + 
1032                  (Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 +
1033                  (Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150;
1034
1035       /* CD drive latency */
1036       if (!cdd.latency)
1037       {
1038         /* Fixes a few games hanging during intro because they expect data to be read with some delay */
1039         /* Radical Rex needs at least one interrupt delay */
1040         /* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal) need at least 6 interrupts delay  */
1041         /* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 6 is OK) */
1042         /* Jeopardy & ESPN Sunday Night NFL are picky about this as well: 10 interrupts delay (+ seek time) seems OK */
1043         cdd.latency = 10;
1044       }
1045
1046       /* CD drive seek time */
1047       /* max. seek time = 1.5 s = 1.5 x 75 = 112.5 CDD interrupts (rounded to 120) for 270000 sectors max on disc. */
1048       /* Note: This is only a rough approximation since, on real hardware, seek time is much likely not linear and */
1049       /* latency much larger than above value, but this model works fine for Sonic CD (track 26 playback needs to  */
1050       /* be enough delayed to start in sync with intro sequence, as compared with real hardware recording).        */
1051       if (lba > cdd.lba)
1052       {
1053         cdd.latency += (((lba - cdd.lba) * 120) / 270000);
1054       }
1055       else 
1056       {
1057         cdd.latency += (((cdd.lba - lba) * 120) / 270000);
1058       }
1059
1060       /* update current LBA */
1061       cdd.lba = lba;
1062
1063       /* get track index */
1064       while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
1065
1066 #ifdef USE_LIBTREMOR
1067 #ifdef DISABLE_MANY_OGG_OPEN_FILES
1068       /* check if track index has changed */
1069       if (index != cdd.index)
1070       {
1071         /* close previous track VORBIS file structure to save memory */
1072         if (cdd.toc.tracks[cdd.index].vf.datasource)
1073         {
1074           ogg_free(cdd.index);
1075         }
1076
1077         /* open current track VORBIS file */
1078         if (cdd.toc.tracks[index].vf.seekable)
1079         {
1080           ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
1081         }
1082       }
1083 #endif
1084 #endif
1085
1086       /* update current track index */
1087       cdd.index = index;
1088
1089       /* stay within track limits when seeking files */
1090       if (lba < cdd.toc.tracks[index].start) 
1091       {
1092         lba = cdd.toc.tracks[index].start;
1093       }
1094       
1095       /* seek to current block */
1096       if (!index)
1097       {
1098         /* DATA track */
1099         pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
1100       }
1101 #ifdef USE_LIBTREMOR
1102       else if (cdd.toc.tracks[index].vf.seekable)
1103       {
1104         /* VORBIS AUDIO track */
1105         ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
1106       }
1107 #endif
1108 #if 0
1109       else if (cdd.toc.tracks[index].fd)
1110       {
1111         /* PCM AUDIO track */
1112         fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
1113       }
1114 #else
1115       else
1116       {
1117         cdd_change_track(index, lba);
1118       }
1119 #endif
1120
1121       /* no audio track playing (yet) */
1122       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1123
1124       /* update status */
1125       cdd.status = CD_PLAY;
1126
1127       /* return track index in RS2-RS3 */
1128       set_reg16(0x38, (CD_PLAY << 8) | 0x02);
1129       set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[index + 1] : 0x0A0A);
1130       set_reg16(0x3c, 0x0000);
1131       set_reg16(0x3e, 0x0000);
1132       Pico_mcd->s68k_regs[0x40+0] = 0x00;
1133       break;
1134     }
1135
1136     case 0x04:  /* Seek */
1137     {
1138       /* reset track index */
1139       int index = 0;
1140
1141       /* new LBA position */
1142       int lba = ((Pico_mcd->s68k_regs[0x44+0] * 10 + Pico_mcd->s68k_regs[0x44+1]) * 60 + 
1143                  (Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 +
1144                  (Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150;
1145
1146       /* CD drive seek time  */
1147       /* We are using similar linear model as above, although still not exactly accurate, */
1148       /* it works fine for Switch/Panic! intro (Switch needs at least 30 interrupts while */
1149       /* seeking from 00:05:63 to 24:03:19, Panic! when seeking from 00:05:60 to 24:06:07) */
1150       if (lba > cdd.lba)
1151       {
1152         cdd.latency = ((lba - cdd.lba) * 120) / 270000;
1153       }
1154       else
1155       {
1156         cdd.latency = ((cdd.lba - lba) * 120) / 270000;
1157       }
1158
1159       /* update current LBA */
1160       cdd.lba = lba;
1161
1162       /* get current track index */
1163       while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
1164
1165 #ifdef USE_LIBTREMOR
1166 #ifdef DISABLE_MANY_OGG_OPEN_FILES
1167       /* check if track index has changed */
1168       if (index != cdd.index)
1169       {
1170         /* close previous track VORBIS file structure to save memory */
1171         if (cdd.toc.tracks[cdd.index].vf.datasource)
1172         {
1173           ogg_free(cdd.index);
1174         }
1175
1176         /* open current track VORBIS file */
1177         if (cdd.toc.tracks[index].vf.seekable)
1178         {
1179           ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
1180         }
1181       }
1182 #endif
1183 #endif
1184
1185       /* update current track index */
1186       cdd.index = index;
1187
1188       /* stay within track limits */
1189       if (lba < cdd.toc.tracks[index].start) 
1190       {
1191         lba = cdd.toc.tracks[index].start;
1192       }
1193       
1194       /* seek to current block */
1195       if (!index)
1196       {
1197         /* DATA track */
1198         pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
1199       }
1200 #ifdef USE_LIBTREMOR
1201       else if (cdd.toc.tracks[index].vf.seekable)
1202       {
1203         /* VORBIS AUDIO track */
1204         ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
1205       }
1206 #endif
1207 #if 0
1208       else if (cdd.toc.tracks[index].fd)
1209       {
1210         /* PCM AUDIO track */
1211         fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
1212       }
1213 #endif
1214
1215       /* no audio track playing */
1216       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1217
1218       /* update status */
1219       cdd.status = CD_SEEK;
1220
1221       /* 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) */
1222       set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
1223       set_reg16(0x3a, 0x0000);
1224       set_reg16(0x3c, 0x0000);
1225       set_reg16(0x3e, 0x0000);
1226       set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
1227       return;
1228     }
1229
1230     case 0x06:  /* Pause */
1231     {
1232       /* no audio track playing */
1233       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1234
1235       /* update status (RS1-RS8 unchanged) */
1236       cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY;
1237       break;
1238     }
1239
1240     case 0x07:  /* Resume */
1241     {
1242       /* update status (RS1-RS8 unchanged) */
1243       cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_PLAY;
1244       break;
1245     }
1246
1247     case 0x08:  /* Forward Scan */
1248     {
1249       /* reset scanning direction / speed */
1250       cdd.scanOffset = CD_SCAN_SPEED;
1251
1252       /* update status (RS1-RS8 unchanged) */
1253       cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_SCAN;
1254       break;
1255     }
1256
1257     case 0x09:  /* Rewind Scan */
1258     {
1259       /* reset scanning direction / speed */
1260       cdd.scanOffset = -CD_SCAN_SPEED;
1261
1262       /* update status (RS1-RS8 unchanged) */
1263       cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_SCAN;
1264       break;
1265     }
1266
1267
1268     case 0x0a:  /* N-Track Jump Control ? (usually sent before CD_SEEK or CD_PLAY commands) */
1269     {
1270       /* TC3 corresponds to seek direction (00=forward, FF=reverse) */
1271       /* TC4-TC7 are related to seek length (4x4 bits i.e parameter values are between -65535 and +65535) */
1272       /* Maybe related to number of auto-sequenced track jumps/moves for CD DSP (cf. CXD2500BQ datasheet) */
1273       /* also see US Patent nr. 5222054 for a detailled description of seeking operation using Track Jump */
1274
1275       /* no audio track playing */
1276       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1277
1278       /* update status (RS1-RS8 unchanged) */
1279       cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_READY;
1280       break;
1281     }
1282
1283     case 0x0c:  /* Close Tray */
1284     {
1285       /* no audio track playing */
1286       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1287
1288       /* update status */
1289       cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
1290
1291       /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
1292       set_reg16(0x38, 0x0000);
1293       set_reg16(0x3a, 0x0000);
1294       set_reg16(0x3c, 0x0000);
1295       set_reg16(0x3e, 0x0000);
1296       set_reg16(0x40, 0x000f);
1297
1298       if (PicoMCDcloseTray)
1299         PicoMCDcloseTray();
1300
1301       return;
1302     }
1303
1304     case 0x0d:  /* Open Tray */
1305     {
1306       /* no audio track playing */
1307       Pico_mcd->s68k_regs[0x36+0] = 0x01;
1308
1309       /* update status (RS1-RS8 ignored) */
1310       cdd.status = CD_OPEN;
1311       set_reg16(0x38, CD_OPEN << 8);
1312       set_reg16(0x3a, 0x0000);
1313       set_reg16(0x3c, 0x0000);
1314       set_reg16(0x3e, 0x0000);
1315       set_reg16(0x40, ~CD_OPEN & 0x0f);
1316
1317       if (PicoMCDopenTray)
1318         PicoMCDopenTray();
1319       return;
1320     }
1321
1322     default:  /* Unknown command */
1323 #ifdef LOG_CDD
1324       error("Unknown CDD Command !!!\n");
1325 #endif
1326       Pico_mcd->s68k_regs[0x38+0] = cdd.status;
1327       break;
1328   }
1329
1330   /* only compute checksum when necessary */
1331   Pico_mcd->s68k_regs[0x40 + 1] =
1332     ~(Pico_mcd->s68k_regs[0x38 + 0] + Pico_mcd->s68k_regs[0x38 + 1] +
1333     Pico_mcd->s68k_regs[0x3a + 0] + Pico_mcd->s68k_regs[0x3a + 1] +
1334     Pico_mcd->s68k_regs[0x3c + 0] + Pico_mcd->s68k_regs[0x3c + 1] +
1335     Pico_mcd->s68k_regs[0x3e + 0] + Pico_mcd->s68k_regs[0x3e + 1] +
1336     Pico_mcd->s68k_regs[0x40 + 0]) & 0x0f;
1337 }
1338
1339 // vim:shiftwidth=2:ts=2:expandtab