OSDN Git Service

[VM][General] Merge Upstream 20180530.
[csp-qt/common_source_project-fm7.git] / source / src / vm / scsi_cdrom.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2016.03.06-
6
7         [ SCSI CD-ROM drive ]
8 */
9
10 #include "scsi_cdrom.h"
11 #include "../fifo.h"
12
13 #define CDDA_OFF        0
14 #define CDDA_PLAYING    1
15 #define CDDA_PAUSED     2
16
17 // 0-99 is reserved for SCSI_DEV class
18 #define EVENT_CDDA      100
19
20 void SCSI_CDROM::initialize()
21 {
22         SCSI_DEV::initialize();
23         fio_img = new FILEIO();
24         
25         if(44100 % emu->get_sound_rate() == 0) {
26                 mix_loop_num = 44100 / emu->get_sound_rate();
27         } else {
28                 mix_loop_num = 0;
29         }
30         event_cdda = -1;
31         cdda_status = CDDA_OFF;
32 }
33
34 void SCSI_CDROM::release()
35 {
36         if(fio_img->IsOpened()) {
37                 fio_img->Fclose();
38         }
39         delete fio_img;
40         SCSI_DEV::release();
41 }
42
43 void SCSI_CDROM::reset()
44 {
45         touch_sound();
46         SCSI_DEV::reset();
47         set_cdda_status(CDDA_OFF);
48 }
49
50 uint32_t SCSI_CDROM::read_signal(int id)
51 {
52         switch(id) {
53         case SIG_SCSI_CDROM_PLAYING:
54                 return (cdda_status == CDDA_PLAYING && cdda_interrupt) ? 0xffffffff : 0;
55                 
56         case SIG_SCSI_CDROM_SAMPLE_L:
57                 return (uint32_t)abs(cdda_sample_l);
58                 
59         case SIG_SCSI_CDROM_SAMPLE_R:
60                 return (uint32_t)abs(cdda_sample_r);
61         }
62         return SCSI_DEV::read_signal(id);
63 }
64
65 void SCSI_CDROM::event_callback(int event_id, int err)
66 {
67         switch (event_id) {
68         case EVENT_CDDA:
69                 // read 16bit 2ch samples in the cd-da buffer, called 44100 times/sec
70                 cdda_sample_l = (int)(int16_t)(cdda_buffer[cdda_buffer_ptr + 0] + cdda_buffer[cdda_buffer_ptr + 1] * 0x100);
71                 cdda_sample_r = (int)(int16_t)(cdda_buffer[cdda_buffer_ptr + 2] + cdda_buffer[cdda_buffer_ptr + 3] * 0x100);
72                 
73                 if((cdda_buffer_ptr += 4) % 2352 == 0) {
74                         // one frame finished
75                         if(++cdda_playing_frame == cdda_end_frame) {
76                                 // reached to end frame
77                                 if(cdda_repeat) {
78                                         // reload buffer
79                                         fio_img->Fseek(cdda_start_frame * 2352, FILEIO_SEEK_SET);
80                                         fio_img->Fread(cdda_buffer, sizeof(cdda_buffer), 1);
81                                         cdda_buffer_ptr = 0;
82                                         cdda_playing_frame = cdda_start_frame;
83                                         access = true;
84                                 } else {
85                                         // stop
86                                         if(cdda_interrupt) {
87                                                 write_signals(&outputs_done, 0xffffffff);
88                                         }
89                                         set_cdda_status(CDDA_OFF);
90                                 }
91                         } else if(cdda_buffer_ptr == array_length(cdda_buffer)) {
92                                 // refresh buffer
93                                 fio_img->Fread(cdda_buffer, sizeof(cdda_buffer), 1);
94                                 cdda_buffer_ptr = 0;
95                                 access = true;
96                         }
97                 }
98                 break;
99         default:
100                 SCSI_DEV::event_callback(event_id, err);
101                 break;
102         }
103 }
104
105 void SCSI_CDROM::set_cdda_status(uint8_t status)
106 {
107         if(status == CDDA_PLAYING) {
108                 if(mix_loop_num == 0) {
109                         if(event_cdda == -1) {
110                                 register_event(this, EVENT_CDDA, 1000000.0 / 44100.0, true, &event_cdda);
111                         }
112                 }
113                 if(cdda_status != CDDA_PLAYING) {
114                         touch_sound();
115                         set_realtime_render(this, true);
116                 }
117         } else {
118                 if(event_cdda != -1) {
119                         cancel_event(this, event_cdda);
120                         event_cdda = -1;
121                 }
122                 if(cdda_status == CDDA_PLAYING) {
123                         touch_sound();
124                         set_realtime_render(this, false);
125                 }
126         }
127         cdda_status = status;
128 }
129
130 void SCSI_CDROM::reset_device()
131 {
132         set_cdda_status(CDDA_OFF);
133         SCSI_DEV::reset_device();
134 }
135
136 bool SCSI_CDROM::is_device_ready()
137 {
138         return mounted();
139 }
140
141 int SCSI_CDROM::get_command_length(int value)
142 {
143         switch(value) {
144         case 0xd8:
145         case 0xd9:
146         case 0xda:
147         case 0xdd:
148         case 0xde:
149                 return 10;
150         }
151         return SCSI_DEV::get_command_length(value);
152 }
153
154 int SCSI_CDROM::get_track(uint32_t lba)
155 {
156         int track = 0;
157         
158         for(int i = 0; i < track_num; i++) {
159                 if(lba >= toc_table[i].index0) {
160                         track = i;
161                 } else {
162                         break;
163                 }
164         }
165         return track;
166 }
167
168 double SCSI_CDROM::get_seek_time(uint32_t lba)
169 {
170         if(fio_img->IsOpened()) {
171                 uint32_t cur_position = (int)fio_img->Ftell();
172                 int distance = abs((int)(lba * physical_block_size()) - (int)cur_position);
173                 double ratio = (double)distance / 333000 / physical_block_size(); // 333000: sectors in media
174                 return max(10, (int)(400000 * 2 * ratio));
175         } else {
176                 return 400000; // 400msec
177         }
178 }
179
180 uint32_t lba_to_msf(uint32_t lba)
181 {
182         uint8_t m = lba / (60 * 75);
183         lba -= m * (60 * 75);
184         uint8_t s = lba / 75;
185         uint8_t f = lba % 75;
186
187         return ((m / 10) << 20) | ((m % 10) << 16) | ((s / 10) << 12) | ((s % 10) << 8) | ((f / 10) << 4) | ((f % 10) << 0);
188 }
189
190 uint32_t lba_to_msf_alt(uint32_t lba)
191 {
192         uint32_t ret = 0;
193         ret |= ((lba / (60 * 75)) & 0xff) << 16;
194         ret |= (((lba / 75) % 60) & 0xff) <<  8;
195         ret |= ((lba % 75)        & 0xff) <<  0;
196         return ret;
197 }
198
199 void SCSI_CDROM::start_command()
200 {
201         touch_sound();
202         switch(command[0]) {
203         case SCSI_CMD_READ6:
204                 seek_time = 10;//get_seek_time((command[1] & 0x1f) * 0x10000 + command[2] * 0x100 + command[3]);
205                 set_cdda_status(CDDA_OFF);
206                 break;
207                 
208         case SCSI_CMD_READ10:
209         case SCSI_CMD_READ12:
210                 seek_time = 10;//get_seek_time(command[2] * 0x1000000 + command[3] * 0x10000 + command[4] * 0x100 + command[5]);
211                 set_cdda_status(CDDA_OFF);
212                 break;
213                 
214         case 0xd8:
215                 #ifdef _SCSI_DEBUG_LOG
216                         this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Set Audio Playback Start Position\n"), scsi_id);
217                 #endif
218                 if(is_device_ready()) {
219                         if(command[2] == 0 && command[3] == 0 && command[4] == 0) {
220                                 // stop cd-da if all params are zero
221                                 cdda_start_frame = 0;
222                                 cdda_end_frame = toc_table[track_num].index0; // end of disc
223                                 set_cdda_status(CDDA_OFF);
224                         } else {
225                                 switch(command[9] & 0xc0) {
226                                 case 0x00:
227                                         cdda_start_frame = (command[2] << 16) | (command[3] << 8) | command[4];
228                                         break;
229                                 case 0x40:
230                                         {
231                                                 uint8_t m = FROM_BCD(command[2]);
232                                                 uint8_t s = FROM_BCD(command[3]);
233                                                 uint8_t f = FROM_BCD(command[4]);
234                                                 cdda_start_frame = f + 75 * (s + m * 60);
235                                                 
236                                                 // PCE tries to be clever here and set (start of track + track pregap size) to skip the pregap
237                                                 // (I guess it wants the TOC to have the real start sector for data tracks and the start of the pregap for audio?)
238                                                 int track =get_track(cdda_start_frame);
239                                                 cdda_start_frame -= toc_table[track].pregap;
240                                                 
241                                                 if(cdda_start_frame < toc_table[track].index1) {
242                                                         cdda_start_frame = toc_table[track].index1; // don't play pregap
243                                                 } else if(cdda_start_frame > max_logical_block) {
244                                                         cdda_start_frame = 0;
245                                                 }
246                                         }
247                                         break;
248                                 case 0x80:
249                                         cdda_start_frame = toc_table[FROM_BCD(command[2]) - 1].index1;
250                                         break;
251                                 default:
252                                         cdda_start_frame = 0;
253                                         break;
254                                 }
255 //                              if(cdda_status == CDDA_PAUSED) {
256 //                                      cdda_end_frame = toc_table[track_num].index0; // end of disc
257 //                                      set_cdda_status(CDDA_OFF);
258 //                              } else
259                                 if((command[1] & 3) != 0) {
260                                         cdda_end_frame = toc_table[track_num].index0; // end of disc
261                                         set_cdda_status(CDDA_PLAYING);
262                                 } else {
263                                         cdda_end_frame = toc_table[get_track(cdda_start_frame) + 1].index1; // end of this track
264                                         set_cdda_status(CDDA_PAUSED);
265                                 }
266                                 cdda_repeat = false;
267                                 cdda_interrupt = ((command[1] & 3) == 2);
268                                 
269                                 // read buffer
270                                 double seek_time = get_seek_time(cdda_start_frame);
271                                 fio_img->Fseek(cdda_start_frame * 2352, FILEIO_SEEK_SET);
272                                 fio_img->Fread(cdda_buffer, sizeof(cdda_buffer), 1);
273                                 cdda_buffer_ptr = 0;
274                                 cdda_playing_frame = cdda_start_frame;
275                                 access = true;
276                                 
277                                 // change to status phase
278                                 set_dat(SCSI_STATUS_GOOD);
279                                 set_phase_delay(SCSI_PHASE_STATUS, seek_time);
280                                 return;
281                         }
282                 }
283                 // change to status phase
284                 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
285                 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
286                 return;
287                 
288         case 0xd9:
289                 #ifdef _SCSI_DEBUG_LOG
290                         this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Set Audio Playback End Position\n"), scsi_id);
291                 #endif
292                 if(is_device_ready()) {
293                         switch(command[9] & 0xc0) {
294                         case 0x00:
295                                 cdda_end_frame = (command[3] << 16) | (command[4] << 8) | command[5];
296                                 break;
297                         case 0x40:
298                                 {
299                                         uint8_t m = FROM_BCD(command[2]);
300                                         uint8_t s = FROM_BCD(command[3]);
301                                         uint8_t f = FROM_BCD(command[4]);
302                                         cdda_end_frame = f + 75 * (s + m * 60);
303                                         
304                                         // PCE tries to be clever here and set (start of track + track pregap size) to skip the pregap
305                                         // (I guess it wants the TOC to have the real start sector for data tracks and the start of the pregap for audio?)
306                                         int track =get_track(cdda_end_frame);
307                                         
308                                         if(cdda_end_frame > toc_table[track].index1 && (cdda_end_frame - toc_table[track].pregap) <= toc_table[track].index1) {
309                                                 cdda_end_frame = toc_table[track].index1;
310                                         }
311                                 }
312                                 break;
313                         case 0x80:
314                                 cdda_end_frame = toc_table[FROM_BCD(command[2]) - 1].index1;
315                                 break;
316                         }
317                         if((command[1] & 3) != 0) {
318                                 set_cdda_status(CDDA_PLAYING);
319                                 cdda_repeat = ((command[1] & 3) == 1);
320                                 cdda_interrupt = ((command[1] & 3) == 2);
321                         } else {
322                                 set_cdda_status(CDDA_OFF);
323                         }
324                 }
325                 // change to status phase
326                 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
327                 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
328                 return;
329                 
330         case 0xda:
331                 #ifdef _SCSI_DEBUG_LOG
332                         this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Pause\n"), scsi_id);
333                 #endif
334                 if(is_device_ready()) {
335                         if(cdda_status == CDDA_PLAYING) {
336                                 set_cdda_status(CDDA_OFF);
337                         }
338                 }
339                 // change to status phase
340                 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
341                 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
342                 return;
343                 
344         case 0xdd:
345                 #ifdef _SCSI_DEBUG_LOG
346                         this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Read Sub Channel Q\n"), scsi_id);
347                 #endif
348                 if(is_device_ready()) {
349                         // create track info
350                         uint32_t frame = (cdda_status == CDDA_OFF) ? cdda_start_frame : cdda_playing_frame;
351                         uint32_t msf_abs = lba_to_msf_alt(frame);
352                         int track = get_track(frame);
353                         uint32_t msf_rel = lba_to_msf_alt(frame - toc_table[track].index0);
354                         buffer->clear();
355                         buffer->write((cdda_status == CDDA_PLAYING) ? 0x00 : (cdda_status == CDDA_PAUSED) ? 0x02 : 0x03);
356                         buffer->write(0x01 | (toc_table[track].is_audio ? 0x00 : 0x40));
357                         buffer->write(TO_BCD(track + 1));               // Track
358                         buffer->write(0x01);                            // Index
359                         buffer->write(TO_BCD((msf_rel >> 16) & 0xff));  // M (relative)
360                         buffer->write(TO_BCD((msf_rel >>  8) & 0xff));  // S (relative)
361                         buffer->write(TO_BCD((msf_rel >>  0) & 0xff));  // F (relative)
362                         buffer->write(TO_BCD((msf_abs >> 16) & 0xff));  // M (absolute)
363                         buffer->write(TO_BCD((msf_abs >>  8) & 0xff));  // S (absolute)
364                         buffer->write(TO_BCD((msf_abs >>  0) & 0xff));  // F (absolute)
365                         // transfer length
366                         remain = buffer->count();
367                         // set first data
368                         set_dat(buffer->read());
369                         // change to data in phase
370                         set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
371                 } else {
372                         // change to status phase
373                         set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
374                         set_phase_delay(SCSI_PHASE_STATUS, 10.0);
375                 }
376                 return;
377                 
378         case 0xde:
379                 #ifdef _SCSI_DEBUG_LOG
380                         this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Get Dir Info\n"), scsi_id);
381                 #endif
382                 if(is_device_ready()) {
383                         buffer->clear();
384                         switch(command[1]) {
385                         case 0x00:      /* Get first and last track numbers */
386                                 buffer->write(TO_BCD(1));
387                                 buffer->write(TO_BCD(track_num));
388                                 break;
389                         case 0x01:      /* Get total disk size in MSF format */
390                                 {
391                                         uint32_t msf = lba_to_msf(toc_table[track_num].index0 + 150);
392                                         buffer->write((msf >> 16) & 0xff);
393                                         buffer->write((msf >>  8) & 0xff);
394                                         buffer->write((msf >>  0) & 0xff);
395                                 }
396                                 break;
397                         case 0x02:      /* Get track information */
398                                 if(command[2] == 0xaa) {
399                                         uint32_t msf = lba_to_msf(toc_table[track_num].index0 + 150);
400                                         buffer->write((msf >> 16) & 0xff);
401                                         buffer->write((msf >>  8) & 0xff);
402                                         buffer->write((msf >>  0) & 0xff);
403                                         buffer->write(0x04); // correct ?
404                                 } else {
405                                         int track = max(FROM_BCD(command[2]), 1);
406                                         uint32_t frame = toc_table[track - 1].index0;
407                                         // PCE wants the start sector for data tracks to *not* include the pregap
408                                         if(!toc_table[track - 1].is_audio) {
409                                                 frame += toc_table[track - 1].pregap;
410                                         }
411                                         uint32_t msf = lba_to_msf(toc_table[track - 1].index1 + 150);
412                                         buffer->write((msf >> 16) & 0xff); // M
413                                         buffer->write((msf >>  8) & 0xff); // S
414                                         buffer->write((msf >>  0) & 0xff); // F
415                                         buffer->write(toc_table[track - 1].is_audio ? 0x00 : 0x04);
416                                 }
417                                 break;
418                         }
419                         // transfer length
420                         remain = buffer->count();
421                         // set first data
422                         set_dat(buffer->read());
423                         // change to data in phase
424                         set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
425                 } else {
426                         // change to status phase
427                         set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
428                         set_phase_delay(SCSI_PHASE_STATUS, 10.0);
429                 }
430                 return;
431         }
432         
433         // start standard command
434         SCSI_DEV::start_command();
435 }
436
437 bool SCSI_CDROM::read_buffer(int length)
438 {
439         if(!fio_img->IsOpened()) {
440                 set_sense_code(SCSI_SENSE_NOTREADY);
441                 return false;
442         }
443         uint32_t offset = (uint32_t)(position % 2352);
444         
445         if(fio_img->Fseek((long)position, FILEIO_SEEK_SET) != 0) {
446                 set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_SEEKERR
447                 return false;
448         }
449         while(length > 0) {
450                 uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
451                 int tmp_length = min(length, (int)sizeof(tmp_buffer));
452                 
453                 if(fio_img->Fread(tmp_buffer, tmp_length, 1) != 1) {
454                         set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_NORECORDFND
455                         return false;
456                 }
457                 for(int i = 0; i < tmp_length && length > 0; i++) {
458                         if(offset >= 16 && offset < 16 + 2048) {
459                                 int value = tmp_buffer[i];
460                                 buffer->write(value);
461                                 length--;
462                         }
463                         position++;
464                         offset = (offset + 1) % 2352;
465                 }
466                 access = true;
467         }
468         set_sense_code(SCSI_SENSE_NOSENSE);
469         return true;
470 }
471
472 int get_frames_from_msf(const char *string)
473 {
474         const char *ptr = string;
475         int frames[3] = {0};
476         int index = 0;
477         
478         while(1) {
479                 if(*ptr >= '0' && *ptr <= '9') {
480                         frames[index] = frames[index] * 10 + (*ptr - '0');
481                 } else if(*ptr == ':') {
482                         if(++index == 3) {
483                                 // abnormal data
484                                 break;
485                         }
486                 } else if(*ptr == '\r' || *ptr == '\n' || *ptr == '\0') {
487                         // end of line
488                         break;
489                 }
490                 ptr++;
491         }
492         return (frames[0] * 60 + frames[1]) * 75 + frames[2]; // 75frames/sec
493 }
494
495 int hexatoi(const char *string)
496 {
497         const char *ptr = string;
498         int value = 0;
499         
500         while(1) {
501                 if(*ptr >= '0' && *ptr <= '9') {
502                         value = value * 16 + (*ptr - '0');
503                 } else if(*ptr >= 'a' && *ptr <= 'f') {
504                         value = value * 16 + (*ptr - 'a' + 10);
505                 } else if(*ptr >= 'A' && *ptr <= 'F') {
506                         value = value * 16 + (*ptr - 'A' + 10);
507                 } else if(*ptr == '\r' || *ptr == '\n' || *ptr == '\0') {
508                         break;
509                 }
510                 ptr++;
511         }
512         return value;
513 }
514
515 void SCSI_CDROM::open(const _TCHAR* file_path)
516 {
517         _TCHAR img_file_path[_MAX_PATH];
518         
519         close();
520         
521         if(check_file_extension(file_path, _T(".cue"))) {
522                 // get image file name
523                 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img"), get_file_path_without_extensiton(file_path));
524                 if(!FILEIO::IsFileExisting(img_file_path)) {
525                         my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.bin"), get_file_path_without_extensiton(file_path));
526                         if(!FILEIO::IsFileExisting(img_file_path)) {
527                                 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.gz"), get_file_path_without_extensiton(file_path));
528                                 if(!FILEIO::IsFileExisting(img_file_path)) {
529                                         my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img.gz"), get_file_path_without_extensiton(file_path));
530                                         if(!FILEIO::IsFileExisting(img_file_path)) {
531                                                 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.bin.gz"), get_file_path_without_extensiton(file_path));
532                                         }
533                                 }
534                         }
535                 }
536                 if(fio_img->Fopen(img_file_path, FILEIO_READ_BINARY)) {
537                         // get image file size
538                         if((max_logical_block = fio_img->FileLength() / 2352) > 0) {
539                                 // read cue file
540                                 FILEIO* fio = new FILEIO();
541                                 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
542                                         char line[1024], *ptr;
543                                         int track = -1;
544                                         while(fio->Fgets(line, 1024) != NULL) {
545                                                 if(strstr(line, "FILE") != NULL) {
546                                                         // do nothing
547                                                 } else if((ptr = strstr(line, "TRACK")) != NULL) {
548                                                         // "TRACK 01 AUDIO"
549                                                         // "TRACK 02 MODE1/2352"
550                                                         ptr += 6;
551                                                         while(*ptr == ' ' || *ptr == 0x09) {
552                                                                 ptr++;
553                                                         }
554                                                         if((track = atoi(ptr)) > 0) {
555                                                                 if(track > track_num) {
556                                                                         track_num = track;
557                                                                 }
558                                                                 toc_table[track - 1].is_audio = (strstr(line, "AUDIO") != NULL);
559                                                         }
560                                                 } else if((ptr = strstr(line, "PREGAP")) != NULL) {
561                                                         // "PREGAP 00:02:00"
562                                                         if(track > 0) {
563                                                                 toc_table[track - 1].pregap = get_frames_from_msf(ptr + 7);
564                                                         }
565                                                 } else if((ptr = strstr(line, "INDEX")) != NULL) {
566                                                         // "INDEX 01 00:00:00"
567                                                         if(track > 0) {
568                                                                 ptr += 6;
569                                                                 while(*ptr == ' ' || *ptr == 0x09) {
570                                                                         ptr++;
571                                                                 }
572                                                                 int num = atoi(ptr);
573                                                                 while(*ptr >= '0' && *ptr <= '9') {
574                                                                         ptr++;
575                                                                 }
576                                                                 if(num == 0) {
577                                                                         toc_table[track - 1].index0 = get_frames_from_msf(ptr);
578                                                                 } else if(num == 1) {
579                                                                         toc_table[track - 1].index1 = get_frames_from_msf(ptr);
580                                                                 }
581                                                         }
582                                                 }
583                                         }
584                                         if(track_num != 0) {
585                                                 for(int i = 1; i < track_num; i++) {
586                                                         if(toc_table[i].index0 == 0) {
587                                                                 toc_table[i].index0 = toc_table[i].index1 - toc_table[i].pregap;
588                                                         } else if(toc_table[i].pregap == 0) {
589                                                                 toc_table[i].pregap = toc_table[i].index1 - toc_table[i].index0;
590                                                         }
591                                                 }
592                                                 toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
593                                                 toc_table[track_num].index0 = toc_table[track_num].index1 = max_logical_block;
594                                         } else {
595                                                 fio_img->Fclose();
596                                         }
597                                         fio->Fclose();
598                                 }
599                                 delete fio;
600                         }
601                 }
602         } else if(check_file_extension(file_path, _T(".ccd"))) {
603                 // get image file name
604                 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img"), get_file_path_without_extensiton(file_path));
605                 if(!FILEIO::IsFileExisting(img_file_path)) {
606                         my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.gz"), get_file_path_without_extensiton(file_path));
607                         if(!FILEIO::IsFileExisting(img_file_path)) {
608                                 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img.gz"), get_file_path_without_extensiton(file_path));
609                         }
610                 }
611                 if(fio_img->Fopen(img_file_path, FILEIO_READ_BINARY)) {
612                         // get image file size
613                         if((max_logical_block = fio_img->FileLength() / 2352) > 0) {
614                                 // read cue file
615                                 FILEIO* fio = new FILEIO();
616                                 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
617                                         char line[1024], *ptr;
618                                         int track = -1;
619                                         while(fio->Fgets(line, 1024) != NULL) {
620                                                 if(strstr(line, "[Session ") != NULL) {
621                                                         track = -1;
622                                                 } else if((ptr = strstr(line, "Point=0x")) != NULL) {
623                                                         if((track = hexatoi(ptr + 8)) > 0 && track < 0xa0) {
624                                                                 if(track > track_num) {
625                                                                         track_num = track;
626                                                                 }
627                                                         }
628                                                 } else if((ptr = strstr(line, "Control=0x")) != NULL) {
629                                                         if(track > 0 && track < 0xa0) {
630                                                                 toc_table[track - 1].is_audio = (hexatoi(ptr + 10) != 4);
631                                                         }
632                                                 } else if((ptr = strstr(line, "ALBA=-")) != NULL) {
633                                                         if(track > 0 && track < 0xa0) {
634                                                                 toc_table[track - 1].pregap = atoi(ptr + 6);
635                                                         }
636                                                 } else if((ptr = strstr(line, "PLBA=")) != NULL) {
637                                                         if(track > 0 && track < 0xa0) {
638                                                                 toc_table[track - 1].index1 = atoi(ptr + 5);
639                                                         }
640                                                 }
641                                         }
642                                         if(track_num != 0) {
643                                                 for(int i = 1; i < track_num; i++) {
644                                                         toc_table[i].index0 = toc_table[i].index1 - toc_table[i].pregap;
645                                                 }
646                                                 toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
647                                                 toc_table[track_num].index0 = toc_table[track_num].index1 = max_logical_block;
648                                         } else {
649                                                 fio_img->Fclose();
650                                         }
651                                         fio->Fclose();
652                                 }
653                                 delete fio;
654                         }
655                 }
656         }
657 #ifdef _SCSI_DEBUG_LOG
658         if(mounted()) {
659                 for(int i = 0; i < track_num + 1; i++) {
660                         uint32_t idx0_msf = lba_to_msf(toc_table[i].index0);
661                         uint32_t idx1_msf = lba_to_msf(toc_table[i].index1);
662                         uint32_t pgap_msf = lba_to_msf(toc_table[i].pregap);
663                         this->out_debug_log(_T("Track%02d: Index0=%02x:%02x:%02x Index1=%02x:%02x:%02x PreGpap=%02x:%02x:%02x\n"), i + 1,
664                         (idx0_msf >> 16) & 0xff, (idx0_msf >> 8) & 0xff, idx0_msf & 0xff,
665                         (idx1_msf >> 16) & 0xff, (idx1_msf >> 8) & 0xff, idx1_msf & 0xff,
666                         (pgap_msf >> 16) & 0xff, (pgap_msf >> 8) & 0xff, pgap_msf & 0xff);
667                 }
668         }
669 #endif
670 }
671
672 void SCSI_CDROM::close()
673 {
674         if(fio_img->IsOpened()) {
675                 fio_img->Fclose();
676         }
677         memset(toc_table, 0, sizeof(toc_table));
678         track_num = 0;
679         set_cdda_status(CDDA_OFF);
680 }
681
682 bool SCSI_CDROM::mounted()
683 {
684         return fio_img->IsOpened();
685 }
686
687 bool SCSI_CDROM::accessed()
688 {
689         bool value = access;
690         access = false;
691         return value;
692 }
693
694 void SCSI_CDROM::mix(int32_t* buffer, int cnt)
695 {
696         if(cdda_status == CDDA_PLAYING) {
697                 if(mix_loop_num != 0) {
698                         int tmp_l = 0, tmp_r = 0;
699                         for(int i = 0; i < mix_loop_num; i++) {
700                                 event_callback(EVENT_CDDA, 0);
701                                 tmp_l += cdda_sample_l;
702                                 tmp_r += cdda_sample_r;
703                         }
704                         cdda_sample_l = tmp_l / mix_loop_num;
705                         cdda_sample_r = tmp_r / mix_loop_num;
706                 }
707                 int32_t val_l = apply_volume(apply_volume(cdda_sample_l, volume_m), volume_l);
708                 int32_t val_r = apply_volume(apply_volume(cdda_sample_r, volume_m), volume_r);
709                 
710                 for(int i = 0; i < cnt; i++) {
711                         *buffer++ += val_l; // L
712                         *buffer++ += val_r; // R
713                 }
714         }
715 }
716
717 void SCSI_CDROM::set_volume(int ch, int decibel_l, int decibel_r)
718 {
719         volume_l = decibel_to_volume(decibel_l);
720         volume_r = decibel_to_volume(decibel_r);
721 }
722
723 void SCSI_CDROM::set_volume(int volume)
724 {
725         volume_m = (int)(1024.0 * (max(0, min(100, volume)) / 100.0));
726 }
727
728 #define STATE_VERSION   3
729
730 #include "../statesub.h"
731
732 void SCSI_CDROM::decl_state()
733 {
734         enter_decl_state(STATE_VERSION);
735
736         DECL_STATE_ENTRY_UINT32(cdda_start_frame);
737         DECL_STATE_ENTRY_UINT32(cdda_end_frame);
738         DECL_STATE_ENTRY_UINT32(cdda_playing_frame);
739         DECL_STATE_ENTRY_UINT8(cdda_status);
740         DECL_STATE_ENTRY_BOOL(cdda_repeat);
741         DECL_STATE_ENTRY_BOOL(cdda_interrupt);
742         DECL_STATE_ENTRY_1D_ARRAY(cdda_buffer, sizeof(cdda_buffer));
743         DECL_STATE_ENTRY_INT32(cdda_buffer_ptr);
744         DECL_STATE_ENTRY_INT32(cdda_sample_l);
745         DECL_STATE_ENTRY_INT32(cdda_sample_r);
746         DECL_STATE_ENTRY_INT32(event_cdda);
747 //      DECL_STATE_ENTRY_INT32(mix_loop_num);
748         DECL_STATE_ENTRY_INT32(volume_m);
749 //      if(fio_img->IsOpened()) {
750 //              state_fio->FputUint32(fio_img->Ftell());
751 //      } else {
752 //              state_fio->FputUint32(0);
753 //      }
754
755         leave_decl_state();
756
757         // ToDo: Add Fix Value.
758         SCSI_DEV::decl_state();
759 }
760
761 #include "../state_data.h"
762
763 void SCSI_CDROM::save_state(FILEIO* state_fio)
764 {
765         uint32_t crc_value = 0xffffffff;
766         if(state_entry != NULL) {
767                 state_entry->save_state(state_fio, &crc_value);
768         }
769 //      state_fio->FputUint32(STATE_VERSION);
770 //      state_fio->FputInt32(this_device_id);
771         
772 //      state_fio->FputUint32(cdda_start_frame);
773 //      state_fio->FputUint32(cdda_end_frame);
774 //      state_fio->FputUint32(cdda_playing_frame);
775 //      state_fio->FputUint8(cdda_status);
776 //      state_fio->FputBool(cdda_repeat);
777 //      state_fio->FputBool(cdda_interrupt);
778 //      state_fio->Fwrite(cdda_buffer, sizeof(cdda_buffer), 1);
779 //      state_fio->FputInt32(cdda_buffer_ptr);
780 //      state_fio->FputInt32(cdda_sample_l);
781 //      state_fio->FputInt32(cdda_sample_r);
782 //      state_fio->FputInt32(event_cdda);
783 ////    state_fio->FputInt32(mix_loop_num);
784 //      state_fio->FputInt32(volume_m);
785         csp_state_data_saver saver(state_fio);
786         bool stat = false;
787         if(fio_img->IsOpened()) {
788                 saver.put_dword(fio_img->Ftell(), &crc_value, &stat);
789         } else {
790                 saver.put_dword(0, &crc_value, &stat);
791         }
792         saver.post_proc_saving(&crc_value, &stat);
793
794         //SCSI_DEV::save_state(state_fio);
795 }
796
797 bool SCSI_CDROM::load_state(FILEIO* state_fio)
798 {
799         uint32_t crc_value = 0xffffffff;
800         bool mb = false;
801         bool stat = false;
802         if(state_entry != NULL) {
803            mb = state_entry->load_state(state_fio, &crc_value);
804         }
805         if(!mb) return false;
806         csp_state_data_saver saver(state_fio);
807 //      if(state_fio->FgetUint32() != STATE_VERSION) {
808 //              return false;
809 //      }
810 //      if(state_fio->FgetInt32() != this_device_id) {
811 //              return false;
812 //      }
813 //      cdda_start_frame = state_fio->FgetUint32();
814 //      cdda_end_frame = state_fio->FgetUint32();
815 //      cdda_playing_frame = state_fio->FgetUint32();
816 //      cdda_status = state_fio->FgetUint8();
817 //      cdda_repeat = state_fio->FgetBool();
818 //      cdda_interrupt = state_fio->FgetBool();
819 //      state_fio->Fread(cdda_buffer, sizeof(cdda_buffer), 1);
820 //      cdda_buffer_ptr = state_fio->FgetInt32();
821 //      cdda_sample_l = state_fio->FgetInt32();
822 //      cdda_sample_r = state_fio->FgetInt32();
823 //      event_cdda = state_fio->FgetInt32();
824 //      mix_loop_num = state_fio->FgetInt32();
825 //      volume_m = state_fio->FgetInt32();
826         uint32_t offset = saver.get_dword(&crc_value, &stat);
827         if(!(saver.post_proc_loading(&crc_value, &stat))) return false;
828         
829         // post process
830         if(fio_img->IsOpened()) {
831                 fio_img->Fseek(offset, FILEIO_SEEK_SET);
832         }
833 //      return SCSI_DEV::load_state(state_fio);
834         return true;
835 }
836