58a605362ab5360377c050d9d8431960161779ae
[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 = cdd.loaded ? CD_STOP : 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   return 0;
430 }
431
432 int cdd_unload(void)
433 {
434   int was_loaded = cdd.loaded;
435
436   if (cdd.loaded)
437   {
438     int i;
439
440     /* close CD tracks */
441     if (cdd.toc.tracks[0].fd)
442     {
443       pm_close(cdd.toc.tracks[0].fd);
444       cdd.toc.tracks[0].fd = NULL;
445     }
446
447     for (i = 1; i < cdd.toc.last; i++)
448     {
449 #ifdef USE_LIBTREMOR
450       if (cdd.toc.tracks[i].vf.datasource)
451       {
452         /* close VORBIS file (if still opened) */
453         ov_clear(&cdd.toc.tracks[i].vf);
454       }
455       else
456 #endif
457       if (cdd.toc.tracks[i].fd)
458       {
459         /* close file */
460         if (Pico_mcd->cdda_type == CT_MP3)
461           fclose(cdd.toc.tracks[i].fd);
462         else
463           pm_close(cdd.toc.tracks[0].fd);
464
465         /* detect single file images */
466         if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)
467         {
468           /* exit loop */
469           i = cdd.toc.last;
470         }
471       }
472     }
473
474     /* CD unloaded */
475     cdd.loaded = 0;
476   }
477
478   /* reset TOC */
479   memset(&cdd.toc, 0x00, sizeof(cdd.toc));
480     
481   /* unknown CD image file format */
482   cdd.sectorSize = 0;
483
484   return was_loaded;
485 }
486
487 void cdd_read_data(uint8 *dst)
488 {
489   /* only read DATA track sectors */
490   if ((cdd.lba >= 0) && (cdd.lba < cdd.toc.tracks[0].end))
491   {
492     /* BIN format ? */
493     if (cdd.sectorSize == 2352)
494     {
495       /* skip 16-byte header */
496       pm_seek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET);
497     }
498
499     /* read sector data (Mode 1 = 2048 bytes) */
500     pm_read(dst, 2048, cdd.toc.tracks[0].fd);
501   }
502 }
503
504 #if 0
505 void cdd_read_audio(unsigned int samples)
506 {
507   /* previous audio outputs */
508   int16 l = cdd.audio[0];
509   int16 r = cdd.audio[1];
510
511   /* get number of internal clocks (samples) needed */
512   samples = blip_clocks_needed(blip[0], samples);
513
514   /* audio track playing ? */
515   if (!Pico_mcd->regs[0x36>>1].byte.h && cdd.toc.tracks[cdd.index].fd)
516   {
517     int i, mul, delta;
518
519     /* current CD-DA fader volume */
520     int curVol = cdd.volume;
521
522     /* CD-DA fader volume setup (0-1024) */
523     int endVol = Pico_mcd->regs[0x34>>1].w >> 4;
524
525     /* read samples from current block */
526 #ifdef USE_LIBTREMOR
527     if (cdd.toc.tracks[cdd.index].vf.datasource)
528     {
529       int len, done = 0;
530       int16 *ptr = (int16 *) (cdc.ram);
531       samples = samples * 4;
532       while (done < samples)
533       {
534         len = ov_read(&cdd.toc.tracks[cdd.index].vf, (char *)(cdc.ram + done), samples - done, 0);
535         if (len <= 0) 
536         {
537           done = samples;
538           break;
539         }
540         done += len;
541       }
542       samples = done / 4;
543
544       /* process 16-bit (host-endian) stereo samples */
545       for (i=0; i<samples; i++)
546       {
547         /* CD-DA fader multiplier (cf. LC7883 datasheet) */
548         /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
549         mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
550
551         /* left channel */
552         delta = ((ptr[0] * mul) / 1024) - l;
553         ptr++;
554         l += delta;
555         blip_add_delta_fast(blip[0], i, delta);
556
557         /* right channel */
558         delta = ((ptr[0] * mul) / 1024) - r;
559         ptr++;
560         r += delta;
561         blip_add_delta_fast(blip[1], i, delta);
562
563         /* update CD-DA fader volume (one step/sample) */
564         if (curVol < endVol)
565         {
566           /* fade-in */
567           curVol++;
568         }
569         else if (curVol > endVol)
570         {
571           /* fade-out */
572           curVol--;
573         }
574         else if (!curVol)
575         {
576           /* audio will remain muted until next setup */
577           break;
578         }
579       }
580     }
581     else
582 #endif
583     {
584 #ifdef LSB_FIRST
585       int16 *ptr = (int16 *) (cdc.ram);
586 #else
587       uint8 *ptr = cdc.ram;
588 #endif
589       fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd);
590
591       /* process 16-bit (little-endian) stereo samples */
592       for (i=0; i<samples; i++)
593       {
594         /* CD-DA fader multiplier (cf. LC7883 datasheet) */
595         /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */
596         mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03);
597
598         /* left channel */
599   #ifdef LSB_FIRST
600         delta = ((ptr[0] * mul) / 1024) - l;
601         ptr++;
602   #else
603         delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l;
604         ptr += 2;
605   #endif
606         l += delta;
607         blip_add_delta_fast(blip[0], i, delta);
608
609         /* right channel */
610   #ifdef LSB_FIRST
611         delta = ((ptr[0] * mul) / 1024) - r;
612         ptr++;
613   #else
614         delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r;
615         ptr += 2;
616   #endif
617         r += delta;
618         blip_add_delta_fast(blip[1], i, delta);
619
620         /* update CD-DA fader volume (one step/sample) */
621         if (curVol < endVol)
622         {
623           /* fade-in */
624           curVol++;
625         }
626         else if (curVol > endVol)
627         {
628           /* fade-out */
629           curVol--;
630         }
631         else if (!curVol)
632         {
633           /* audio will remain muted until next setup */
634           break;
635         }
636       }
637     }
638
639     /* save current CD-DA fader volume */
640     cdd.volume = curVol;
641
642     /* save last audio output for next frame */
643     cdd.audio[0] = l;
644     cdd.audio[1] = r;
645   }
646   else
647   {
648     /* no audio output */
649     if (l) blip_add_delta_fast(blip[0], 0, -l);
650     if (r) blip_add_delta_fast(blip[1], 0, -r);
651
652     /* save audio output for next frame */
653     cdd.audio[0] = 0;
654     cdd.audio[1] = 0;
655   }
656
657   /* end of Blip Buffer timeframe */
658   blip_end_frame(blip[0], samples);
659   blip_end_frame(blip[1], samples);
660 }
661 #endif
662
663
664 void cdd_update(void)
665 {  
666 #ifdef LOG_CDD
667   error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
668 #endif
669   
670   /* seeking disc */
671   if (cdd.status == CD_SEEK)
672   {
673     /* drive latency */
674     if (cdd.latency > 0)
675     {
676       cdd.latency--;
677       return;
678     }
679
680     /* drive is ready */
681     cdd.status = CD_READY;
682   }
683
684   /* reading disc */
685   else if (cdd.status == CD_PLAY)
686   {
687     /* drive latency */
688     if (cdd.latency > 0)
689     {
690       cdd.latency--;
691       return;
692     }
693
694     /* track type */
695     if (!cdd.index)
696     {
697       /* DATA sector header (CD-ROM Mode 1) */
698       uint8 header[4];
699       uint32 msf = cdd.lba + 150;
700       header[0] = lut_BCD_8[(msf / 75) / 60];
701       header[1] = lut_BCD_8[(msf / 75) % 60];
702       header[2] = lut_BCD_8[(msf % 75)];
703       header[3] = 0x01;
704
705       /* data track sector read is controlled by CDC */
706       cdd.lba += cdc_decoder_update(header);
707     }
708     else if (cdd.index < cdd.toc.last)
709     {
710       uint8 header[4] = { 0, };
711
712       /* check against audio track start index */
713       if (cdd.lba >= cdd.toc.tracks[cdd.index].start)
714       {
715         /* audio track playing */
716         Pico_mcd->regs[0x36>>1].byte.h = 0x00;
717       }
718
719       /* audio blocks are still sent to CDC as well as CD DAC/Fader */
720       cdc_decoder_update(header);
721  
722       /* next audio block is automatically read */
723       cdd.lba++;
724     }
725     else
726     {
727       /* end of disc */
728       cdd.status = CD_END;
729       return;
730     }
731
732     /* check end of current track */
733     if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
734     {
735 #ifdef USE_LIBTREMOR
736 #ifdef DISABLE_MANY_OGG_OPEN_FILES
737       /* close previous track VORBIS file structure to save memory */
738       if (cdd.toc.tracks[cdd.index].vf.datasource)
739       {
740         ogg_free(cdd.index);
741       }
742 #endif
743 #endif
744       /* play next track */
745       cdd.index++;
746
747       /* PAUSE between tracks */
748       Pico_mcd->regs[0x36>>1].byte.h = 0x01;
749
750       /* seek to next audio track start */
751 #ifdef USE_LIBTREMOR
752       if (cdd.toc.tracks[cdd.index].vf.seekable)
753       {
754 #ifdef DISABLE_MANY_OGG_OPEN_FILES
755         /* VORBIS file need to be opened first */
756         ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
757 #endif
758         ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, -cdd.toc.tracks[cdd.index].offset);
759       }
760       else
761 #endif 
762 #if 0
763       if (cdd.toc.tracks[cdd.index].fd)
764       {
765         fseek(cdd.toc.tracks[cdd.index].fd, (cdd.toc.tracks[cdd.index].start * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
766       }
767 #else
768       {
769         cdd_change_track(cdd.index, cdd.lba);
770       }
771 #endif
772     }
773   }
774
775   /* scanning disc */
776   else if (cdd.status == CD_SCAN)
777   {
778     /* fast-forward or fast-rewind */
779     cdd.lba += cdd.scanOffset;
780
781     /* check current track limits */
782     if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
783     {
784 #ifdef USE_LIBTREMOR
785 #ifdef DISABLE_MANY_OGG_OPEN_FILES
786       /* close previous track VORBIS file structure to save memory */
787       if (cdd.toc.tracks[cdd.index].vf.datasource)
788       {
789         ogg_free(cdd.index);
790       }
791 #endif
792 #endif
793       /* next track */
794       cdd.index++;
795
796       /* skip directly to track start position */
797       cdd.lba = cdd.toc.tracks[cdd.index].start;
798       
799       /* AUDIO track playing ? */
800       if (cdd.status == CD_PLAY)
801       {
802         Pico_mcd->regs[0x36>>1].byte.h = 0x00;
803       }
804     }
805     else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
806     {
807 #ifdef USE_LIBTREMOR
808 #ifdef DISABLE_MANY_OGG_OPEN_FILES
809       /* close previous track VORBIS file structure to save memory */
810       if (cdd.toc.tracks[cdd.index].vf.datasource)
811       {
812         ogg_free(cdd.index);
813       }
814 #endif
815 #endif
816
817       /* previous track */
818       cdd.index--;
819
820       /* skip directly to track end position */
821       cdd.lba = cdd.toc.tracks[cdd.index].end;
822     }
823
824     /* check disc limits */
825     if (cdd.index < 0)
826     {
827       cdd.index = 0;
828       cdd.lba = 0;
829     }
830     else if (cdd.index >= cdd.toc.last)
831     {
832       /* no AUDIO track playing */
833       Pico_mcd->regs[0x36>>1].byte.h = 0x01;
834
835       /* end of disc */
836       cdd.index = cdd.toc.last;
837       cdd.lba = cdd.toc.end;
838       cdd.status = CD_END;
839       return;
840     }
841
842     /* seek to current block */
843     if (!cdd.index)
844     {
845       /* no AUDIO track playing */
846       Pico_mcd->regs[0x36>>1].byte.h = 0x01;
847
848       /* DATA track */
849       pm_seek(cdd.toc.tracks[0].fd, cdd.lba * cdd.sectorSize, SEEK_SET);
850     }
851 #ifdef USE_LIBTREMOR
852     else if (cdd.toc.tracks[cdd.index].vf.seekable)
853     {
854 #ifdef DISABLE_MANY_OGG_OPEN_FILES
855       /* check if a new track is being played */
856       if (!cdd.toc.tracks[cdd.index].vf.datasource)
857       {
858         /* VORBIS file need to be opened first */
859         ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
860       }
861 #endif
862       /* VORBIS AUDIO track */
863       ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (cdd.lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
864     }
865 #endif 
866 #if 0
867     else if (cdd.toc.tracks[cdd.index].fd)
868     {
869       /* PCM AUDIO track */
870       fseek(cdd.toc.tracks[cdd.index].fd, (cdd.lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
871     }
872 #else
873     else
874     {
875       cdd_change_track(cdd.index, cdd.lba);
876     }
877 #endif
878   }
879 }
880
881 #define set_reg16(r, v) { \
882   uint16 _v = v; \
883   Pico_mcd->s68k_regs[(r)] = _v >> 8; \
884   Pico_mcd->s68k_regs[(r)+1] = _v; \
885 }
886
887 void cdd_process(void)
888 {
889   /* Process CDD command */
890   switch (Pico_mcd->regs[0x42>>1].byte.h & 0x0f)
891   {
892     case 0x00:  /* Drive Status */
893     {
894       /* RS1-RS8 normally unchanged */
895       Pico_mcd->regs[0x38>>1].byte.h = cdd.status;
896
897       /* unless RS1 indicated invalid track infos */
898       if (Pico_mcd->regs[0x38>>1].byte.l == 0x0f)
899       {
900         /* and SEEK has ended */
901         if (cdd.status != CD_SEEK)
902         {
903           /* then return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */
904           Pico_mcd->regs[0x38>>1].byte.l = 0x02;
905           set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
906         }
907       }
908       break;
909     }
910
911     case 0x01:  /* Stop Drive */
912     {
913       /* update status */
914       cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
915
916       /* no audio track playing */
917       Pico_mcd->regs[0x36>>1].byte.h = 0x01;
918
919       /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
920       set_reg16(0x38, 0x0000);
921       set_reg16(0x3a, 0x0000);
922       set_reg16(0x3c, 0x0000);
923       set_reg16(0x3e, 0x0000);
924       set_reg16(0x40, 0x000f);
925       return;
926     }
927
928     case 0x02:  /* Read TOC */
929     {
930       /* Infos automatically retrieved by CDD processor from Q-Channel */
931       /* commands 0x00-0x02 (current block) and 0x03-0x05 (Lead-In) */
932       switch (Pico_mcd->regs[0x44>>1].byte.l)
933       {
934         case 0x00:  /* Current Absolute Time (MM:SS:FF) */
935         {
936           int lba = cdd.lba + 150;
937           set_reg16(0x38, cdd.status << 8);
938           set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
939           set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
940           set_reg16(0x3e, lut_BCD_16[(lba%75)]);
941           Pico_mcd->regs[0x40>>1].byte.h = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
942           break;
943         }
944
945         case 0x01:  /* Current Track Relative Time (MM:SS:FF) */
946         {
947           int lba = cdd.lba - cdd.toc.tracks[cdd.index].start;
948           set_reg16(0x38, (cdd.status << 8) | 0x01);
949           set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
950           set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
951           set_reg16(0x3e, lut_BCD_16[(lba%75)]);
952           Pico_mcd->regs[0x40>>1].byte.h = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
953           break;
954         }
955
956         case 0x02:  /* Current Track Number */
957         {
958           set_reg16(0x38, (cdd.status << 8) | 0x02);
959           set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
960           set_reg16(0x3c, 0x0000);
961           set_reg16(0x3e, 0x0000); /* Disk Control Code (?) in RS6 */
962           Pico_mcd->regs[0x40>>1].byte.h = 0x00;
963           break;
964         }
965
966         case 0x03:  /* Total length (MM:SS:FF) */
967         {
968           int lba = cdd.toc.end + 150;
969           set_reg16(0x38, (cdd.status << 8) | 0x03);
970           set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
971           set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
972           set_reg16(0x3e, lut_BCD_16[(lba%75)]);
973           Pico_mcd->regs[0x40>>1].byte.h = 0x00;
974           break;
975         }
976
977         case 0x04:  /* First & Last Track Numbers */
978         {
979           set_reg16(0x38, (cdd.status << 8) | 0x04);
980           set_reg16(0x3a, 0x0001);
981           set_reg16(0x3c, lut_BCD_16[cdd.toc.last]);
982           set_reg16(0x3e, 0x0000); /* Drive Version (?) in RS6-RS7 */
983           Pico_mcd->regs[0x40>>1].byte.h = 0x00;  /* Lead-In flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
984           break;
985         }
986
987         case 0x05:  /* Track Start Time (MM:SS:FF) */
988         {
989           int track = Pico_mcd->regs[0x46>>1].byte.h * 10 + Pico_mcd->regs[0x46>>1].byte.l;
990           int lba = cdd.toc.tracks[track-1].start + 150;
991           set_reg16(0x38, (cdd.status << 8) | 0x05);
992           set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
993           set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
994           set_reg16(0x3e, lut_BCD_16[(lba%75)]);
995           Pico_mcd->regs[0x40>>1].byte.h = track % 10;  /* Track Number (low digit) */
996           if (track == 1)
997           {
998             /* RS6 bit 3 is set for the first (DATA) track */
999             Pico_mcd->regs[0x3e>>1].byte.h |= 0x08;
1000           }
1001           break;
1002         }
1003
1004         default:
1005         {
1006 #ifdef LOG_ERROR
1007           error("Unknown CDD Command %02X (%X)\n", Pico_mcd->regs[0x44>>1].byte.l, s68k.pc);
1008 #endif
1009           return;
1010         }
1011       }
1012       break;
1013     }
1014
1015     case 0x03:  /* Play  */
1016     {
1017       /* reset track index */
1018       int index = 0;
1019
1020       /* new LBA position */
1021       int lba = ((Pico_mcd->regs[0x44>>1].byte.h * 10 + Pico_mcd->regs[0x44>>1].byte.l) * 60 + 
1022                  (Pico_mcd->regs[0x46>>1].byte.h * 10 + Pico_mcd->regs[0x46>>1].byte.l)) * 75 +
1023                  (Pico_mcd->regs[0x48>>1].byte.h * 10 + Pico_mcd->regs[0x48>>1].byte.l) - 150;
1024
1025       /* CD drive latency */
1026       if (!cdd.latency)
1027       {
1028         /* Fixes a few games hanging during intro because they expect data to be read with some delay */
1029         /* Radical Rex needs at least one interrupt delay */
1030         /* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal) need at least 6 interrupts delay  */
1031         /* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 6 is OK) */
1032         /* Jeopardy & ESPN Sunday Night NFL are picky about this as well: 10 interrupts delay (+ seek time) seems OK */
1033         cdd.latency = 10;
1034       }
1035
1036       /* CD drive seek time */
1037       /* max. seek time = 1.5 s = 1.5 x 75 = 112.5 CDD interrupts (rounded to 120) for 270000 sectors max on disc. */
1038       /* Note: This is only a rough approximation since, on real hardware, seek time is much likely not linear and */
1039       /* latency much larger than above value, but this model works fine for Sonic CD (track 26 playback needs to  */
1040       /* be enough delayed to start in sync with intro sequence, as compared with real hardware recording).        */
1041       if (lba > cdd.lba)
1042       {
1043         cdd.latency += (((lba - cdd.lba) * 120) / 270000);
1044       }
1045       else 
1046       {
1047         cdd.latency += (((cdd.lba - lba) * 120) / 270000);
1048       }
1049
1050       /* update current LBA */
1051       cdd.lba = lba;
1052
1053       /* get track index */
1054       while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
1055
1056 #ifdef USE_LIBTREMOR
1057 #ifdef DISABLE_MANY_OGG_OPEN_FILES
1058       /* check if track index has changed */
1059       if (index != cdd.index)
1060       {
1061         /* close previous track VORBIS file structure to save memory */
1062         if (cdd.toc.tracks[cdd.index].vf.datasource)
1063         {
1064           ogg_free(cdd.index);
1065         }
1066
1067         /* open current track VORBIS file */
1068         if (cdd.toc.tracks[index].vf.seekable)
1069         {
1070           ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
1071         }
1072       }
1073 #endif
1074 #endif
1075
1076       /* update current track index */
1077       cdd.index = index;
1078
1079       /* stay within track limits when seeking files */
1080       if (lba < cdd.toc.tracks[index].start) 
1081       {
1082         lba = cdd.toc.tracks[index].start;
1083       }
1084       
1085       /* seek to current block */
1086       if (!index)
1087       {
1088         /* DATA track */
1089         pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
1090       }
1091 #ifdef USE_LIBTREMOR
1092       else if (cdd.toc.tracks[index].vf.seekable)
1093       {
1094         /* VORBIS AUDIO track */
1095         ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
1096       }
1097 #endif
1098 #if 0
1099       else if (cdd.toc.tracks[index].fd)
1100       {
1101         /* PCM AUDIO track */
1102         fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
1103       }
1104 #else
1105       else
1106       {
1107         cdd_change_track(index, lba);
1108       }
1109 #endif
1110
1111       /* no audio track playing (yet) */
1112       Pico_mcd->regs[0x36>>1].byte.h = 0x01;
1113
1114       /* update status */
1115       cdd.status = CD_PLAY;
1116
1117       /* return track index in RS2-RS3 */
1118       set_reg16(0x38, (CD_PLAY << 8) | 0x02);
1119       set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[index + 1] : 0x0A0A);
1120       set_reg16(0x3c, 0x0000);
1121       set_reg16(0x3e, 0x0000);
1122       Pico_mcd->regs[0x40>>1].byte.h = 0x00;
1123       break;
1124     }
1125
1126     case 0x04:  /* Seek */
1127     {
1128       /* reset track index */
1129       int index = 0;
1130
1131       /* new LBA position */
1132       int lba = ((Pico_mcd->regs[0x44>>1].byte.h * 10 + Pico_mcd->regs[0x44>>1].byte.l) * 60 + 
1133                  (Pico_mcd->regs[0x46>>1].byte.h * 10 + Pico_mcd->regs[0x46>>1].byte.l)) * 75 +
1134                  (Pico_mcd->regs[0x48>>1].byte.h * 10 + Pico_mcd->regs[0x48>>1].byte.l) - 150;
1135
1136       /* CD drive seek time  */
1137       /* We are using similar linear model as above, although still not exactly accurate, */
1138       /* it works fine for Switch/Panic! intro (Switch needs at least 30 interrupts while */
1139       /* seeking from 00:05:63 to 24:03:19, Panic! when seeking from 00:05:60 to 24:06:07) */
1140       if (lba > cdd.lba)
1141       {
1142         cdd.latency = ((lba - cdd.lba) * 120) / 270000;
1143       }
1144       else
1145       {
1146         cdd.latency = ((cdd.lba - lba) * 120) / 270000;
1147       }
1148
1149       /* update current LBA */
1150       cdd.lba = lba;
1151
1152       /* get current track index */
1153       while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
1154
1155 #ifdef USE_LIBTREMOR
1156 #ifdef DISABLE_MANY_OGG_OPEN_FILES
1157       /* check if track index has changed */
1158       if (index != cdd.index)
1159       {
1160         /* close previous track VORBIS file structure to save memory */
1161         if (cdd.toc.tracks[cdd.index].vf.datasource)
1162         {
1163           ogg_free(cdd.index);
1164         }
1165
1166         /* open current track VORBIS file */
1167         if (cdd.toc.tracks[index].vf.seekable)
1168         {
1169           ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
1170         }
1171       }
1172 #endif
1173 #endif
1174
1175       /* update current track index */
1176       cdd.index = index;
1177
1178       /* stay within track limits */
1179       if (lba < cdd.toc.tracks[index].start) 
1180       {
1181         lba = cdd.toc.tracks[index].start;
1182       }
1183       
1184       /* seek to current block */
1185       if (!index)
1186       {
1187         /* DATA track */
1188         pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
1189       }
1190 #ifdef USE_LIBTREMOR
1191       else if (cdd.toc.tracks[index].vf.seekable)
1192       {
1193         /* VORBIS AUDIO track */
1194         ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
1195       }
1196 #endif
1197 #if 0
1198       else if (cdd.toc.tracks[index].fd)
1199       {
1200         /* PCM AUDIO track */
1201         fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
1202       }
1203 #endif
1204
1205       /* no audio track playing */
1206       Pico_mcd->regs[0x36>>1].byte.h = 0x01;
1207
1208       /* update status */
1209       cdd.status = CD_SEEK;
1210
1211       /* 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) */
1212       set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
1213       set_reg16(0x3a, 0x0000);
1214       set_reg16(0x3c, 0x0000);
1215       set_reg16(0x3e, 0x0000);
1216       set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
1217       return;
1218     }
1219
1220     case 0x06:  /* Pause */
1221     {
1222       /* no audio track playing */
1223       Pico_mcd->regs[0x36>>1].byte.h = 0x01;
1224
1225       /* update status (RS1-RS8 unchanged) */
1226       cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_READY;
1227       break;
1228     }
1229
1230     case 0x07:  /* Resume */
1231     {
1232       /* update status (RS1-RS8 unchanged) */
1233       cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_PLAY;
1234       break;
1235     }
1236
1237     case 0x08:  /* Forward Scan */
1238     {
1239       /* reset scanning direction / speed */
1240       cdd.scanOffset = CD_SCAN_SPEED;
1241
1242       /* update status (RS1-RS8 unchanged) */
1243       cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_SCAN;
1244       break;
1245     }
1246
1247     case 0x09:  /* Rewind 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->regs[0x38>>1].byte.h = CD_SCAN;
1254       break;
1255     }
1256
1257
1258     case 0x0a:  /* N-Track Jump Control ? (usually sent before CD_SEEK or CD_PLAY commands) */
1259     {
1260       /* TC3 corresponds to seek direction (00=forward, FF=reverse) */
1261       /* TC4-TC7 are related to seek length (4x4 bits i.e parameter values are between -65535 and +65535) */
1262       /* Maybe related to number of auto-sequenced track jumps/moves for CD DSP (cf. CXD2500BQ datasheet) */
1263       /* also see US Patent nr. 5222054 for a detailled description of seeking operation using Track Jump */
1264
1265       /* no audio track playing */
1266       Pico_mcd->regs[0x36>>1].byte.h = 0x01;
1267
1268       /* update status (RS1-RS8 unchanged) */
1269       cdd.status = Pico_mcd->regs[0x38>>1].byte.h = CD_READY;
1270       break;
1271     }
1272
1273     case 0x0c:  /* Close Tray */
1274     {
1275       /* no audio track playing */
1276       Pico_mcd->regs[0x36>>1].byte.h = 0x01;
1277
1278       /* update status */
1279       cdd.status = cdd.loaded ? CD_STOP : NO_DISC;
1280
1281       /* RS1-RS8 ignored, expects 0x0 ("no disc" ?) in RS0 once */
1282       set_reg16(0x38, 0x0000);
1283       set_reg16(0x3a, 0x0000);
1284       set_reg16(0x3c, 0x0000);
1285       set_reg16(0x3e, 0x0000);
1286       set_reg16(0x40, 0x000f);
1287
1288       if (PicoMCDcloseTray)
1289         PicoMCDcloseTray();
1290       return;
1291     }
1292
1293     case 0x0d:  /* Open Tray */
1294     {
1295       /* no audio track playing */
1296       Pico_mcd->regs[0x36>>1].byte.h = 0x01;
1297
1298       /* update status (RS1-RS8 ignored) */
1299       cdd.status = CD_OPEN;
1300       set_reg16(0x38, CD_OPEN << 8);
1301       set_reg16(0x3a, 0x0000);
1302       set_reg16(0x3c, 0x0000);
1303       set_reg16(0x3e, 0x0000);
1304       set_reg16(0x40, ~CD_OPEN & 0x0f);
1305
1306       if (PicoMCDopenTray)
1307         PicoMCDopenTray();
1308       return;
1309     }
1310
1311     default:  /* Unknown command */
1312 #ifdef LOG_CDD
1313       error("Unknown CDD Command !!!\n");
1314 #endif
1315       Pico_mcd->regs[0x38>>1].byte.h = cdd.status;
1316       break;
1317   }
1318
1319   /* only compute checksum when necessary */
1320   Pico_mcd->regs[0x40>>1].byte.l =
1321     ~(Pico_mcd->regs[0x38>>1].byte.h + Pico_mcd->regs[0x38>>1].byte.l +
1322     Pico_mcd->regs[0x3a>>1].byte.h + Pico_mcd->regs[0x3a>>1].byte.l +
1323     Pico_mcd->regs[0x3c>>1].byte.h + Pico_mcd->regs[0x3c>>1].byte.l +
1324     Pico_mcd->regs[0x3e>>1].byte.h + Pico_mcd->regs[0x3e>>1].byte.l +
1325     Pico_mcd->regs[0x40>>1].byte.h) & 0x0f;
1326 }
1327
1328 // vim:shiftwidth=2:ts=2:expandtab