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)
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)
90 osd->main_window_handle = hwnd;
91 osd->instance_handle = hinst;
93 osd->initialize(sound_rate, sound_samples);
95 osd->vm = vm = new VM(this);
96 // Below is temporally workaround. I will fix ASAP (or give up): 20160311 K.Ohta
97 // Problems seem to be resolved. See fm7.cpp. 20160319 K.Ohta
98 // Still not resolved with FM-7/77 :-( 20160407 K.Ohta
99 #if defined(_FM7) || defined(_FMNEW7) || defined(_FM8) || \
100 defined(_FM77_VARIANTS)
102 osd->vm = vm = new VM(this);
105 initialize_auto_key();
108 initialize_debugger();
111 vm->initialize_sound(sound_rate, sound_samples);
112 #ifdef USE_SOUND_VOLUME
113 for(int i = 0; i < USE_SOUND_VOLUME; i++) {
114 vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
118 now_suspended = false;
138 EmuThreadClass *EMU::get_parent_handler()
140 return osd->get_parent_handler();
143 void EMU::set_parent_handler(EmuThreadClass *p, DrawThreadClass *q)
145 osd->set_parent_thread(p);
146 osd->set_draw_thread(q);
149 void EMU::set_host_cpus(int v)
151 osd->host_cpus = (v <= 0) ? 1 : v;
154 int EMU::get_host_cpus()
156 return osd->host_cpus;
160 // ----------------------------------------------------------------------------
162 // ----------------------------------------------------------------------------
164 int EMU::get_frame_interval()
166 #ifdef SUPPORT_VARIABLE_TIMING
167 static int prev_interval = 0;
168 static double prev_fps = -1;
169 double fps = vm->get_frame_rate();
170 if(prev_fps != fps) {
171 prev_interval = (int)(1024. * 1000. / fps + 0.5);
174 return prev_interval;
176 return (int)(1024. * 1000. / FRAMES_PER_SEC + 0.5);
180 bool EMU::is_frame_skippable()
182 return vm->is_frame_skippable();
189 now_suspended = false;
200 #if !defined(_USE_QT) // Temporally
201 osd->update_socket();
206 // virtual machine may be driven to fill sound buffer
207 int extra_frames = 0;
208 osd->update_sound(&extra_frames);
210 // drive virtual machine
211 if(extra_frames == 0) {
217 osd->add_extra_frames(extra_frames);
223 // check if virtual machine should be reinitialized
224 bool reinitialize = false;
226 reinitialize |= (cpu_type != config.cpu_type);
227 cpu_type = config.cpu_type;
229 #ifdef USE_SOUND_DEVICE_TYPE
230 reinitialize |= (sound_device_type != config.sound_device_type);
231 sound_device_type = config.sound_device_type;
234 reinitialize |= (printer_device_type != config.printer_device_type);
235 printer_device_type = config.printer_device_type;
240 // reinitialize virtual machine
243 osd->vm = vm = new VM(this);
244 vm->initialize_sound(sound_rate, sound_samples);
245 #ifdef USE_SOUND_VOLUME
246 for(int i = 0; i < USE_SOUND_VOLUME; i++) {
247 vm->set_sound_device_volume(i, config.sound_volume_l[i], config.sound_volume_r[i]);
252 // restore inserted medias
255 // reset virtual machine
262 #if !defined(_USE_QT) // Temporally
263 osd->restart_record_sound();
264 osd->restart_record_video();
268 #ifdef USE_SPECIAL_RESET
269 void EMU::special_reset()
271 // reset virtual machine
276 #if !defined(_USE_QT) // Temporally
277 restart_record_sound();
278 restart_record_video();
283 #ifdef USE_NOTIFY_POWER_OFF
284 void EMU::notify_power_off()
286 vm->notify_power_off();
290 void EMU::power_off()
299 now_suspended = true;
308 void EMU::unlock_vm()
313 void EMU::force_unlock_vm()
315 osd->force_unlock_vm();
319 bool EMU::is_vm_locked()
321 return osd->is_vm_locked();
324 // ----------------------------------------------------------------------------
326 // ----------------------------------------------------------------------------
329 void EMU::key_modifiers(uint32_t mod)
331 osd->key_modifiers(mod);
335 void EMU::set_mouse_pointer(int x, int y)
337 osd->set_mouse_pointer(x, y);
340 void EMU::set_mouse_button(int button)
342 osd->set_mouse_button(button);
345 int EMU::get_mouse_button()
347 return osd->get_mouse_button();
352 void EMU::key_down(int code, bool repeat)
354 osd->key_down(code, repeat);
357 void EMU::key_up(int code)
362 void EMU::key_lost_focus()
364 osd->key_lost_focus();
367 #ifdef ONE_BOARD_MICRO_COMPUTER
368 void EMU::press_button(int num)
370 int code = vm_buttons[num].code;
373 osd->key_down_native(code, false);
374 osd->get_key_buffer()[code] = KEY_KEEP_FRAMES;
376 // code=0: reset virtual machine
383 void EMU::enable_mouse()
388 void EMU::disable_mouse()
390 osd->disable_mouse();
393 void EMU::toggle_mouse()
398 bool EMU::is_mouse_enabled()
400 return osd->is_mouse_enabled();
405 void EMU::initialize_auto_key()
407 auto_key_buffer = new FIFO(65536);
408 auto_key_buffer->clear();
409 auto_key_phase = auto_key_shift = 0;
410 osd->now_auto_key = false;
413 void EMU::release_auto_key()
415 if(auto_key_buffer) {
416 auto_key_buffer->release();
417 delete auto_key_buffer;
421 void EMU::start_auto_key()
425 osd->now_auto_key = true;
428 void EMU::stop_auto_key()
431 osd->key_up_native(VK_LSHIFT);
433 auto_key_phase = auto_key_shift = 0;
434 osd->now_auto_key = false;
437 #ifndef USE_AUTO_KEY_SHIFT
438 #define USE_AUTO_KEY_SHIFT 0
441 #define VK_LSHIFT 0xA0
444 void EMU::update_auto_key()
446 switch(auto_key_phase) {
448 if(auto_key_buffer && !auto_key_buffer->empty()) {
449 // update shift key status
450 int shift = auto_key_buffer->read_not_remove(0) & 0x100;
451 if(shift && !auto_key_shift) {
452 osd->key_down_native(VK_LSHIFT, false);
453 } else if(!shift && auto_key_shift) {
454 osd->key_up_native(VK_LSHIFT);
456 auto_key_shift = shift;
460 case 3 + USE_AUTO_KEY_SHIFT:
461 if(auto_key_buffer && !auto_key_buffer->empty()) {
462 osd->key_down_native(auto_key_buffer->read_not_remove(0) & 0xff, false);
466 case USE_AUTO_KEY + USE_AUTO_KEY_SHIFT:
467 if(auto_key_buffer && !auto_key_buffer->empty()) {
468 osd->key_up_native(auto_key_buffer->read_not_remove(0) & 0xff);
472 case USE_AUTO_KEY_RELEASE + USE_AUTO_KEY_SHIFT:
473 if(auto_key_buffer && !auto_key_buffer->empty()) {
474 // wait enough while vm analyzes one line
475 if(auto_key_buffer->read() == 0xd) {
481 if(auto_key_buffer && !auto_key_buffer->empty()) {
496 void EMU::update_joystick()
498 uint32_t *joy_buffer = osd->get_joy_buffer();
499 uint8_t *key_buffer = osd->get_key_buffer();
501 memset(joy_status, 0, sizeof(joy_status));
503 for(int i = 0; i < 4; i++) {
504 for(int j = 0; j < 16; j++) {
505 if(config.joy_buttons[i][j] < 0) {
506 int code = -config.joy_buttons[i][j];
507 if(code < 256 && key_buffer[code]) {
508 joy_status[i] |= (1 << j);
511 int stick = config.joy_buttons[i][j] >> 4;
512 int button = config.joy_buttons[i][j] & 15;
513 if(stick < 2 && (joy_buffer[stick & 3] & (1 << button))) {
514 joy_status[i] |= (1 << j);
522 const uint8_t* EMU::get_key_buffer()
524 return (const uint8_t*)osd->get_key_buffer();
528 const uint32_t* EMU::get_joy_buffer()
530 return (const uint32_t*)joy_status;
535 const int32_t* EMU::get_mouse_buffer()
537 return (const int32_t*)osd->get_mouse_buffer();
541 // ----------------------------------------------------------------------------
543 // ----------------------------------------------------------------------------
545 int EMU::get_window_width(int mode)
547 return osd->get_window_width(mode);
550 int EMU::get_window_height(int mode)
552 return osd->get_window_height(mode);
555 void EMU::set_host_window_size(int window_width, int window_height, bool window_mode)
557 osd->set_host_window_size(window_width, window_height, window_mode);
560 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)
562 osd->set_vm_screen_size(screen_width, screen_height, window_width, window_height, window_width_aspect, window_height_aspect);
565 int EMU::get_vm_window_width()
567 return osd->get_vm_window_width();
570 int EMU::get_vm_window_height()
572 return osd->get_vm_window_height();
575 int EMU::get_vm_window_width_aspect()
577 return osd->get_vm_window_width_aspect();
580 int EMU::get_vm_window_height_aspect()
582 return osd->get_vm_window_height_aspect();
585 #if defined(USE_MINIMUM_RENDERING)
586 bool EMU::is_screen_changed()
588 return vm->is_screen_changed();
592 int EMU::draw_screen()
594 return osd->draw_screen();
597 scrntype_t* EMU::get_screen_buffer(int y)
599 return osd->get_vm_screen_buffer(y);
602 #ifdef USE_CRT_FILTER
603 void EMU::screen_skip_line(bool skip_line)
605 osd->screen_skip_line = skip_line;
609 #ifdef ONE_BOARD_MICRO_COMPUTER
610 void EMU::reload_bitmap()
612 osd->reload_bitmap();
617 void EMU::update_screen(HDC hdc)
619 osd->update_screen(hdc);
623 void EMU::capture_screen()
625 osd->capture_screen();
628 bool EMU::start_record_video(int fps)
630 return osd->start_record_video(fps);
633 void EMU::stop_record_video()
635 osd->stop_record_video();
638 bool EMU::is_video_recording()
640 return osd->now_record_video;
643 // ----------------------------------------------------------------------------
645 // ----------------------------------------------------------------------------
647 void EMU::mute_sound()
652 void EMU::start_record_sound()
654 osd->start_record_sound();
657 void EMU::stop_record_sound()
659 osd->stop_record_sound();
662 bool EMU::is_sound_recording()
664 return osd->now_record_sound;
667 // ----------------------------------------------------------------------------
669 // ----------------------------------------------------------------------------
671 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
672 void EMU::get_video_buffer()
674 osd->get_video_buffer();
677 void EMU::mute_video_dev(bool l, bool r)
679 osd->mute_video_dev(l, r);
683 #ifdef USE_MOVIE_PLAYER
684 bool EMU::open_movie_file(const _TCHAR* file_path)
686 return osd->open_movie_file(file_path);
689 void EMU::close_movie_file()
691 osd->close_movie_file();
694 void EMU::play_movie()
699 void EMU::stop_movie()
704 void EMU::pause_movie()
709 double EMU::get_movie_frame_rate()
711 return osd->get_movie_frame_rate();
714 int EMU::get_movie_sound_rate()
716 return osd->get_movie_sound_rate();
719 void EMU::set_cur_movie_frame(int frame, bool relative)
721 osd->set_cur_movie_frame(frame, relative);
724 uint32_t EMU::get_cur_movie_frame()
726 return osd->get_cur_movie_frame();
730 #ifdef USE_VIDEO_CAPTURE
731 int EMU::get_cur_capture_dev_index()
733 return osd->get_cur_capture_dev_index();
736 int EMU::get_num_capture_devs()
738 return osd->get_num_capture_devs();
741 _TCHAR* EMU::get_capture_dev_name(int index)
743 return osd->get_capture_dev_name(index);
746 void EMU::open_capture_dev(int index, bool pin)
748 osd->open_capture_dev(index, pin);
751 void EMU::close_capture_dev()
753 osd->close_capture_dev();
756 void EMU::show_capture_dev_filter()
758 osd->show_capture_dev_filter();
761 void EMU::show_capture_dev_pin()
763 osd->show_capture_dev_pin();
766 void EMU::show_capture_dev_source()
768 osd->show_capture_dev_source();
771 void EMU::set_capture_dev_channel(int ch)
773 osd->set_capture_dev_channel(ch);
777 // ----------------------------------------------------------------------------
779 // ----------------------------------------------------------------------------
782 void EMU::create_bitmap(bitmap_t *bitmap, int width, int height)
784 osd->create_bitmap(bitmap, width, height);
787 void EMU::release_bitmap(bitmap_t *bitmap)
789 osd->release_bitmap(bitmap);
792 void EMU::create_font(font_t *font, const _TCHAR *family, int width, int height, int rotate, bool bold, bool italic)
794 osd->create_font(font, family, width, height, rotate, bold, italic);
797 void EMU::release_font(font_t *font)
799 osd->release_font(font);
802 void EMU::create_pen(pen_t *pen, int width, uint8_t r, uint8_t g, uint8_t b)
804 osd->create_pen(pen, width, r, g, b);
807 void EMU::release_pen(pen_t *pen)
809 osd->release_pen(pen);
812 void EMU::clear_bitmap(bitmap_t *bitmap, uint8_t r, uint8_t g, uint8_t b)
814 osd->clear_bitmap(bitmap, r, g, b);
817 int EMU::get_text_width(bitmap_t *bitmap, font_t *font, const char *text)
819 return osd->get_text_width(bitmap, font, text);
822 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)
824 osd->draw_text_to_bitmap(bitmap, font, x, y, text, r, g, b);
827 void EMU::draw_line_to_bitmap(bitmap_t *bitmap, pen_t *pen, int sx, int sy, int ex, int ey)
829 osd->draw_line_to_bitmap(bitmap, pen, sx, sy, ex, ey);
832 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)
834 osd->draw_rectangle_to_bitmap(bitmap, x, y, width, height, r, g, b);
837 void EMU::draw_point_to_bitmap(bitmap_t *bitmap, int x, int y, uint8_t r, uint8_t g, uint8_t b)
839 osd->draw_point_to_bitmap(bitmap, x, y, r, g, b);
842 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)
844 osd->stretch_bitmap(dest, dest_x, dest_y, dest_width, dest_height, source, source_x, source_y, source_width, source_height);
847 void EMU::write_bitmap_to_file(bitmap_t *bitmap, const _TCHAR *file_path)
849 osd->write_bitmap_to_file(bitmap, file_path);
853 // ----------------------------------------------------------------------------
855 // ----------------------------------------------------------------------------
858 int EMU::get_socket(int ch)
860 return osd->get_socket(ch);
863 void EMU::notify_socket_connected(int ch)
865 osd->notify_socket_connected(ch);
868 void EMU::notify_socket_disconnected(int ch)
870 osd->notify_socket_disconnected(ch);
873 bool EMU::initialize_socket_tcp(int ch)
875 return osd->initialize_socket_tcp(ch);
878 bool EMU::initialize_socket_udp(int ch)
880 return osd->initialize_socket_udp(ch);
883 bool EMU::connect_socket(int ch, uint32_t ipaddr, int port)
885 return osd->connect_socket(ch, ipaddr, port);
888 void EMU::disconnect_socket(int ch)
890 osd->disconnect_socket(ch);
893 bool EMU::listen_socket(int ch)
895 return osd->listen_socket(ch);
898 void EMU::send_socket_data_tcp(int ch)
900 osd->send_socket_data_tcp(ch);
903 void EMU::send_socket_data_udp(int ch, uint32_t ipaddr, int port)
905 osd->send_socket_data_udp(ch, ipaddr, port);
908 void EMU::send_socket_data(int ch)
910 osd->send_socket_data(ch);
913 void EMU::recv_socket_data(int ch)
915 osd->recv_socket_data(ch);
919 // ----------------------------------------------------------------------------
921 // ----------------------------------------------------------------------------
924 void EMU::initialize_debug_log()
926 _TCHAR path[_MAX_PATH];
927 debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
930 void EMU::release_debug_log()
940 static _TCHAR prev_buffer[1024] = {0};
943 void EMU::out_debug_log(const _TCHAR* format, ...)
949 va_start(ap, format);
950 my_vstprintf_s(buffer, 1024, format, ap);
953 if(_tcscmp(prev_buffer, buffer) == 0) {
956 my_tcscpy_s(prev_buffer, 1024, buffer);
958 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
959 AGAR_DebugLog(AGAR_LOG_DEBUG, "%s", buffer);
962 _ftprintf(debug_log, _T("%s"), buffer);
964 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
966 debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
974 void EMU::force_out_debug_log(const _TCHAR* format, ...)
980 va_start(ap, format);
981 my_vstprintf_s(buffer, 1024, format, ap);
983 my_tcscpy_s(prev_buffer, 1024, buffer);
985 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
986 AGAR_DebugLog(AGAR_LOG_DEBUG, "%s", buffer);
989 _ftprintf(debug_log, _T("%s"), buffer);
991 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
993 debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
1001 void EMU::out_message(const _TCHAR* format, ...)
1004 va_start(ap, format);
1005 my_vstprintf_s(message, 1024, format, ap); // Security for MSVC:C6386.
1007 message_count = 4; // 4sec
1010 // ----------------------------------------------------------------------------
1012 // ----------------------------------------------------------------------------
1015 void EMU::sleep(uint32_t ms)
1021 // ----------------------------------------------------------------------------
1023 // ----------------------------------------------------------------------------
1025 static uint8_t hex2uint8(char *value)
1028 memset(tmp, 0, sizeof(tmp));
1029 memcpy(tmp, value, 2);
1030 return (uint8_t)strtoul(tmp, NULL, 16);
1033 static uint16_t hex2uint16(char *value)
1036 memset(tmp, 0, sizeof(tmp));
1037 memcpy(tmp, value, 4);
1038 return (uint16_t)strtoul(tmp, NULL, 16);
1041 static bool hex2bin(const _TCHAR* file_path, const _TCHAR* dest_path)
1043 bool result = false;
1044 FILEIO *fio_s = new FILEIO();
1045 if(fio_s->Fopen(file_path, FILEIO_READ_BINARY)) {
1048 uint8_t buffer[0x10000];
1049 memset(buffer, 0xff, sizeof(buffer));
1050 while(fio_s->Fgets(line, sizeof(line)) != NULL) {
1051 if(line[0] != ':') continue;
1052 int bytes = hex2uint8(line + 1);
1053 int offset = hex2uint16(line + 3);
1054 uint8_t record_type = hex2uint8(line + 7);
1055 if(record_type == 0x01) break;
1056 if(record_type != 0x00) continue;
1057 for(int i = 0; i < bytes; i++) {
1058 if(offset + i < sizeof(buffer)) {
1059 if(length < offset + i) {
1060 length = offset + i;
1062 buffer[offset + i] = hex2uint8(line + 9 + 2 * i);
1067 FILEIO *fio_d = new FILEIO();
1068 if(fio_d->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
1069 fio_d->Fwrite(buffer, length, 1);
1081 void EMU::initialize_media()
1084 memset(&cart_status, 0, sizeof(cart_status));
1087 memset(floppy_disk_status, 0, sizeof(floppy_disk_status));
1090 memset(&quick_disk_status, 0, sizeof(quick_disk_status));
1093 memset(&tape_status, 0, sizeof(tape_status));
1095 #ifdef USE_COMPACT_DISC
1096 memset(&compact_disc_status, 0, sizeof(compact_disc_status));
1098 #ifdef USE_LASER_DISC
1099 memset(&laser_disc_status, 0, sizeof(laser_disc_status));
1104 void EMU::update_media()
1107 for(int drv = 0; drv < MAX_FD; drv++) {
1108 if(floppy_disk_status[drv].wait_count != 0 && --floppy_disk_status[drv].wait_count == 0) {
1109 vm->open_floppy_disk(drv, floppy_disk_status[drv].path, floppy_disk_status[drv].bank);
1110 out_message(_T("FD%d: %s"), drv + FD_BASE_NUMBER, floppy_disk_status[drv].path);
1115 for(int drv = 0; drv < MAX_QD; drv++) {
1116 if(quick_disk_status[drv].wait_count != 0 && --quick_disk_status[drv].wait_count == 0) {
1117 vm->open_quick_disk(drv, quick_disk_status[drv].path);
1118 out_message(_T("QD%d: %s"), drv + QD_BASE_NUMBER, quick_disk_status[drv].path);
1123 if(tape_status.wait_count != 0 && --tape_status.wait_count == 0) {
1124 if(tape_status.play) {
1125 vm->play_tape(tape_status.path);
1127 vm->rec_tape(tape_status.path);
1129 out_message(_T("CMT: %s"), tape_status.path);
1132 #ifdef USE_COMPACT_DISC
1133 if(compact_disc_status.wait_count != 0 && --compact_disc_status.wait_count == 0) {
1134 vm->open_compact_disc(compact_disc_status.path);
1135 out_message(_T("CD: %s"), compact_disc_status.path);
1138 #ifdef USE_LASER_DISC
1139 if(laser_disc_status.wait_count != 0 && --laser_disc_status.wait_count == 0) {
1140 vm->open_laser_disc(laser_disc_status.path);
1141 out_message(_T("LD: %s"), laser_disc_status.path);
1145 for(int drv = 0; drv < MAX_BUBBLE; drv++) {
1146 if(bubble_casette_status[drv].wait_count != 0 && --bubble_casette_status[drv].wait_count == 0) {
1147 vm->open_bubble_casette(drv, bubble_casette_status[drv].path, bubble_casette_status[drv].bank);
1148 out_message(_T("Bubble%d: %s"), drv, bubble_casette_status[drv].path);
1154 void EMU::restore_media()
1157 for(int drv = 0; drv < MAX_CART; drv++) {
1158 if(cart_status[drv].path[0] != _T('\0')) {
1159 if(check_file_extension(cart_status[drv].path, _T(".hex")) && hex2bin(cart_status[drv].path, create_local_path(_T("hex2bin.$$$")))) {
1160 vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
1161 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
1163 vm->open_cart(drv, cart_status[drv].path);
1169 for(int drv = 0; drv < MAX_FD; drv++) {
1170 if(floppy_disk_status[drv].path[0] != _T('\0')) {
1171 vm->open_floppy_disk(drv, floppy_disk_status[drv].path, floppy_disk_status[drv].bank);
1176 for(int drv = 0; drv < MAX_QD; drv++) {
1177 if(quick_disk_status[drv].path[0] != _T('\0')) {
1178 vm->open_quick_disk(drv, quick_disk_status[drv].path);
1183 if(tape_status.path[0] != _T('\0')) {
1184 if(tape_status.play) {
1185 vm->play_tape(tape_status.path);
1187 tape_status.path[0] = _T('\0');
1191 #ifdef USE_COMPACT_DISC
1192 if(compact_disc_status.path[0] != _T('\0')) {
1193 vm->open_compact_disc(compact_disc_status.path);
1196 #ifdef USE_LASER_DISC
1197 if(laser_disc_status.path[0] != _T('\0')) {
1198 vm->open_laser_disc(laser_disc_status.path);
1202 for(int drv = 0; drv < MAX_BUBBLE; drv++) {
1203 if(bubble_casette_status[drv].path[0] != _T('\0')) {
1204 vm->open_bubble_casette(drv, bubble_casette_status[drv].path, bubble_casette_status[drv].bank);
1211 void EMU::open_cart(int drv, const _TCHAR* file_path)
1213 if(drv < MAX_CART) {
1214 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
1215 vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
1216 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
1218 vm->open_cart(drv, file_path);
1220 my_tcscpy_s(cart_status[drv].path, _MAX_PATH, file_path);
1221 out_message(_T("Cart%d: %s"), drv + 1, file_path);
1223 // restart recording
1224 bool s = osd->now_record_sound;
1225 bool v = osd->now_record_video;
1226 stop_record_sound();
1227 stop_record_video();
1228 if(s) osd->start_record_sound();
1229 if(v) osd->start_record_video(-1);
1233 void EMU::close_cart(int drv)
1235 if(drv < MAX_CART) {
1236 vm->close_cart(drv);
1237 clear_media_status(&cart_status[drv]);
1238 out_message(_T("Cart%d: Ejected"), drv + 1);
1241 stop_record_video();
1242 stop_record_sound();
1246 bool EMU::is_cart_inserted(int drv)
1248 if(drv < MAX_CART) {
1249 return vm->is_cart_inserted(drv);
1257 void EMU::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
1260 if(vm->is_floppy_disk_inserted(drv)) {
1261 vm->close_floppy_disk(drv);
1263 #ifdef SUPPORT_VARIABLE_TIMING
1264 floppy_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
1266 floppy_disk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1268 out_message(_T("FD%d: Ejected"), drv + FD_BASE_NUMBER);
1269 } else if(floppy_disk_status[drv].wait_count == 0) {
1270 vm->open_floppy_disk(drv, file_path, bank);
1271 out_message(_T("FD%d: %s"), drv + FD_BASE_NUMBER, file_path);
1273 my_tcscpy_s(floppy_disk_status[drv].path, _MAX_PATH, file_path);
1274 floppy_disk_status[drv].bank = bank;
1278 void EMU::close_floppy_disk(int drv)
1281 vm->close_floppy_disk(drv);
1282 clear_media_status(&floppy_disk_status[drv]);
1283 out_message(_T("FD%d: Ejected"), drv + FD_BASE_NUMBER);
1287 bool EMU::is_floppy_disk_inserted(int drv)
1290 return vm->is_floppy_disk_inserted(drv);
1296 void EMU::is_floppy_disk_protected(int drv, bool value)
1299 vm->is_floppy_disk_protected(drv, value);
1303 bool EMU::is_floppy_disk_protected(int drv)
1306 return vm->is_floppy_disk_protected(drv);
1314 void EMU::open_quick_disk(int drv, const _TCHAR* file_path)
1317 if(vm->is_quick_disk_inserted(drv)) {
1318 vm->close_quick_disk(drv);
1320 #ifdef SUPPORT_VARIABLE_TIMING
1321 quick_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
1323 quick_disk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1325 out_message(_T("QD%d: Ejected"), drv + QD_BASE_NUMBER);
1326 } else if(quick_disk_status[drv].wait_count == 0) {
1327 vm->open_quick_disk(drv, file_path);
1328 out_message(_T("QD%d: %s"), drv + QD_BASE_NUMBER, file_path);
1330 my_tcscpy_s(quick_disk_status[drv].path, _MAX_PATH, file_path);
1334 void EMU::close_quick_disk(int drv)
1337 vm->close_quick_disk(drv);
1338 clear_media_status(&quick_disk_status[drv]);
1339 out_message(_T("QD%d: Ejected"), drv + QD_BASE_NUMBER);
1343 bool EMU::is_quick_disk_inserted(int drv)
1346 return vm->is_quick_disk_inserted(drv);
1354 void EMU::play_tape(const _TCHAR* file_path)
1356 if(vm->is_tape_inserted()) {
1359 #ifdef SUPPORT_VARIABLE_TIMING
1360 tape_status.wait_count = (int)(vm->get_frame_rate() / 2);
1362 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1364 out_message(_T("CMT: Ejected"));
1365 } else if(tape_status.wait_count == 0) {
1366 vm->play_tape(file_path);
1367 out_message(_T("CMT: %s"), file_path);
1369 my_tcscpy_s(tape_status.path, _MAX_PATH, file_path);
1370 tape_status.play = true;
1373 void EMU::rec_tape(const _TCHAR* file_path)
1375 if(vm->is_tape_inserted()) {
1378 #ifdef SUPPORT_VARIABLE_TIMING
1379 tape_status.wait_count = (int)(vm->get_frame_rate() / 2);
1381 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1383 out_message(_T("CMT: Ejected"));
1384 } else if(tape_status.wait_count == 0) {
1385 vm->rec_tape(file_path);
1386 out_message(_T("CMT: %s"), file_path);
1388 my_tcscpy_s(tape_status.path, _MAX_PATH, file_path);
1389 tape_status.play = false;
1392 void EMU::close_tape()
1395 clear_media_status(&tape_status);
1396 out_message(_T("CMT: Ejected"));
1399 bool EMU::is_tape_inserted()
1401 return vm->is_tape_inserted();
1404 #ifndef TAPE_BINARY_ONLY
1405 bool EMU::is_tape_playing()
1407 return vm->is_tape_playing();
1410 bool EMU::is_tape_recording()
1412 return vm->is_tape_recording();
1415 int EMU::get_tape_position()
1417 return vm->get_tape_position();
1421 #ifdef USE_TAPE_BUTTON
1422 void EMU::push_play()
1427 void EMU::push_stop()
1432 void EMU::push_fast_forward()
1434 vm->push_fast_forward();
1437 void EMU::push_fast_rewind()
1439 vm->push_fast_rewind();
1442 void EMU::push_apss_forward()
1444 vm->push_apss_forward();
1447 void EMU::push_apss_rewind()
1449 vm->push_apss_rewind();
1454 #ifdef USE_COMPACT_DISC
1455 void EMU::open_compact_disc(const _TCHAR* file_path)
1457 if(vm->is_compact_disc_inserted()) {
1458 vm->close_compact_disc();
1460 #ifdef SUPPORT_VARIABLE_TIMING
1461 compact_disc_status.wait_count = (int)(vm->get_frame_rate() / 2);
1463 compact_disc_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1465 out_message(_T("CD: Ejected"));
1466 } else if(compact_disc_status.wait_count == 0) {
1467 vm->open_compact_disc(file_path);
1468 out_message(_T("CD: %s"), file_path);
1470 my_tcscpy_s(compact_disc_status.path, _MAX_PATH, file_path);
1473 void EMU::close_compact_disc()
1475 vm->close_compact_disc();
1476 clear_media_status(&compact_disc_status);
1477 out_message(_T("CD: Ejected"));
1480 bool EMU::is_compact_disc_inserted()
1482 return vm->is_compact_disc_inserted();
1486 #ifdef USE_LASER_DISC
1487 void EMU::open_laser_disc(const _TCHAR* file_path)
1489 if(vm->is_laser_disc_inserted()) {
1490 vm->close_laser_disc();
1492 #ifdef SUPPORT_VARIABLE_TIMING
1493 laser_disc_status.wait_count = (int)(vm->get_frame_rate() / 2);
1495 laser_disc_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1497 out_message(_T("LD: Ejected"));
1498 } else if(laser_disc_status.wait_count == 0) {
1499 vm->open_laser_disc(file_path);
1500 out_message(_T("LD: %s"), file_path);
1502 my_tcscpy_s(laser_disc_status.path, _MAX_PATH, file_path);
1505 void EMU::close_laser_disc()
1507 vm->close_laser_disc();
1508 clear_media_status(&laser_disc_status);
1509 out_message(_T("LD: Ejected"));
1512 bool EMU::is_laser_disc_inserted()
1514 return vm->is_laser_disc_inserted();
1518 #ifdef USE_BINARY_FILE1
1519 void EMU::load_binary(int drv, const _TCHAR* file_path)
1521 if(drv < MAX_BINARY) {
1522 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
1523 vm->load_binary(drv, create_local_path(_T("hex2bin.$$$")));
1524 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
1526 vm->load_binary(drv, file_path);
1528 out_message(_T("Load: %s"), file_path);
1532 void EMU::save_binary(int drv, const _TCHAR* file_path)
1534 if(drv < MAX_BINARY) {
1535 vm->save_binary(drv, file_path);
1536 out_message(_T("Save: %s"), file_path);
1541 void EMU::open_bubble_casette(int drv, const _TCHAR* file_path, int bank)
1543 if(drv < MAX_BUBBLE) {
1544 if(vm->is_bubble_casette_inserted(drv)) {
1545 vm->close_bubble_casette(drv);
1547 #ifdef SUPPORT_VARIABLE_TIMING
1548 bubble_casette_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
1550 bubble_casette_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1552 out_message(_T("Bubble%d: Ejected"), drv + 1);
1553 } else if(bubble_casette_status[drv].wait_count == 0) {
1554 vm->open_bubble_casette(drv, file_path, bank);
1555 out_message(_T("Bubble%d: %s"), drv + 1, file_path);
1557 my_tcscpy_s(bubble_casette_status[drv].path, _MAX_PATH, file_path);
1558 bubble_casette_status[drv].bank = bank;
1562 void EMU::close_bubble_casette(int drv)
1564 if(drv < MAX_BUBBLE) {
1565 vm->close_bubble_casette(drv);
1566 clear_media_status(&bubble_casette_status[drv]);
1567 out_message(_T("Bubble%d: Ejected"), drv + 1);
1571 bool EMU::is_bubble_casette_inserted(int drv)
1573 if(drv < MAX_BUBBLE) {
1574 return vm->is_bubble_casette_inserted(drv);
1580 bool EMU::is_bubble_casette_protected(int drv)
1582 if(drv < MAX_BUBBLE) {
1583 return vm->is_bubble_casette_protected(drv);
1589 void EMU::is_bubble_casette_protected(int drv, bool flag)
1591 if(drv < MAX_BUBBLE) {
1592 return vm->is_bubble_casette_protected(drv, flag);
1599 #ifdef USE_ACCESS_LAMP
1600 uint32_t EMU::get_access_lamp_status()
1602 return vm->get_access_lamp_status();
1606 #ifdef USE_LED_DEVICE
1607 uint32_t EMU::get_led_status()
1609 return vm->get_led_status();
1613 #ifdef USE_SOUND_VOLUME
1614 void EMU::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
1616 vm->set_sound_device_volume(ch, decibel_l, decibel_r);
1620 void EMU::update_config()
1622 vm->update_config();
1627 // ----------------------------------------------------------------------------
1629 // ----------------------------------------------------------------------------
1632 #define STATE_VERSION 2
1634 void EMU::save_state()
1636 save_state_tmp(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)));
1639 void EMU::load_state()
1641 if(FILEIO::IsFileExisting(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)))) {
1642 save_state_tmp(create_local_path(_T("$temp$.sta")));
1643 if(!load_state_tmp(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)))) {
1644 out_debug_log(_T("failed to load state file\n"));
1645 load_state_tmp(create_local_path(_T("$temp$.sta")));
1647 FILEIO::RemoveFile(create_local_path(_T("$temp$.sta")));
1651 void EMU::save_state_tmp(const _TCHAR* file_path)
1653 FILEIO* fio = new FILEIO();
1655 if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
1656 // save state file version
1657 fio->FputUint32(STATE_VERSION);
1659 save_config_state((void *)fio);
1660 // save inserted medias
1662 fio->Fwrite(&cart_status, sizeof(cart_status), 1);
1665 fio->Fwrite(floppy_disk_status, sizeof(floppy_disk_status), 1);
1666 fio->Fwrite(d88_file, sizeof(d88_file), 1);
1669 fio->Fwrite(&quick_disk_status, sizeof(quick_disk_status), 1);
1672 fio->Fwrite(&tape_status, sizeof(tape_status), 1);
1674 #ifdef USE_COMPACT_DISC
1675 fio->Fwrite(&compact_disc_status, sizeof(compact_disc_status), 1);
1677 #ifdef USE_LASER_DISC
1678 fio->Fwrite(&laser_disc_status, sizeof(laser_disc_status), 1);
1681 fio->Fwrite(floppy_disk_status, sizeof(floppy_disk_status), 1);
1682 fio->Fwrite(d88_file, sizeof(d88_file), 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);