OSDN Git Service

[VM][SCSI_CDROM] Delete some ToDo(s).
[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 #include <algorithm>
14 #include <cctype> 
15
16 #define CDDA_OFF        0
17 #define CDDA_PLAYING    1
18 #define CDDA_PAUSED     2
19 #define _SCSI_DEBUG_LOG
20 #define _CDROM_DEBUG_LOG
21 // 0-99 is reserved for SCSI_DEV class
22 #define EVENT_CDDA                                              100
23 #define EVENT_CDDA_DELAY_PLAY                   101
24 #define EVENT_CDROM_SEEK_SCSI                   102
25 #define EVENT_CDROM_DELAY_INTERRUPT_ON  103
26 #define EVENT_CDROM_DELAY_INTERRUPT_OFF 104
27 #define EVENT_CDDA_DELAY_STOP                   105
28
29 void SCSI_CDROM::initialize()
30 {
31         SCSI_DEV::initialize();
32         fio_img = new FILEIO();
33         
34         if(44100 % emu->get_sound_rate() == 0) {
35                 mix_loop_num = 44100 / emu->get_sound_rate();
36         } else {
37                 mix_loop_num = 0;
38         }
39         event_cdda = -1;
40         event_cdda_delay_play = -1;
41         event_delay_interrupt = -1;
42         cdda_status = CDDA_OFF;
43         is_cue = false;
44         current_track = 0;
45         read_sectors = 0;
46         for(int i = 0; i < 99; i++) {
47                 memset(track_data_path[i], 0x00, _MAX_PATH * sizeof(_TCHAR));
48         }
49 }
50
51 void SCSI_CDROM::release()
52 {
53         if(fio_img->IsOpened()) {
54                 fio_img->Fclose();
55         }
56         delete fio_img;
57         SCSI_DEV::release();
58 }
59
60 void SCSI_CDROM::reset()
61 {
62         touch_sound();
63         if(event_delay_interrupt != -1) cancel_event(this, event_delay_interrupt);
64         if(event_cdda_delay_play != -1) cancel_event(this, event_cdda_delay_play);
65         if(event_cdda != -1) cancel_event(this, event_cdda);
66         event_cdda = -1;
67         event_cdda_delay_play = -1;
68         event_delay_interrupt = -1;
69         SCSI_DEV::reset();
70         set_cdda_status(CDDA_OFF);
71         read_sectors = 0;
72         // Q: Does not seek to track 0? 20181118 K.O
73         //current_track = 0;
74
75 }
76
77 uint32_t SCSI_CDROM::read_signal(int id)
78 {
79         switch(id) {
80         case SIG_SCSI_CDROM_PLAYING:
81                 return (cdda_status == CDDA_PLAYING && cdda_interrupt) ? 0xffffffff : 0;
82                 
83         case SIG_SCSI_CDROM_SAMPLE_L:
84                 return (uint32_t)abs(cdda_sample_l);
85                 
86         case SIG_SCSI_CDROM_SAMPLE_R:
87                 return (uint32_t)abs(cdda_sample_r);
88         }
89         return SCSI_DEV::read_signal(id);
90 }
91
92 void SCSI_CDROM::event_callback(int event_id, int err)
93 {
94         switch (event_id) {
95         case EVENT_CDROM_DELAY_INTERRUPT_ON:
96                 write_signals(&outputs_done, 0xffffffff);
97                 event_delay_interrupt = -1;
98                 break;
99         case EVENT_CDROM_DELAY_INTERRUPT_OFF:
100                 write_signals(&outputs_done, 0x00000000);
101                 event_delay_interrupt = -1;
102                 break;
103         case EVENT_CDDA_DELAY_PLAY:
104                 if(cdda_status != CDDA_PLAYING) {
105                         set_cdda_status(CDDA_PLAYING);
106                 }
107                 event_cdda_delay_play = -1;
108                 break;
109         case EVENT_CDROM_SEEK_SCSI:
110                 seek_time = 10.0;
111                 event_cdda_delay_play = -1;
112                 SCSI_DEV::start_command();
113                 break;
114         case EVENT_CDDA:
115                 if(event_cdda_delay_play > -1) return; // WAIT for SEEK COMPLETED
116                 // read 16bit 2ch samples in the cd-da buffer, called 44100 times/sec
117                 
118                 cdda_sample_l = (int)(int16_t)(cdda_buffer[cdda_buffer_ptr + 0] + cdda_buffer[cdda_buffer_ptr + 1] * 0x100);
119                 cdda_sample_r = (int)(int16_t)(cdda_buffer[cdda_buffer_ptr + 2] + cdda_buffer[cdda_buffer_ptr + 3] * 0x100);
120                 // ToDo: CLEAR IRQ Line (for PCE)
121                 if((cdda_buffer_ptr += 4) % 2352 == 0) {
122                         // one frame finished
123                         if(++cdda_playing_frame == cdda_end_frame) {
124                                 // reached to end frame
125                                 #ifdef _CDROM_DEBUG_LOG
126                                 this->out_debug_log(_T("Reaches to the end of track.(FRAME %d). START_FRAME=%d END_FRAME=%d REPEAT=%s INTERRUPT=%s\n"),
127                                                                         cdda_playing_frame, cdda_start_frame, cdda_end_frame, 
128                                                                         (cdda_repeat) ? _T("YES") : _T("NO"), (cdda_interrupt) ? _T("YES") : _T("NO"));
129                                 #endif
130                                 if(cdda_repeat) {
131                                         // reload buffer
132                                         if(is_cue) {
133                                                 fio_img->Fclose();
134                                                 //current_track = 0;
135                                                 //int trk = get_track(cdda_start_frame);
136                                                 int trk = current_track;
137                                                 fio_img->Fseek((cdda_start_frame - toc_table[trk].lba_offset) * 2352, FILEIO_SEEK_SET);
138                                         } else {
139                                                 fio_img->Fseek(cdda_start_frame * 2352, FILEIO_SEEK_SET);
140                                         }
141                                         read_sectors = fio_img->Fread(cdda_buffer, 2352 * sizeof(uint8_t) , array_length(cdda_buffer) / 2352);
142                                         cdda_buffer_ptr = 0;
143                                         cdda_playing_frame = cdda_start_frame;
144                                         access = true;
145                                 } else {
146                                         // Stop
147                                         //if(event_cdda_delay_play >= 0) cancel_event(this, event_cdda_delay_play);
148                                         set_cdda_status(CDDA_OFF);
149                                         //register_event(this, EVENT_CDDA_DELAY_STOP, 1000.0, false, &event_cdda_delay_play);
150                                 }
151                         } else if((cdda_buffer_ptr % 2352) == 0) {
152                                 // refresh buffer
153                                 read_sectors--;
154                                 if(read_sectors <= 0) {
155                                         read_sectors = fio_img->Fread(cdda_buffer, 2352 * sizeof(uint8_t), array_length(cdda_buffer) / 2352);
156                                         cdda_buffer_ptr = 0;
157                                         access = true;
158                                 } else {
159                                 }
160                         }
161                 }
162                 break;
163         case EVENT_CDDA_DELAY_STOP:
164                 if(cdda_interrupt) {
165                         write_signals(&outputs_done, 0xffffffff);
166                 }
167                 set_cdda_status(CDDA_OFF);
168                 event_cdda_delay_play = -1;
169                 break;                  
170         default:
171                 SCSI_DEV::event_callback(event_id, err);
172                 break;
173         }
174 }
175
176 void SCSI_CDROM::set_cdda_status(uint8_t status)
177 {
178         if(status == CDDA_PLAYING) {
179                 if(mix_loop_num == 0) {
180                         if(event_cdda == -1) {
181                                 register_event(this, EVENT_CDDA, 1000000.0 / 44100.0, true, &event_cdda);
182                         }
183                 }
184                 if(cdda_status != CDDA_PLAYING) {
185                         //// Notify to release bus.
186                         write_signals(&outputs_done, 0x00000000);
187                         if(cdda_status == CDDA_OFF) {
188                                 //get_track_by_track_num(current_track); // Re-Play
189                                 //memset(cdda_buffer, 0x00, sizeof(cdda_buffer));
190                                 cdda_playing_frame = cdda_start_frame;
191                                 get_track(cdda_playing_frame);
192                                 cdda_buffer_ptr = 0;
193                         } else if(cdda_status == CDDA_PAUSED) {
194                                 // Unpause
195                                 access = true;
196                         }
197                         touch_sound();
198                         set_realtime_render(this, true);
199                         #ifdef _CDROM_DEBUG_LOG
200                                 this->out_debug_log(_T("Play CDDA from %s.\n"), (cdda_status == CDDA_PAUSED) ? _T("PAUSED") : _T("STOPPED"));
201                         #endif
202                 }
203         } else {
204                 if(event_cdda != -1) {
205                         cancel_event(this, event_cdda);
206                         event_cdda = -1;
207                 }
208                 if(cdda_status == CDDA_PLAYING) {
209                         // Notify to release bus.
210                         write_signals(&outputs_done, 0x00000000);
211                         //if(event_delay_interrupt >= 0) cancel_event(this, event_delay_interrupt);
212                         //register_event(this, EVENT_CDROM_DELAY_INTERRUPT_OFF, 1.0e6 / (44100.0 * 2352), false, &event_delay_interrupt);
213                         if(status == CDDA_OFF) {
214                                 memset(cdda_buffer, 0x00, sizeof(cdda_buffer));
215                                 cdda_buffer_ptr = 0;
216                                 read_sectors = 0;
217                                 //if(is_cue) {
218                                 //      if(fio_img->IsOpened()) fio_img->Fclose();
219                                 //}
220                                 //current_track = 0;
221                         }
222                         touch_sound();
223                         set_realtime_render(this, false);
224                         #ifdef _CDROM_DEBUG_LOG
225                                 this->out_debug_log(_T("%s playing CDDA.\n"), (status == CDDA_PAUSED) ? _T("PAUSE") : _T("STOP"));
226                         #endif
227                 }
228         }
229         cdda_status = status;
230 }
231
232 void SCSI_CDROM::reset_device()
233 {
234         set_cdda_status(CDDA_OFF);
235         SCSI_DEV::reset_device();
236 }
237
238 bool SCSI_CDROM::is_device_ready()
239 {
240         return mounted();
241 }
242
243 int SCSI_CDROM::get_command_length(int value)
244 {
245         switch(value) {
246         case 0xd8:
247         case 0xd9:
248         case 0xda:
249         case 0xdd:
250         case 0xde:
251                 return 10;
252         }
253         return SCSI_DEV::get_command_length(value);
254 }
255
256 void SCSI_CDROM::get_track_by_track_num(int track)
257 {
258         if((track <= 0) || (track >= track_num)) {
259                 if(is_cue) {
260                         if(fio_img->IsOpened()) fio_img->Fclose();
261                 }
262                 //if(track <= 0) current_track = 0;
263                 //if(track >= track_num)current_track = track_num;
264                 current_track = 0;
265                 return;
266         }
267         if(is_cue) {
268                 // ToDo: Apply audio with some codecs.
269                 if((current_track != track) || !(fio_img->IsOpened())){
270                         if(fio_img->IsOpened()) {
271                                 fio_img->Fclose();
272                         }
273                 #ifdef _CDROM_DEBUG_LOG
274                         this->out_debug_log(_T("LOAD TRK #%02d from %s\n"), track, track_data_path[track - 1]);
275                 #endif
276                         
277                         if((track > 0) && (track < 100) && (track < track_num)) {
278                                 if((strlen(track_data_path[track - 1]) <= 0) ||
279                                    !(fio_img->Fopen(track_data_path[track - 1], FILEIO_READ_BINARY))) {
280                                         track = 0;
281                                 }       
282                         } else {
283                                 track = 0;
284                         }
285                 }
286         }
287         current_track = track;
288 }
289
290 // Detect only track num.
291 int SCSI_CDROM::get_track_noop(uint32_t lba)
292 {
293         int track = 0;
294         for(int i = 0; i < track_num; i++) {
295                 if(lba >= toc_table[i].index0) {
296                         track = i;
297                 } else {
298                         break;
299                 }
300         }
301         return track;
302 }       
303
304 int SCSI_CDROM::get_track(uint32_t lba)
305 {
306         int track = 0;
307         track = get_track_noop(lba);
308         if(is_cue) {
309                 get_track_by_track_num(track);
310         } else {
311                 current_track = track;
312         }
313         return track;
314 }
315
316 double SCSI_CDROM::get_seek_time(uint32_t lba)
317 {
318         if(fio_img->IsOpened()) {
319                 uint32_t cur_position = (uint32_t)fio_img->Ftell();
320                 int distance;
321                 if(is_cue) {
322                         int track = 0;
323                         for(int i = 0; i < track_num; i++) {
324                                 if(lba >= toc_table[i].index0) {
325                                         track = i;
326                                 } else {
327                                         break;
328                                 }
329                         }
330                         distance = abs((int)(lba * physical_block_size()) - (int)(cur_position + toc_table[current_track].lba_offset * physical_block_size()));
331                         if(track != current_track) {
332                                 current_track = get_track(lba);
333                         }
334                 } else {
335                         distance = abs((int)(lba * physical_block_size()) - (int)cur_position);
336                 }
337                 double ratio = ((double)distance / 333000.0) / physical_block_size(); // 333000: sectors in media
338                 return max(10, (int)(400000 * 2 * ratio));
339         } else {
340                 return 400000; // 400msec
341         }
342 }
343
344 uint32_t SCSI_CDROM::lba_to_msf(uint32_t lba)
345 {
346         uint8_t m = lba / (60 * 75);
347         lba -= m * (60 * 75);
348         uint8_t s = lba / 75;
349         uint8_t f = lba % 75;
350
351         return ((m / 10) << 20) | ((m % 10) << 16) | ((s / 10) << 12) | ((s % 10) << 8) | ((f / 10) << 4) | ((f % 10) << 0);
352 }
353
354 uint32_t SCSI_CDROM::lba_to_msf_alt(uint32_t lba)
355 {
356         uint32_t ret = 0;
357         ret |= ((lba / (60 * 75)) & 0xff) << 16;
358         ret |= (((lba / 75) % 60) & 0xff) <<  8;
359         ret |= ((lba % 75)        & 0xff) <<  0;
360         return ret;
361 }
362
363 void SCSI_CDROM::start_command()
364 {
365         touch_sound();
366         #ifdef _SCSI_DEBUG_LOG
367 //      this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: #%02x %02x %02x %02x %02x %02x\n"), scsi_id, command[0], command[1], command[2], command[3], command[4], command[5]);
368         #endif
369         switch(command[0]) {
370         case SCSI_CMD_READ6:
371                 //seek_time = 10;//get_seek_time((command[1] & 0x1f) * 0x10000 + command[2] * 0x100 + command[3]);
372                 seek_time = get_seek_time((command[1] & 0x1f) * 0x10000 + command[2] * 0x100 + command[3]);
373                 set_cdda_status(CDDA_OFF);
374                 if(seek_time > 10.0) {
375                         if(event_cdda_delay_play >= 0) {
376                                 cancel_event(this, event_cdda_delay_play);
377                                 event_cdda_delay_play = -1;
378                         }
379                         register_event(this, EVENT_CDROM_SEEK_SCSI, seek_time - 10.0, false, &event_cdda_delay_play);
380                         return;
381                 } else {
382                         seek_time = 10.0;
383                 }
384                 break;
385         case SCSI_CMD_READ10:
386         case SCSI_CMD_READ12:
387                 seek_time = get_seek_time((command[1] & 0x1f) * 0x10000 + command[2] * 0x100 + command[3]);
388                 set_cdda_status(CDDA_OFF);
389                 if(seek_time > 10.0) {
390                         if(event_cdda_delay_play >= 0) {
391                                 cancel_event(this, event_cdda_delay_play);
392                                 event_cdda_delay_play = -1;
393                         }
394                         register_event(this, EVENT_CDROM_SEEK_SCSI, seek_time - 10.0, false, &event_cdda_delay_play);
395                         return;
396                 } else {
397                         seek_time = 10.0;
398                 }
399                 break;
400                 
401         case 0xd8:
402                 #ifdef _SCSI_DEBUG_LOG
403                 this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Set Audio Playback Start Position CMD=%02x ARG=%02x %02x %02x %02x\n"), scsi_id, command[9], command[2], command[3], command[4], command[5]);
404                 #endif
405                 if(is_device_ready()) {
406                         if(command[2] == 0 && command[3] == 0 && command[4] == 0) {
407                                 // stop cd-da if all params are zero
408                                 cdda_start_frame = 0;
409                                 cdda_end_frame = toc_table[track_num].index0; // end of disc
410                                 double seek_time = get_seek_time(cdda_end_frame);
411                                 if(is_cue) {
412                                         get_track_by_track_num(track_num);
413                                 }
414                                 //set_cdda_status(CDDA_OFF);
415                                 if(event_cdda_delay_play >= 0) cancel_event(this, event_cdda_delay_play);
416                                 register_event(this, EVENT_CDDA_DELAY_STOP, (seek_time > 10.0) ? seek_time : 10.0, false, &event_cdda_delay_play);
417                         } else {
418                                 uint32_t seek_offset = 0;
419                                 switch(command[9] & 0xc0) {
420                                 case 0x00:
421                                         cdda_start_frame = (command[2] << 16) | (command[3] << 8) | command[4];
422                                         break;
423                                 case 0x40:
424                                         {
425                                                 uint8_t m = FROM_BCD(command[2]);
426                                                 uint8_t s = FROM_BCD(command[3]);
427                                                 uint8_t f = FROM_BCD(command[4]);
428                                                 cdda_start_frame = f + 75 * (s + m * 60);
429                                                 
430                                                 // PCE tries to be clever here and set (start of track + track pregap size) to skip the pregap
431                                                 // (I guess it wants the TOC to have the real start sector for data tracks and the start of the pregap for audio?)
432                                                 int track = get_track(cdda_start_frame);
433                                                 if(cdda_start_frame >= toc_table[track].pregap) {
434                                                         cdda_start_frame -= toc_table[track].pregap;
435                                                 }
436                                                 if(cdda_start_frame < toc_table[track].index0) {
437                                                         cdda_start_frame = toc_table[track].index0; // don't play pregap
438                                                 } else if(cdda_start_frame > max_logical_block) {
439                                                         cdda_start_frame = 0;
440                                                 }
441                                         }
442                                         break;
443                                 case 0x80:
444                                         {
445                                                 int8_t track = FROM_BCD(command[2] - 1);
446                                                 cdda_start_frame = toc_table[track].index1;
447                                                 if(cdda_start_frame >= toc_table[track].pregap) {
448                                                         cdda_start_frame -= toc_table[track].pregap;
449                                                 }
450                                         }
451                                         break;
452                                 default:
453                                         cdda_start_frame = 0;
454                                         break;
455                                 }
456 //                              if(cdda_status == CDDA_PAUSED) {
457 //                                      cdda_end_frame = toc_table[track_num].index0; // end of disc
458 //                                      set_cdda_status(CDDA_OFF);
459 //                              } else
460                                 double delay_time = get_seek_time(cdda_start_frame);
461                                 if((command[1] & 3) != 0) {
462                                         if((is_cue) && (current_track != track_num)){
463                                                 get_track_by_track_num(track_num);
464                                         }
465                                         cdda_end_frame = toc_table[track_num].index0; // end of disc
466                                         double seek_time = get_seek_time(cdda_start_frame);
467                                         if(event_cdda_delay_play >= 0) {
468                                                 cancel_event(this, event_cdda_delay_play);
469                                                 event_cdda_delay_play = -1;
470                                         }
471                                         //set_cdda_status(CDDA_PLAYING);
472                                         register_event(this, EVENT_CDROM_SEEK_SCSI, seek_time, false, &event_cdda_delay_play);
473                                 } else {
474                                         uint32_t _sframe = cdda_start_frame;
475                                         //cdda_end_frame = toc_table[get_track(_sframe) + 1].index1; // end of this track
476                                         //cdda_end_frame = toc_table[get_track(_sframe)].index1; // end of this track
477                                         set_cdda_status(CDDA_PAUSED);
478                                 }
479                                 cdda_repeat = false;
480                                 cdda_interrupt = ((command[1] & 3) == 2);
481                                 
482                                 // read buffer
483                                 //double delay_time = 10.0;
484 #if 1
485                                 if(is_cue) {
486                                         //if(cdda_start_frame > 150) cdda_start_frame = cdda_start_frame - 150;
487                                         fio_img->Fseek((cdda_start_frame - toc_table[current_track].index0) * 2352, FILEIO_SEEK_SET);
488                                 } else {
489                                         fio_img->Fseek(cdda_start_frame * 2352, FILEIO_SEEK_SET);
490                                 }
491 #endif
492                                 read_sectors = fio_img->Fread(cdda_buffer, 2352 * sizeof(uint8_t), array_length(cdda_buffer) / 2352);
493                                 cdda_buffer_ptr = 0;
494                                 cdda_playing_frame = cdda_start_frame;
495                                 access = true;
496                                 
497                                 // change to status phase
498                                 set_dat(SCSI_STATUS_GOOD);
499                                 // From Mame 0.203
500                                 if(event_delay_interrupt >= 0) cancel_event(this, event_delay_interrupt);
501                                 register_event(this, EVENT_CDROM_DELAY_INTERRUPT_ON, delay_time, false, &event_delay_interrupt);
502                                 //set_phase_delay(SCSI_PHASE_STATUS, delay_time + 10.0);
503                                 //write_signals(&outputs_done, 0xffffffff);
504                                 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
505                                 return;
506                         }
507                 }
508                 // change to status phase
509                 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
510                 // From Mame 0.203
511                 //if(is_device_ready()) write_signals(&outputs_done, 0xffffffff);
512                 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
513
514                 return;
515                 
516         case 0xd9:
517                 #ifdef _SCSI_DEBUG_LOG
518                 this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Set Audio Playback End Position CMD=%02x ARG=%02x %02x %02x %02x\n"), scsi_id, command[9], command[2], command[3], command[4], command[5]);
519                 #endif
520                 if(is_device_ready()) {
521                         
522                         switch(command[9] & 0xc0) {
523                         case 0x00:
524                                 cdda_end_frame = (command[3] << 16) | (command[4] << 8) | command[5];
525                                 break;
526                         case 0x40:
527                                 {
528                                         uint8_t m = FROM_BCD(command[2]);
529                                         uint8_t s = FROM_BCD(command[3]);
530                                         uint8_t f = FROM_BCD(command[4]);
531                                         cdda_end_frame = f + 75 * (s + m * 60);
532                                         
533                                         // PCE tries to be clever here and set (start of track + track pregap size) to skip the pregap
534                                         // (I guess it wants the TOC to have the real start sector for data tracks and the start of the pregap for audio?)
535                                         
536 //                                      int track = get_track(cdda_start_frame);
537                                         int track = current_track;
538                                         cdda_playing_frame = cdda_start_frame;
539 //                                      if(is_cue) {
540 //                                              fio_img->Fseek((cdda_start_frame - toc_table[current_track].lba_offset) * 2352, FILEIO_SEEK_SET);
541 //                                      } else {
542 //                                              fio_img->Fseek(cdda_start_frame * 2352, FILEIO_SEEK_SET);
543 //                                      }
544                                         //read_sectors = fio_img->Fread(cdda_buffer, 2352 * sizeof(uint8_t), array_length(cdda_buffer) / 2352);
545
546                                         if(cdda_end_frame > toc_table[track + 1].index1 && (cdda_end_frame - toc_table[track].pregap) <= toc_table[track + 1].index1) {
547                                                 cdda_end_frame = toc_table[track + 1].index1;
548                                         }
549                                         cdda_buffer_ptr = 0;
550                                 }
551                                 break;
552                         case 0x80:
553                                 {
554                                         int _track = FROM_BCD(command[2]) - 1;
555                                         if(_track >= 0) {
556                                                 cdda_end_frame = toc_table[_track].index0;
557                                                 if(is_cue) {
558                                                         if(current_track != _track) {
559                                                                 get_track_by_track_num(_track);
560                                                                 cdda_start_frame = toc_table[_track].index0;
561                                                                 cdda_end_frame = toc_table[_track].lba_size + toc_table[_track].lba_offset;
562                                                                 cdda_playing_frame = cdda_start_frame;
563                                                                 if(is_cue) {
564                                                                         fio_img->Fseek((cdda_start_frame - toc_table[current_track].lba_offset) * 2352, FILEIO_SEEK_SET);
565                                                                 } else {
566                                                                         fio_img->Fseek(cdda_start_frame * 2352, FILEIO_SEEK_SET);
567                                                                 }
568                                                                 read_sectors = fio_img->Fread(cdda_buffer, 2352 * sizeof(uint8_t), array_length(cdda_buffer) / 2352);
569                                                                 cdda_buffer_ptr = 0;
570                                                         }
571                                                 }
572                                         }
573                                 }
574                                 break;
575                         default:
576                                 break; // ToDo
577                         }
578                         if((command[1] & 3) != 0) {
579                                 cdda_repeat = ((command[1] & 3) == 1);
580                                 cdda_interrupt = ((command[1] & 3) == 2);
581                                 
582                                 if(event_cdda_delay_play >= 0) cancel_event(this, event_cdda_delay_play);
583                                 register_event(this, EVENT_CDDA_DELAY_PLAY, 10.0, false, &event_cdda_delay_play);
584                                 //set_cdda_status(CDDA_PLAYING);
585                         } else {
586                                 set_cdda_status(CDDA_OFF);
587                                 cdda_start_frame = toc_table[track_num].index0;;
588                                 cdda_end_frame = toc_table[track_num].index1; // end of disc
589                                 double seek_time = get_seek_time(cdda_start_frame);
590                                 //double seek_time = 10.0;
591                                 get_track_by_track_num(track_num); // END OF DISC
592
593                                 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
594 //                              if(event_cdda_delay_play >= 0) cancel_event(this, event_cdda_delay_play);
595 //                              register_event(this, EVENT_CDDA_DELAY_STOP, (seek_time > 10.0) ? seek_time : 10.0, false, &event_cdda_delay_play);
596                                 if(is_device_ready()) {
597                                         if(event_delay_interrupt >= 0) {
598                                                 cancel_event(this, event_delay_interrupt);
599                                                 event_delay_interrupt = -1;
600                                         }
601                                         register_event(this, EVENT_CDROM_DELAY_INTERRUPT_ON, (seek_time > 10.0) ? (seek_time + 10.0) : (10.0 + 10.0), false, &event_delay_interrupt);
602                                 }
603                                 set_phase_delay(SCSI_PHASE_STATUS, (seek_time > 10.0) ? (seek_time + 10.0) : (10.0 + 10.0));
604                                 return;
605                         }
606                 }
607                 // change to status phase
608                 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
609                 if(is_device_ready()) {
610                         write_signals(&outputs_done, 0xffffffff);
611                         //if(event_delay_interrupt >= 0) cancel_event(this, event_delay_interrupt);
612                         //register_event(this, EVENT_CDROM_DELAY_INTERRUPT_ON, 10.0, false, &event_delay_interrupt);
613
614                 }
615                 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
616                 return;
617                 
618         case 0xda:
619                 #ifdef _SCSI_DEBUG_LOG
620                         this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Pause\n"), scsi_id);
621                 #endif
622                 if(is_device_ready()) {
623                         if(cdda_status == CDDA_PLAYING) {
624                                 set_cdda_status(CDDA_PAUSED);
625                         }
626                 }
627                 // change to status phase
628                 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
629                 if(is_device_ready()) write_signals(&outputs_done, 0xffffffff);
630                 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
631                 return;
632                 
633         case 0xdd:
634                 #ifdef _SCSI_DEBUG_LOG
635                         this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Read Sub Channel Q\n"), scsi_id);
636                 #endif
637                 if(is_device_ready()) {
638                         // create track info
639                         uint32_t frame = (cdda_status == CDDA_OFF) ? cdda_start_frame : cdda_playing_frame;
640                         uint32_t msf_abs = lba_to_msf_alt(frame);
641                         int track;
642                         double delay_time = 10.0;
643                         track = current_track;
644                         if((cdda_status == CDDA_OFF) && (toc_table[track].is_audio)) { // OK? (or force ERROR) 20181120 K.O
645                                 //set_cdda_status(CDDA_PLAYING);
646                                 delay_time = get_seek_time(frame);
647                                 //delay_time = 10.0;
648                                 if(event_cdda_delay_play >= 0) {
649                                         cancel_event(this, event_cdda_delay_play);
650                                         event_cdda_delay_play = -1;
651                                 }
652                                 register_event(this, EVENT_CDDA_DELAY_PLAY, delay_time, false, &event_cdda_delay_play);
653                         }
654                         uint32_t msf_rel = lba_to_msf_alt(frame - toc_table[track].index0);
655                         buffer->clear();
656                         buffer->write((cdda_status == CDDA_PLAYING) ? 0x00 : (cdda_status == CDDA_PAUSED) ? 0x02 : 0x03);
657                         buffer->write(0x01 | (toc_table[track].is_audio ? 0x00 : 0x40));
658                         buffer->write(TO_BCD(track + 1));               // Track
659                         buffer->write(0x01);                            // Index
660                         buffer->write(TO_BCD((msf_rel >> 16) & 0xff));  // M (relative)
661                         buffer->write(TO_BCD((msf_rel >>  8) & 0xff));  // S (relative)
662                         buffer->write(TO_BCD((msf_rel >>  0) & 0xff));  // F (relative)
663                         buffer->write(TO_BCD((msf_abs >> 16) & 0xff));  // M (absolute)
664                         buffer->write(TO_BCD((msf_abs >>  8) & 0xff));  // S (absolute)
665                         buffer->write(TO_BCD((msf_abs >>  0) & 0xff));  // F (absolute)
666                         // transfer length
667                         remain = buffer->count();
668                         // set first data
669                         set_dat(buffer->read());
670                         // change to data in phase
671                         set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
672                 } else {
673                         // change to status phase
674                         set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
675                         set_phase_delay(SCSI_PHASE_STATUS, 10.0);
676                 }
677                 return;
678                 
679         case 0xde:
680                 #ifdef _SCSI_DEBUG_LOG
681                         this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Get Dir Info\n"), scsi_id);
682                 #endif
683                 if(is_device_ready()) {
684                         buffer->clear();
685                 #ifdef _SCSI_DEBUG_LOG
686                         this->out_debug_log(_T("[SCSI_DEV:ID=%d] CMD=%02x ARG=%02x \n"), scsi_id, command[1], command[2]);
687                 #endif
688                         switch(command[1]) {
689                         case 0x00:      /* Get first and last track numbers */
690                                 buffer->write(TO_BCD(1));
691                                 buffer->write(TO_BCD(track_num));
692                                 break;
693                         case 0x01:      /* Get total disk size in MSF format */
694                                 {
695                                         uint32_t msf = lba_to_msf(toc_table[track_num].index0 + 150);
696                                         buffer->write((msf >> 16) & 0xff);
697                                         buffer->write((msf >>  8) & 0xff);
698                                         buffer->write((msf >>  0) & 0xff);
699                                 }
700                                 break;
701                         case 0x02:      /* Get track information */
702                                 if(command[2] == 0xaa) {
703                                         uint32_t msf = lba_to_msf(toc_table[track_num].index0 + 150);
704                                         buffer->write((msf >> 16) & 0xff);
705                                         buffer->write((msf >>  8) & 0xff);
706                                         buffer->write((msf >>  0) & 0xff);
707                                         buffer->write(0x04); // correct ?
708                                 } else {
709                                         int track = max(FROM_BCD(command[2]), 1);
710                                         uint32_t frame = toc_table[track].index0;
711                                         // PCE wants the start sector for data tracks to *not* include the pregap
712                                         if(!toc_table[track].is_audio) {
713                                                 frame += toc_table[track].pregap;
714                                         }
715                                         get_track_by_track_num(track);
716                                         
717                                         uint32_t msf = lba_to_msf(toc_table[track].index1 + 150);
718                                         buffer->write((msf >> 16) & 0xff); // M
719                                         buffer->write((msf >>  8) & 0xff); // S
720                                         buffer->write((msf >>  0) & 0xff); // F
721                                         buffer->write(toc_table[track].is_audio ? 0x00 : 0x04);
722                                 }
723                                 break;
724                         }
725                         // transfer length
726                         remain = buffer->count();
727                         // set first data
728                         set_dat(buffer->read());
729                         // change to data in phase
730                         set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
731                 } else {
732                         // change to status phase
733                         set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
734                         set_phase_delay(SCSI_PHASE_STATUS, 10.0);
735                 }
736                 return;
737         case 0xff:
738                 // End of List
739                 set_dat(SCSI_STATUS_CHKCOND);
740                 return;
741         }
742         
743         // start standard command
744         SCSI_DEV::start_command();
745 }
746
747 bool SCSI_CDROM::read_buffer(int length)
748 {
749         if(!fio_img->IsOpened()) {
750                 set_sense_code(SCSI_SENSE_NOTREADY);
751                 return false;
752         }
753         uint32_t offset = (uint32_t)(position % 2352);
754
755         if(is_cue) {
756                 // ToDo: Need seek wait.
757                 #ifdef _CDROM_DEBUG_LOG
758                         this->out_debug_log(_T("Seek to LBA %d\n"), position / 2352);
759                 #endif
760                 if(fio_img->Fseek(((long)position - (long)(toc_table[current_track].lba_offset * 2352)), FILEIO_SEEK_SET) != 0) {
761                         set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_SEEKERR
762                         #ifdef _SCSI_DEBUG_LOG
763                                 this->out_debug_log(_T("[SCSI_DEV:ID=%d] Error on reading (ILLGLBLKADDR) at line %d\n"), scsi_id, __LINE__);
764                         #endif
765                         return false;
766                 }
767         } else {
768                 if(fio_img->Fseek((long)position, FILEIO_SEEK_SET) != 0) {
769                         set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_SEEKERR
770                         #ifdef _SCSI_DEBUG_LOG
771                                 this->out_debug_log(_T("[SCSI_DEV:ID=%d] Error on reading (ILLGLBLKADDR) at line %d\n"), scsi_id, __LINE__);
772                         #endif
773                         return false;
774                 }
775         }
776         while(length > 0) {
777                 uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
778                 int tmp_length = min(length, (int)sizeof(tmp_buffer));
779                 
780                 if(fio_img->Fread(tmp_buffer, tmp_length, 1) != 1) {
781                         #ifdef _SCSI_DEBUG_LOG
782                         this->out_debug_log(_T("[SCSI_DEV:ID=%d] Error on reading (ILLGLBLKADDR) at line %d\n"), scsi_id, __LINE__);
783                         #endif
784                         
785                         set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_NORECORDFND
786                         return false;
787                 }
788                 for(int i = 0; i < tmp_length && length > 0; i++) {
789                         if(offset >= 16 && offset < 16 + 2048) {
790                                 int value = tmp_buffer[i];
791                                 buffer->write(value);
792                                 length--;
793                         }
794                         position++;
795                         offset = (offset + 1) % 2352;
796                 }
797                 access = true;
798         }
799         // Is This right? 20181120 K.O
800         //write_signals(&outputs_done, 0xffffffff); // Maybe don't need "DONE SIGNAL" with reading DATA TRACK. 20181207 K.O
801         set_sense_code(SCSI_SENSE_NOSENSE);
802         return true;
803 }
804
805 int get_frames_from_msf(const char *string)
806 {
807         const char *ptr = string;
808         int frames[3] = {0};
809         int index = 0;
810         
811         while(1) {
812                 if(*ptr >= '0' && *ptr <= '9') {
813                         frames[index] = frames[index] * 10 + (*ptr - '0');
814                 } else if(*ptr == ':') {
815                         if(++index == 3) {
816                                 // abnormal data
817                                 break;
818                         }
819                 } else if(*ptr == '\r' || *ptr == '\n' || *ptr == '\0') {
820                         // end of line
821                         break;
822                 }
823                 ptr++;
824         }
825         return (frames[0] * 60 + frames[1]) * 75 + frames[2]; // 75frames/sec
826 }
827
828 int hexatoi(const char *string)
829 {
830         const char *ptr = string;
831         int value = 0;
832         
833         while(1) {
834                 if(*ptr >= '0' && *ptr <= '9') {
835                         value = value * 16 + (*ptr - '0');
836                 } else if(*ptr >= 'a' && *ptr <= 'f') {
837                         value = value * 16 + (*ptr - 'a' + 10);
838                 } else if(*ptr >= 'A' && *ptr <= 'F') {
839                         value = value * 16 + (*ptr - 'A' + 10);
840                 } else if(*ptr == '\r' || *ptr == '\n' || *ptr == '\0') {
841                         break;
842                 }
843                 ptr++;
844         }
845         return value;
846 }
847
848 #include <string>
849
850 bool SCSI_CDROM::open_cue_file(const _TCHAR* file_path)
851 {
852         std::string line_buf;
853         std::string line_buf_shadow;
854         std::string image_tmp_data_path;
855
856         _TCHAR full_path_cue[_MAX_PATH];
857         size_t ptr;
858         int line_count = 0;
859         int slen;
860         int nr_current_track = 0;
861         FILEIO* fio = new FILEIO();
862         if(fio == NULL) return false;
863
864         memset(full_path_cue, 0x00, sizeof(full_path_cue));
865         image_tmp_data_path.clear();
866
867         get_long_full_path_name(file_path, full_path_cue, sizeof(full_path_cue));
868         
869         _TCHAR *parent_dir = get_parent_dir(full_path_cue);
870
871         size_t _arg1_ptr;
872         size_t _arg2_ptr;
873         size_t _arg2_ptr_s;
874         size_t _arg3_ptr;
875         size_t _arg3_ptr_s;
876
877         std::string _arg1;
878         std::string _arg2;
879         std::string _arg3;
880         
881         if(fio->Fopen(file_path, FILEIO_READ_ASCII)) { // ToDo: Support not ASCII cue file (i.e. SJIS/UTF8).20181118 K.O
882                 line_buf.clear();
883                 for(int i = 0; i < 100; i++) {
884                         memset(&(track_data_path[i][0]), 0x00, _MAX_PATH * sizeof(_TCHAR));
885                 }
886                 int _c;
887                 bool is_eof = false;
888                 int sptr = 0;
889                 while(1) {
890                         line_buf.clear();
891                         int _np = 0;
892                         _c = EOF;
893                         do {
894                                 _c = fio->Fgetc();
895                                 if((_c == '\0') || (_c == '\n') || (_c == EOF)) break;;
896                                 if(_c != '\r') line_buf.push_back((char)_c);
897                         } while(1);
898                         if(_c == EOF) is_eof = true;
899                         slen = (int)line_buf.length();
900                         if(slen <= 0) goto _n_continue;
901                         // Trim head of Space or TAB
902                         ptr = 0;
903                         sptr = 0;
904                         // Tokenize
905                         _arg1.clear();
906                         _arg2.clear();
907                         _arg3.clear();
908                         
909                         ptr = line_buf.find_first_not_of((const char*)" \t");
910                         if(ptr == std::string::npos) {
911                                 goto _n_continue;
912                         }
913                         // Token1
914                         line_buf_shadow = line_buf.substr(ptr);
915
916                         _arg1_ptr = line_buf_shadow.find_first_of((const char *)" \t");
917                         _arg1 = line_buf_shadow.substr(0, _arg1_ptr);
918                         _arg2 = line_buf_shadow.substr(_arg1_ptr);
919                         std::transform(_arg1.begin(), _arg1.end(), _arg1.begin(),
920                                                    [](unsigned char c) -> unsigned char{ return std::toupper(c); });
921
922                         _arg2_ptr = _arg2.find_first_not_of((const char *)" \t");
923
924                         if(_arg2_ptr != std::string::npos) {
925                                 _arg2 = _arg2.substr(_arg2_ptr);
926                         }
927
928                         if(_arg1 == "REM") {
929                                 // REM
930                                 goto _n_continue;
931                         } else if(_arg1 == "FILE") {
932                                 _arg2_ptr = _arg2.find_first_of((const char *)"\"") + 1;
933                                 if(_arg2_ptr == std::string::npos) goto _n_continue;
934                                 
935                                 _arg2 = _arg2.substr(_arg2_ptr);
936                                 _arg3_ptr = _arg2.find_first_of((const char *)"\"");
937                                 if(_arg3_ptr == std::string::npos) goto _n_continue;
938                                 _arg2 = _arg2.substr(0, _arg3_ptr);
939                                 
940                                 image_tmp_data_path.clear();
941                                 image_tmp_data_path = std::string(parent_dir);
942                                 image_tmp_data_path.append(_arg2);
943                                 
944                                 #ifdef _CDROM_DEBUG_LOG
945                                         this->out_debug_log(_T("**FILE %s\n"), image_tmp_data_path.c_str());
946                                 #endif
947                                 goto _n_continue; // ToDo: Check ARG2 (BINARY etc..) 20181118 K.O
948                         } else if(_arg1 == "TRACK") {
949                                 _arg2_ptr_s = _arg2.find_first_of((const char *)" \t");
950                                 
951                                 _arg3 = _arg2.substr(_arg2_ptr_s);
952                                 _arg2 = _arg2.substr(0, _arg2_ptr_s);
953                                 _arg3_ptr = _arg3.find_first_not_of((const char *)" \t");
954                                 int _nr_num = atoi(_arg2.c_str());
955                                 
956                                 // Set image file
957                                 if((_nr_num > 0) && (_nr_num < 100) && (_arg3_ptr != std::string::npos)) {
958                                         nr_current_track = _nr_num;
959                                         _arg3 = _arg3.substr(_arg3_ptr);
960                                         
961                                         memset(track_data_path[_nr_num - 1], 0x00, sizeof(_TCHAR) * _MAX_PATH);
962                                         strncpy((char *)(track_data_path[_nr_num - 1]), image_tmp_data_path.c_str(), _MAX_PATH);
963                                         
964                                         _arg3_ptr_s = _arg3.find_first_of((const char *)" \t\n");
965                                         _arg3.substr(0, _arg3_ptr_s);
966                                         
967                                         std::transform(_arg3.begin(), _arg3.end(), _arg3.begin(),
968                                                                    [](unsigned char c) -> unsigned char{ return std::toupper(c); });
969                                         
970                                         toc_table[nr_current_track].is_audio = false;
971                                         toc_table[nr_current_track].index0 = 0;
972                                         toc_table[nr_current_track].index1 = 0;
973                                         toc_table[nr_current_track].pregap = 0;
974                                                 
975                                         if(_arg3.compare("AUDIO") == 0) {
976                                                 toc_table[nr_current_track].is_audio = true;
977                                         } else if(_arg3.compare("MODE1/2352") == 0) {
978                                                 toc_table[nr_current_track].is_audio = false;
979                                         } else {
980                                                 // ToDo:  another type
981                                         }
982                                         if(track_num < (_nr_num + 1)) track_num = _nr_num + 1;
983                                 } else {
984                                         // ToDo: 20181118 K.Ohta
985                                         nr_current_track = 0;
986                                 }
987                                 goto _n_continue;
988                         } else if(_arg1 == "INDEX") {
989                                 
990                                 if((nr_current_track > 0) && (nr_current_track < 100)) {
991                                         _arg2_ptr_s = _arg2.find_first_of((const char *)" \t");
992                                         if(_arg2_ptr_s == std::string::npos) goto _n_continue;
993                                         
994                                         _arg3 = _arg2.substr(_arg2_ptr_s);
995                                         _arg2 = _arg2.substr(0, _arg2_ptr_s);
996                                         _arg3_ptr = _arg3.find_first_not_of((const char *)" \t");
997                                         if(_arg3_ptr == std::string::npos) goto _n_continue;
998
999                                         _arg3 = _arg3.substr(_arg3_ptr);
1000                                         _arg3_ptr_s = _arg3.find_first_of((const char *)" \t");
1001                                         _arg3.substr(0, _arg3_ptr_s);
1002                                         int index_type = atoi(_arg2.c_str());
1003
1004                                         switch(index_type) {
1005                                         case 0:
1006                                                 toc_table[nr_current_track].index0 = get_frames_from_msf(_arg3.c_str());
1007                                                 break;
1008                                         case 1:
1009                                                 toc_table[nr_current_track].index1 = get_frames_from_msf(_arg3.c_str());
1010                                                 break;
1011                                         default:
1012                                                 break;
1013                                         }
1014                                         goto _n_continue;
1015                                 } else {
1016                                         goto _n_continue;
1017                                 }
1018                         } else if(_arg1 == "PREGAP") {
1019                                 if((nr_current_track > 0) && (nr_current_track < 100)) {
1020                                         _arg2_ptr_s = _arg2.find_first_of((const char *)" \t");
1021                                         _arg2 = _arg2.substr(0, _arg2_ptr_s - 1);
1022                                         
1023                                         toc_table[nr_current_track].pregap = get_frames_from_msf(_arg2.c_str());
1024                                         goto _n_continue;
1025                                 } else {
1026                                         goto _n_continue;
1027                                 }
1028                         }
1029                 _n_continue:
1030                         if(is_eof) break;
1031                         line_buf.clear();
1032                         continue;
1033                 }
1034                 // Finish
1035                 max_logical_block = 0;
1036                 if(track_num > 0) {
1037                         toc_table[0].lba_offset = 0;
1038                         toc_table[0].lba_size = 0;
1039                         toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
1040                         // P1: Calc
1041                         int _n = 0;
1042                         for(int i = 1; i < track_num; i++) {
1043
1044                                 if(fio_img->IsOpened()) {
1045                                         fio_img->Fclose();
1046                                 }
1047                                 if(toc_table[i].index1 != 0) {
1048                                         toc_table[i].index0 = toc_table[i].index0 + max_logical_block;
1049                                         toc_table[i].index1 = toc_table[i].index1 + max_logical_block;
1050                                         if(toc_table[i].index0 != max_logical_block) {
1051                                                 if(toc_table[i].pregap == 0) {
1052                                                         toc_table[i].pregap = toc_table[i].index1 - toc_table[i].index0;
1053                                                 }
1054                                         }
1055                                 } else {
1056                                         toc_table[i].index1 = toc_table[i].index1 + max_logical_block;
1057                                         if(toc_table[i].index0 == 0) {
1058                                                 toc_table[i].index0 = toc_table[i].index1 - toc_table[i].pregap;
1059                                         } else {
1060                                                 toc_table[i].index0 = toc_table[i].index0 + max_logical_block;
1061                                                 if(toc_table[i].pregap == 0) {
1062                                                         toc_table[i].pregap = toc_table[i].index1 - toc_table[i].index0;
1063                                                 }
1064                                         }
1065                                 }
1066                                 // Even...
1067                                 if(toc_table[i].pregap <= 0) {
1068                                         toc_table[i].pregap = 150; // Default PREGAP must be 2Sec. From OoTake.(Only with PCE? Not with FM-Towns?)
1069                                 }
1070
1071                                 _n = 0;
1072                                 if(strlen(track_data_path[i - 1]) > 0) {
1073                                         if(fio_img->Fopen(track_data_path[i - 1], FILEIO_READ_BINARY)) {
1074                                                 if((_n = fio_img->FileLength() / 2352) > 0) {
1075                                                         max_logical_block += _n;
1076                                                 } else {
1077                                                         _n = 0;
1078                                                 }
1079                                                 fio_img->Fclose();
1080                                         }
1081                                 }
1082                                 toc_table[i].lba_size = _n;
1083                                 toc_table[i].lba_offset = max_logical_block - _n;
1084
1085                                 
1086                                 //#ifdef _CDROM_DEBUG_LOG
1087                                 this->out_debug_log(_T("TRACK#%02d TYPE=%s PREGAP=%d INDEX0=%d INDEX1=%d LBA_SIZE=%d LBA_OFFSET=%d PATH=%s\n"),
1088                                                                         i, (toc_table[i].is_audio) ? _T("AUDIO") : _T("MODE1/2352"),
1089                                                                         toc_table[i].pregap, toc_table[i].index0, toc_table[i].index1,
1090                                                                         toc_table[i].lba_size, toc_table[i].lba_offset, track_data_path[i - 1]);
1091                                 //#endif
1092                         }
1093                         toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
1094 //                      toc_table[track_num].index0 = toc_table[track_num].index1 = max_logical_block;
1095 //                      toc_table[track_num].lba_offset = max_logical_block;
1096 //                      toc_table[track_num].lba_size = 0;
1097                         
1098                 }
1099                 fio->Fclose();
1100         }
1101         delete fio;
1102
1103         is_cue = false;
1104         if(track_num > 0) is_cue = true;
1105         // Not Cue FILE.
1106         return is_cue;
1107 }
1108
1109 void SCSI_CDROM::open(const _TCHAR* file_path)
1110 {
1111         _TCHAR img_file_path[_MAX_PATH];
1112         
1113         close();
1114         
1115         if(check_file_extension(file_path, _T(".cue"))) {
1116 #if 1
1117                 is_cue = false;
1118                 current_track = 0;
1119                 open_cue_file(file_path);
1120 #else
1121                 // get image file name
1122                 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img"), get_file_path_without_extensiton(file_path));
1123                 if(!FILEIO::IsFileExisting(img_file_path)) {
1124                         my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.bin"), get_file_path_without_extensiton(file_path));
1125                         if(!FILEIO::IsFileExisting(img_file_path)) {
1126                                 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.gz"), get_file_path_without_extensiton(file_path));
1127                                 if(!FILEIO::IsFileExisting(img_file_path)) {
1128                                         my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img.gz"), get_file_path_without_extensiton(file_path));
1129                                         if(!FILEIO::IsFileExisting(img_file_path)) {
1130                                                 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.bin.gz"), get_file_path_without_extensiton(file_path));
1131                                         }
1132                                 }
1133                         }
1134                 }
1135                 if(fio_img->Fopen(img_file_path, FILEIO_READ_BINARY)) {
1136                         // get image file size
1137                         if((max_logical_block = fio_img->FileLength() / 2352) > 0) {
1138                                 // read cue file
1139                                 FILEIO* fio = new FILEIO();
1140                                 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
1141                                         char line[1024], *ptr;
1142                                         int track = -1;
1143                                         while(fio->Fgets(line, 1024) != NULL) {
1144                                                 if(strstr(line, "FILE") != NULL) {
1145                                                         // do nothing
1146                                                 } else if((ptr = strstr(line, "TRACK")) != NULL) {
1147                                                         // "TRACK 01 AUDIO"
1148                                                         // "TRACK 02 MODE1/2352"
1149                                                         ptr += 6;
1150                                                         while(*ptr == ' ' || *ptr == 0x09) {
1151                                                                 ptr++;
1152                                                         }
1153                                                         if((track = atoi(ptr)) > 0) {
1154                                                                 if(track > track_num) {
1155                                                                         track_num = track;
1156                                                                 }
1157                                                                 toc_table[track - 1].is_audio = (strstr(line, "AUDIO") != NULL);
1158                                                         }
1159                                                 } else if((ptr = strstr(line, "PREGAP")) != NULL) {
1160                                                         // "PREGAP 00:02:00"
1161                                                         if(track > 0) {
1162                                                                 toc_table[track - 1].pregap = get_frames_from_msf(ptr + 7);
1163                                                         }
1164                                                 } else if((ptr = strstr(line, "INDEX")) != NULL) {
1165                                                         // "INDEX 01 00:00:00"
1166                                                         if(track > 0) {
1167                                                                 ptr += 6;
1168                                                                 while(*ptr == ' ' || *ptr == 0x09) {
1169                                                                         ptr++;
1170                                                                 }
1171                                                                 int num = atoi(ptr);
1172                                                                 while(*ptr >= '0' && *ptr <= '9') {
1173                                                                         ptr++;
1174                                                                 }
1175                                                                 if(num == 0) {
1176                                                                         toc_table[track - 1].index0 = get_frames_from_msf(ptr);
1177                                                                 } else if(num == 1) {
1178                                                                         toc_table[track - 1].index1 = get_frames_from_msf(ptr);
1179                                                                 }
1180                                                         }
1181                                                 }
1182                                         }
1183                                         if(track_num != 0) {
1184                                                 for(int i = 1; i < track_num; i++) {
1185                                                         if(toc_table[i].index0 == 0) {
1186                                                                 toc_table[i].index0 = toc_table[i].index1 - toc_table[i].pregap;
1187                                                         } else if(toc_table[i].pregap == 0) {
1188                                                                 toc_table[i].pregap = toc_table[i].index1 - toc_table[i].index0;
1189                                                         }
1190                                                 }
1191                                                 toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
1192                                                 toc_table[track_num].index0 = toc_table[track_num].index1 = max_logical_block;
1193                                         } else {
1194                                                 fio_img->Fclose();
1195                                         }
1196                                         fio->Fclose();
1197                                 }
1198                                 delete fio;
1199                         }
1200                 }
1201 #endif
1202         } else if(check_file_extension(file_path, _T(".ccd"))) {
1203                 // get image file name
1204                 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img"), get_file_path_without_extensiton(file_path));
1205                 if(!FILEIO::IsFileExisting(img_file_path)) {
1206                         my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.gz"), get_file_path_without_extensiton(file_path));
1207                         if(!FILEIO::IsFileExisting(img_file_path)) {
1208                                 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img.gz"), get_file_path_without_extensiton(file_path));
1209                         }
1210                 }
1211                 if(fio_img->Fopen(img_file_path, FILEIO_READ_BINARY)) {
1212                         is_cue = false;
1213                         current_track = 0;
1214                         // get image file size
1215                         if((max_logical_block = fio_img->FileLength() / 2352) > 0) {
1216                                 // read cue file
1217                                 FILEIO* fio = new FILEIO();
1218                                 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
1219                                         char line[1024], *ptr;
1220                                         int track = -1;
1221                                         while(fio->Fgets(line, 1024) != NULL) {
1222                                                 if(strstr(line, "[Session ") != NULL) {
1223                                                         track = -1;
1224                                                 } else if((ptr = strstr(line, "Point=0x")) != NULL) {
1225                                                         if((track = hexatoi(ptr + 8)) > 0 && track < 0xa0) {
1226                                                                 if(track > track_num) {
1227                                                                         track_num = track;
1228                                                                 }
1229                                                         }
1230                                                 } else if((ptr = strstr(line, "Control=0x")) != NULL) {
1231                                                         if(track > 0 && track < 0xa0) {
1232                                                                 toc_table[track - 1].is_audio = (hexatoi(ptr + 10) != 4);
1233                                                         }
1234                                                 } else if((ptr = strstr(line, "ALBA=-")) != NULL) {
1235                                                         if(track > 0 && track < 0xa0) {
1236                                                                 toc_table[track - 1].pregap = atoi(ptr + 6);
1237                                                         }
1238                                                 } else if((ptr = strstr(line, "PLBA=")) != NULL) {
1239                                                         if(track > 0 && track < 0xa0) {
1240                                                                 toc_table[track - 1].index1 = atoi(ptr + 5);
1241                                                         }
1242                                                 }
1243                                         }
1244                                         if(track_num != 0) {
1245                                                 toc_table[0].lba_offset = 0;
1246                                                 toc_table[0].pregap = 0;
1247                                                 for(int i = 1; i < track_num; i++) {
1248                                                         toc_table[i].index0 = toc_table[i].index1 - toc_table[i].pregap;
1249                                                         toc_table[i].lba_offset = toc_table[i].pregap;
1250                                                         toc_table[i - 1].lba_size = toc_table[i].pregap - toc_table[i - 1].pregap;
1251                                                 }
1252                                                 toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
1253                                                 toc_table[track_num].index0 = toc_table[track_num].index1 = max_logical_block;
1254                                                 if(track_num > 0) {
1255                                                         toc_table[track_num].lba_size = max_logical_block - toc_table[track_num - 1].lba_offset;
1256                                                 } else {
1257                                                         toc_table[track_num].lba_size = 0;
1258                                                 }
1259                                         } else {
1260                                                 fio_img->Fclose();
1261                                         }
1262                                         fio->Fclose();
1263                                 }
1264                                 delete fio;
1265                         }
1266                 }
1267         }
1268 #ifdef _SCSI_DEBUG_LOG
1269         if(mounted()) {
1270                 for(int i = 0; i < track_num + 1; i++) {
1271                         uint32_t idx0_msf = lba_to_msf(toc_table[i].index0);
1272                         uint32_t idx1_msf = lba_to_msf(toc_table[i].index1);
1273                         uint32_t pgap_msf = lba_to_msf(toc_table[i].pregap);
1274                         this->out_debug_log(_T("Track%02d: Index0=%02x:%02x:%02x Index1=%02x:%02x:%02x PreGpap=%02x:%02x:%02x\n"), i + 1,
1275                         (idx0_msf >> 16) & 0xff, (idx0_msf >> 8) & 0xff, idx0_msf & 0xff,
1276                         (idx1_msf >> 16) & 0xff, (idx1_msf >> 8) & 0xff, idx1_msf & 0xff,
1277                         (pgap_msf >> 16) & 0xff, (pgap_msf >> 8) & 0xff, pgap_msf & 0xff);
1278                 }
1279         }
1280 #endif
1281 }
1282
1283 void SCSI_CDROM::close()
1284 {
1285         if(fio_img->IsOpened()) {
1286                 fio_img->Fclose();
1287         }
1288         memset(toc_table, 0, sizeof(toc_table));
1289         track_num = 0;
1290         is_cue = false;
1291         current_track = 0;
1292         set_cdda_status(CDDA_OFF);
1293 }
1294
1295 bool SCSI_CDROM::mounted()
1296 {
1297         if(is_cue) return true;
1298         return fio_img->IsOpened();
1299 }
1300
1301 bool SCSI_CDROM::accessed()
1302 {
1303         bool value = access;
1304         access = false;
1305         return value;
1306 }
1307
1308 void SCSI_CDROM::mix(int32_t* buffer, int cnt)
1309 {
1310         if(cdda_status == CDDA_PLAYING) {
1311                 if(mix_loop_num != 0) {
1312                         int tmp_l = 0, tmp_r = 0;
1313                         for(int i = 0; i < mix_loop_num; i++) {
1314                                 event_callback(EVENT_CDDA, 0);
1315                                 tmp_l += cdda_sample_l;
1316                                 tmp_r += cdda_sample_r;
1317                         }
1318                         cdda_sample_l = tmp_l / mix_loop_num;
1319                         cdda_sample_r = tmp_r / mix_loop_num;
1320                 }
1321                 int32_t val_l = apply_volume(apply_volume(cdda_sample_l, volume_m), volume_l);
1322                 int32_t val_r = apply_volume(apply_volume(cdda_sample_r, volume_m), volume_r);
1323                 
1324                 for(int i = 0; i < cnt; i++) {
1325                         *buffer++ += val_l; // L
1326                         *buffer++ += val_r; // R
1327                 }
1328         }
1329 }
1330
1331 void SCSI_CDROM::set_volume(int ch, int decibel_l, int decibel_r)
1332 {
1333         volume_l = decibel_to_volume(decibel_l + 3.0);
1334         volume_r = decibel_to_volume(decibel_r + 3.0);
1335 }
1336
1337 void SCSI_CDROM::set_volume(int volume)
1338 {
1339         volume_m = (int)(1024.0 * (max(0, min(100, volume)) / 100.0));
1340 }
1341
1342 #define STATE_VERSION   4
1343
1344 // Q: If loading state when using another (saved) image? 20181013 K.O
1345 //    May need close() and open() (or ...?).
1346 bool SCSI_CDROM::process_state(FILEIO* state_fio, bool loading)
1347 {
1348         uint32_t offset = 0;
1349         
1350         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
1351                 return false;
1352         }
1353         if(!state_fio->StateCheckInt32(this_device_id)) {
1354                 return false;
1355         }
1356         state_fio->StateValue(cdda_start_frame);
1357         state_fio->StateValue(cdda_end_frame);
1358         state_fio->StateValue(cdda_playing_frame);
1359         state_fio->StateValue(cdda_status);
1360         state_fio->StateValue(cdda_repeat);
1361         state_fio->StateValue(cdda_interrupt);
1362         state_fio->StateArray(cdda_buffer, sizeof(cdda_buffer), 1);
1363         state_fio->StateValue(cdda_buffer_ptr);
1364         state_fio->StateValue(cdda_sample_l);
1365         state_fio->StateValue(cdda_sample_r);
1366         state_fio->StateValue(event_cdda);
1367         state_fio->StateValue(event_cdda_delay_play);
1368         state_fio->StateValue(event_delay_interrupt);
1369         state_fio->StateValue(read_sectors);
1370 //      state_fio->StateValue(mix_loop_num);
1371         state_fio->StateValue(volume_m);
1372         if(loading) {
1373                 offset = state_fio->FgetUint32_LE();
1374         } else {
1375                 if(fio_img->IsOpened()) {
1376                         offset = fio_img->Ftell();
1377                 }
1378                 state_fio->FputUint32_LE(offset);
1379         }
1380         
1381         state_fio->StateValue(is_cue);
1382         state_fio->StateValue(current_track);
1383         // ToDo: Re-Open Image.20181118 K.O
1384         // post process
1385         if(loading && fio_img->IsOpened()) {
1386                 fio_img->Fseek(offset, FILEIO_SEEK_SET);
1387         }
1388         return SCSI_DEV::process_state(state_fio, loading);
1389 }