OSDN Git Service

[VM][Qt][OSD][Genaral] Sync to upstream ; phase 1: Merege upstream 20151217.
[csp-qt/common_source_project-fm7.git] / source / src / emu.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.08.18 -
6
7         [ win32 emulation i/f ]
8 */
9
10 #include "emu.h"
11 #include "vm/vm.h"
12 #include "fileio.h"
13 #if defined(_USE_AGAR)
14 #include <SDL/SDL.h>
15 #include "agar_main.h"
16 #include "agar_logger.h"
17 #include <ctime>
18 # elif defined(_USE_QT)
19 //#include <SDL/SDL.h>
20
21 #include "qt_main.h"
22 #include "mainwidget.h"
23 #include "qt_gldraw.h"
24
25 #include "agar_logger.h"
26 #include <ctime>
27 # endif
28
29 #ifndef FD_BASE_NUMBER
30 #define FD_BASE_NUMBER 1
31 #endif
32 #ifndef QD_BASE_NUMBER
33 #define QD_BASE_NUMBER 1
34 #endif
35
36 // ----------------------------------------------------------------------------
37 // initialize
38 // ----------------------------------------------------------------------------
39 #if defined(_USE_QT)
40 extern void get_long_full_path_name(_TCHAR* src, _TCHAR* dst);
41 #include <string>
42 #endif
43
44 #if defined(_USE_QT)
45 EMU::EMU(class Ui_MainWindow *hwnd, GLDrawClass *hinst)
46 #elif defined(OSD_WIN32)
47 EMU::EMU(HWND hwnd, HINSTANCE hinst)
48 #else
49 EMU::EMU()
50 #endif
51 {
52 #ifdef _DEBUG_LOG
53         initialize_debug_log();
54 #endif
55         message_count = 0;
56         
57         // store main window handle
58 #if !defined(_USE_QT)
59         // check os version
60         OSVERSIONINFO os_info;
61         os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
62         GetVersionEx(&os_info);
63         vista_or_later = (os_info.dwPlatformId == 2 && os_info.dwMajorVersion >= 6);
64 #endif  
65         // get module path
66         // Initialize keymod.
67 #if defined(_USE_QT)
68         std::string tmps;
69         _TCHAR tmp_path[PATH_MAX], *ptr;
70         my_procname.copy(tmp_path, PATH_MAX, 0);
71         memset(app_path, 0x00, sizeof(app_path));
72         get_long_full_path_name(tmp_path, app_path);
73         //AGAR_DebugLog("APPPATH=%s\n", app_path);
74         host_cpus = 4;
75 #else
76         _TCHAR tmp_path[_MAX_PATH], *ptr;
77         memset(tmp_path, 0x00, _MAX_PATH);
78         GetModuleFileName(NULL, tmp_path, _MAX_PATH);
79         GetFullPathName(tmp_path, _MAX_PATH, app_path, &ptr);
80         *ptr = _T('\0');
81 #endif  
82 #ifdef USE_FD1
83                 // initialize d88 file info
84         memset(d88_file, 0, sizeof(d88_file));
85 #endif
86                 // load sound config
87         static const int freq_table[8] = {
88                         2000, 4000, 8000, 11025, 22050, 44100,
89 #ifdef OVERRIDE_SOUND_FREQ_48000HZ
90                         OVERRIDE_SOUND_FREQ_48000HZ,
91 #else
92                         48000,
93 #endif
94                         96000,
95         };
96         static const double late_table[5] = {0.05, 0.1, 0.2, 0.3, 0.4};
97         
98         if(!(0 <= config.sound_frequency && config.sound_frequency < 8)) {
99                 config.sound_frequency = 6;     // default: 48KHz
100         }
101         if(!(0 <= config.sound_latency && config.sound_latency < 5)) {
102                 config.sound_latency = 1;       // default: 100msec
103         }
104         sound_rate = freq_table[config.sound_frequency];
105         sound_samples = (int)(sound_rate * late_table[config.sound_latency] + 0.5);
106                 
107 #ifdef USE_CPU_TYPE
108         cpu_type = config.cpu_type;
109 #endif
110 #ifdef USE_SOUND_DEVICE_TYPE
111         sound_device_type = config.sound_device_type;
112 #endif
113         osd = new OSD();
114 #if defined(_USE_QT)
115         osd->main_window_handle = hwnd;
116         osd->glv = hinst;
117 #endif  
118         osd->initialize(sound_rate, sound_samples);
119         osd->lock_vm();
120         osd->vm = vm = new VM(this);
121         
122         initialize_media();
123         osd->initialize_printer();
124         vm->initialize_sound(sound_rate, sound_samples);
125         vm->reset();
126         osd->unlock_vm();
127         
128         now_suspended = false;
129 }
130
131 EMU::~EMU()
132 {
133         osd->release();
134         delete osd;
135         delete vm;
136
137 #ifdef _DEBUG_LOG
138         release_debug_log();
139 #endif
140 }
141
142 #ifdef OSD_QT
143 EmuThreadClass *EMU::get_parent_handler()
144 {
145         return osd->get_parent_handler();
146 }
147
148 void EMU::set_parent_handler(EmuThreadClass *p, DrawThreadClass *q)
149 {
150         osd->set_parent_thread(p);
151         osd->set_draw_thread(q);
152 }
153
154 void EMU::set_host_cpus(int v)
155 {
156         osd->host_cpus = (v <= 0) ? 1 : v;
157 }
158
159 int EMU::get_host_cpus()
160 {
161         return osd->host_cpus;
162 }
163 #endif
164
165 // ----------------------------------------------------------------------------
166 // drive machine
167 // ----------------------------------------------------------------------------
168
169 int EMU::frame_interval()
170 {
171 #if 1
172 #ifdef SUPPORT_VARIABLE_TIMING
173         static int prev_interval = 0;
174         static double prev_fps = -1;
175         double fps = vm->frame_rate();
176         if(prev_fps != fps) {
177                 prev_interval = (int)(1024. * 1000. / fps + 0.5);
178                 prev_fps = fps;
179         }
180         return prev_interval;
181 #else
182         return (int)(1024. * 1000. / FRAMES_PER_SEC + 0.5);
183 #endif
184 #else
185         return (int)(1024. * 1000. / FRAMES_PER_SEC + 0.5);
186 #endif
187 }
188
189 int EMU::run()
190 {
191         if(now_suspended) {
192                 osd->restore();
193                 now_suspended = false;
194         }
195         osd->update_input();
196         osd->update_printer();
197 #ifdef USE_SOCKET
198         //osd->update_socket();
199 #endif
200         update_media();
201         
202         // virtual machine may be driven to fill sound buffer
203         int extra_frames = 0;
204         osd->update_sound(&extra_frames);
205         // drive virtual machine
206         if(extra_frames == 0) {
207                 osd->lock_vm();
208                 vm->run();
209                 extra_frames = 1;
210                 osd->unlock_vm();
211         }
212         osd->add_extra_frames(extra_frames);
213         return extra_frames;
214 }
215
216 void EMU::reset()
217 {
218         // check if virtual machine should be reinitialized
219         bool reinitialize = false;
220 #ifdef USE_CPU_TYPE
221         reinitialize |= (cpu_type != config.cpu_type);
222         cpu_type = config.cpu_type;
223 #endif
224 #ifdef USE_SOUND_DEVICE_TYPE
225         reinitialize |= (sound_device_type != config.sound_device_type);
226         sound_device_type = config.sound_device_type;
227 #endif
228         if(reinitialize) {
229                 // stop sound
230                 osd->stop_sound();
231                 // reinitialize virtual machine
232                 osd->lock_vm();         
233                 delete vm;
234                 osd->vm = vm = new VM(this);
235                 vm->initialize_sound(sound_rate, sound_samples);
236                 vm->reset();
237                 osd->unlock_vm();
238                 // restore inserted medias
239                 restore_media();
240         } else {
241            // reset virtual machine
242                 osd->lock_vm();         
243                 vm->reset();
244                 osd->unlock_vm();               
245         }
246         
247         // reset printer
248         osd->reset_printer();
249
250 #if !defined(_USE_QT) // Temporally
251         // restart recording
252         osd->restart_rec_sound();
253         osd->restart_rec_video();
254 #endif  
255 }
256
257 #ifdef USE_SPECIAL_RESET
258 void EMU::special_reset()
259 {
260         // reset virtual machine
261         osd->lock_vm();         
262         vm->special_reset();
263         osd->unlock_vm();
264         // reset printer
265         osd->reset_printer();
266         
267         // restart recording
268 #if !defined(_USE_QT) // Temporally
269         restart_rec_sound();
270         restart_rec_video();
271 #endif  
272 }
273 #endif
274
275 #ifdef USE_NOTIFY_POWER_OFF
276 void EMU::notify_power_off()
277 {
278         vm->notify_power_off();
279 }
280 #endif
281
282 void EMU::power_off()
283 {
284         osd->power_off();
285 }
286
287 void EMU::suspend()
288 {
289         if(!now_suspended) {
290                 osd->suspend();
291                 now_suspended = true;
292         }
293 }
294
295 void EMU::lock_vm()
296 {
297         osd->lock_vm();
298 }
299
300 void EMU::unlock_vm()
301 {
302         osd->unlock_vm();
303 }
304
305 void EMU::force_unlock_vm()
306 {
307         osd->force_unlock_vm();
308 }
309
310
311 // ----------------------------------------------------------------------------
312 // input
313 // ----------------------------------------------------------------------------
314
315 #ifdef OSD_QT
316 void EMU::key_modifiers(uint32 mod)
317 {
318         osd->key_modifiers(mod);
319 }
320 #endif
321
322 void EMU::key_down(int code, bool repeat)
323 {
324         osd->key_down(code, repeat);
325 }
326
327 void EMU::key_up(int code)
328 {
329         osd->key_up(code);
330 }
331
332 void EMU::key_lost_focus()
333 {
334         osd->key_lost_focus();
335 }
336
337 #ifdef ONE_BOARD_MICRO_COMPUTER
338 void EMU::press_button(int num)
339 {
340         osd->press_button(num);
341 }
342 #endif
343
344 void EMU::enable_mouse()
345 {
346         osd->enable_mouse();
347 }
348
349 void EMU::disenable_mouse()
350 {
351         osd->disenable_mouse();
352 }
353
354 void EMU::toggle_mouse()
355 {
356         osd->toggle_mouse();
357 }
358
359 bool EMU::get_mouse_enabled()
360 {
361         return osd->get_mouse_enabled();
362 }
363
364 #ifdef USE_AUTO_KEY
365 void EMU::start_auto_key()
366 {
367         osd->start_auto_key();
368 }
369
370 void EMU::stop_auto_key()
371 {
372         osd->stop_auto_key();
373 }
374
375 bool EMU::now_auto_key()
376 {
377         return osd->now_auto_key();
378 }
379 #endif
380
381 uint8* EMU::key_buffer()
382 {
383         return osd->key_buffer();
384 }
385
386 uint32* EMU::joy_buffer()
387 {
388         return osd->joy_buffer();
389 }
390 int* EMU::mouse_buffer()
391 {
392         return osd->mouse_buffer();
393 }
394
395 // ----------------------------------------------------------------------------
396 // screen
397 // ----------------------------------------------------------------------------
398
399 int EMU::get_window_width(int mode)
400 {
401         return osd->get_window_width(mode);
402 }
403
404 int EMU::get_window_height(int mode)
405 {
406         return osd->get_window_height(mode);
407 }
408
409 void EMU::set_window_size(int width, int height, bool window_mode)
410 {
411         osd->set_window_size(width, height, window_mode);
412 }
413
414 void EMU::set_vm_screen_size(int sw, int sh, int swa, int sha, int ww, int wh)
415 {
416         osd->set_vm_screen_size(sw, sh, swa, sha, ww, wh);
417 }
418
419 #if defined(USE_MINIMUM_RENDERING)
420 bool EMU::screen_changed()
421 {
422         return vm->screen_changed();
423 }
424 #endif
425
426 int EMU::draw_screen()
427 {
428         return osd->draw_screen();
429 }
430
431 scrntype* EMU::screen_buffer(int y)
432 {
433         return osd->get_vm_screen_buffer(y);
434 }
435
436 #ifdef USE_CRT_FILTER
437 void EMU::screen_skip_line(bool skip_line)
438 {
439         osd->screen_skip_line = skip_line;
440 }
441 #endif
442
443 #ifdef ONE_BOARD_MICRO_COMPUTER
444 void EMU::reload_bitmap()
445 {
446         osd->reload_bitmap();
447 }
448 #endif
449
450 #ifdef OSD_WIN32
451 void EMU::update_screen(HDC hdc)
452 {
453         osd->update_screen(hdc);
454 }
455 #endif
456
457 void EMU::capture_screen()
458 {
459         osd->capture_screen();
460 }
461
462 bool EMU::start_rec_video(int fps)
463 {
464         return osd->start_rec_video(fps);
465 }
466
467 void EMU::stop_rec_video()
468 {
469         osd->stop_rec_video();
470 }
471
472 bool EMU::now_rec_video()
473 {
474         return osd->now_rec_video;
475 }
476
477 // ----------------------------------------------------------------------------
478 // sound
479 // ----------------------------------------------------------------------------
480
481 void EMU::mute_sound()
482 {
483         osd->mute_sound();
484 }
485
486 void EMU::start_rec_sound()
487 {
488         osd->start_rec_sound();
489 }
490
491 void EMU::stop_rec_sound()
492 {
493         osd->stop_rec_sound();
494 }
495
496 bool EMU::now_rec_sound()
497 {
498         return osd->now_rec_sound;
499 }
500
501 // ----------------------------------------------------------------------------
502 // video
503 // ----------------------------------------------------------------------------
504
505 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
506 void EMU::get_video_buffer()
507 {
508         osd->get_video_buffer();
509 }
510
511 void EMU::mute_video_dev(bool l, bool r)
512 {
513         osd->mute_video_dev(l, r);
514 }
515 #endif
516
517 #ifdef USE_MOVIE_PLAYER
518 bool EMU::open_movie_file(const _TCHAR* file_path)
519 {
520         return osd->open_movie_file(file_path);
521 }
522
523 void EMU::close_movie_file()
524 {
525         osd->close_movie_file();
526 }
527
528 void EMU::play_movie()
529 {
530         osd->play_movie();
531 }
532
533 void EMU::stop_movie()
534 {
535         osd->stop_movie();
536 }
537
538 void EMU::pause_movie()
539 {
540         osd->pause_movie();
541 }
542
543 double EMU::get_movie_frame_rate()
544 {
545         return osd->get_movie_frame_rate();
546 }
547
548 int EMU::get_movie_sound_rate()
549 {
550         return osd->get_movie_sound_rate();
551 }
552
553 void EMU::set_cur_movie_frame(int frame, bool relative)
554 {
555         osd->set_cur_movie_frame(frame, relative);
556 }
557
558 uint32 EMU::get_cur_movie_frame()
559 {
560         return osd->get_cur_movie_frame();
561 }
562 #endif
563
564 #ifdef USE_VIDEO_CAPTURE
565 int EMU::get_cur_capture_dev_index()
566 {
567         return osd->get_cur_capture_dev_index();
568 }
569
570 int EMU::get_num_capture_devs()
571 {
572         return osd->get_num_capture_devs();
573 }
574
575 _TCHAR* EMU::get_capture_dev_name(int index)
576 {
577         return osd->get_capture_dev_name(index);
578 }
579
580 void EMU::open_capture_dev(int index, bool pin)
581 {
582         osd->open_capture_dev(index, pin);
583 }
584
585 void EMU::close_capture_dev()
586 {
587         osd->close_capture_dev();
588 }
589
590 void EMU::show_capture_dev_filter()
591 {
592         osd->show_capture_dev_filter();
593 }
594
595 void EMU::show_capture_dev_pin()
596 {
597         osd->show_capture_dev_pin();
598 }
599
600 void EMU::show_capture_dev_source()
601 {
602         osd->show_capture_dev_source();
603 }
604
605 void EMU::set_capture_dev_channel(int ch)
606 {
607         osd->set_capture_dev_channel(ch);
608 }
609 #endif
610
611 // ----------------------------------------------------------------------------
612 // printer
613 // ----------------------------------------------------------------------------
614
615 void EMU::printer_out(uint8 value)
616 {
617         osd->printer_out(value);
618 }
619
620 void EMU::printer_strobe(bool value)
621 {
622         osd->printer_strobe(value);
623 }
624
625 // ----------------------------------------------------------------------------
626 // socket
627 // ----------------------------------------------------------------------------
628
629 #ifdef USE_SOCKET
630 int EMU::get_socket(int ch)
631 {
632         return osd->get_socket(ch);
633 }
634
635 void EMU::socket_connected(int ch)
636 {
637         osd->socket_connected(ch);
638 }
639
640 void EMU::socket_disconnected(int ch)
641 {
642         osd->socket_disconnected(ch);
643 }
644
645 bool EMU::init_socket_tcp(int ch)
646 {
647         return osd->init_socket_tcp(ch);
648 }
649
650 bool EMU::init_socket_udp(int ch)
651 {
652         return osd->init_socket_udp(ch);
653 }
654
655 bool EMU::connect_socket(int ch, uint32 ipaddr, int port)
656 {
657         return osd->connect_socket(ch, ipaddr, port);
658 }
659
660 void EMU::disconnect_socket(int ch)
661 {
662         osd->disconnect_socket(ch);
663 }
664  
665 bool EMU::listen_socket(int ch)
666 {
667         return osd->listen_socket(ch);
668 }
669
670 void EMU::send_data_tcp(int ch)
671 {
672         osd->send_data_tcp(ch);
673 }
674
675 void EMU::send_data_udp(int ch, uint32 ipaddr, int port)
676 {
677         osd->send_data_udp(ch, ipaddr, port);
678 }
679
680 void EMU::send_data(int ch)
681 {
682         osd->send_data(ch);
683 }
684
685 void EMU::recv_data(int ch)
686 {
687         osd->recv_data(ch);
688 }
689 #endif
690
691 // ----------------------------------------------------------------------------
692 // debug log
693 // ----------------------------------------------------------------------------
694
695 #ifdef _DEBUG_LOG
696 void EMU::initialize_debug_log()
697 {
698 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
699         
700 #else // Window
701         TCHAR path[_MAX_PATH];
702         debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
703 #endif
704 }
705
706 void EMU::release_debug_log()
707 {
708 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
709
710 #else
711         if(debug_log) {
712                 fclose(debug_log);
713                 debug_log = NULL;
714         }
715 #endif
716 }
717 #endif
718
719 void EMU::out_debug_log(const _TCHAR* format, ...)
720 {
721 #ifdef _DEBUG_LOG
722         va_list ap;
723         _TCHAR buffer[1024];
724         static _TCHAR prev_buffer[1024] = {0};
725         
726         va_start(ap, format);
727         my_vstprintf_s(buffer, 1024, format, ap);
728         va_end(ap);
729
730 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
731         AGAR_DebugLog(AGAR_LOG_DEBUG, "%s", buffer);
732 #else
733         if(my_tcscmp(prev_buffer, buffer) == 0) {
734                 return;
735         }
736         my_tcscpy_s(prev_buffer, 1024, buffer);
737         if(debug_log) {
738                 _ftprintf(debug_log, _T("%s"), buffer);
739                 static int size = 0;
740                 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
741                         fclose(debug_log);
742                         debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
743                         size = 0;
744                 }
745         }
746 #endif
747 #endif
748 }
749
750 void EMU::out_message(const _TCHAR* format, ...)
751 {
752         va_list ap;
753         va_start(ap, format);
754         my_vstprintf_s(message, 260, format, ap); // Security for MSVC:C6386.
755         va_end(ap);
756         message_count = 4; // 4sec
757 }
758
759 // ----------------------------------------------------------------------------
760 // misc
761 // ----------------------------------------------------------------------------
762
763
764 void EMU::sleep(uint32 ms)
765 {
766         osd->sleep(ms);
767 }
768
769
770 // ----------------------------------------------------------------------------
771 // user interface
772 // ----------------------------------------------------------------------------
773
774 static uint8 hex2uint8(char *value)
775 {
776         char tmp[3];
777         memset(tmp, 0, sizeof(tmp));
778         memcpy(tmp, value, 2);
779         return (uint8)strtoul(tmp, NULL, 16);
780 }
781
782 static uint16 hex2uint16(char *value)
783 {
784         char tmp[5];
785         memset(tmp, 0, sizeof(tmp));
786         memcpy(tmp, value, 4);
787         return (uint16)strtoul(tmp, NULL, 16);
788 }
789
790 static bool hex2bin(const _TCHAR* file_path, const _TCHAR* dest_path)
791 {
792         bool result = false;
793         FILEIO *fio_s = new FILEIO();
794         if(fio_s->Fopen(file_path, FILEIO_READ_BINARY)) {
795                 int length = 0;
796                 char line[1024];
797                 uint8 buffer[0x10000];
798                 memset(buffer, 0xff, sizeof(buffer));
799                 while(fio_s->Fgets(line, sizeof(line)) != NULL) {
800                         if(line[0] != ':') continue;
801                         int bytes = hex2uint8(line + 1);
802                         int offset = hex2uint16(line + 3);
803                         uint8 record_type = hex2uint8(line + 7);
804                         if(record_type == 0x01) break;
805                         if(record_type != 0x00) continue;
806                         for(int i = 0; i < bytes; i++) {
807                                 if(offset + i < sizeof(buffer)) {
808                                         if(length < offset + i) {
809                                                 length = offset + i;
810                                         }
811                                         buffer[offset + i] = hex2uint8(line + 9 + 2 * i);
812                                 }
813                         }
814                 }
815                 if(length > 0) {
816                         FILEIO *fio_d = new FILEIO();
817                         if(fio_d->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
818                                 fio_d->Fwrite(buffer, length, 1);
819                                 fio_d->Fclose();
820                                 result = true;
821                         }
822                         delete fio_d;
823                 }
824                 fio_s->Fclose();
825         }
826         delete fio_s;
827         return result;
828 }
829
830 void EMU::initialize_media()
831 {
832 #ifdef USE_CART1
833         memset(&cart_status, 0, sizeof(cart_status));
834 #endif
835 #ifdef USE_FD1
836         memset(disk_status, 0, sizeof(disk_status));
837 #endif
838 #ifdef USE_QD1
839         memset(&quickdisk_status, 0, sizeof(quickdisk_status));
840 #endif
841 #ifdef USE_TAPE
842         memset(&tape_status, 0, sizeof(tape_status));
843 #endif
844 #ifdef USE_LASER_DISC
845         memset(&laser_disc_status, 0, sizeof(laser_disc_status));
846 #endif
847 }
848
849
850 void EMU::update_media()
851 {
852 #ifdef USE_FD1
853         for(int drv = 0; drv < MAX_FD; drv++) {
854                 if(disk_status[drv].wait_count != 0 && --disk_status[drv].wait_count == 0) {
855                         vm->open_disk(drv, disk_status[drv].path, disk_status[drv].bank);
856                         out_message(_T("FD%d: %s"), drv + FD_BASE_NUMBER, disk_status[drv].path);
857                 }
858         }
859 #endif
860 #ifdef USE_QD1
861         for(int drv = 0; drv < MAX_QD; drv++) {
862                 if(quickdisk_status[drv].wait_count != 0 && --quickdisk_status[drv].wait_count == 0) {
863                         vm->open_quickdisk(drv, quickdisk_status[drv].path);
864                         out_message(_T("QD%d: %s"), drv + QD_BASE_NUMBER, quickdisk_status[drv].path);
865                 }
866         }
867 #endif
868 #ifdef USE_TAPE
869         if(tape_status.wait_count != 0 && --tape_status.wait_count == 0) {
870                 if(tape_status.play) {
871                         vm->play_tape(tape_status.path);
872                 } else {
873                         vm->rec_tape(tape_status.path);
874                 }
875                 out_message(_T("CMT: %s"), tape_status.path);
876         }
877 #endif
878 #ifdef USE_LASER_DISC
879         if(laser_disc_status.wait_count != 0 && --laser_disc_status.wait_count == 0) {
880                 vm->open_laser_disc(laser_disc_status.path);
881                 out_message(_T("LD: %s"), laser_disc_status.path);
882         }
883 #endif
884 }
885
886 void EMU::restore_media()
887 {
888 #ifdef USE_CART1
889         for(int drv = 0; drv < MAX_CART; drv++) {
890                 if(cart_status[drv].path[0] != _T('\0')) {
891                         if(check_file_extension(cart_status[drv].path, _T(".hex")) && hex2bin(cart_status[drv].path, create_local_path(_T("hex2bin.$$$")))) {
892                                 vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
893                                 FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
894                         } else {
895                                 vm->open_cart(drv, cart_status[drv].path);
896                         }
897                 }
898         }
899 #endif
900 #ifdef USE_FD1
901         for(int drv = 0; drv < MAX_FD; drv++) {
902                 if(disk_status[drv].path[0] != _T('\0')) {
903                         vm->open_disk(drv, disk_status[drv].path, disk_status[drv].bank);
904                 }
905         }
906 #endif
907 #ifdef USE_QD1
908         for(int drv = 0; drv < MAX_QD; drv++) {
909                 if(quickdisk_status[drv].path[0] != _T('\0')) {
910                         vm->open_quickdisk(drv, quickdisk_status[drv].path);
911                 }
912         }
913 #endif
914 #ifdef USE_TAPE
915         if(tape_status.path[0] != _T('\0')) {
916                 if(tape_status.play) {
917                         vm->play_tape(tape_status.path);
918                 } else {
919                         tape_status.path[0] = _T('\0');
920                 }
921         }
922 #endif
923 #ifdef USE_LASER_DISC
924         if(laser_disc_status.path[0] != _T('\0')) {
925                 vm->open_laser_disc(laser_disc_status.path);
926         }
927 #endif
928 }
929
930 #ifdef USE_CART1
931 void EMU::open_cart(int drv, const _TCHAR* file_path)
932 {
933         if(drv < MAX_CART) {
934                 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
935                         vm->open_cart(drv, create_local_path(_T("hex2bin.$$$")));
936                         FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
937                 } else {
938                         vm->open_cart(drv, file_path);
939                 }
940                 my_tcscpy_s(cart_status[drv].path, _MAX_PATH, file_path);
941                 out_message(_T("Cart%d: %s"), drv + 1, file_path);
942                 
943                 // restart recording
944                 bool s = osd->now_rec_sound;
945                 bool v = osd->now_rec_video;
946                 stop_rec_sound();
947                 stop_rec_video();
948                 if(s) osd->start_rec_sound();
949                 if(v) osd->start_rec_video(-1);
950         }
951 }
952
953 void EMU::close_cart(int drv)
954 {
955         if(drv < MAX_CART) {
956                 vm->close_cart(drv);
957                 clear_media_status(&cart_status[drv]);
958                 out_message(_T("Cart%d: Ejected"), drv + 1);
959                 
960                 // stop recording
961                 stop_rec_video();
962                 stop_rec_sound();
963         }
964 }
965
966 bool EMU::cart_inserted(int drv)
967 {
968         if(drv < MAX_CART) {
969                 return vm->cart_inserted(drv);
970         } else {
971                 return false;
972         }
973 }
974 #endif
975
976 #ifdef USE_FD1
977 void EMU::open_disk(int drv, const _TCHAR* file_path, int bank)
978 {
979         if(drv < MAX_FD) {
980                 if(vm->disk_inserted(drv)) {
981                         vm->close_disk(drv);
982                         // wait 0.5sec
983 #ifdef SUPPORT_VARIABLE_TIMING
984                         disk_status[drv].wait_count = (int)(vm->frame_rate() / 2);
985 #else
986                         disk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
987 #endif
988                         out_message(_T("FD%d: Ejected"), drv + FD_BASE_NUMBER);
989                 } else if(disk_status[drv].wait_count == 0) {
990                         vm->open_disk(drv, file_path, bank);
991                         out_message(_T("FD%d: %s"), drv + FD_BASE_NUMBER, file_path);
992                 }
993                 my_tcscpy_s(disk_status[drv].path, _MAX_PATH, file_path);
994                 disk_status[drv].bank = bank;
995         }
996 }
997
998 void EMU::close_disk(int drv)
999 {
1000         if(drv < MAX_FD) {
1001                 vm->close_disk(drv);
1002                 clear_media_status(&disk_status[drv]);
1003                 out_message(_T("FD%d: Ejected"), drv + FD_BASE_NUMBER);
1004         }
1005 }
1006
1007 bool EMU::disk_inserted(int drv)
1008 {
1009         if(drv < MAX_FD) {
1010                 return vm->disk_inserted(drv);
1011         } else {
1012                 return false;
1013         }
1014 }
1015
1016 void EMU::set_disk_protected(int drv, bool value)
1017 {
1018         if(drv < MAX_FD) {
1019                 vm->set_disk_protected(drv, value);
1020         }
1021 }
1022
1023 bool EMU::get_disk_protected(int drv)
1024 {
1025         if(drv < MAX_FD) {
1026                 return vm->get_disk_protected(drv);
1027         } else {
1028                 return false;
1029         }
1030 }
1031 #endif
1032
1033 int EMU::get_access_lamp(void)
1034 {
1035    int stat = 0;
1036 #if defined(USE_ACCESS_LAMP)
1037 # if defined(USE_FD1) || defined(USE_QD1)
1038 #  if !defined(_MSC_VER)
1039 //   LockVM();
1040 #  endif
1041
1042    stat = vm->access_lamp(); // Return accessing drive number.
1043 #  if !defined(_MSC_VER)
1044 //   UnlockVM();
1045 #  endif
1046 # endif
1047 #endif
1048    return stat;
1049 }
1050
1051
1052 #ifdef USE_QD1
1053 void EMU::open_quickdisk(int drv, const _TCHAR* file_path)
1054 {
1055         if(drv < MAX_QD) {
1056                 if(vm->quickdisk_inserted(drv)) {
1057                         vm->close_quickdisk(drv);
1058                         // wait 0.5sec
1059 #ifdef SUPPORT_VARIABLE_TIMING
1060                         quickdisk_status[drv].wait_count = (int)(vm->frame_rate() / 2);
1061 #else
1062                         quickdisk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1063 #endif
1064                         out_message(_T("QD%d: Ejected"), drv + QD_BASE_NUMBER);
1065                 } else if(quickdisk_status[drv].wait_count == 0) {
1066                         vm->open_quickdisk(drv, file_path);
1067                         out_message(_T("QD%d: %s"), drv + QD_BASE_NUMBER, file_path);
1068                 }
1069                 my_tcscpy_s(quickdisk_status[drv].path, _MAX_PATH, file_path);
1070         }
1071 }
1072
1073 void EMU::close_quickdisk(int drv)
1074 {
1075         if(drv < MAX_QD) {
1076                 vm->close_quickdisk(drv);
1077                 clear_media_status(&quickdisk_status[drv]);
1078                 out_message(_T("QD%d: Ejected"), drv + QD_BASE_NUMBER);
1079         }
1080 }
1081
1082 bool EMU::quickdisk_inserted(int drv)
1083 {
1084         if(drv < MAX_QD) {
1085                 return vm->quickdisk_inserted(drv);
1086         } else {
1087                 return false;
1088         }
1089 }
1090 #endif
1091
1092 #ifdef USE_TAPE
1093 void EMU::play_tape(const _TCHAR* file_path)
1094 {
1095         if(vm->tape_inserted()) {
1096                 vm->close_tape();
1097                 // wait 0.5sec
1098 #ifdef SUPPORT_VARIABLE_TIMING
1099                 tape_status.wait_count = (int)(vm->frame_rate() / 2);
1100 #else
1101                 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1102 #endif
1103                 out_message(_T("CMT: Ejected"));
1104         } else if(tape_status.wait_count == 0) {
1105                 vm->play_tape(file_path);
1106                 out_message(_T("CMT: %s"), file_path);
1107         }
1108         my_tcscpy_s(tape_status.path, _MAX_PATH, file_path);
1109         tape_status.play = true;
1110 }
1111
1112 void EMU::rec_tape(const _TCHAR* file_path)
1113 {
1114         if(vm->tape_inserted()) {
1115                 vm->close_tape();
1116                 // wait 0.5sec
1117 #ifdef SUPPORT_VARIABLE_TIMING
1118                 tape_status.wait_count = (int)(vm->frame_rate() / 2);
1119 #else
1120                 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1121 #endif
1122                 out_message(_T("CMT: Ejected"));
1123         } else if(tape_status.wait_count == 0) {
1124                 vm->rec_tape(file_path);
1125                 out_message(_T("CMT: %s"), file_path);
1126         }
1127         my_tcscpy_s(tape_status.path, _MAX_PATH, file_path);
1128         tape_status.play = false;
1129 }
1130
1131 void EMU::close_tape()
1132 {
1133         vm->close_tape();
1134         clear_media_status(&tape_status);
1135         out_message(_T("CMT: Ejected"));
1136 }
1137
1138 bool EMU::tape_inserted()
1139 {
1140         return vm->tape_inserted();
1141 }
1142
1143 #ifndef TAPE_BINARY_ONLY
1144 bool EMU::tape_playing()
1145 {
1146         return vm->tape_playing();
1147 }
1148
1149 bool EMU::tape_recording()
1150 {
1151         return vm->tape_recording();
1152 }
1153
1154 int EMU::tape_position()
1155 {
1156         return vm->tape_position();
1157 }
1158 #endif
1159
1160 #ifdef USE_TAPE_BUTTON
1161 void EMU::push_play()
1162 {
1163         vm->push_play();
1164 }
1165
1166 void EMU::push_stop()
1167 {
1168         vm->push_stop();
1169 }
1170
1171 void EMU::push_fast_forward()
1172 {
1173         vm->push_fast_forward();
1174 }
1175
1176 void EMU::push_fast_rewind()
1177 {
1178         vm->push_fast_rewind();
1179 }
1180
1181 void EMU::push_apss_forward()
1182 {
1183         vm->push_apss_forward();
1184 }
1185
1186 void EMU::push_apss_rewind()
1187 {
1188         vm->push_apss_rewind();
1189 }
1190 #endif
1191 #endif
1192
1193 #ifdef USE_LASER_DISC
1194 void EMU::open_laser_disc(const _TCHAR* file_path)
1195 {
1196         if(vm->laser_disc_inserted()) {
1197                 vm->close_laser_disc();
1198                 // wait 0.5sec
1199 #ifdef SUPPORT_VARIABLE_TIMING
1200                 laser_disc_status.wait_count = (int)(vm->frame_rate() / 2);
1201 #else
1202                 laser_disc_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1203 #endif
1204                 out_message(_T("LD: Ejected"));
1205         } else if(laser_disc_status.wait_count == 0) {
1206                 vm->open_laser_disc(file_path);
1207                 out_message(_T("LD: %s"), file_path);
1208         }
1209         my_tcscpy_s(laser_disc_status.path, _MAX_PATH, file_path);
1210 }
1211
1212 void EMU::close_laser_disc()
1213 {
1214         vm->close_laser_disc();
1215         clear_media_status(&laser_disc_status);
1216         out_message(_T("LD: Ejected"));
1217 }
1218
1219 bool EMU::laser_disc_inserted()
1220 {
1221         return vm->laser_disc_inserted();
1222 }
1223 #endif
1224
1225 #ifdef USE_BINARY_FILE1
1226 void EMU::load_binary(int drv, const _TCHAR* file_path)
1227 {
1228         if(drv < MAX_BINARY) {
1229                 if(check_file_extension(file_path, _T(".hex")) && hex2bin(file_path, create_local_path(_T("hex2bin.$$$")))) {
1230                         vm->load_binary(drv, create_local_path(_T("hex2bin.$$$")));
1231                         FILEIO::RemoveFile(create_local_path(_T("hex2bin.$$$")));
1232                 } else {
1233                         vm->load_binary(drv, file_path);
1234                 }
1235                 out_message(_T("Load: %s"), file_path);
1236         }
1237 }
1238
1239 void EMU::save_binary(int drv, const _TCHAR* file_path)
1240 {
1241         if(drv < MAX_BINARY) {
1242                 vm->save_binary(drv, file_path);
1243                 out_message(_T("Save: %s"), file_path);
1244         }
1245 }
1246 #endif
1247 #ifdef SUPPORT_DUMMY_DEVICE_LED
1248 uint32 EMU::get_led_status(void)
1249 {
1250         return vm->get_led_status();
1251 }
1252 #endif
1253
1254 bool EMU::now_skip()
1255 {
1256         return vm->now_skip();
1257 }
1258
1259 void EMU::update_config()
1260 {
1261         vm->update_config();
1262 }
1263
1264
1265
1266 // ----------------------------------------------------------------------------
1267 // state
1268 // ----------------------------------------------------------------------------
1269
1270 #ifdef USE_STATE
1271 #define STATE_VERSION   2
1272
1273 void EMU::save_state()
1274 {
1275         save_state_tmp(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)));
1276 }
1277
1278 void EMU::load_state()
1279 {
1280         const _TCHAR *file_name = create_local_path(_T("%s.sta"), _T(CONFIG_NAME));
1281         if(FILEIO::IsFileExists(file_name)) {
1282                 save_state_tmp(create_local_path(_T("$temp$.sta")));
1283                 if(!load_state_tmp(file_name)) {
1284                         out_debug_log("failed to load state file\n");
1285                         load_state_tmp(create_local_path(_T("$temp$.sta")));
1286                 }
1287                 FILEIO::RemoveFile(create_local_path(_T("$temp$.sta")));
1288         }
1289 }
1290
1291 void EMU::save_state_tmp(const _TCHAR* file_path)
1292 {
1293         FILEIO* fio = new FILEIO();
1294         osd->lock_vm();
1295         if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
1296                 // save state file version
1297                 fio->FputUint32(STATE_VERSION);
1298                 // save config
1299                 save_config_state((void *)fio);
1300                 // save inserted medias
1301 #ifdef USE_CART1
1302                 fio->Fwrite(&cart_status, sizeof(cart_status), 1);
1303 #endif
1304 #ifdef USE_FD1
1305                 fio->Fwrite(disk_status, sizeof(disk_status), 1);
1306                 fio->Fwrite(d88_file, sizeof(d88_file), 1);
1307 #endif
1308 #ifdef USE_QD1
1309                 fio->Fwrite(&quickdisk_status, sizeof(quickdisk_status), 1);
1310 #endif
1311 #ifdef USE_TAPE
1312                 fio->Fwrite(&tape_status, sizeof(tape_status), 1);
1313 #endif
1314 #ifdef USE_LASER_DISC
1315                 fio->Fwrite(&laser_disc_status, sizeof(laser_disc_status), 1);
1316 #endif
1317                 // save vm state
1318                 vm->save_state(fio);
1319                 // end of state file
1320                 fio->FputInt32(-1);
1321                 fio->Fclose();
1322         }
1323         osd->unlock_vm();
1324         delete fio;
1325 }
1326
1327 bool EMU::load_state_tmp(const _TCHAR* file_path)
1328 {
1329         bool result = false;
1330         FILEIO* fio = new FILEIO();
1331         osd->lock_vm();
1332         if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
1333                 // check state file version
1334                 if(fio->FgetUint32() == STATE_VERSION) {
1335                         // load config
1336                         if(load_config_state((void *)fio)) {
1337                                 // load inserted medias
1338 #ifdef USE_CART1
1339                                 fio->Fread(&cart_status, sizeof(cart_status), 1);
1340 #endif
1341 #ifdef USE_FD1
1342                                 fio->Fread(disk_status, sizeof(disk_status), 1);
1343                                 fio->Fread(d88_file, sizeof(d88_file), 1);
1344 #endif
1345 #ifdef USE_QD1
1346                                 fio->Fread(&quickdisk_status, sizeof(quickdisk_status), 1);
1347 #endif
1348 #ifdef USE_TAPE
1349                                 fio->Fread(&tape_status, sizeof(tape_status), 1);
1350 #endif
1351 #ifdef USE_LASER_DISC
1352                                 fio->Fread(&laser_disc_status, sizeof(laser_disc_status), 1);
1353 #endif
1354                                 // check if virtual machine should be reinitialized
1355                                 bool reinitialize = false;
1356 #ifdef USE_CPU_TYPE
1357                                 reinitialize |= (cpu_type != config.cpu_type);
1358                                 cpu_type = config.cpu_type;
1359 #endif
1360 #ifdef USE_SOUND_DEVICE_TYPE
1361                                 reinitialize |= (sound_device_type != config.sound_device_type);
1362                                 sound_device_type = config.sound_device_type;
1363 #endif
1364                                 if(reinitialize) {
1365                                         // stop sound
1366                                         //osd->lock_vm();
1367                                         // reinitialize virtual machine
1368                                         osd->stop_sound();
1369                                         delete vm;
1370                                         osd->vm = vm = new VM(this);
1371                                         vm->initialize_sound(sound_rate, sound_samples);
1372                                         vm->reset();
1373                                         //osd->unlock_vm();
1374                                 }
1375                                 // restore inserted medias
1376                                 restore_media();
1377                                 // load vm state
1378                                 if(vm->load_state(fio)) {
1379                                         // check end of state
1380                                         result = (fio->FgetInt32() == -1);
1381                                 }
1382                         }
1383                 }
1384                 fio->Fclose();
1385         }
1386         osd->unlock_vm();
1387         delete fio;
1388         return result;
1389 }
1390 #endif
1391
1392 #if defined(USE_DIG_RESOLUTION)
1393 void EMU::get_screen_resolution(int *w, int *h)
1394 {
1395         vm->get_screen_resolution(w, h);
1396 }
1397 #endif