2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
10 #include "scsi_cdrom.h"
14 #define CDDA_PLAYING 1
17 // 0-99 is reserved for SCSI_DEV class
18 #define EVENT_CDDA 100
20 void SCSI_CDROM::initialize()
22 SCSI_DEV::initialize();
23 fio_img = new FILEIO();
25 if(44100 % emu->get_sound_rate() == 0) {
26 mix_loop_num = 44100 / emu->get_sound_rate();
31 cdda_status = CDDA_OFF;
34 void SCSI_CDROM::release()
36 if(fio_img->IsOpened()) {
43 void SCSI_CDROM::reset()
47 set_cdda_status(CDDA_OFF);
50 uint32_t SCSI_CDROM::read_signal(int id)
53 case SIG_SCSI_CDROM_PLAYING:
54 return (cdda_status == CDDA_PLAYING && cdda_interrupt) ? 0xffffffff : 0;
56 case SIG_SCSI_CDROM_SAMPLE_L:
57 return (uint32_t)abs(cdda_sample_l);
59 case SIG_SCSI_CDROM_SAMPLE_R:
60 return (uint32_t)abs(cdda_sample_r);
62 return SCSI_DEV::read_signal(id);
65 void SCSI_CDROM::event_callback(int event_id, int err)
69 // read 16bit 2ch samples in the cd-da buffer, called 44100 times/sec
70 cdda_sample_l = (int)(int16_t)(cdda_buffer[cdda_buffer_ptr + 0] + cdda_buffer[cdda_buffer_ptr + 1] * 0x100);
71 cdda_sample_r = (int)(int16_t)(cdda_buffer[cdda_buffer_ptr + 2] + cdda_buffer[cdda_buffer_ptr + 3] * 0x100);
73 if((cdda_buffer_ptr += 4) % 2352 == 0) {
75 if(++cdda_playing_frame == cdda_end_frame) {
76 // reached to end frame
79 fio_img->Fseek(cdda_start_frame * 2352, FILEIO_SEEK_SET);
80 fio_img->Fread(cdda_buffer, sizeof(cdda_buffer), 1);
82 cdda_playing_frame = cdda_start_frame;
87 write_signals(&outputs_done, 0xffffffff);
89 set_cdda_status(CDDA_OFF);
91 } else if(cdda_buffer_ptr == array_length(cdda_buffer)) {
93 fio_img->Fread(cdda_buffer, sizeof(cdda_buffer), 1);
100 SCSI_DEV::event_callback(event_id, err);
105 void SCSI_CDROM::set_cdda_status(uint8_t status)
107 if(status == CDDA_PLAYING) {
108 if(mix_loop_num == 0) {
109 if(event_cdda == -1) {
110 register_event(this, EVENT_CDDA, 1000000.0 / 44100.0, true, &event_cdda);
113 if(cdda_status != CDDA_PLAYING) {
115 set_realtime_render(this, true);
118 if(event_cdda != -1) {
119 cancel_event(this, event_cdda);
122 if(cdda_status == CDDA_PLAYING) {
124 set_realtime_render(this, false);
127 cdda_status = status;
130 void SCSI_CDROM::reset_device()
132 set_cdda_status(CDDA_OFF);
133 SCSI_DEV::reset_device();
136 bool SCSI_CDROM::is_device_ready()
141 int SCSI_CDROM::get_command_length(int value)
151 return SCSI_DEV::get_command_length(value);
154 int SCSI_CDROM::get_track(uint32_t lba)
158 for(int i = 0; i < track_num; i++) {
159 if(lba >= toc_table[i].index0) {
168 double SCSI_CDROM::get_seek_time(uint32_t lba)
170 if(fio_img->IsOpened()) {
171 uint32_t cur_position = (int)fio_img->Ftell();
172 int distance = abs((int)(lba * physical_block_size()) - (int)cur_position);
173 double ratio = (double)distance / 333000 / physical_block_size(); // 333000: sectors in media
174 return max(10, (int)(400000 * 2 * ratio));
176 return 400000; // 400msec
180 uint32_t lba_to_msf(uint32_t lba)
182 uint8_t m = lba / (60 * 75);
183 lba -= m * (60 * 75);
184 uint8_t s = lba / 75;
185 uint8_t f = lba % 75;
187 return ((m / 10) << 20) | ((m % 10) << 16) | ((s / 10) << 12) | ((s % 10) << 8) | ((f / 10) << 4) | ((f % 10) << 0);
190 uint32_t lba_to_msf_alt(uint32_t lba)
193 ret |= ((lba / (60 * 75)) & 0xff) << 16;
194 ret |= (((lba / 75) % 60) & 0xff) << 8;
195 ret |= ((lba % 75) & 0xff) << 0;
199 void SCSI_CDROM::start_command()
204 seek_time = 10;//get_seek_time((command[1] & 0x1f) * 0x10000 + command[2] * 0x100 + command[3]);
205 set_cdda_status(CDDA_OFF);
208 case SCSI_CMD_READ10:
209 case SCSI_CMD_READ12:
210 seek_time = 10;//get_seek_time(command[2] * 0x1000000 + command[3] * 0x10000 + command[4] * 0x100 + command[5]);
211 set_cdda_status(CDDA_OFF);
215 #ifdef _SCSI_DEBUG_LOG
216 this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Set Audio Playback Start Position\n"), scsi_id);
218 if(is_device_ready()) {
219 if(command[2] == 0 && command[3] == 0 && command[4] == 0) {
220 // stop cd-da if all params are zero
221 cdda_start_frame = 0;
222 cdda_end_frame = toc_table[track_num].index0; // end of disc
223 set_cdda_status(CDDA_OFF);
225 switch(command[9] & 0xc0) {
227 cdda_start_frame = (command[2] << 16) | (command[3] << 8) | command[4];
231 uint8_t m = FROM_BCD(command[2]);
232 uint8_t s = FROM_BCD(command[3]);
233 uint8_t f = FROM_BCD(command[4]);
234 cdda_start_frame = f + 75 * (s + m * 60);
236 // PCE tries to be clever here and set (start of track + track pregap size) to skip the pregap
237 // (I guess it wants the TOC to have the real start sector for data tracks and the start of the pregap for audio?)
238 int track =get_track(cdda_start_frame);
239 cdda_start_frame -= toc_table[track].pregap;
241 if(cdda_start_frame < toc_table[track].index1) {
242 cdda_start_frame = toc_table[track].index1; // don't play pregap
243 } else if(cdda_start_frame > max_logical_block) {
244 cdda_start_frame = 0;
249 cdda_start_frame = toc_table[FROM_BCD(command[2]) - 1].index1;
252 cdda_start_frame = 0;
255 // if(cdda_status == CDDA_PAUSED) {
256 // cdda_end_frame = toc_table[track_num].index0; // end of disc
257 // set_cdda_status(CDDA_OFF);
259 if((command[1] & 3) != 0) {
260 cdda_end_frame = toc_table[track_num].index0; // end of disc
261 set_cdda_status(CDDA_PLAYING);
263 cdda_end_frame = toc_table[get_track(cdda_start_frame) + 1].index1; // end of this track
264 set_cdda_status(CDDA_PAUSED);
267 cdda_interrupt = ((command[1] & 3) == 2);
270 double seek_time = get_seek_time(cdda_start_frame);
271 fio_img->Fseek(cdda_start_frame * 2352, FILEIO_SEEK_SET);
272 fio_img->Fread(cdda_buffer, sizeof(cdda_buffer), 1);
274 cdda_playing_frame = cdda_start_frame;
277 // change to status phase
278 set_dat(SCSI_STATUS_GOOD);
279 set_phase_delay(SCSI_PHASE_STATUS, seek_time);
283 // change to status phase
284 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
285 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
289 #ifdef _SCSI_DEBUG_LOG
290 this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Set Audio Playback End Position\n"), scsi_id);
292 if(is_device_ready()) {
293 switch(command[9] & 0xc0) {
295 cdda_end_frame = (command[3] << 16) | (command[4] << 8) | command[5];
299 uint8_t m = FROM_BCD(command[2]);
300 uint8_t s = FROM_BCD(command[3]);
301 uint8_t f = FROM_BCD(command[4]);
302 cdda_end_frame = f + 75 * (s + m * 60);
304 // PCE tries to be clever here and set (start of track + track pregap size) to skip the pregap
305 // (I guess it wants the TOC to have the real start sector for data tracks and the start of the pregap for audio?)
306 int track =get_track(cdda_end_frame);
308 if(cdda_end_frame > toc_table[track].index1 && (cdda_end_frame - toc_table[track].pregap) <= toc_table[track].index1) {
309 cdda_end_frame = toc_table[track].index1;
314 cdda_end_frame = toc_table[FROM_BCD(command[2]) - 1].index1;
317 if((command[1] & 3) != 0) {
318 set_cdda_status(CDDA_PLAYING);
319 cdda_repeat = ((command[1] & 3) == 1);
320 cdda_interrupt = ((command[1] & 3) == 2);
322 set_cdda_status(CDDA_OFF);
325 // change to status phase
326 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
327 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
331 #ifdef _SCSI_DEBUG_LOG
332 this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Pause\n"), scsi_id);
334 if(is_device_ready()) {
335 if(cdda_status == CDDA_PLAYING) {
336 set_cdda_status(CDDA_OFF);
339 // change to status phase
340 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
341 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
345 #ifdef _SCSI_DEBUG_LOG
346 this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Read Sub Channel Q\n"), scsi_id);
348 if(is_device_ready()) {
350 uint32_t frame = (cdda_status == CDDA_OFF) ? cdda_start_frame : cdda_playing_frame;
351 uint32_t msf_abs = lba_to_msf_alt(frame);
352 int track = get_track(frame);
353 uint32_t msf_rel = lba_to_msf_alt(frame - toc_table[track].index0);
355 buffer->write((cdda_status == CDDA_PLAYING) ? 0x00 : (cdda_status == CDDA_PAUSED) ? 0x02 : 0x03);
356 buffer->write(0x01 | (toc_table[track].is_audio ? 0x00 : 0x40));
357 buffer->write(TO_BCD(track + 1)); // Track
358 buffer->write(0x01); // Index
359 buffer->write(TO_BCD((msf_rel >> 16) & 0xff)); // M (relative)
360 buffer->write(TO_BCD((msf_rel >> 8) & 0xff)); // S (relative)
361 buffer->write(TO_BCD((msf_rel >> 0) & 0xff)); // F (relative)
362 buffer->write(TO_BCD((msf_abs >> 16) & 0xff)); // M (absolute)
363 buffer->write(TO_BCD((msf_abs >> 8) & 0xff)); // S (absolute)
364 buffer->write(TO_BCD((msf_abs >> 0) & 0xff)); // F (absolute)
366 remain = buffer->count();
368 set_dat(buffer->read());
369 // change to data in phase
370 set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
372 // change to status phase
373 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
374 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
379 #ifdef _SCSI_DEBUG_LOG
380 this->out_debug_log(_T("[SCSI_DEV:ID=%d] Command: NEC Get Dir Info\n"), scsi_id);
382 if(is_device_ready()) {
385 case 0x00: /* Get first and last track numbers */
386 buffer->write(TO_BCD(1));
387 buffer->write(TO_BCD(track_num));
389 case 0x01: /* Get total disk size in MSF format */
391 uint32_t msf = lba_to_msf(toc_table[track_num].index0 + 150);
392 buffer->write((msf >> 16) & 0xff);
393 buffer->write((msf >> 8) & 0xff);
394 buffer->write((msf >> 0) & 0xff);
397 case 0x02: /* Get track information */
398 if(command[2] == 0xaa) {
399 uint32_t msf = lba_to_msf(toc_table[track_num].index0 + 150);
400 buffer->write((msf >> 16) & 0xff);
401 buffer->write((msf >> 8) & 0xff);
402 buffer->write((msf >> 0) & 0xff);
403 buffer->write(0x04); // correct ?
405 int track = max(FROM_BCD(command[2]), 1);
406 uint32_t frame = toc_table[track - 1].index0;
407 // PCE wants the start sector for data tracks to *not* include the pregap
408 if(!toc_table[track - 1].is_audio) {
409 frame += toc_table[track - 1].pregap;
411 uint32_t msf = lba_to_msf(toc_table[track - 1].index1 + 150);
412 buffer->write((msf >> 16) & 0xff); // M
413 buffer->write((msf >> 8) & 0xff); // S
414 buffer->write((msf >> 0) & 0xff); // F
415 buffer->write(toc_table[track - 1].is_audio ? 0x00 : 0x04);
420 remain = buffer->count();
422 set_dat(buffer->read());
423 // change to data in phase
424 set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
426 // change to status phase
427 set_dat(is_device_ready() ? SCSI_STATUS_GOOD : SCSI_STATUS_CHKCOND);
428 set_phase_delay(SCSI_PHASE_STATUS, 10.0);
433 // start standard command
434 SCSI_DEV::start_command();
437 void SCSI_CDROM::read_buffer(int length)
439 if(fio_img->IsOpened()) {
440 uint32_t offset = (uint32_t)(position % 2352);
442 fio_img->Fseek((long)position, FILEIO_SEEK_SET);
444 uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
445 int tmp_length = min(length, (int)sizeof(tmp_buffer));
447 fio_img->Fread(tmp_buffer, tmp_length, 1);
448 for(int i = 0; i < tmp_length && length > 0; i++) {
449 if(offset >= 16 && offset < 16 + 2048) {
450 int value = tmp_buffer[i];
451 buffer->write(value);
455 offset = (offset + 1) % 2352;
462 int get_frames_from_msf(const char *string)
464 const char *ptr = string;
469 if(*ptr >= '0' && *ptr <= '9') {
470 frames[index] = frames[index] * 10 + (*ptr - '0');
471 } else if(*ptr == ':') {
476 } else if(*ptr == '\r' || *ptr == '\n' || *ptr == '\0') {
482 return (frames[0] * 60 + frames[1]) * 75 + frames[2]; // 75frames/sec
485 int hexatoi(const char *string)
487 const char *ptr = string;
491 if(*ptr >= '0' && *ptr <= '9') {
492 value = value * 16 + (*ptr - '0');
493 } else if(*ptr >= 'a' && *ptr <= 'f') {
494 value = value * 16 + (*ptr - 'a' + 10);
495 } else if(*ptr >= 'A' && *ptr <= 'F') {
496 value = value * 16 + (*ptr - 'A' + 10);
497 } else if(*ptr == '\r' || *ptr == '\n' || *ptr == '\0') {
505 void SCSI_CDROM::open(const _TCHAR* file_path)
507 _TCHAR img_file_path[_MAX_PATH];
511 if(check_file_extension(file_path, _T(".cue"))) {
512 // get image file name
513 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img"), get_file_path_without_extensiton(file_path));
514 if(!FILEIO::IsFileExisting(img_file_path)) {
515 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.bin"), get_file_path_without_extensiton(file_path));
516 if(!FILEIO::IsFileExisting(img_file_path)) {
517 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.gz"), get_file_path_without_extensiton(file_path));
518 if(!FILEIO::IsFileExisting(img_file_path)) {
519 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img.gz"), get_file_path_without_extensiton(file_path));
520 if(!FILEIO::IsFileExisting(img_file_path)) {
521 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.bin.gz"), get_file_path_without_extensiton(file_path));
526 if(fio_img->Fopen(img_file_path, FILEIO_READ_BINARY)) {
527 // get image file size
528 if((max_logical_block = fio_img->FileLength() / 2352) > 0) {
530 FILEIO* fio = new FILEIO();
531 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
532 char line[1024], *ptr;
534 while(fio->Fgets(line, 1024) != NULL) {
535 if(strstr(line, "FILE") != NULL) {
537 } else if((ptr = strstr(line, "TRACK")) != NULL) {
539 // "TRACK 02 MODE1/2352"
541 while(*ptr == ' ' || *ptr == 0x09) {
544 if((track = atoi(ptr)) > 0) {
545 if(track > track_num) {
548 toc_table[track - 1].is_audio = (strstr(line, "AUDIO") != NULL);
550 } else if((ptr = strstr(line, "PREGAP")) != NULL) {
553 toc_table[track - 1].pregap = get_frames_from_msf(ptr + 7);
555 } else if((ptr = strstr(line, "INDEX")) != NULL) {
556 // "INDEX 01 00:00:00"
559 while(*ptr == ' ' || *ptr == 0x09) {
563 while(*ptr >= '0' && *ptr <= '9') {
567 toc_table[track - 1].index0 = get_frames_from_msf(ptr);
568 } else if(num == 1) {
569 toc_table[track - 1].index1 = get_frames_from_msf(ptr);
575 for(int i = 1; i < track_num; i++) {
576 if(toc_table[i].index0 == 0) {
577 toc_table[i].index0 = toc_table[i].index1 - toc_table[i].pregap;
578 } else if(toc_table[i].pregap == 0) {
579 toc_table[i].pregap = toc_table[i].index1 - toc_table[i].index0;
582 toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
583 toc_table[track_num].index0 = toc_table[track_num].index1 = max_logical_block;
592 } else if(check_file_extension(file_path, _T(".ccd"))) {
593 // get image file name
594 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img"), get_file_path_without_extensiton(file_path));
595 if(!FILEIO::IsFileExisting(img_file_path)) {
596 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.gz"), get_file_path_without_extensiton(file_path));
597 if(!FILEIO::IsFileExisting(img_file_path)) {
598 my_stprintf_s(img_file_path, _MAX_PATH, _T("%s.img.gz"), get_file_path_without_extensiton(file_path));
601 if(fio_img->Fopen(img_file_path, FILEIO_READ_BINARY)) {
602 // get image file size
603 if((max_logical_block = fio_img->FileLength() / 2352) > 0) {
605 FILEIO* fio = new FILEIO();
606 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
607 char line[1024], *ptr;
609 while(fio->Fgets(line, 1024) != NULL) {
610 if(strstr(line, "[Session ") != NULL) {
612 } else if((ptr = strstr(line, "Point=0x")) != NULL) {
613 if((track = hexatoi(ptr + 8)) > 0 && track < 0xa0) {
614 if(track > track_num) {
618 } else if((ptr = strstr(line, "Control=0x")) != NULL) {
619 if(track > 0 && track < 0xa0) {
620 toc_table[track - 1].is_audio = (hexatoi(ptr + 10) != 4);
622 } else if((ptr = strstr(line, "ALBA=-")) != NULL) {
623 if(track > 0 && track < 0xa0) {
624 toc_table[track - 1].pregap = atoi(ptr + 6);
626 } else if((ptr = strstr(line, "PLBA=")) != NULL) {
627 if(track > 0 && track < 0xa0) {
628 toc_table[track - 1].index1 = atoi(ptr + 5);
633 for(int i = 1; i < track_num; i++) {
634 toc_table[i].index0 = toc_table[i].index1 - toc_table[i].pregap;
636 toc_table[0].index0 = toc_table[0].index1 = toc_table[0].pregap = 0;
637 toc_table[track_num].index0 = toc_table[track_num].index1 = max_logical_block;
647 #ifdef _SCSI_DEBUG_LOG
649 for(int i = 0; i < track_num + 1; i++) {
650 uint32_t idx0_msf = lba_to_msf(toc_table[i].index0);
651 uint32_t idx1_msf = lba_to_msf(toc_table[i].index1);
652 uint32_t pgap_msf = lba_to_msf(toc_table[i].pregap);
653 this->out_debug_log(_T("Track%02d: Index0=%02x:%02x:%02x Index1=%02x:%02x:%02x PreGpap=%02x:%02x:%02x\n"), i + 1,
654 (idx0_msf >> 16) & 0xff, (idx0_msf >> 8) & 0xff, idx0_msf & 0xff,
655 (idx1_msf >> 16) & 0xff, (idx1_msf >> 8) & 0xff, idx1_msf & 0xff,
656 (pgap_msf >> 16) & 0xff, (pgap_msf >> 8) & 0xff, pgap_msf & 0xff);
662 void SCSI_CDROM::close()
664 if(fio_img->IsOpened()) {
667 memset(toc_table, 0, sizeof(toc_table));
669 set_cdda_status(CDDA_OFF);
672 bool SCSI_CDROM::mounted()
674 return fio_img->IsOpened();
677 bool SCSI_CDROM::accessed()
684 void SCSI_CDROM::mix(int32_t* buffer, int cnt)
686 if(cdda_status == CDDA_PLAYING) {
687 if(mix_loop_num != 0) {
688 int tmp_l = 0, tmp_r = 0;
689 for(int i = 0; i < mix_loop_num; i++) {
690 event_callback(EVENT_CDDA, 0);
691 tmp_l += cdda_sample_l;
692 tmp_r += cdda_sample_r;
694 cdda_sample_l = tmp_l / mix_loop_num;
695 cdda_sample_r = tmp_r / mix_loop_num;
697 int32_t val_l = apply_volume(apply_volume(cdda_sample_l, volume_m), volume_l);
698 int32_t val_r = apply_volume(apply_volume(cdda_sample_r, volume_m), volume_r);
700 for(int i = 0; i < cnt; i++) {
701 *buffer++ += val_l; // L
702 *buffer++ += val_r; // R
707 void SCSI_CDROM::set_volume(int ch, int decibel_l, int decibel_r)
709 volume_l = decibel_to_volume(decibel_l);
710 volume_r = decibel_to_volume(decibel_r);
713 void SCSI_CDROM::set_volume(int volume)
715 volume_m = (int)(1024.0 * (max(0, min(100, volume)) / 100.0));
718 #define STATE_VERSION 3
720 #include "../statesub.h"
722 void SCSI_CDROM::decl_state()
724 enter_decl_state(STATE_VERSION);
726 DECL_STATE_ENTRY_UINT32(cdda_start_frame);
727 DECL_STATE_ENTRY_UINT32(cdda_end_frame);
728 DECL_STATE_ENTRY_UINT32(cdda_playing_frame);
729 DECL_STATE_ENTRY_UINT8(cdda_status);
730 DECL_STATE_ENTRY_BOOL(cdda_repeat);
731 DECL_STATE_ENTRY_BOOL(cdda_interrupt);
732 DECL_STATE_ENTRY_1D_ARRAY(cdda_buffer, sizeof(cdda_buffer));
733 DECL_STATE_ENTRY_INT32(cdda_buffer_ptr);
734 DECL_STATE_ENTRY_INT32(cdda_sample_l);
735 DECL_STATE_ENTRY_INT32(cdda_sample_r);
736 DECL_STATE_ENTRY_INT32(event_cdda);
737 // DECL_STATE_ENTRY_INT32(mix_loop_num);
738 DECL_STATE_ENTRY_INT32(volume_m);
739 // if(fio_img->IsOpened()) {
740 // state_fio->FputUint32(fio_img->Ftell());
742 // state_fio->FputUint32(0);
747 // ToDo: Add Fix Value.
748 SCSI_DEV::decl_state();
751 #include "../state_data.h"
753 void SCSI_CDROM::save_state(FILEIO* state_fio)
755 uint32_t crc_value = 0xffffffff;
756 if(state_entry != NULL) {
757 state_entry->save_state(state_fio, &crc_value);
759 // state_fio->FputUint32(STATE_VERSION);
760 // state_fio->FputInt32(this_device_id);
762 // state_fio->FputUint32(cdda_start_frame);
763 // state_fio->FputUint32(cdda_end_frame);
764 // state_fio->FputUint32(cdda_playing_frame);
765 // state_fio->FputUint8(cdda_status);
766 // state_fio->FputBool(cdda_repeat);
767 // state_fio->FputBool(cdda_interrupt);
768 // state_fio->Fwrite(cdda_buffer, sizeof(cdda_buffer), 1);
769 // state_fio->FputInt32(cdda_buffer_ptr);
770 // state_fio->FputInt32(cdda_sample_l);
771 // state_fio->FputInt32(cdda_sample_r);
772 // state_fio->FputInt32(event_cdda);
773 //// state_fio->FputInt32(mix_loop_num);
774 // state_fio->FputInt32(volume_m);
775 csp_state_data_saver saver(state_fio);
777 if(fio_img->IsOpened()) {
778 saver.put_dword(fio_img->Ftell(), &crc_value, &stat);
780 saver.put_dword(0, &crc_value, &stat);
782 saver.post_proc_saving(&crc_value, &stat);
784 //SCSI_DEV::save_state(state_fio);
787 bool SCSI_CDROM::load_state(FILEIO* state_fio)
789 uint32_t crc_value = 0xffffffff;
792 if(state_entry != NULL) {
793 mb = state_entry->load_state(state_fio, &crc_value);
795 if(!mb) return false;
796 csp_state_data_saver saver(state_fio);
797 // if(state_fio->FgetUint32() != STATE_VERSION) {
800 // if(state_fio->FgetInt32() != this_device_id) {
803 // cdda_start_frame = state_fio->FgetUint32();
804 // cdda_end_frame = state_fio->FgetUint32();
805 // cdda_playing_frame = state_fio->FgetUint32();
806 // cdda_status = state_fio->FgetUint8();
807 // cdda_repeat = state_fio->FgetBool();
808 // cdda_interrupt = state_fio->FgetBool();
809 // state_fio->Fread(cdda_buffer, sizeof(cdda_buffer), 1);
810 // cdda_buffer_ptr = state_fio->FgetInt32();
811 // cdda_sample_l = state_fio->FgetInt32();
812 // cdda_sample_r = state_fio->FgetInt32();
813 // event_cdda = state_fio->FgetInt32();
814 // mix_loop_num = state_fio->FgetInt32();
815 // volume_m = state_fio->FgetInt32();
816 uint32_t offset = saver.get_dword(&crc_value, &stat);
817 if(!(saver.post_proc_loading(&crc_value, &stat))) return false;
820 if(fio_img->IsOpened()) {
821 fio_img->Fseek(offset, FILEIO_SEEK_SET);
823 // return SCSI_DEV::load_state(state_fio);