OSDN Git Service

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