OSDN Git Service

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