OSDN Git Service

[GENERAL] Merge upstream 2018-02-27.
[csp-qt/common_source_project-fm7.git] / source / src / vm / event.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2006.11.29-
6
7         [ event manager ]
8 */
9
10 #include "event.h"
11
12 #define EVENT_MIX       0
13
14 void EVENT::initialize()
15 {
16         DEVICE::initialize();
17         // load config
18         if(!(0 <= config.cpu_power && config.cpu_power <= 4)) {
19                 config.cpu_power = 0;
20         }
21         power = config.cpu_power;
22         
23         // initialize sound buffer
24         sound_buffer = NULL;
25         sound_tmp = NULL;
26         
27         dont_skip_frames = 0;
28         prev_skip = next_skip = false;
29         sound_changed = false;
30         
31         vline_start_clock = 0;
32         cur_vline = 0;
33         vclocks[0] = (int)((double)d_cpu[0].cpu_clocks / (double)FRAMES_PER_SEC / (double)LINES_PER_FRAME + 0.5); // temporary
34 }
35
36 void EVENT::initialize_sound(int rate, int samples)
37 {
38         // initialize sound
39         sound_samples = samples;
40         sound_tmp_samples = samples * 2;
41         sound_buffer = (uint16_t*)malloc(sound_samples * sizeof(uint16_t) * 2);
42         memset(sound_buffer, 0, sound_samples * sizeof(uint16_t) * 2);
43         sound_tmp = (int32_t*)malloc(sound_tmp_samples * sizeof(int32_t) * 2);
44         memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32_t) * 2);
45         buffer_ptr = 0;
46         mix_counter = 1;
47         mix_limit = (int)((double)(emu->get_sound_rate() / 2000.0)); // per 0.5ms.
48         
49         // register event
50         this->register_event(this, EVENT_MIX, 1000000.0 / rate, true, NULL);
51 }
52
53 void EVENT::release()
54 {
55         // release sound
56         if(sound_buffer) {
57                 free(sound_buffer);
58         }
59         if(sound_tmp) {
60                 free(sound_tmp);
61         }
62 }
63
64 void EVENT::reset()
65 {
66         // clear events except loop event
67         for(int i = 0; i < MAX_EVENT; i++) {
68                 if(event[i].active && event[i].loop_clock == 0) {
69                         cancel_event(NULL, i);
70                 }
71         }
72         
73         event_remain = 0;
74         cpu_remain = cpu_accum = cpu_done = 0;
75         
76         // reset sound
77         if(sound_buffer) {
78                 memset(sound_buffer, 0, sound_samples * sizeof(uint16_t) * 2);
79         }
80         if(sound_tmp) {
81                 memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32_t) * 2);
82         }
83 //      buffer_ptr = 0;
84         
85 #ifdef _DEBUG_LOG
86         initialize_done = true;
87 #endif
88 }
89
90 void EVENT::drive()
91 {
92         // raise pre frame events to update timing settings
93         for(int i = 0; i < frame_event_count; i++) {
94                 frame_event[i]->event_pre_frame();
95         }
96         
97         // generate clocks per line
98         if(frames_per_sec != next_frames_per_sec || lines_per_frame != next_lines_per_frame) {
99                 frames_per_sec = next_frames_per_sec;
100                 lines_per_frame = next_lines_per_frame;
101                 
102                 int sum = (int)((double)d_cpu[0].cpu_clocks / frames_per_sec + 0.5);
103                 int remain = sum;
104                 
105                 for(int i = 0; i < lines_per_frame; i++) {
106                         assert(i < MAX_LINES);
107                         vclocks[i] = (int)(sum / lines_per_frame);
108                         remain -= vclocks[i];
109                 }
110                 for(int i = 0; i < remain; i++) {
111                         int index = (int)((double)lines_per_frame * (double)i / (double)remain);
112                         assert(index < MAX_LINES);
113                         vclocks[index]++;
114                 }
115                 for(int i = 1; i < dcount_cpu; i++) {
116                         d_cpu[i].update_clocks = (int)(1024.0 * (double)d_cpu[i].cpu_clocks / (double)d_cpu[0].cpu_clocks + 0.5);
117                 }
118                 for(DEVICE* device = vm->first_device; device; device = device->next_device) {
119                         if(device->get_event_manager_id() == this_device_id) {
120                                 device->update_timing(d_cpu[0].cpu_clocks, frames_per_sec, lines_per_frame);
121                         }
122                 }
123         }
124         
125         // run virtual machine for 1 frame period
126         for(int i = 0; i < frame_event_count; i++) {
127                 frame_event[i]->event_frame();
128         }
129         for(cur_vline = 0; cur_vline < lines_per_frame; cur_vline++) {
130                 vline_start_clock = get_current_clock();
131                 
132                 // run virtual machine per line
133                 for(int i = 0; i < vline_event_count; i++) {
134                         vline_event[i]->event_vline(cur_vline, vclocks[cur_vline]);
135                 }
136                 
137                 if(event_remain < 0) {
138                         if(-event_remain > vclocks[cur_vline]) {
139                                 update_event(vclocks[cur_vline]);
140                         } else {
141                                 update_event(-event_remain);
142                         }
143                 }
144                 event_remain += vclocks[cur_vline];
145                 cpu_remain += vclocks[cur_vline] << power;
146                 
147                 while(event_remain > 0) {
148                         int event_done = event_remain;
149                         if(cpu_remain > 0) {
150                                 int cpu_done_tmp;
151                                 if(dcount_cpu == 1) {
152                                         // run one opecode on primary cpu
153                                         cpu_done_tmp = d_cpu[0].device->run(-1);
154                                 } else {
155                                         // sync to sub cpus
156                                         if(cpu_done == 0) {
157                                                 // run one opecode on primary cpu
158                                                 cpu_done = d_cpu[0].device->run(-1);
159                                         }
160                                         
161                                         // sub cpu runs continuously and no events will be fired while the given clocks,
162                                         // so I need to give small enough clocks...
163                                         cpu_done_tmp = (cpu_done < 4) ? cpu_done : 4;
164                                         cpu_done -= cpu_done_tmp;
165                                         
166                                         for(int i = 1; i < dcount_cpu; i++) {
167                                                 // run sub cpus
168                                                 d_cpu[i].accum_clocks += d_cpu[i].update_clocks * cpu_done_tmp;
169                                                 int sub_clock = d_cpu[i].accum_clocks >> 10;
170                                                 if(sub_clock) {
171                                                         d_cpu[i].accum_clocks -= sub_clock << 10;
172                                                         d_cpu[i].device->run(sub_clock);
173                                                 }
174                                         }
175                                 }
176                                 cpu_remain -= cpu_done_tmp;
177                                 cpu_accum += cpu_done_tmp;
178                                 event_done = cpu_accum >> power;
179                                 cpu_accum -= event_done << power;
180                         }
181                         if(event_done > 0) {
182                                 if(event_done > event_remain) {
183                                         update_event(event_remain);
184                                 } else {
185                                         update_event(event_done);
186                                 }
187                                 event_remain -= event_done;
188                         }
189                 }
190         }
191 }
192
193 void EVENT::update_event(int clock)
194 {
195         uint64_t event_clocks_tmp = event_clocks + clock;
196         
197         while(first_fire_event != NULL && first_fire_event->expired_clock <= event_clocks_tmp) {
198                 event_t *event_handle = first_fire_event;
199                 uint64_t expired_clock = event_handle->expired_clock;
200                 
201                 first_fire_event = event_handle->next;
202                 if(first_fire_event != NULL) {
203                         first_fire_event->prev = NULL;
204                 }
205                 if(event_handle->loop_clock != 0) {
206                         event_handle->accum_clocks += event_handle->loop_clock;
207                         uint64_t clock_tmp = event_handle->accum_clocks >> 10;
208                         event_handle->accum_clocks -= clock_tmp << 10;
209                         event_handle->expired_clock += clock_tmp;
210                         insert_event(event_handle);
211                 } else {
212                         event_handle->active = false;
213                         event_handle->next = first_free_event;
214                         first_free_event = event_handle;
215                 }
216                 event_clocks = expired_clock;
217                 event_handle->device->event_callback(event_handle->event_id, 0);
218         }
219         event_clocks = event_clocks_tmp;
220 }
221
222 uint32_t EVENT::get_current_clock()
223 {
224         return (uint32_t)(event_clocks & 0xffffffff);
225 }
226
227 uint32_t EVENT::get_passed_clock(uint32_t prev)
228 {
229         uint32_t current = get_current_clock();
230         return (current > prev) ? current - prev : current + (0xffffffff - prev) + 1;
231 }
232
233 double EVENT::get_passed_usec(uint32_t prev)
234 {
235         return 1000000.0 * get_passed_clock(prev) / d_cpu[0].cpu_clocks;
236 }
237
238 uint32_t EVENT::get_passed_clock_since_vline()
239 {
240         return get_passed_clock(vline_start_clock);
241 }
242
243 double EVENT::get_passed_usec_since_vline()
244 {
245         return get_passed_usec(vline_start_clock);
246 }
247
248 uint32_t EVENT::get_cpu_pc(int index)
249 {
250         return d_cpu[index].device->get_pc();
251 }
252
253 void EVENT::register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id)
254 {
255 #ifdef _DEBUG_LOG
256         if(!initialize_done && !loop) {
257                 this->out_debug_log(_T("EVENT: non-loop event is registered before initialize is done\n"));
258         }
259 #endif
260         
261         // register event
262         if(first_free_event == NULL) {
263 #ifdef _DEBUG_LOG
264                 this->out_debug_log(_T("EVENT: too many events !!!\n"));
265 #endif
266                 if(register_id != NULL) {
267                         *register_id = -1;
268                 }
269                 return;
270         }
271         event_t *event_handle = first_free_event;
272         first_free_event = first_free_event->next;
273         
274         if(register_id != NULL) {
275                 *register_id = event_handle->index;
276         }
277         event_handle->active = true;
278         event_handle->device = device;
279         event_handle->event_id = event_id;
280         uint64_t clock;
281         if(loop) {
282                 event_handle->loop_clock = (uint64_t)(1024.0 * (double)d_cpu[0].cpu_clocks / 1000000.0 * usec + 0.5);
283                 event_handle->accum_clocks = event_handle->loop_clock;
284                 clock = event_handle->accum_clocks >> 10;
285                 event_handle->accum_clocks -= clock << 10;
286         } else {
287                 clock = (uint64_t)((double)d_cpu[0].cpu_clocks / 1000000.0 * usec + 0.5);
288                 event_handle->loop_clock = 0;
289                 event_handle->accum_clocks = 0;
290         }
291         event_handle->expired_clock = event_clocks + clock;
292         
293         insert_event(event_handle);
294 }
295
296 void EVENT::register_event_by_clock(DEVICE* device, int event_id, uint64_t clock, bool loop, int* register_id)
297 {
298 #ifdef _DEBUG_LOG
299         if(!initialize_done && !loop) {
300                 this->out_debug_log(_T("EVENT: device (name=%s, id=%d) registeres non-loop event before initialize is done\n"), device->this_device_name, device->this_device_id);
301         }
302 #endif
303         
304         // register event
305         if(first_free_event == NULL) {
306 #ifdef _DEBUG_LOG
307                 this->out_debug_log(_T("EVENT: too many events !!!\n"));
308 #endif
309                 if(register_id != NULL) {
310                         *register_id = -1;
311                 }
312                 return;
313         }
314         event_t *event_handle = first_free_event;
315         first_free_event = first_free_event->next;
316         
317         if(register_id != NULL) {
318                 *register_id = event_handle->index;
319         }
320         event_handle->active = true;
321         event_handle->device = device;
322         event_handle->event_id = event_id;
323         event_handle->expired_clock = event_clocks + clock;
324         event_handle->loop_clock = loop ? (clock << 10) : 0;
325         event_handle->accum_clocks = 0;
326         
327         insert_event(event_handle);
328 }
329
330 void EVENT::insert_event(event_t *event_handle)
331 {
332         if(first_fire_event == NULL) {
333                 first_fire_event = event_handle;
334                 event_handle->prev = event_handle->next = NULL;
335         } else {
336                 for(event_t *insert_pos = first_fire_event; insert_pos != NULL; insert_pos = insert_pos->next) {
337                         if(insert_pos->expired_clock > event_handle->expired_clock) {
338                                 if(insert_pos->prev != NULL) {
339                                         // insert
340                                         insert_pos->prev->next = event_handle;
341                                         event_handle->prev = insert_pos->prev;
342                                         event_handle->next = insert_pos;
343                                         insert_pos->prev = event_handle;
344                                         break;
345                                 } else {
346                                         // add to head
347                                         first_fire_event = event_handle;
348                                         event_handle->prev = NULL;
349                                         event_handle->next = insert_pos;
350                                         insert_pos->prev = event_handle;
351                                         break;
352                                 }
353                         } else if(insert_pos->next == NULL) {
354                                 // add to tail
355                                 insert_pos->next = event_handle;
356                                 event_handle->prev = insert_pos;
357                                 event_handle->next = NULL;
358                                 break;
359                         }
360                 }
361         }
362 }
363
364 void EVENT::cancel_event(DEVICE* device, int register_id)
365 {
366         // cancel registered event
367         if(0 <= register_id && register_id < MAX_EVENT) {
368                 event_t *event_handle = &event[register_id];
369                 if(device != NULL && device != event_handle->device) {
370                         this->out_debug_log(_T("EVENT: device (name=%s, id=%d) tries to cancel event that is not its own !!!\n"), device->this_device_name, device->this_device_id);
371                         return;
372                 }
373                 if(event_handle->active) {
374                         if(event_handle->prev != NULL) {
375                                 event_handle->prev->next = event_handle->next;
376                         } else {
377                                 first_fire_event = event_handle->next;
378                         }
379                         if(event_handle->next != NULL) {
380                                 event_handle->next->prev = event_handle->prev;
381                         }
382                         event_handle->active = false;
383                         event_handle->next = first_free_event;
384                         first_free_event = event_handle;
385                 }
386         }
387 }
388
389 void EVENT::register_frame_event(DEVICE* device)
390 {
391         if(frame_event_count < MAX_EVENT) {
392                 for(int i = 0; i < frame_event_count; i++) {
393                         if(frame_event[i] == device) {
394 #ifdef _DEBUG_LOG
395                                 this->out_debug_log(_T("EVENT: device (name=%s, id=%d) has already registered frame event !!!\n"), device->this_device_name, device->this_device_id);
396 #endif
397                                 return;
398                         }
399                 }
400                 frame_event[frame_event_count++] = device;
401 #ifdef _DEBUG_LOG
402         } else {
403                 this->out_debug_log(_T("EVENT: too many frame events !!!\n"));
404 #endif
405         }
406 }
407
408 void EVENT::register_vline_event(DEVICE* device)
409 {
410         if(vline_event_count < MAX_EVENT) {
411                 for(int i = 0; i < vline_event_count; i++) {
412                         if (vline_event[i] == device) {
413 #ifdef _DEBUG_LOG
414                                 this->out_debug_log(_T("EVENT: device (name=%s, id=%d) has already registered vline event !!!\n"), device->this_device_name, device->this_device_id);
415 #endif
416                                 return;
417                         }
418                 }
419                 vline_event[vline_event_count++] = device;
420 #ifdef _DEBUG_LOG
421         } else {
422                 this->out_debug_log(_T("EVENT: too many vline events !!!\n"));
423 #endif
424         }
425 }
426
427 uint32_t EVENT::get_event_remaining_clock(int register_id)
428 {
429         if(0 <= register_id && register_id < MAX_EVENT) {
430                 event_t *event_handle = &event[register_id];
431                 if(event_handle->active && event->expired_clock > event_clocks) {
432                         return (uint32_t)(event->expired_clock - event_clocks);
433                 }
434         }
435         return 0;
436 }
437
438 double EVENT::get_event_remaining_usec(int register_id)
439 {
440         return 1000000.0 * get_event_remaining_clock(register_id) / d_cpu[0].cpu_clocks;
441 }
442
443 void EVENT::touch_sound()
444 {
445         if(!(config.sound_strict_rendering || (need_mix > 0))) {
446                 int samples = mix_counter;
447                 if(samples >= (sound_tmp_samples - buffer_ptr)) {
448                         samples = sound_tmp_samples - buffer_ptr;
449                 }
450                 if(samples > 0) {
451                         mix_sound(samples);
452                         mix_counter -= samples;
453                 }
454         }
455 }
456
457 void EVENT::set_realtime_render(DEVICE* device, bool flag)
458 {
459         assert(device != NULL && device->this_device_id < MAX_DEVICE);
460         if(dev_need_mix[device->this_device_id] != flag) {
461                 if(flag) {
462                         need_mix++;
463                 } else {
464                         assert(need_mix > 0);
465                         need_mix--;
466                         if(need_mix < 0) need_mix = 0;
467                 }
468                 dev_need_mix[device->this_device_id] = flag;
469         }
470 }
471
472 void EVENT::event_callback(int event_id, int err)
473 {
474         // mix sound
475         if(prev_skip && dont_skip_frames == 0 && !sound_changed) {
476                 buffer_ptr = 0;
477         }
478         int remain = sound_tmp_samples - buffer_ptr;
479         
480         if(remain > 0) {
481                 int samples = mix_counter;
482                 
483                 if(config.sound_strict_rendering || (need_mix > 0)) {
484                         if(samples < 1) {
485                                 samples = 1;
486                         }
487                 }
488                 if(samples >= remain) {
489                         samples = remain;
490                 }
491                 if(config.sound_strict_rendering || (need_mix > 0)) {
492                         if(samples > 0) {
493                                 mix_sound(samples);
494                         }
495                         mix_counter = 1;
496                 } else {
497                         if(samples > 0 && mix_counter >= mix_limit) {
498                                 mix_sound(samples);
499                                 mix_counter -= samples;
500                         }
501                         mix_counter++;
502                 }
503         }
504 }
505
506 void EVENT::mix_sound(int samples)
507 {
508         if(samples > 0) {
509                 int32_t* buffer = sound_tmp + buffer_ptr * 2;
510                 memset(buffer, 0, samples * sizeof(int32_t) * 2);
511                 for(int i = 0; i < dcount_sound; i++) {
512                         d_sound[i]->mix(buffer, samples);
513                 }
514                 if(!sound_changed) {
515                         for(int i = 0; i < samples * 2; i += 2) {
516                                 if(buffer[i] != sound_tmp[0] || buffer[i + 1] != sound_tmp[1]) {
517                                         sound_changed = true;
518                                         break;
519                                 }
520                         }
521                 }
522                 buffer_ptr += samples;
523         } else {
524                 // notify to sound devices
525                 for(int i = 0; i < dcount_sound; i++) {
526                         d_sound[i]->mix(sound_tmp + buffer_ptr * 2, 0);
527                 }
528         }
529 }
530
531 uint16_t* EVENT::create_sound(int* extra_frames)
532 {
533         if(prev_skip && dont_skip_frames == 0 && !sound_changed) {
534                 memset(sound_buffer, 0, sound_samples * sizeof(uint16_t) * 2);
535                 *extra_frames = 0;
536                 return sound_buffer;
537         }
538         int frames = 0;
539         
540         // drive extra frames to fill the sound buffer
541         while(sound_samples > buffer_ptr) {
542                 drive();
543                 frames++;
544         }
545 #ifdef LOW_PASS_FILTER
546         // low-pass filter
547         for(int i = 0; i < sound_samples - 1; i++) {
548                 sound_tmp[i * 2    ] = (sound_tmp[i * 2    ] + sound_tmp[i * 2 + 2]) / 2; // L
549                 sound_tmp[i * 2 + 1] = (sound_tmp[i * 2 + 1] + sound_tmp[i * 2 + 3]) / 2; // R
550         }
551 #endif
552         // copy to buffer
553         for(int i = 0; i < sound_samples * 2; i++) {
554                 int dat = sound_tmp[i];
555                 uint16_t highlow = (uint16_t)(dat & 0x0000ffff);
556                 
557                 if((dat > 0) && (highlow >= 0x8000)) {
558                         sound_buffer[i] = 0x7fff;
559                         continue;
560                 }
561                 if((dat < 0) && (highlow < 0x8000)) {
562                         sound_buffer[i] = 0x8000;
563                         continue;
564                 }
565                 sound_buffer[i] = highlow;
566         }
567         if(buffer_ptr > sound_samples) {
568                 buffer_ptr -= sound_samples;
569                 memcpy(sound_tmp, sound_tmp + sound_samples * 2, buffer_ptr * sizeof(int32_t) * 2);
570         } else {
571                 buffer_ptr = 0;
572         }
573         *extra_frames = frames;
574         return sound_buffer;
575 }
576
577 int EVENT::get_sound_buffer_ptr()
578 {
579         return buffer_ptr;
580 }
581
582 void EVENT::request_skip_frames()
583 {
584         next_skip = true;
585 }
586
587 bool EVENT::is_frame_skippable()
588 {
589         bool value = next_skip;
590         
591         if(sound_changed || (prev_skip && !next_skip)) {
592                 dont_skip_frames = (int)frames_per_sec;
593         }
594         if(dont_skip_frames > 0) {
595                 value = false;
596                 dont_skip_frames--;
597         }
598         prev_skip = next_skip;
599         next_skip = false;
600         sound_changed = false;
601         
602         return value;
603 }
604
605 void EVENT::update_config()
606 {
607         if(power != config.cpu_power) {
608                 power = config.cpu_power;
609                 cpu_accum = 0;
610         }
611 }
612
613 #define STATE_VERSION   3
614
615 void EVENT::save_state(FILEIO* state_fio)
616 {
617         state_fio->FputUint32(STATE_VERSION);
618         state_fio->FputInt32(this_device_id);
619         
620         state_fio->FputInt32(dcount_cpu);
621         for(int i = 0; i < dcount_cpu; i++) {
622                 state_fio->FputUint32(d_cpu[i].cpu_clocks);
623                 state_fio->FputUint32(d_cpu[i].update_clocks);
624                 state_fio->FputUint32(d_cpu[i].accum_clocks);
625         }
626         state_fio->Fwrite(vclocks, sizeof(vclocks), 1);
627         state_fio->FputInt32(event_remain);
628         state_fio->FputInt32(cpu_remain);
629         state_fio->FputInt32(cpu_accum);
630         state_fio->FputInt32(cpu_done);
631         state_fio->FputUint64(event_clocks);
632         for(int i = 0; i < MAX_EVENT; i++) {
633                 state_fio->FputInt32(event[i].device != NULL ? event[i].device->this_device_id : -1);
634                 state_fio->FputInt32(event[i].event_id);
635                 state_fio->FputUint64(event[i].expired_clock);
636                 state_fio->FputUint64(event[i].loop_clock);
637                 state_fio->FputUint64(event[i].accum_clocks);
638                 state_fio->FputBool(event[i].active);
639                 state_fio->FputInt32(event[i].next != NULL ? event[i].next->index : -1);
640                 state_fio->FputInt32(event[i].prev != NULL ? event[i].prev->index : -1);
641         }
642         state_fio->FputInt32(first_free_event != NULL ? first_free_event->index : -1);
643         state_fio->FputInt32(first_fire_event != NULL ? first_fire_event->index : -1);
644         state_fio->FputDouble(frames_per_sec);
645         state_fio->FputDouble(next_frames_per_sec);
646         state_fio->FputInt32(lines_per_frame);
647         state_fio->FputInt32(next_lines_per_frame);
648         state_fio->Fwrite(dev_need_mix, sizeof(dev_need_mix), 1);
649         state_fio->FputInt32(need_mix);
650 }
651
652 bool EVENT::load_state(FILEIO* state_fio)
653 {
654         if(state_fio->FgetUint32() != STATE_VERSION) {
655                 return false;
656         }
657         if(state_fio->FgetInt32() != this_device_id) {
658                 return false;
659         }
660         if(state_fio->FgetInt32() != dcount_cpu) {
661                 return false;
662         }
663         for(int i = 0; i < dcount_cpu; i++) {
664                 d_cpu[i].cpu_clocks = state_fio->FgetUint32();
665                 d_cpu[i].update_clocks = state_fio->FgetUint32();
666                 d_cpu[i].accum_clocks = state_fio->FgetUint32();
667         }
668         state_fio->Fread(vclocks, sizeof(vclocks), 1);
669         event_remain = state_fio->FgetInt32();
670         cpu_remain = state_fio->FgetInt32();
671         cpu_accum = state_fio->FgetInt32();
672         cpu_done = state_fio->FgetInt32();
673         event_clocks = state_fio->FgetUint64();
674         for(int i = 0; i < MAX_EVENT; i++) {
675                 event[i].device = vm->get_device(state_fio->FgetInt32());
676                 event[i].event_id = state_fio->FgetInt32();
677                 event[i].expired_clock = state_fio->FgetUint64();
678                 event[i].loop_clock = state_fio->FgetUint64();
679                 event[i].accum_clocks = state_fio->FgetUint64();
680                 event[i].active = state_fio->FgetBool();
681                 event[i].next = (event_t *)get_event(state_fio->FgetInt32());
682                 event[i].prev = (event_t *)get_event(state_fio->FgetInt32());
683         }
684         first_free_event = (event_t *)get_event(state_fio->FgetInt32());
685         first_fire_event = (event_t *)get_event(state_fio->FgetInt32());
686         frames_per_sec = state_fio->FgetDouble();
687         next_frames_per_sec = state_fio->FgetDouble();
688         lines_per_frame = state_fio->FgetInt32();
689         next_lines_per_frame = state_fio->FgetInt32();
690         state_fio->Fread(dev_need_mix, sizeof(dev_need_mix), 1);
691         need_mix = state_fio->FgetInt32();
692         
693         // post process
694         if(sound_buffer) {
695                 memset(sound_buffer, 0, sound_samples * sizeof(uint16_t) * 2);
696         }
697         if(sound_tmp) {
698                 memset(sound_tmp, 0, sound_tmp_samples * sizeof(int32_t) * 2);
699         }
700         buffer_ptr = 0;
701         mix_counter = 1;
702         mix_limit = (int)((double)(emu->get_sound_rate() / 2000.0));  // per 0.5ms.
703         return true;
704 }
705
706 void* EVENT::get_event(int index)
707 {
708         if(index >= 0 && index < MAX_EVENT) {
709                 return &event[index];
710         }
711         return NULL;
712 }