OSDN Git Service

[VM][FM7][WIP] Fix still not working some software without re-construct VMs at FM...
[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 #if defined(_USE_QT)
11 #include <string>
12 #endif
13 #include "emu.h"
14 #include "vm/vm.h"
15 #include "fifo.h"
16 #include "fileio.h"
17
18 #ifndef FD_BASE_NUMBER
19 #define FD_BASE_NUMBER 1
20 #endif
21 #ifndef QD_BASE_NUMBER
22 #define QD_BASE_NUMBER 1
23 #endif
24
25 // ----------------------------------------------------------------------------
26 // initialize
27 // ----------------------------------------------------------------------------
28 #if defined(_USE_QT)
29 // Please permit at least them m(.. )m
30 //extern void get_long_full_path_name(_TCHAR* src, _TCHAR* dst);
31 #include <string>
32 #endif
33
34 #if defined(_USE_QT)
35 EMU::EMU(class Ui_MainWindow *hwnd, GLDrawClass *hinst)
36 #elif defined(OSD_WIN32)
37 EMU::EMU(HWND hwnd, HINSTANCE hinst)
38 #else
39 EMU::EMU()
40 #endif
41 {
42         message_count = 0;
43         // store main window handle
44 #ifdef USE_FD1
45         // initialize d88 file info
46         memset(d88_file, 0, sizeof(d88_file));
47 #endif
48 #ifdef USE_BUBBLE1
49         // initialize d88 file info
50         memset(b77_file, 0, sizeof(b77_file));
51 #endif
52         // load sound config
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,
57 #else
58                 48000,
59 #endif
60                 96000,
61         };
62         static const double late_table[5] = {0.05, 0.1, 0.2, 0.3, 0.4};
63         
64         if(!(0 <= config.sound_frequency && config.sound_frequency < 8)) {
65                 config.sound_frequency = 6;     // default: 48KHz
66         }
67         if(!(0 <= config.sound_latency && config.sound_latency < 5)) {
68                 config.sound_latency = 1;       // default: 100msec
69         }
70         sound_rate = freq_table[config.sound_frequency];
71         sound_samples = (int)(sound_rate * late_table[config.sound_latency] + 0.5);
72
73 #ifdef USE_CPU_TYPE
74         cpu_type = config.cpu_type;
75 #endif
76 #ifdef USE_SOUND_DEVICE_TYPE
77         sound_device_type = config.sound_device_type;
78 #endif
79 #ifdef USE_PRINTER
80         printer_device_type = config.printer_device_type;
81 #endif
82         
83         // initialize osd
84         osd = new OSD();
85 #if defined(OSD_QT)
86         osd->main_window_handle = hwnd;
87         osd->glv = hinst;
88         osd->host_cpus = 4;
89 #elif defined(OSD_WIN32)
90         osd->main_window_handle = hwnd;
91         osd->instance_handle = hinst;
92 #endif
93         osd->initialize(sound_rate, sound_samples);
94         // initialize vm
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)
101         delete vm;
102         osd->vm = vm = new VM(this);
103 #endif
104 #ifdef USE_AUTO_KEY
105         initialize_auto_key();
106 #endif
107 #ifdef USE_DEBUGGER
108         initialize_debugger();
109 #endif
110         initialize_media();
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]);
115         }
116 #endif
117         vm->reset();
118         now_suspended = false;
119 }
120
121 EMU::~EMU()
122 {
123 #ifdef USE_AUTO_KEY
124         release_auto_key();
125 #endif
126 #ifdef USE_DEBUGGER
127         release_debugger();
128 #endif
129         delete vm;
130         osd->release();
131         delete osd;
132 #ifdef _DEBUG_LOG
133         release_debug_log();
134 #endif
135 }
136
137 #ifdef OSD_QT
138 EmuThreadClass *EMU::get_parent_handler()
139 {
140         return osd->get_parent_handler();
141 }
142
143 void EMU::set_parent_handler(EmuThreadClass *p, DrawThreadClass *q)
144 {
145         osd->set_parent_thread(p);
146         osd->set_draw_thread(q);
147 }
148
149 void EMU::set_host_cpus(int v)
150 {
151         osd->host_cpus = (v <= 0) ? 1 : v;
152 }
153
154 int EMU::get_host_cpus()
155 {
156         return osd->host_cpus;
157 }
158 #endif
159
160 // ----------------------------------------------------------------------------
161 // drive machine
162 // ----------------------------------------------------------------------------
163
164 int EMU::get_frame_interval()
165 {
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);
172                 prev_fps = fps;
173         }
174         return prev_interval;
175 #else
176         return (int)(1024. * 1000. / FRAMES_PER_SEC + 0.5);
177 #endif
178 }
179
180 bool EMU::is_frame_skippable()
181 {
182         return vm->is_frame_skippable();
183 }
184
185 int EMU::run()
186 {
187         if(now_suspended) {
188                 osd->restore();
189                 now_suspended = false;
190         }
191         osd->update_input();
192 #ifdef USE_AUTO_KEY
193         update_auto_key();
194 #endif
195 #ifdef USE_JOYSTICK
196         update_joystick();
197 #endif
198         
199 #ifdef USE_SOCKET
200 #if !defined(_USE_QT) // Temporally
201         osd->update_socket();
202 #endif
203 #endif
204         update_media();
205         
206         // virtual machine may be driven to fill sound buffer
207         int extra_frames = 0;
208         osd->update_sound(&extra_frames);
209         
210         // drive virtual machine
211         if(extra_frames == 0) {
212                 osd->lock_vm();
213                 vm->run();
214                 extra_frames = 1;
215                 osd->unlock_vm();
216         }
217         osd->add_extra_frames(extra_frames);
218         return extra_frames;
219 }
220
221 void EMU::reset()
222 {
223         // check if virtual machine should be reinitialized
224         bool reinitialize = false;
225 #ifdef USE_CPU_TYPE
226         reinitialize |= (cpu_type != config.cpu_type);
227         cpu_type = config.cpu_type;
228 #endif
229 #ifdef USE_SOUND_DEVICE_TYPE
230         reinitialize |= (sound_device_type != config.sound_device_type);
231         sound_device_type = config.sound_device_type;
232 #endif
233 #ifdef USE_PRINTER
234         reinitialize |= (printer_device_type != config.printer_device_type);
235         printer_device_type = config.printer_device_type;
236 #endif
237         if(reinitialize) {
238                 // stop sound
239                 osd->stop_sound();
240                 // reinitialize virtual machine
241                 osd->lock_vm();         
242                 delete vm;
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]);
248                 }
249 #endif
250                 vm->reset();
251                 osd->unlock_vm();
252                 // restore inserted medias
253                 restore_media();
254         } else {
255                 // reset virtual machine
256                 osd->lock_vm();         
257                 vm->reset();
258                 osd->unlock_vm();               
259         }
260         
261         // restart recording
262 #if !defined(_USE_QT) // Temporally
263         osd->restart_record_sound();
264         osd->restart_record_video();
265 #endif  
266 }
267
268 #ifdef USE_SPECIAL_RESET
269 void EMU::special_reset()
270 {
271         // reset virtual machine
272         osd->lock_vm();         
273         vm->special_reset();
274         osd->unlock_vm();
275         // restart recording
276 #if !defined(_USE_QT) // Temporally
277         restart_record_sound();
278         restart_record_video();
279 #endif  
280 }
281 #endif
282
283 #ifdef USE_NOTIFY_POWER_OFF
284 void EMU::notify_power_off()
285 {
286         vm->notify_power_off();
287 }
288 #endif
289
290 void EMU::power_off()
291 {
292         osd->power_off();
293 }
294
295 void EMU::suspend()
296 {
297         if(!now_suspended) {
298                 osd->suspend();
299                 now_suspended = true;
300         }
301 }
302
303 void EMU::lock_vm()
304 {
305         osd->lock_vm();
306 }
307
308 void EMU::unlock_vm()
309 {
310         osd->unlock_vm();
311 }
312
313 void EMU::force_unlock_vm()
314 {
315         osd->force_unlock_vm();
316 }
317
318
319 bool EMU::is_vm_locked()
320 {
321         return osd->is_vm_locked();
322 }
323
324 // ----------------------------------------------------------------------------
325 // input
326 // ----------------------------------------------------------------------------
327
328 #ifdef OSD_QT
329 void EMU::key_modifiers(uint32_t mod)
330 {
331         osd->key_modifiers(mod);
332 }
333
334         # ifdef USE_MOUSE
335 void EMU::set_mouse_pointer(int x, int y)
336 {
337         osd->set_mouse_pointer(x, y);
338 }
339
340 void EMU::set_mouse_button(int button)
341 {
342         osd->set_mouse_button(button);
343 }
344
345 int EMU::get_mouse_button()
346 {
347         return osd->get_mouse_button();
348 }
349         #endif
350 #endif
351
352 void EMU::key_down(int code, bool repeat)
353 {
354         osd->key_down(code, repeat);
355 }
356
357 void EMU::key_up(int code)
358 {
359         osd->key_up(code);
360 }
361
362 void EMU::key_lost_focus()
363 {
364         osd->key_lost_focus();
365 }
366
367 #ifdef ONE_BOARD_MICRO_COMPUTER
368 void EMU::press_button(int num)
369 {
370         int code = vm_buttons[num].code;
371         
372         if(code) {
373                 osd->key_down_native(code, false);
374                 osd->get_key_buffer()[code] = KEY_KEEP_FRAMES;
375         } else {
376                 // code=0: reset virtual machine
377                 vm->reset();
378         }
379 }
380 #endif
381
382 #ifdef USE_MOUSE
383 void EMU::enable_mouse()
384 {
385         osd->enable_mouse();
386 }
387
388 void EMU::disable_mouse()
389 {
390         osd->disable_mouse();
391 }
392
393 void EMU::toggle_mouse()
394 {
395         osd->toggle_mouse();
396 }
397
398 bool EMU::is_mouse_enabled()
399 {
400         return osd->is_mouse_enabled();
401 }
402 #endif
403
404 #ifdef USE_AUTO_KEY
405 void EMU::initialize_auto_key()
406 {
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;
411 }
412
413 void EMU::release_auto_key()
414 {
415         if(auto_key_buffer) {
416                 auto_key_buffer->release();
417                 delete auto_key_buffer;
418         }
419 }
420
421 void EMU::start_auto_key()
422 {
423         auto_key_phase = 1;
424         auto_key_shift = 0;
425         osd->now_auto_key = true;
426 }
427
428 void EMU::stop_auto_key()
429 {
430         if(auto_key_shift) {
431                 osd->key_up_native(VK_LSHIFT);
432         }
433         auto_key_phase = auto_key_shift = 0;
434         osd->now_auto_key = false;
435 }
436
437 #ifndef USE_AUTO_KEY_SHIFT
438 #define USE_AUTO_KEY_SHIFT 0
439 #endif
440 #ifndef VK_LSHIFT
441 #define VK_LSHIFT 0xA0
442 #endif
443
444 void EMU::update_auto_key()
445 {
446         switch(auto_key_phase) {
447         case 1:
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);
455                         }
456                         auto_key_shift = shift;
457                         auto_key_phase++;
458                         break;
459                 }
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);
463                 }
464                 auto_key_phase++;
465                 break;
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);
469                 }
470                 auto_key_phase++;
471                 break;
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) {
476                                 auto_key_phase++;
477                                 break;
478                         }
479                 }
480         case 30:
481                 if(auto_key_buffer && !auto_key_buffer->empty()) {
482                         auto_key_phase = 1;
483                 } else {
484                         stop_auto_key();
485                 }
486                 break;
487         default:
488                 if(auto_key_phase) {
489                         auto_key_phase++;
490                 }
491         }
492 }
493 #endif
494
495 #ifdef USE_JOYSTICK
496 void EMU::update_joystick()
497 {
498         uint32_t *joy_buffer = osd->get_joy_buffer();
499         uint8_t *key_buffer = osd->get_key_buffer();
500         
501         memset(joy_status, 0, sizeof(joy_status));
502         
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);
509                                 }
510                         } else {
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);
515                                 }
516                         }
517                 }
518         }
519 }
520 #endif
521
522 const uint8_t* EMU::get_key_buffer()
523 {
524         return (const uint8_t*)osd->get_key_buffer();
525 }
526
527 #ifdef USE_JOYSTICK
528 const uint32_t* EMU::get_joy_buffer()
529 {
530         return (const uint32_t*)joy_status;
531 }
532 #endif
533
534 #ifdef USE_MOUSE
535 const int32_t* EMU::get_mouse_buffer()
536 {
537         return (const int32_t*)osd->get_mouse_buffer();
538 }
539 #endif
540
541 // ----------------------------------------------------------------------------
542 // screen
543 // ----------------------------------------------------------------------------
544
545 int EMU::get_window_width(int mode)
546 {
547         return osd->get_window_width(mode);
548 }
549
550 int EMU::get_window_height(int mode)
551 {
552         return osd->get_window_height(mode);
553 }
554
555 void EMU::set_host_window_size(int window_width, int window_height, bool window_mode)
556 {
557         osd->set_host_window_size(window_width, window_height, window_mode);
558 }
559
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)
561 {
562         osd->set_vm_screen_size(screen_width, screen_height, window_width, window_height, window_width_aspect, window_height_aspect);
563 }
564
565 int EMU::get_vm_window_width()
566 {
567         return osd->get_vm_window_width();
568 }
569
570 int EMU::get_vm_window_height()
571 {
572         return osd->get_vm_window_height();
573 }
574
575 int EMU::get_vm_window_width_aspect()
576 {
577         return osd->get_vm_window_width_aspect();
578 }
579
580 int EMU::get_vm_window_height_aspect()
581 {
582         return osd->get_vm_window_height_aspect();
583 }
584
585 #if defined(USE_MINIMUM_RENDERING)
586 bool EMU::is_screen_changed()
587 {
588         return vm->is_screen_changed();
589 }
590 #endif
591
592 int EMU::draw_screen()
593 {
594         return osd->draw_screen();
595 }
596
597 scrntype_t* EMU::get_screen_buffer(int y)
598 {
599         return osd->get_vm_screen_buffer(y);
600 }
601
602 #ifdef USE_CRT_FILTER
603 void EMU::screen_skip_line(bool skip_line)
604 {
605         osd->screen_skip_line = skip_line;
606 }
607 #endif
608
609 #ifdef ONE_BOARD_MICRO_COMPUTER
610 void EMU::reload_bitmap()
611 {
612         osd->reload_bitmap();
613 }
614 #endif
615
616 #ifdef OSD_WIN32
617 void EMU::update_screen(HDC hdc)
618 {
619         osd->update_screen(hdc);
620 }
621 #endif
622
623 void EMU::capture_screen()
624 {
625         osd->capture_screen();
626 }
627
628 bool EMU::start_record_video(int fps)
629 {
630         return osd->start_record_video(fps);
631 }
632
633 void EMU::stop_record_video()
634 {
635         osd->stop_record_video();
636 }
637
638 bool EMU::is_video_recording()
639 {
640         return osd->now_record_video;
641 }
642
643 // ----------------------------------------------------------------------------
644 // sound
645 // ----------------------------------------------------------------------------
646
647 void EMU::mute_sound()
648 {
649         osd->mute_sound();
650 }
651
652 void EMU::start_record_sound()
653 {
654         osd->start_record_sound();
655 }
656
657 void EMU::stop_record_sound()
658 {
659         osd->stop_record_sound();
660 }
661
662 bool EMU::is_sound_recording()
663 {
664         return osd->now_record_sound;
665 }
666
667 // ----------------------------------------------------------------------------
668 // video
669 // ----------------------------------------------------------------------------
670
671 #if defined(USE_MOVIE_PLAYER) || defined(USE_VIDEO_CAPTURE)
672 void EMU::get_video_buffer()
673 {
674         osd->get_video_buffer();
675 }
676
677 void EMU::mute_video_dev(bool l, bool r)
678 {
679         osd->mute_video_dev(l, r);
680 }
681 #endif
682
683 #ifdef USE_MOVIE_PLAYER
684 bool EMU::open_movie_file(const _TCHAR* file_path)
685 {
686         return osd->open_movie_file(file_path);
687 }
688
689 void EMU::close_movie_file()
690 {
691         osd->close_movie_file();
692 }
693
694 void EMU::play_movie()
695 {
696         osd->play_movie();
697 }
698
699 void EMU::stop_movie()
700 {
701         osd->stop_movie();
702 }
703
704 void EMU::pause_movie()
705 {
706         osd->pause_movie();
707 }
708
709 double EMU::get_movie_frame_rate()
710 {
711         return osd->get_movie_frame_rate();
712 }
713
714 int EMU::get_movie_sound_rate()
715 {
716         return osd->get_movie_sound_rate();
717 }
718
719 void EMU::set_cur_movie_frame(int frame, bool relative)
720 {
721         osd->set_cur_movie_frame(frame, relative);
722 }
723
724 uint32_t EMU::get_cur_movie_frame()
725 {
726         return osd->get_cur_movie_frame();
727 }
728 #endif
729
730 #ifdef USE_VIDEO_CAPTURE
731 int EMU::get_cur_capture_dev_index()
732 {
733         return osd->get_cur_capture_dev_index();
734 }
735
736 int EMU::get_num_capture_devs()
737 {
738         return osd->get_num_capture_devs();
739 }
740
741 _TCHAR* EMU::get_capture_dev_name(int index)
742 {
743         return osd->get_capture_dev_name(index);
744 }
745
746 void EMU::open_capture_dev(int index, bool pin)
747 {
748         osd->open_capture_dev(index, pin);
749 }
750
751 void EMU::close_capture_dev()
752 {
753         osd->close_capture_dev();
754 }
755
756 void EMU::show_capture_dev_filter()
757 {
758         osd->show_capture_dev_filter();
759 }
760
761 void EMU::show_capture_dev_pin()
762 {
763         osd->show_capture_dev_pin();
764 }
765
766 void EMU::show_capture_dev_source()
767 {
768         osd->show_capture_dev_source();
769 }
770
771 void EMU::set_capture_dev_channel(int ch)
772 {
773         osd->set_capture_dev_channel(ch);
774 }
775 #endif
776
777 // ----------------------------------------------------------------------------
778 // printer
779 // ----------------------------------------------------------------------------
780
781 #ifdef USE_PRINTER
782 void EMU::create_bitmap(bitmap_t *bitmap, int width, int height)
783 {
784         osd->create_bitmap(bitmap, width, height);
785 }
786
787 void EMU::release_bitmap(bitmap_t *bitmap)
788 {
789         osd->release_bitmap(bitmap);
790 }
791
792 void EMU::create_font(font_t *font, const _TCHAR *family, int width, int height, int rotate, bool bold, bool italic)
793 {
794         osd->create_font(font, family, width, height, rotate, bold, italic);
795 }
796
797 void EMU::release_font(font_t *font)
798 {
799         osd->release_font(font);
800 }
801
802 void EMU::create_pen(pen_t *pen, int width, uint8_t r, uint8_t g, uint8_t b)
803 {
804         osd->create_pen(pen, width, r, g, b);
805 }
806
807 void EMU::release_pen(pen_t *pen)
808 {
809         osd->release_pen(pen);
810 }
811
812 void EMU::clear_bitmap(bitmap_t *bitmap, uint8_t r, uint8_t g, uint8_t b)
813 {
814         osd->clear_bitmap(bitmap, r, g, b);
815 }
816
817 int EMU::get_text_width(bitmap_t *bitmap, font_t *font, const char *text)
818 {
819         return osd->get_text_width(bitmap, font, text);
820 }
821
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)
823 {
824         osd->draw_text_to_bitmap(bitmap, font, x, y, text, r, g, b);
825 }
826
827 void EMU::draw_line_to_bitmap(bitmap_t *bitmap, pen_t *pen, int sx, int sy, int ex, int ey)
828 {
829         osd->draw_line_to_bitmap(bitmap, pen, sx, sy, ex, ey);
830 }
831
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)
833 {
834         osd->draw_rectangle_to_bitmap(bitmap, x, y, width, height, r, g, b);
835 }
836
837 void EMU::draw_point_to_bitmap(bitmap_t *bitmap, int x, int y, uint8_t r, uint8_t g, uint8_t b)
838 {
839         osd->draw_point_to_bitmap(bitmap, x, y, r, g, b);
840 }
841
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)
843 {
844         osd->stretch_bitmap(dest, dest_x, dest_y, dest_width, dest_height, source, source_x, source_y, source_width, source_height);
845 }
846
847 void EMU::write_bitmap_to_file(bitmap_t *bitmap, const _TCHAR *file_path)
848 {
849         osd->write_bitmap_to_file(bitmap, file_path);
850 }
851 #endif
852
853 // ----------------------------------------------------------------------------
854 // socket
855 // ----------------------------------------------------------------------------
856
857 #ifdef USE_SOCKET
858 int EMU::get_socket(int ch)
859 {
860         return osd->get_socket(ch);
861 }
862
863 void EMU::notify_socket_connected(int ch)
864 {
865         osd->notify_socket_connected(ch);
866 }
867
868 void EMU::notify_socket_disconnected(int ch)
869 {
870         osd->notify_socket_disconnected(ch);
871 }
872
873 bool EMU::initialize_socket_tcp(int ch)
874 {
875         return osd->initialize_socket_tcp(ch);
876 }
877
878 bool EMU::initialize_socket_udp(int ch)
879 {
880         return osd->initialize_socket_udp(ch);
881 }
882
883 bool EMU::connect_socket(int ch, uint32_t ipaddr, int port)
884 {
885         return osd->connect_socket(ch, ipaddr, port);
886 }
887
888 void EMU::disconnect_socket(int ch)
889 {
890         osd->disconnect_socket(ch);
891 }
892  
893 bool EMU::listen_socket(int ch)
894 {
895         return osd->listen_socket(ch);
896 }
897
898 void EMU::send_socket_data_tcp(int ch)
899 {
900         osd->send_socket_data_tcp(ch);
901 }
902
903 void EMU::send_socket_data_udp(int ch, uint32_t ipaddr, int port)
904 {
905         osd->send_socket_data_udp(ch, ipaddr, port);
906 }
907
908 void EMU::send_socket_data(int ch)
909 {
910         osd->send_socket_data(ch);
911 }
912
913 void EMU::recv_socket_data(int ch)
914 {
915         osd->recv_socket_data(ch);
916 }
917 #endif
918
919 // ----------------------------------------------------------------------------
920 // debug log
921 // ----------------------------------------------------------------------------
922
923 #ifdef _DEBUG_LOG
924 void EMU::initialize_debug_log()
925 {
926         _TCHAR path[_MAX_PATH];
927         debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
928 }
929
930 void EMU::release_debug_log()
931 {
932         if(debug_log) {
933                 fclose(debug_log);
934                 debug_log = NULL;
935         }
936 }
937 #endif
938
939 #ifdef _DEBUG_LOG
940 static _TCHAR prev_buffer[1024] = {0};
941 #endif
942
943 void EMU::out_debug_log(const _TCHAR* format, ...)
944 {
945 #ifdef _DEBUG_LOG
946         va_list ap;
947         _TCHAR buffer[1024];
948         
949         va_start(ap, format);
950         my_vstprintf_s(buffer, 1024, format, ap);
951         va_end(ap);
952         
953         if(_tcscmp(prev_buffer, buffer) == 0) {
954                 return;
955         }
956         my_tcscpy_s(prev_buffer, 1024, buffer);
957         
958 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
959         AGAR_DebugLog(AGAR_LOG_DEBUG, "%s", buffer);
960 #else
961         if(debug_log) {
962                 _ftprintf(debug_log, _T("%s"), buffer);
963                 static int size = 0;
964                 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
965                         fclose(debug_log);
966                         debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
967                         size = 0;
968                 }
969         }
970 #endif
971 #endif
972 }
973
974 void EMU::force_out_debug_log(const _TCHAR* format, ...)
975 {
976 #ifdef _DEBUG_LOG
977         va_list ap;
978         _TCHAR buffer[1024];
979         
980         va_start(ap, format);
981         my_vstprintf_s(buffer, 1024, format, ap);
982         va_end(ap);
983         my_tcscpy_s(prev_buffer, 1024, buffer);
984         
985 #if defined(_USE_QT) || defined(_USE_AGAR) || defined(_USE_SDL)
986         AGAR_DebugLog(AGAR_LOG_DEBUG, "%s", buffer);
987 #else
988         if(debug_log) {
989                 _ftprintf(debug_log, _T("%s"), buffer);
990                 static int size = 0;
991                 if((size += _tcslen(buffer)) > 0x8000000) { // 128MB
992                         fclose(debug_log);
993                         debug_log = _tfopen(create_date_file_path(_T("log")), _T("w"));
994                         size = 0;
995                 }
996         }
997 #endif
998 #endif
999 }
1000
1001 void EMU::out_message(const _TCHAR* format, ...)
1002 {
1003         va_list ap;
1004         va_start(ap, format);
1005         my_vstprintf_s(message, 1024, format, ap); // Security for MSVC:C6386.
1006         va_end(ap);
1007         message_count = 4; // 4sec
1008 }
1009
1010 // ----------------------------------------------------------------------------
1011 // misc
1012 // ----------------------------------------------------------------------------
1013
1014
1015 void EMU::sleep(uint32_t ms)
1016 {
1017         osd->sleep(ms);
1018 }
1019
1020
1021 // ----------------------------------------------------------------------------
1022 // user interface
1023 // ----------------------------------------------------------------------------
1024
1025 static uint8_t hex2uint8(char *value)
1026 {
1027         char tmp[3];
1028         memset(tmp, 0, sizeof(tmp));
1029         memcpy(tmp, value, 2);
1030         return (uint8_t)strtoul(tmp, NULL, 16);
1031 }
1032
1033 static uint16_t hex2uint16(char *value)
1034 {
1035         char tmp[5];
1036         memset(tmp, 0, sizeof(tmp));
1037         memcpy(tmp, value, 4);
1038         return (uint16_t)strtoul(tmp, NULL, 16);
1039 }
1040
1041 static bool hex2bin(const _TCHAR* file_path, const _TCHAR* dest_path)
1042 {
1043         bool result = false;
1044         FILEIO *fio_s = new FILEIO();
1045         if(fio_s->Fopen(file_path, FILEIO_READ_BINARY)) {
1046                 int length = 0;
1047                 char line[1024];
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;
1061                                         }
1062                                         buffer[offset + i] = hex2uint8(line + 9 + 2 * i);
1063                                 }
1064                         }
1065                 }
1066                 if(length > 0) {
1067                         FILEIO *fio_d = new FILEIO();
1068                         if(fio_d->Fopen(dest_path, FILEIO_WRITE_BINARY)) {
1069                                 fio_d->Fwrite(buffer, length, 1);
1070                                 fio_d->Fclose();
1071                                 result = true;
1072                         }
1073                         delete fio_d;
1074                 }
1075                 fio_s->Fclose();
1076         }
1077         delete fio_s;
1078         return result;
1079 }
1080
1081 void EMU::initialize_media()
1082 {
1083 #ifdef USE_CART1
1084         memset(&cart_status, 0, sizeof(cart_status));
1085 #endif
1086 #ifdef USE_FD1
1087         memset(floppy_disk_status, 0, sizeof(floppy_disk_status));
1088 #endif
1089 #ifdef USE_QD1
1090         memset(&quick_disk_status, 0, sizeof(quick_disk_status));
1091 #endif
1092 #ifdef USE_TAPE
1093         memset(&tape_status, 0, sizeof(tape_status));
1094 #endif
1095 #ifdef USE_COMPACT_DISC
1096         memset(&compact_disc_status, 0, sizeof(compact_disc_status));
1097 #endif
1098 #ifdef USE_LASER_DISC
1099         memset(&laser_disc_status, 0, sizeof(laser_disc_status));
1100 #endif
1101 }
1102
1103
1104 void EMU::update_media()
1105 {
1106 #ifdef USE_FD1
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);
1111                 }
1112         }
1113 #endif
1114 #ifdef USE_QD1
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);
1119                 }
1120         }
1121 #endif
1122 #ifdef USE_TAPE
1123         if(tape_status.wait_count != 0 && --tape_status.wait_count == 0) {
1124                 if(tape_status.play) {
1125                         vm->play_tape(tape_status.path);
1126                 } else {
1127                         vm->rec_tape(tape_status.path);
1128                 }
1129                 out_message(_T("CMT: %s"), tape_status.path);
1130         }
1131 #endif
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);
1136         }
1137 #endif
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);
1142         }
1143 #endif
1144 #ifdef USE_BUBBLE1
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);
1149                 }
1150         }
1151 #endif
1152 }
1153
1154 void EMU::restore_media()
1155 {
1156 #ifdef USE_CART1
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.$$$")));
1162                         } else {
1163                                 vm->open_cart(drv, cart_status[drv].path);
1164                         }
1165                 }
1166         }
1167 #endif
1168 #ifdef USE_FD1
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);
1172                 }
1173         }
1174 #endif
1175 #ifdef USE_QD1
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);
1179                 }
1180         }
1181 #endif
1182 #ifdef USE_TAPE
1183         if(tape_status.path[0] != _T('\0')) {
1184                 if(tape_status.play) {
1185                         vm->play_tape(tape_status.path);
1186                 } else {
1187                         tape_status.path[0] = _T('\0');
1188                 }
1189         }
1190 #endif
1191 #ifdef USE_COMPACT_DISC
1192         if(compact_disc_status.path[0] != _T('\0')) {
1193                 vm->open_compact_disc(compact_disc_status.path);
1194         }
1195 #endif
1196 #ifdef USE_LASER_DISC
1197         if(laser_disc_status.path[0] != _T('\0')) {
1198                 vm->open_laser_disc(laser_disc_status.path);
1199         }
1200 #endif
1201 #ifdef USE_BUBBLE1
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);
1205                 }
1206         }
1207 #endif
1208 }
1209
1210 #ifdef USE_CART1
1211 void EMU::open_cart(int drv, const _TCHAR* file_path)
1212 {
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.$$$")));
1217                 } else {
1218                         vm->open_cart(drv, file_path);
1219                 }
1220                 my_tcscpy_s(cart_status[drv].path, _MAX_PATH, file_path);
1221                 out_message(_T("Cart%d: %s"), drv + 1, file_path);
1222                 
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);
1230         }
1231 }
1232
1233 void EMU::close_cart(int drv)
1234 {
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);
1239                 
1240                 // stop recording
1241                 stop_record_video();
1242                 stop_record_sound();
1243         }
1244 }
1245
1246 bool EMU::is_cart_inserted(int drv)
1247 {
1248         if(drv < MAX_CART) {
1249                 return vm->is_cart_inserted(drv);
1250         } else {
1251                 return false;
1252         }
1253 }
1254 #endif
1255
1256 #ifdef USE_FD1
1257 void EMU::open_floppy_disk(int drv, const _TCHAR* file_path, int bank)
1258 {
1259         if(drv < MAX_FD) {
1260                 if(vm->is_floppy_disk_inserted(drv)) {
1261                         vm->close_floppy_disk(drv);
1262                         // wait 0.5sec
1263 #ifdef SUPPORT_VARIABLE_TIMING
1264                         floppy_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
1265 #else
1266                         floppy_disk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1267 #endif
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);
1272                 }
1273                 my_tcscpy_s(floppy_disk_status[drv].path, _MAX_PATH, file_path);
1274                 floppy_disk_status[drv].bank = bank;
1275         }
1276 }
1277
1278 void EMU::close_floppy_disk(int drv)
1279 {
1280         if(drv < MAX_FD) {
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);
1284         }
1285 }
1286
1287 bool EMU::is_floppy_disk_inserted(int drv)
1288 {
1289         if(drv < MAX_FD) {
1290                 return vm->is_floppy_disk_inserted(drv);
1291         } else {
1292                 return false;
1293         }
1294 }
1295
1296 void EMU::is_floppy_disk_protected(int drv, bool value)
1297 {
1298         if(drv < MAX_FD) {
1299                 vm->is_floppy_disk_protected(drv, value);
1300         }
1301 }
1302
1303 bool EMU::is_floppy_disk_protected(int drv)
1304 {
1305         if(drv < MAX_FD) {
1306                 return vm->is_floppy_disk_protected(drv);
1307         } else {
1308                 return false;
1309         }
1310 }
1311 #endif
1312
1313 #ifdef USE_QD1
1314 void EMU::open_quick_disk(int drv, const _TCHAR* file_path)
1315 {
1316         if(drv < MAX_QD) {
1317                 if(vm->is_quick_disk_inserted(drv)) {
1318                         vm->close_quick_disk(drv);
1319                         // wait 0.5sec
1320 #ifdef SUPPORT_VARIABLE_TIMING
1321                         quick_disk_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
1322 #else
1323                         quick_disk_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1324 #endif
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);
1329                 }
1330                 my_tcscpy_s(quick_disk_status[drv].path, _MAX_PATH, file_path);
1331         }
1332 }
1333
1334 void EMU::close_quick_disk(int drv)
1335 {
1336         if(drv < MAX_QD) {
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);
1340         }
1341 }
1342
1343 bool EMU::is_quick_disk_inserted(int drv)
1344 {
1345         if(drv < MAX_QD) {
1346                 return vm->is_quick_disk_inserted(drv);
1347         } else {
1348                 return false;
1349         }
1350 }
1351 #endif
1352
1353 #ifdef USE_TAPE
1354 void EMU::play_tape(const _TCHAR* file_path)
1355 {
1356         if(vm->is_tape_inserted()) {
1357                 vm->close_tape();
1358                 // wait 0.5sec
1359 #ifdef SUPPORT_VARIABLE_TIMING
1360                 tape_status.wait_count = (int)(vm->get_frame_rate() / 2);
1361 #else
1362                 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1363 #endif
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);
1368         }
1369         my_tcscpy_s(tape_status.path, _MAX_PATH, file_path);
1370         tape_status.play = true;
1371 }
1372
1373 void EMU::rec_tape(const _TCHAR* file_path)
1374 {
1375         if(vm->is_tape_inserted()) {
1376                 vm->close_tape();
1377                 // wait 0.5sec
1378 #ifdef SUPPORT_VARIABLE_TIMING
1379                 tape_status.wait_count = (int)(vm->get_frame_rate() / 2);
1380 #else
1381                 tape_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1382 #endif
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);
1387         }
1388         my_tcscpy_s(tape_status.path, _MAX_PATH, file_path);
1389         tape_status.play = false;
1390 }
1391
1392 void EMU::close_tape()
1393 {
1394         vm->close_tape();
1395         clear_media_status(&tape_status);
1396         out_message(_T("CMT: Ejected"));
1397 }
1398
1399 bool EMU::is_tape_inserted()
1400 {
1401         return vm->is_tape_inserted();
1402 }
1403
1404 #ifndef TAPE_BINARY_ONLY
1405 bool EMU::is_tape_playing()
1406 {
1407         return vm->is_tape_playing();
1408 }
1409
1410 bool EMU::is_tape_recording()
1411 {
1412         return vm->is_tape_recording();
1413 }
1414
1415 int EMU::get_tape_position()
1416 {
1417         return vm->get_tape_position();
1418 }
1419 #endif
1420
1421 #ifdef USE_TAPE_BUTTON
1422 void EMU::push_play()
1423 {
1424         vm->push_play();
1425 }
1426
1427 void EMU::push_stop()
1428 {
1429         vm->push_stop();
1430 }
1431
1432 void EMU::push_fast_forward()
1433 {
1434         vm->push_fast_forward();
1435 }
1436
1437 void EMU::push_fast_rewind()
1438 {
1439         vm->push_fast_rewind();
1440 }
1441
1442 void EMU::push_apss_forward()
1443 {
1444         vm->push_apss_forward();
1445 }
1446
1447 void EMU::push_apss_rewind()
1448 {
1449         vm->push_apss_rewind();
1450 }
1451 #endif
1452 #endif
1453
1454 #ifdef USE_COMPACT_DISC
1455 void EMU::open_compact_disc(const _TCHAR* file_path)
1456 {
1457         if(vm->is_compact_disc_inserted()) {
1458                 vm->close_compact_disc();
1459                 // wait 0.5sec
1460 #ifdef SUPPORT_VARIABLE_TIMING
1461                 compact_disc_status.wait_count = (int)(vm->get_frame_rate() / 2);
1462 #else
1463                 compact_disc_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1464 #endif
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);
1469         }
1470         my_tcscpy_s(compact_disc_status.path, _MAX_PATH, file_path);
1471 }
1472
1473 void EMU::close_compact_disc()
1474 {
1475         vm->close_compact_disc();
1476         clear_media_status(&compact_disc_status);
1477         out_message(_T("CD: Ejected"));
1478 }
1479
1480 bool EMU::is_compact_disc_inserted()
1481 {
1482         return vm->is_compact_disc_inserted();
1483 }
1484 #endif
1485
1486 #ifdef USE_LASER_DISC
1487 void EMU::open_laser_disc(const _TCHAR* file_path)
1488 {
1489         if(vm->is_laser_disc_inserted()) {
1490                 vm->close_laser_disc();
1491                 // wait 0.5sec
1492 #ifdef SUPPORT_VARIABLE_TIMING
1493                 laser_disc_status.wait_count = (int)(vm->get_frame_rate() / 2);
1494 #else
1495                 laser_disc_status.wait_count = (int)(FRAMES_PER_SEC / 2);
1496 #endif
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);
1501         }
1502         my_tcscpy_s(laser_disc_status.path, _MAX_PATH, file_path);
1503 }
1504
1505 void EMU::close_laser_disc()
1506 {
1507         vm->close_laser_disc();
1508         clear_media_status(&laser_disc_status);
1509         out_message(_T("LD: Ejected"));
1510 }
1511
1512 bool EMU::is_laser_disc_inserted()
1513 {
1514         return vm->is_laser_disc_inserted();
1515 }
1516 #endif
1517
1518 #ifdef USE_BINARY_FILE1
1519 void EMU::load_binary(int drv, const _TCHAR* file_path)
1520 {
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.$$$")));
1525                 } else {
1526                         vm->load_binary(drv, file_path);
1527                 }
1528                 out_message(_T("Load: %s"), file_path);
1529         }
1530 }
1531
1532 void EMU::save_binary(int drv, const _TCHAR* file_path)
1533 {
1534         if(drv < MAX_BINARY) {
1535                 vm->save_binary(drv, file_path);
1536                 out_message(_T("Save: %s"), file_path);
1537         }
1538 }
1539 #endif
1540 #ifdef USE_BUBBLE1
1541 void EMU::open_bubble_casette(int drv, const _TCHAR* file_path, int bank)
1542 {
1543         if(drv < MAX_BUBBLE) {
1544                 if(vm->is_bubble_casette_inserted(drv)) {
1545                         vm->close_bubble_casette(drv);
1546                         // wait 0.5sec
1547 #ifdef SUPPORT_VARIABLE_TIMING
1548                         bubble_casette_status[drv].wait_count = (int)(vm->get_frame_rate() / 2);
1549 #else
1550                         bubble_casette_status[drv].wait_count = (int)(FRAMES_PER_SEC / 2);
1551 #endif
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);
1556                 }
1557                 my_tcscpy_s(bubble_casette_status[drv].path, _MAX_PATH, file_path);
1558                 bubble_casette_status[drv].bank = bank;
1559         }
1560 }
1561
1562 void EMU::close_bubble_casette(int drv)
1563 {
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);
1568         }
1569 }
1570
1571 bool EMU::is_bubble_casette_inserted(int drv)
1572 {
1573         if(drv < MAX_BUBBLE) {
1574                 return vm->is_bubble_casette_inserted(drv);
1575         } else {
1576                 return false;
1577         }
1578 }
1579
1580 bool EMU::is_bubble_casette_protected(int drv)
1581 {
1582         if(drv < MAX_BUBBLE) {
1583                 return vm->is_bubble_casette_protected(drv);
1584         } else {
1585                 return false;
1586         }
1587 }
1588
1589 void EMU::is_bubble_casette_protected(int drv, bool flag)
1590 {
1591         if(drv < MAX_BUBBLE) {
1592                 return vm->is_bubble_casette_protected(drv, flag);
1593         } else {
1594                 return false;
1595         }
1596 }
1597 #endif
1598
1599 #ifdef USE_ACCESS_LAMP
1600 uint32_t EMU::get_access_lamp_status()
1601 {
1602         return vm->get_access_lamp_status();
1603 }
1604 #endif
1605
1606 #ifdef USE_LED_DEVICE
1607 uint32_t EMU::get_led_status()
1608 {
1609         return vm->get_led_status();
1610 }
1611 #endif
1612
1613 #ifdef USE_SOUND_VOLUME
1614 void EMU::set_sound_device_volume(int ch, int decibel_l, int decibel_r)
1615 {
1616         vm->set_sound_device_volume(ch, decibel_l, decibel_r);
1617 }
1618 #endif
1619
1620 void EMU::update_config()
1621 {
1622         vm->update_config();
1623 }
1624
1625
1626
1627 // ----------------------------------------------------------------------------
1628 // state
1629 // ----------------------------------------------------------------------------
1630
1631 #ifdef USE_STATE
1632 #define STATE_VERSION   2
1633
1634 void EMU::save_state()
1635 {
1636         save_state_tmp(create_local_path(_T("%s.sta"), _T(CONFIG_NAME)));
1637 }
1638
1639 void EMU::load_state()
1640 {
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")));
1646                 }
1647                 FILEIO::RemoveFile(create_local_path(_T("$temp$.sta")));
1648         }
1649 }
1650
1651 void EMU::save_state_tmp(const _TCHAR* file_path)
1652 {
1653         FILEIO* fio = new FILEIO();
1654         osd->lock_vm();
1655         if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
1656                 // save state file version
1657                 fio->FputUint32(STATE_VERSION);
1658                 // save config
1659                 save_config_state((void *)fio);
1660                 // save inserted medias
1661 #ifdef USE_CART1
1662                 fio->Fwrite(&cart_status, sizeof(cart_status), 1);
1663 #endif
1664 #ifdef USE_FD1
1665                 fio->Fwrite(floppy_disk_status, sizeof(floppy_disk_status), 1);
1666                 fio->Fwrite(d88_file, sizeof(d88_file), 1);
1667 #endif
1668 #ifdef USE_QD1
1669                 fio->Fwrite(&quick_disk_status, sizeof(quick_disk_status), 1);
1670 #endif
1671 #ifdef USE_TAPE
1672                 fio->Fwrite(&tape_status, sizeof(tape_status), 1);
1673 #endif
1674 #ifdef USE_COMPACT_DISC
1675                 fio->Fwrite(&compact_disc_status, sizeof(compact_disc_status), 1);
1676 #endif
1677 #ifdef USE_LASER_DISC
1678                 fio->Fwrite(&laser_disc_status, sizeof(laser_disc_status), 1);
1679 #endif
1680 #ifdef USE_FD1
1681                 fio->Fwrite(floppy_disk_status, sizeof(floppy_disk_status), 1);
1682                 fio->Fwrite(d88_file, sizeof(d88_file), 1);
1683 #endif
1684                 // save vm state
1685                 vm->save_state(fio);
1686                 // end of state file
1687                 fio->FputInt32(-1);
1688                 fio->Fclose();
1689         }
1690         osd->unlock_vm();
1691         delete fio;
1692 }
1693
1694 bool EMU::load_state_tmp(const _TCHAR* file_path)
1695 {
1696         bool result = false;
1697         FILEIO* fio = new FILEIO();
1698         osd->lock_vm();
1699         if(fio->Fopen(file_path, FILEIO_READ_BINARY)) {
1700                 // check state file version
1701                 if(fio->FgetUint32() == STATE_VERSION) {
1702                         // load config
1703                         if(load_config_state((void *)fio)) {
1704                                 // load inserted medias
1705 #ifdef USE_CART1
1706                                 fio->Fread(&cart_status, sizeof(cart_status), 1);
1707 #endif
1708 #ifdef USE_FD1
1709                                 fio->Fread(floppy_disk_status, sizeof(floppy_disk_status), 1);
1710                                 fio->Fread(d88_file, sizeof(d88_file), 1);
1711 #endif
1712 #ifdef USE_QD1
1713                                 fio->Fread(&quick_disk_status, sizeof(quick_disk_status), 1);
1714 #endif
1715 #ifdef USE_TAPE
1716                                 fio->Fread(&tape_status, sizeof(tape_status), 1);
1717 #endif
1718 #ifdef USE_COMPACT_DISC
1719                                 fio->Fread(&compact_disc_status, sizeof(compact_disc_status), 1);
1720 #endif
1721 #ifdef USE_LASER_DISC
1722                                 fio->Fread(&laser_disc_status, sizeof(laser_disc_status), 1);
1723 #endif
1724                                 // check if virtual machine should be reinitialized
1725                                 bool reinitialize = false;
1726 #ifdef USE_CPU_TYPE
1727                                 reinitialize |= (cpu_type != config.cpu_type);
1728                                 cpu_type = config.cpu_type;
1729 #endif
1730 #ifdef USE_SOUND_DEVICE_TYPE
1731                                 reinitialize |= (sound_device_type != config.sound_device_type);
1732                                 sound_device_type = config.sound_device_type;
1733 #endif
1734 #ifdef USE_PRINTER
1735                                 reinitialize |= (printer_device_type != config.printer_device_type);
1736                                 printer_device_type = config.printer_device_type;
1737 #endif
1738                                 if(reinitialize) {
1739                                         // stop sound
1740                                         //osd->lock_vm();
1741                                         // reinitialize virtual machine
1742                                         osd->stop_sound();
1743                                         delete vm;
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]);
1749                                         }
1750 #endif
1751                                         vm->reset();
1752                                         //osd->unlock_vm();
1753                                 }
1754                                 // restore inserted medias
1755                                 restore_media();
1756                                 // load vm state
1757                                 if(vm->load_state(fio)) {
1758                                         // check end of state
1759                                         result = (fio->FgetInt32() == -1);
1760                                 }
1761                         }
1762                 }
1763                 fio->Fclose();
1764         }
1765         osd->unlock_vm();
1766         delete fio;
1767         return result;
1768 }
1769 #endif