OSDN Git Service

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