2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
7 [ win32 emulation i/f ]
18 #ifndef FD_BASE_NUMBER
19 #define FD_BASE_NUMBER 1
21 #ifndef QD_BASE_NUMBER
22 #define QD_BASE_NUMBER 1
25 // ----------------------------------------------------------------------------
27 // ----------------------------------------------------------------------------
29 // Please permit at least them m(.. )m
30 //extern void get_long_full_path_name(_TCHAR* src, _TCHAR* dst);
35 EMU::EMU(class Ui_MainWindow *hwnd, GLDrawClass *hinst, USING_FLAGS *p)
36 #elif defined(OSD_WIN32)
37 EMU::EMU(HWND hwnd, HINSTANCE hinst)
43 // store main window handle
45 // initialize d88 file info
46 memset(d88_file, 0, sizeof(d88_file));
49 // initialize d88 file info
50 memset(b77_file, 0, sizeof(b77_file));
53 static const int freq_table[8] = {
54 2000, 4000, 8000, 11025, 22050, 44100,
55 #ifdef OVERRIDE_SOUND_FREQ_48000HZ
56 OVERRIDE_SOUND_FREQ_48000HZ,
62 static const double late_table[5] = {0.05, 0.1, 0.2, 0.3, 0.4};
64 if(!(0 <= config.sound_frequency && config.sound_frequency < 8)) {
65 config.sound_frequency = 6; // default: 48KHz
67 if(!(0 <= config.sound_latency && config.sound_latency < 5)) {
68 config.sound_latency = 1; // default: 100msec
70 sound_rate = freq_table[config.sound_frequency];
71 sound_samples = (int)(sound_rate * late_table[config.sound_latency] + 0.5);
74 cpu_type = config.cpu_type;
76 #ifdef USE_SOUND_DEVICE_TYPE
77 sound_device_type = config.sound_device_type;
80 printer_device_type = config.printer_device_type;
86 osd->main_window_handle = hwnd;
89 #elif defined(OSD_WIN32)
91 osd->main_window_handle = hwnd;
92 osd->instance_handle = hinst;
94 osd->initialize(sound_rate, sound_samples);
96 osd->vm = vm = new VM(this);
97 // Below is temporally workaround. I will fix ASAP (or give up): 20160311 K.Ohta
98 // Problems seem to be resolved. See fm7.cpp. 20160319 K.Ohta
99 // Still not resolved with FM-7/77 :-( 20160407 K.Ohta
100 #if defined(_FM7) || defined(_FMNEW7) || defined(_FM8) || \
101 defined(_FM77_VARIANTS)
103 osd->vm = vm = new VM(this);
106 initialize_auto_key();
109 initialize_debugger();
112 vm->initialize_sound(sound_rate, sound_samples);
113 #ifdef USE_SOUND_VOLUME
114 for(int i = 0; i < USE_SOUND_VOLUME; i++) {
115 vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
119 now_suspended = false;
139 EmuThreadClass *EMU::get_parent_handler()
141 return osd->get_parent_handler();
144 void EMU::set_parent_handler(EmuThreadClass *p, DrawThreadClass *q)
146 osd->set_parent_thread(p);
147 osd->set_draw_thread(q);
150 void EMU::set_host_cpus(int v)
152 osd->host_cpus = (v <= 0) ? 1 : v;
155 int EMU::get_host_cpus()
157 return osd->host_cpus;
161 // ----------------------------------------------------------------------------
163 // ----------------------------------------------------------------------------
165 int EMU::get_frame_interval()
167 #ifdef SUPPORT_VARIABLE_TIMING
168 static int prev_interval = 0;
169 static double prev_fps = -1;
170 double fps = vm->get_frame_rate();
171 if(prev_fps != fps) {
172 prev_interval = (int)(1024. * 1000. / fps + 0.5);
175 return prev_interval;
177 return (int)(1024. * 1000. / FRAMES_PER_SEC + 0.5);
181 bool EMU::is_frame_skippable()
183 return vm->is_frame_skippable();
190 now_suspended = false;
201 #if !defined(_USE_QT) // Temporally
202 osd->update_socket();
207 // virtual machine may be driven to fill sound buffer
208 int extra_frames = 0;
209 osd->update_sound(&extra_frames);
211 // drive virtual machine
212 if(extra_frames == 0) {
218 osd->add_extra_frames(extra_frames);
224 // check if virtual machine should be reinitialized
225 bool reinitialize = false;
227 reinitialize |= (cpu_type != config.cpu_type);
228 cpu_type = config.cpu_type;
230 #ifdef USE_SOUND_DEVICE_TYPE
231 reinitialize |= (sound_device_type != config.sound_device_type);
232 sound_device_type = config.sound_device_type;
235 reinitialize |= (printer_device_type != config.printer_device_type);
236 printer_device_type = config.printer_device_type;
241 // reinitialize virtual machine
244 osd->vm = vm = new VM(this);
245 vm->initialize_sound(sound_rate, sound_samples);
246 #ifdef USE_SOUND_VOLUME
247 for(int i = 0; i < USE_SOUND_VOLUME; i++) {
248 vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
253 // restore inserted medias
256 // reset virtual machine
263 #if !defined(_USE_QT) // Temporally
264 osd->restart_record_sound();
265 osd->restart_record_video();
269 #ifdef USE_SPECIAL_RESET
270 void EMU::special_reset()
272 // reset virtual machine
277 #if !defined(_USE_QT) // Temporally
278 restart_record_sound();
279 restart_record_video();
284 #ifdef USE_NOTIFY_POWER_OFF
285 void EMU::notify_power_off()
287 vm->notify_power_off();
291 void EMU::power_off()
300 now_suspended = true;
309 void EMU::unlock_vm()
314 void EMU::force_unlock_vm()
316 osd->force_unlock_vm();
320 bool EMU::is_vm_locked()
322 return osd->is_vm_locked();
325 // ----------------------------------------------------------------------------
327 // ----------------------------------------------------------------------------
330 void EMU::key_modifiers(uint32_t mod)
332 osd->key_modifiers(mod);
336 void EMU::set_mouse_pointer(int x, int y)
338 osd->set_mouse_pointer(x, y);
341 void EMU::set_mouse_button(int button)
343 osd->set_mouse_button(button);
346 int EMU::get_mouse_button()
348 return osd->get_mouse_button();
353 void EMU::key_down(int code, bool repeat)
355 osd->key_down(code, repeat);
358 void EMU::key_up(int code)
363 void EMU::key_lost_focus()
365 osd->key_lost_focus();
368 #ifdef ONE_BOARD_MICRO_COMPUTER
369 void EMU::press_button(int num)
371 int code = vm_buttons[num].code;
374 osd->key_down_native(code, false);
375 osd->get_key_buffer()[code] = KEY_KEEP_FRAMES;
377 // code=0: reset virtual machine
384 void EMU::enable_mouse()
389 void EMU::disable_mouse()
391 osd->disable_mouse();
394 void EMU::toggle_mouse()
399 bool EMU::is_mouse_enabled()
401 return osd->is_mouse_enabled();
406 void EMU::initialize_auto_key()
408 auto_key_buffer = new FIFO(65536);
409 auto_key_buffer->clear();
410 auto_key_phase = auto_key_shift = 0;
411 osd->now_auto_key = false;
414 void EMU::release_auto_key()
416 if(auto_key_buffer) {
417 auto_key_buffer->release();
418 delete auto_key_buffer;
422 void EMU::start_auto_key()
426 osd->now_auto_key = true;
429 void EMU::stop_auto_key()
432 osd->key_up_native(VK_LSHIFT);
434 auto_key_phase = auto_key_shift = 0;
435 osd->now_auto_key = false;
438 #ifndef USE_AUTO_KEY_SHIFT
439 #define USE_AUTO_KEY_SHIFT 0
442 #define VK_LSHIFT 0xA0
445 void EMU::update_auto_key()
447 switch(auto_key_phase) {
449 if(auto_key_buffer && !auto_key_buffer->empty()) {
450 // update shift key status
451 int shift = auto_key_buffer->read_not_remove(0) & 0x100;
452 if(shift && !auto_key_shift) {
453 osd->key_down_native(VK_LSHIFT, false);
454 } else if(!shift && auto_key_shift) {
455 osd->key_up_native(VK_LSHIFT);
457 auto_key_shift = shift;
461 case 3 + USE_AUTO_KEY_SHIFT:
462 if(auto_key_buffer && !auto_key_buffer->empty()) {
463 osd->key_down_native(auto_key_buffer->read_not_remove(0) & 0xff, false);
467 case USE_AUTO_KEY + USE_AUTO_KEY_SHIFT:
468 if(auto_key_buffer && !auto_key_buffer->empty()) {
469 osd->key_up_native(auto_key_buffer->read_not_remove(0) & 0xff);
473 case USE_AUTO_KEY_RELEASE + USE_AUTO_KEY_SHIFT:
474 if(auto_key_buffer && !auto_key_buffer->empty()) {
475 // wait enough while vm analyzes one line
476 if(auto_key_buffer->read() == 0xd) {
482 if(auto_key_buffer && !auto_key_buffer->empty()) {
497 void EMU::update_joystick()
499 uint32_t *joy_buffer = osd->get_joy_buffer();
500 uint8_t *key_buffer = osd->get_key_buffer();
502 memset(joy_status, 0, sizeof(joy_status));
504 for(int i = 0; i < 4; i++) {
505 for(int j = 0; j < 16; j++) {
506 if(config.joy_buttons[i][j] < 0) {
507 int code = -config.joy_buttons[i][j];
508 if(code < 256 && key_buffer[code]) {
509 joy_status[i] |= (1 << j);
512 int stick = config.joy_buttons[i][j] >> 4;
513 int button = config.joy_buttons[i][j] & 15;
514 if(stick < 2 && (joy_buffer[stick & 3] & (1 << button))) {
515 joy_status[i] |= (1 << j);
523 const uint8_t* EMU::get_key_buffer()
525 return (const uint8_t*)osd->get_key_buffer();
529 const uint32_t* EMU::get_joy_buffer()
531 return (const uint32_t*)joy_status;
536 const int32_t* EMU::get_mouse_buffer()
538 return (const int32_t*)osd->get_mouse_buffer();
542 // ----------------------------------------------------------------------------
544 // ----------------------------------------------------------------------------
546 int EMU::get_window_mode_width(int mode)
548 return osd->get_window_mode_width(mode);
551 int EMU::get_window_mode_height(int mode)
553 return osd->get_window_mode_height(mode);
556 void EMU::set_host_window_size(int window_width, int window_height, bool window_mode)
558 osd->set_host_window_size(window_width, window_height, window_mode);
561 void EMU::set_vm_screen_size(int screen_width, int screen_height, int window_width, int window_height, int window_width_aspect, int window_height_aspect)
563 osd->set_vm_screen_size(screen_width, screen_height, window_width, window_height, window_width_aspect, window_height_aspect);
566 int EMU::get_vm_window_width()
568 return osd->get_vm_window_width();
571 int EMU::get_vm_window_height()
573 return osd->get_vm_window_height();
576 int EMU::get_vm_window_width_aspect()
578 return osd->get_vm_window_width_aspect();
581 int EMU::get_vm_window_height_aspect()
583 return osd->get_vm_window_height_aspect();
586 #if defined(USE_MINIMUM_RENDERING)
587 bool EMU::is_screen_changed()
589 return vm->is_screen_changed();
593 int EMU::draw_screen()
595 return osd->draw_screen();
598 scrntype_t* EMU::get_screen_buffer(int y)
600 return osd->get_vm_screen_buffer(y);
603 #ifdef USE_CRT_FILTER
604 void EMU::screen_skip_line(bool skip_line)
606 osd->screen_skip_line = skip_line;
610 #ifdef ONE_BOARD_MICRO_COMPUTER
611 void EMU::reload_bitmap()
613 osd->reload_bitmap();
618 void EMU::update_screen(HDC hdc)
620 osd->update_screen(hdc);
624 void EMU::capture_screen()
626 osd->capture_screen();
629 bool EMU::start_record_video(int fps)
631 return osd->start_record_video(fps);
634 void EMU::stop_record_video()
636 osd->stop_record_video();
639 bool EMU::is_video_recording()
641 return osd->now_record_video;
644 // ----------------------------------------------------------------------------
646 // ----------------------------------------------------------------------------
648 void EMU::mute_sound()
653 void EMU::start_record_sound()
655 osd->start_record_sound();
658 void EMU::stop_record_sound()
660 osd->stop_record_sound();
663 bool EMU::is_sound_recording()
665 return osd->now_record_sound;
668 // ----------------------------------------------------------------------------
670 // ----------------------------------------------------------------------------
672 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
673 void EMU::get_video_buffer()
675 osd->get_video_buffer();
678 void EMU::mute_video_dev(bool l, bool r)
680 osd->mute_video_dev(l, r);
684 #ifdef USE_MOVIE_PLAYER
685 bool EMU::open_movie_file(const _TCHAR* file_path)
687 return osd->open_movie_file(file_path);
690 void EMU::close_movie_file()
692 osd->close_movie_file();
695 void EMU::play_movie()
700 void EMU::stop_movie()
705 void EMU::pause_movie()
710 double EMU::get_movie_frame_rate()
712 return osd->get_movie_frame_rate();
715 int EMU::get_movie_sound_rate()
717 return osd->get_movie_sound_rate();
720 void EMU::set_cur_movie_frame(int frame, bool relative)
722 osd->set_cur_movie_frame(frame, relative);
725 uint32_t EMU::get_cur_movie_frame()
727 return osd->get_cur_movie_frame();
731 #ifdef USE_VIDEO_CAPTURE
732 int EMU::get_cur_capture_dev_index()
734 return osd->get_cur_capture_dev_index();
737 int EMU::get_num_capture_devs()
739 return osd->get_num_capture_devs();
742 _TCHAR* EMU::get_capture_dev_name(int index)
744 return osd->get_capture_dev_name(index);
747 void EMU::open_capture_dev(int index, bool pin)
749 osd->open_capture_dev(index, pin);
752 void EMU::close_capture_dev()
754 osd->close_capture_dev();
757 void EMU::show_capture_dev_filter()
759 osd->show_capture_dev_filter();
762 void EMU::show_capture_dev_pin()
764 osd->show_capture_dev_pin();
767 void EMU::show_capture_dev_source()
769 osd->show_capture_dev_source();
772 void EMU::set_capture_dev_channel(int ch)
774 osd->set_capture_dev_channel(ch);
778 // ----------------------------------------------------------------------------
780 // ----------------------------------------------------------------------------
783 void EMU::create_bitmap(bitmap_t *bitmap, int width, int height)
785 osd->create_bitmap(bitmap, width, height);
788 void EMU::release_bitmap(bitmap_t *bitmap)
790 osd->release_bitmap(bitmap);
793 void EMU::create_font(font_t *font, const _TCHAR *family, int width, int height, int rotate, bool bold, bool italic)
795 osd->create_font(font, family, width, height, rotate, bold, italic);
798 void EMU::release_font(font_t *font)
800 osd->release_font(font);
803 void EMU::create_pen(pen_t *pen, int width, uint8_t r, uint8_t g, uint8_t b)
805 osd->create_pen(pen, width, r, g, b);
808 void EMU::release_pen(pen_t *pen)
810 osd->release_pen(pen);
813 void EMU::clear_bitmap(bitmap_t *bitmap, uint8_t r, uint8_t g, uint8_t b)
815 osd->clear_bitmap(bitmap, r, g, b);
818 int EMU::get_text_width(bitmap_t *bitmap, font_t *font, const char *text)
820 return osd->get_text_width(bitmap, font, text);
823 void EMU::draw_text_to_bitmap(bitmap_t *bitmap, font_t *font, int x, int y, const char *text, uint8_t r, uint8_t g, uint8_t b)
825 osd->draw_text_to_bitmap(bitmap, font, x, y, text, r, g, b);
828 void EMU::draw_line_to_bitmap(bitmap_t *bitmap, pen_t *pen, int sx, int sy, int ex, int ey)
830 osd->draw_line_to_bitmap(bitmap, pen, sx, sy, ex, ey);
833 void EMU::draw_rectangle_to_bitmap(bitmap_t *bitmap, int x, int y, int width, int height, uint8_t r, uint8_t g, uint8_t b)
835 osd->draw_rectangle_to_bitmap(bitmap, x, y, width, height, r, g, b);
838 void EMU::draw_point_to_bitmap(bitmap_t *bitmap, int x, int y, uint8_t r, uint8_t g, uint8_t b)
840 osd->draw_point_to_bitmap(bitmap, x, y, r, g, b);
843 void EMU::stretch_bitmap(bitmap_t *dest, int dest_x, int dest_y, int dest_width, int dest_height, bitmap_t *source, int source_x, int source_y, int source_width, int source_height)
845 osd->stretch_bitmap(dest, dest_x, dest_y, dest_width, dest_height, source, source_x, source_y, source_width, source_height);
848 void EMU::write_bitmap_to_file(bitmap_t *bitmap, const _TCHAR *file_path)
850 osd->write_bitmap_to_file(bitmap, file_path);
854 // ----------------------------------------------------------------------------
856 // ----------------------------------------------------------------------------
859 int EMU::get_socket(int ch)
861 return osd->get_socket(ch);
864 void EMU::notify_socket_connected(int ch)
866 osd->notify_socket_connected(ch);
869 void EMU::notify_socket_disconnected(int ch)
871 osd->notify_socket_disconnected(ch);
874 bool EMU::initialize_socket_tcp(int ch)
876 return osd->initialize_socket_tcp(ch);
879 bool EMU::initialize_socket_udp(int ch)
881 return osd->initialize_socket_udp(ch);
884 bool EMU::connect_socket(int ch, uint32_t ipaddr, int port)
886 return osd->connect_socket(ch, ipaddr, port);
889 void EMU::disconnect_socket(int ch)
891 osd->disconnect_socket(ch);
894 bool EMU::listen_socket(int ch)
896 return osd->listen_socket(ch);
899 void EMU::send_socket_data_tcp(int ch)
901 osd->send_socket_data_tcp(ch);
904 void EMU::send_socket_data_udp(int ch, uint32_t ipaddr, int port)
906 osd->send_socket_data_udp(ch, ipaddr, port);
909 void EMU::send_socket_data(int ch)
911 osd->send_socket_data(ch);
914 void EMU::recv_socket_data(int ch)
916 osd->recv_socket_data(ch);
920 // ----------------------------------------------------------------------------
922 // ----------------------------------------------------------------------------
925 void EMU::initialize_debug_log()
927 _TCHAR path[_MAX_PATH];
928 debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
931 void EMU::release_debug_log()
941 static _TCHAR prev_buffer[1024] = {0};
944 void EMU::out_debug_log(const _TCHAR* format, ...)
950 va_start(ap, format);
951 my_vstprintf_s(buffer, 1024, format, ap);
954 if(_tcscmp(prev_buffer, buffer) == 0) {
957 my_tcscpy_s(prev_buffer, 1024, buffer);
959 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
960 AGAR_DebugLog(AGAR_LOG_DEBUG, "%s", buffer);
963 _ftprintf(debug_log, _T("%s"), buffer);
965 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
967 debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
975 void EMU::force_out_debug_log(const _TCHAR* format, ...)
981 va_start(ap, format);
982 my_vstprintf_s(buffer, 1024, format, ap);
984 my_tcscpy_s(prev_buffer, 1024, buffer);
986 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
987 AGAR_DebugLog(AGAR_LOG_DEBUG, "%s", buffer);
990 _ftprintf(debug_log, _T("%s"), buffer);
992 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
994 debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
1002 void EMU::out_message(const _TCHAR* format, ...)
1005 va_start(ap, format);
1006 my_vstprintf_s(message, 1024, format, ap); // Security for MSVC:C6386.
1008 message_count = 4; // 4sec
1011 // ----------------------------------------------------------------------------
1013 // ----------------------------------------------------------------------------
1016 void EMU::sleep(uint32_t ms)
1022 // ----------------------------------------------------------------------------
1024 // ----------------------------------------------------------------------------
1026 static uint8_t hex2uint8(char *value)
1029 memset(tmp, 0, sizeof(tmp));
1030 memcpy(tmp, value, 2);
1031 return (uint8_t)strtoul(tmp, NULL, 16);
1034 static uint16_t hex2uint16(char *value)
1037 memset(tmp, 0, sizeof(tmp));
1038 memcpy(tmp, value, 4);
1039 return (uint16_t)strtoul(tmp, NULL, 16);
1042 static bool hex2bin(const _TCHAR* file_path, const _TCHAR* dest_path)
1044 bool result = false;
1045 FILEIO *fio_s = new FILEIO();
1046 if(fio_s->Fopen(file_path, FILEIO_READ_BINARY)) {
1049 uint8_t buffer[0x10000];
1050 memset(buffer, 0xff, sizeof(buffer));
1051 while(fio_s->Fgets(line, sizeof(line)) != NULL) {
1052 if(line[0] != ':') continue;
1053 int bytes = hex2uint8(line + 1);
1054 int offset = hex2uint16(line + 3);
1055 uint8_t record_type = hex2uint8(line + 7);
1056 if(record_type == 0x01) break;
1057 if(record_type != 0x00) continue;
1058 for(int i = 0; i < bytes; i++) {
1059 if(offset + i < sizeof(buffer)) {
1060 if(length < offset + i) {
1061 length = offset + i;
1063 buffer[offset + i] = hex2uint8(line + 9 + 2 * i);
1068 FILEIO *fio_d = new FILEIO();
1069 if(fio_d->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
1070 fio_d->Fwrite(buffer, length, 1);
1082 void EMU::initialize_media()
1085 memset(&cart_status, 0, sizeof(cart_status));
1088 memset(floppy_disk_status, 0, sizeof(floppy_disk_status));
1091 memset(&quick_disk_status, 0, sizeof(quick_disk_status));
1094 memset(&tape_status, 0, sizeof(tape_status));
1096 #ifdef USE_COMPACT_DISC
1097 memset(&compact_disc_status, 0, sizeof(compact_disc_status));
1099 #ifdef USE_LASER_DISC
1100 memset(&laser_disc_status, 0, sizeof(laser_disc_status));
1105 void EMU::update_media()
1108 for(int drv = 0; drv < MAX_FD; drv++) {
1109 if(floppy_disk_status[drv].wait_count != 0 && --floppy_disk_status[drv].wait_count == 0) {
1110 vm->open_floppy_disk(drv, floppy_disk_status[drv].path, floppy_disk_status[drv].bank);
1111 out_message(_T("FD%d: %s"), drv + FD_BASE_NUMBER, floppy_disk_status[drv].path);
1116 for(int drv = 0; drv < MAX_QD; drv++) {
1117 if(quick_disk_status[drv].wait_count != 0 && --quick_disk_status[drv].wait_count == 0) {
1118 vm->open_quick_disk(drv, quick_disk_status[drv].path);
1119 out_message(_T("QD%d: %s"), drv + QD_BASE_NUMBER, quick_disk_status[drv].path);
1124 if(tape_status.wait_count != 0 && --tape_status.wait_count == 0) {
1125 if(tape_status.play) {
1126 vm->play_tape(tape_status.path);
1128 vm->rec_tape(tape_status.path);
1130 out_message(_T("CMT: %s"), tape_status.path);
1133 #ifdef USE_COMPACT_DISC
1134 if(compact_disc_status.wait_count != 0 && --compact_disc_status.wait_count == 0) {
1135 vm->open_compact_disc(compact_disc_status.path);
1136 out_message(_T("CD: %s"), compact_disc_status.path);
1139 #ifdef USE_LASER_DISC
1140 if(laser_disc_status.wait_count != 0 && --laser_disc_status.wait_count == 0) {
1141 vm->open_laser_disc(laser_disc_status.path);
1142 out_message(_T("LD: %s"), laser_disc_status.path);
1146 for(int drv = 0; drv < MAX_BUBBLE; drv++) {
1147 if(bubble_casette_status[drv].wait_count != 0 && --bubble_casette_status[drv].wait_count == 0) {
1148 vm->open_bubble_casette(drv, bubble_casette_status[drv].path, bubble_casette_status[drv].bank);
1149 out_message(_T("Bubble%d: %s"), drv, bubble_casette_status[drv].path);
1155 void EMU::restore_media()
1158 for(int drv = 0; drv < MAX_CART; drv++) {
1159 if(cart_status[drv].path[0] != _T('\0')) {
1160 if(check_file_extension(cart_status[drv].path, _T(".hex")) && hex2bin(cart_status[drv].path, create_local_path(_T("hex2bin.$$$")))) {
1161 vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
1162 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
1164 vm->open_cart(drv, cart_status[drv].path);
1170 for(int drv = 0; drv < MAX_FD; drv++) {
1171 if(floppy_disk_status[drv].path[0] != _T('\0')) {
1172 vm->open_floppy_disk(drv, floppy_disk_status[drv].path, floppy_disk_status[drv].bank);
1177 for(int drv = 0; drv < MAX_QD; drv++) {
1178 if(quick_disk_status[drv].path[0] != _T('\0')) {
1179 vm->open_quick_disk(drv, quick_disk_status[drv].path);
1184 if(tape_status.path[0] != _T('\0')) {
1185 if(tape_status.play) {
1186 vm->play_tape(tape_status.path);
1188 tape_status.path[0] = _T('\0');
1192 #ifdef USE_COMPACT_DISC
1193 if(compact_disc_status.path[0] != _T('\0')) {
1194 vm->open_compact_disc(compact_disc_status.path);
1197 #ifdef USE_LASER_DISC
1198 if(laser_disc_status.path[0] != _T('\0')) {
1199 vm->open_laser_disc(laser_disc_status.path);
1203 for(int drv = 0; drv < MAX_BUBBLE; drv++) {
1204 if(bubble_casette_status[drv].path[0] != _T('\0')) {
1205 vm->open_bubble_casette(drv, bubble_casette_status[drv].path, bubble_casette_status[drv].bank);
1212 void EMU::open_cart(int drv, const _TCHAR* file_path)
1214 if(drv < MAX_CART) {
1215 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
1216 vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
1217 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
1219 vm->open_cart(drv, file_path);
1221 my_tcscpy_s(cart_status[drv].path, _MAX_PATH, file_path);
1222 out_message(_T("Cart%d: %s"), drv + 1, file_path);
1223 #if !defined(_USE_QT)
1224 // restart recording
1225 bool s = osd->now_record_sound;
1226 bool v = osd->now_record_video;
1227 stop_record_sound();
1228 stop_record_video();
1230 if(s) osd->start_record_sound();
1231 if(v) osd->start_record_video(-1);
1236 void EMU::close_cart(int drv)
1238 if(drv < MAX_CART) {
1239 vm->close_cart(drv);
1240 clear_media_status(&cart_status[drv]);
1241 out_message(_T("Cart%d: Ejected"), drv + 1);
1242 #if !defined(_USE_QT)
1244 stop_record_video();
1245 stop_record_sound();
1250 bool EMU::is_cart_inserted(int drv)
1252 if(drv < MAX_CART) {
1253 return vm->is_cart_inserted(drv);
1261 void EMU::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
1264 if(vm->is_floppy_disk_inserted(drv)) {
1265 vm->close_floppy_disk(drv);
1267 #ifdef SUPPORT_VARIABLE_TIMING
1268 floppy_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
1270 floppy_disk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1272 out_message(_T("FD%d: Ejected"), drv + FD_BASE_NUMBER);
1273 } else if(floppy_disk_status[drv].wait_count == 0) {
1274 vm->open_floppy_disk(drv, file_path, bank);
1275 out_message(_T("FD%d: %s"), drv + FD_BASE_NUMBER, file_path);
1277 my_tcscpy_s(floppy_disk_status[drv].path, _MAX_PATH, file_path);
1278 floppy_disk_status[drv].bank = bank;
1282 void EMU::close_floppy_disk(int drv)
1285 vm->close_floppy_disk(drv);
1286 clear_media_status(&floppy_disk_status[drv]);
1287 out_message(_T("FD%d: Ejected"), drv + FD_BASE_NUMBER);
1291 bool EMU::is_floppy_disk_inserted(int drv)
1294 return vm->is_floppy_disk_inserted(drv);
1300 void EMU::is_floppy_disk_protected(int drv, bool value)
1303 vm->is_floppy_disk_protected(drv, value);
1307 bool EMU::is_floppy_disk_protected(int drv)
1310 return vm->is_floppy_disk_protected(drv);
1318 void EMU::open_quick_disk(int drv, const _TCHAR* file_path)
1321 if(vm->is_quick_disk_inserted(drv)) {
1322 vm->close_quick_disk(drv);
1324 #ifdef SUPPORT_VARIABLE_TIMING
1325 quick_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
1327 quick_disk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1329 out_message(_T("QD%d: Ejected"), drv + QD_BASE_NUMBER);
1330 } else if(quick_disk_status[drv].wait_count == 0) {
1331 vm->open_quick_disk(drv, file_path);
1332 out_message(_T("QD%d: %s"), drv + QD_BASE_NUMBER, file_path);
1334 my_tcscpy_s(quick_disk_status[drv].path, _MAX_PATH, file_path);
1338 void EMU::close_quick_disk(int drv)
1341 vm->close_quick_disk(drv);
1342 clear_media_status(&quick_disk_status[drv]);
1343 out_message(_T("QD%d: Ejected"), drv + QD_BASE_NUMBER);
1347 bool EMU::is_quick_disk_inserted(int drv)
1350 return vm->is_quick_disk_inserted(drv);
1358 void EMU::play_tape(const _TCHAR* file_path)
1360 if(vm->is_tape_inserted()) {
1363 #ifdef SUPPORT_VARIABLE_TIMING
1364 tape_status.wait_count = (int)(vm->get_frame_rate() / 2);
1366 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1368 out_message(_T("CMT: Ejected"));
1369 } else if(tape_status.wait_count == 0) {
1370 vm->play_tape(file_path);
1371 out_message(_T("CMT: %s"), file_path);
1373 my_tcscpy_s(tape_status.path, _MAX_PATH, file_path);
1374 tape_status.play = true;
1377 void EMU::rec_tape(const _TCHAR* file_path)
1379 if(vm->is_tape_inserted()) {
1382 #ifdef SUPPORT_VARIABLE_TIMING
1383 tape_status.wait_count = (int)(vm->get_frame_rate() / 2);
1385 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1387 out_message(_T("CMT: Ejected"));
1388 } else if(tape_status.wait_count == 0) {
1389 vm->rec_tape(file_path);
1390 out_message(_T("CMT: %s"), file_path);
1392 my_tcscpy_s(tape_status.path, _MAX_PATH, file_path);
1393 tape_status.play = false;
1396 void EMU::close_tape()
1399 clear_media_status(&tape_status);
1400 out_message(_T("CMT: Ejected"));
1403 bool EMU::is_tape_inserted()
1405 return vm->is_tape_inserted();
1408 #ifndef TAPE_BINARY_ONLY
1409 bool EMU::is_tape_playing()
1411 return vm->is_tape_playing();
1414 bool EMU::is_tape_recording()
1416 return vm->is_tape_recording();
1419 int EMU::get_tape_position()
1421 return vm->get_tape_position();
1425 #ifdef USE_TAPE_BUTTON
1426 void EMU::push_play()
1431 void EMU::push_stop()
1436 void EMU::push_fast_forward()
1438 vm->push_fast_forward();
1441 void EMU::push_fast_rewind()
1443 vm->push_fast_rewind();
1446 void EMU::push_apss_forward()
1448 vm->push_apss_forward();
1451 void EMU::push_apss_rewind()
1453 vm->push_apss_rewind();
1458 #ifdef USE_COMPACT_DISC
1459 void EMU::open_compact_disc(const _TCHAR* file_path)
1461 if(vm->is_compact_disc_inserted()) {
1462 vm->close_compact_disc();
1464 #ifdef SUPPORT_VARIABLE_TIMING
1465 compact_disc_status.wait_count = (int)(vm->get_frame_rate() / 2);
1467 compact_disc_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1469 out_message(_T("CD: Ejected"));
1470 } else if(compact_disc_status.wait_count == 0) {
1471 vm->open_compact_disc(file_path);
1472 out_message(_T("CD: %s"), file_path);
1474 my_tcscpy_s(compact_disc_status.path, _MAX_PATH, file_path);
1477 void EMU::close_compact_disc()
1479 vm->close_compact_disc();
1480 clear_media_status(&compact_disc_status);
1481 out_message(_T("CD: Ejected"));
1484 bool EMU::is_compact_disc_inserted()
1486 return vm->is_compact_disc_inserted();
1490 #ifdef USE_LASER_DISC
1491 void EMU::open_laser_disc(const _TCHAR* file_path)
1493 if(vm->is_laser_disc_inserted()) {
1494 vm->close_laser_disc();
1496 #ifdef SUPPORT_VARIABLE_TIMING
1497 laser_disc_status.wait_count = (int)(vm->get_frame_rate() / 2);
1499 laser_disc_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1501 out_message(_T("LD: Ejected"));
1502 } else if(laser_disc_status.wait_count == 0) {
1503 vm->open_laser_disc(file_path);
1504 out_message(_T("LD: %s"), file_path);
1506 my_tcscpy_s(laser_disc_status.path, _MAX_PATH, file_path);
1509 void EMU::close_laser_disc()
1511 vm->close_laser_disc();
1512 clear_media_status(&laser_disc_status);
1513 out_message(_T("LD: Ejected"));
1516 bool EMU::is_laser_disc_inserted()
1518 return vm->is_laser_disc_inserted();
1522 #ifdef USE_BINARY_FILE1
1523 void EMU::load_binary(int drv, const _TCHAR* file_path)
1525 if(drv < MAX_BINARY) {
1526 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
1527 vm->load_binary(drv, create_local_path(_T("hex2bin.$$$")));
1528 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
1530 vm->load_binary(drv, file_path);
1532 out_message(_T("Load: %s"), file_path);
1536 void EMU::save_binary(int drv, const _TCHAR* file_path)
1538 if(drv < MAX_BINARY) {
1539 vm->save_binary(drv, file_path);
1540 out_message(_T("Save: %s"), file_path);
1545 void EMU::open_bubble_casette(int drv, const _TCHAR* file_path, int bank)
1547 if(drv < MAX_BUBBLE) {
1548 if(vm->is_bubble_casette_inserted(drv)) {
1549 vm->close_bubble_casette(drv);
1551 #ifdef SUPPORT_VARIABLE_TIMING
1552 bubble_casette_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
1554 bubble_casette_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1556 out_message(_T("Bubble%d: Ejected"), drv + 1);
1557 } else if(bubble_casette_status[drv].wait_count == 0) {
1558 vm->open_bubble_casette(drv, file_path, bank);
1559 out_message(_T("Bubble%d: %s"), drv + 1, file_path);
1561 my_tcscpy_s(bubble_casette_status[drv].path, _MAX_PATH, file_path);
1562 bubble_casette_status[drv].bank = bank;
1566 void EMU::close_bubble_casette(int drv)
1568 if(drv < MAX_BUBBLE) {
1569 vm->close_bubble_casette(drv);
1570 clear_media_status(&bubble_casette_status[drv]);
1571 out_message(_T("Bubble%d: Ejected"), drv + 1);
1575 bool EMU::is_bubble_casette_inserted(int drv)
1577 if(drv < MAX_BUBBLE) {
1578 return vm->is_bubble_casette_inserted(drv);
1584 bool EMU::is_bubble_casette_protected(int drv)
1586 if(drv < MAX_BUBBLE) {
1587 return vm->is_bubble_casette_protected(drv);
1593 void EMU::is_bubble_casette_protected(int drv, bool flag)
1595 if(drv < MAX_BUBBLE) {
1596 return vm->is_bubble_casette_protected(drv, flag);
1603 #ifdef USE_ACCESS_LAMP
1604 uint32_t EMU::get_access_lamp_status()
1606 return vm->get_access_lamp_status();
1610 #ifdef USE_LED_DEVICE
1611 uint32_t EMU::get_led_status()
1613 return vm->get_led_status();
1617 #ifdef USE_SOUND_VOLUME
1618 void EMU::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
1620 vm->set_sound_device_volume(ch, decibel_l, decibel_r);
1624 void EMU::update_config()
1626 vm->update_config();
1631 // ----------------------------------------------------------------------------
1633 // ----------------------------------------------------------------------------
1636 #define STATE_VERSION 2
1638 void EMU::save_state()
1640 save_state_tmp(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)));
1643 void EMU::load_state()
1645 if(FILEIO::IsFileExisting(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)))) {
1646 save_state_tmp(create_local_path(_T("$temp$.sta")));
1647 if(!load_state_tmp(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)))) {
1648 out_debug_log(_T("failed to load state file\n"));
1649 load_state_tmp(create_local_path(_T("$temp$.sta")));
1651 FILEIO::RemoveFile(create_local_path(_T("$temp$.sta")));
1655 void EMU::save_state_tmp(const _TCHAR* file_path)
1657 FILEIO* fio = new FILEIO();
1659 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
1660 // save state file version
1661 fio->FputUint32(STATE_VERSION);
1663 save_config_state((void *)fio);
1664 // save inserted medias
1666 fio->Fwrite(&cart_status, sizeof(cart_status), 1);
1669 fio->Fwrite(floppy_disk_status, sizeof(floppy_disk_status), 1);
1670 fio->Fwrite(d88_file, sizeof(d88_file), 1);
1673 fio->Fwrite(&quick_disk_status, sizeof(quick_disk_status), 1);
1676 fio->Fwrite(&tape_status, sizeof(tape_status), 1);
1678 #ifdef USE_COMPACT_DISC
1679 fio->Fwrite(&compact_disc_status, sizeof(compact_disc_status), 1);
1681 #ifdef USE_LASER_DISC
1682 fio->Fwrite(&laser_disc_status, sizeof(laser_disc_status), 1);
1685 vm->save_state(fio);
1686 // end of state file
1694 bool EMU::load_state_tmp(const _TCHAR* file_path)
1696 bool result = false;
1697 FILEIO* fio = new FILEIO();
1699 if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
1700 // check state file version
1701 if(fio->FgetUint32() == STATE_VERSION) {
1703 if(load_config_state((void *)fio)) {
1704 // load inserted medias
1706 fio->Fread(&cart_status, sizeof(cart_status), 1);
1709 fio->Fread(floppy_disk_status, sizeof(floppy_disk_status), 1);
1710 fio->Fread(d88_file, sizeof(d88_file), 1);
1713 fio->Fread(&quick_disk_status, sizeof(quick_disk_status), 1);
1716 fio->Fread(&tape_status, sizeof(tape_status), 1);
1718 #ifdef USE_COMPACT_DISC
1719 fio->Fread(&compact_disc_status, sizeof(compact_disc_status), 1);
1721 #ifdef USE_LASER_DISC
1722 fio->Fread(&laser_disc_status, sizeof(laser_disc_status), 1);
1724 // check if virtual machine should be reinitialized
1725 bool reinitialize = false;
1727 reinitialize |= (cpu_type != config.cpu_type);
1728 cpu_type = config.cpu_type;
1730 #ifdef USE_SOUND_DEVICE_TYPE
1731 reinitialize |= (sound_device_type != config.sound_device_type);
1732 sound_device_type = config.sound_device_type;
1735 reinitialize |= (printer_device_type != config.printer_device_type);
1736 printer_device_type = config.printer_device_type;
1741 // reinitialize virtual machine
1744 osd->vm = vm = new VM(this);
1745 vm->initialize_sound(sound_rate, sound_samples);
1746 #ifdef USE_SOUND_VOLUME
1747 for(int i = 0; i < USE_SOUND_VOLUME; i++) {
1748 vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
1754 // restore inserted medias
1757 if(vm->load_state(fio)) {
1758 // check end of state
1759 result = (fio->FgetInt32() == -1);