OSDN Git Service

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