2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
22 #define MAX_LINES 1024
25 #if !defined(MAX_SOUND_IN_BUFFERS)
26 #define MAX_SOUND_IN_BUFFERS 8
28 #if (MAX_SOUND_IN_BUFFERS <= 0)
29 #define MAX_SOUND_IN_BUFFERS 8
34 EVENT_CPUTYPE_GENERIC = 0,
36 EVENT_CPUTYPE_HUC6280,
47 EVENT_CPUTYPE_TMS9995,
48 EVENT_CPUTYPE_UPD7801,
52 EVENT_CPUTYPE_UPD7810,
53 EVENT_CPUTYPE_UPD7907,
57 class EVENT : public DEVICE
64 uint32_t update_clocks;
65 uint32_t accum_clocks;
69 uint32_t cpu_update_clocks[MAX_CPU][6];
73 int vline_clocks[MAX_LINES];
75 int event_remain, event_extra;
76 int cpu_remain, cpu_accum, cpu_done;
77 uint64_t event_clocks;
79 typedef struct event_t {
82 uint64_t expired_clock;
84 uint64_t accum_clocks;
90 event_t event[MAX_EVENT];
91 event_t *first_free_event;
92 event_t *first_fire_event;
94 DEVICE* frame_event[MAX_EVENT];
95 DEVICE* vline_event[MAX_EVENT];
96 int frame_event_count, vline_event_count;
98 double frames_per_sec, next_frames_per_sec;
99 int lines_per_frame, next_lines_per_frame;
100 uint32_t vline_start_clock;
103 void update_event(int clock);
104 void insert_event(event_t *event_handle);
107 DEVICE* d_sound[MAX_SOUND];
110 uint16_t* sound_buffer;
114 int sound_tmp_samples;
116 int16_t* sound_in_tmp_buffer[MAX_SOUND_IN_BUFFERS]; // This is buffer from recording devices.
117 int sound_in_rate[MAX_SOUND_IN_BUFFERS];
118 int sound_in_samples[MAX_SOUND_IN_BUFFERS];
119 int sound_in_channels[MAX_SOUND_IN_BUFFERS];
120 int sound_in_writeptr[MAX_SOUND_IN_BUFFERS];
121 int sound_in_readptr[MAX_SOUND_IN_BUFFERS];
122 int sound_in_write_size[MAX_SOUND_IN_BUFFERS];
123 int sound_in_read_size[MAX_SOUND_IN_BUFFERS];
124 int sound_in_read_mod[MAX_SOUND_IN_BUFFERS];
126 int dont_skip_frames;
127 bool prev_skip, next_skip;
132 bool dev_need_mix[MAX_DEVICE];
135 void mix_sound(int samples);
136 void* get_event(int index);
139 bool initialize_done;
142 EVENT(VM_TEMPLATE* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
144 dcount_cpu = dcount_sound = 0;
145 frame_event_count = vline_event_count = 0;
148 memset(event, 0, sizeof(event));
149 for(int i = 0; i < MAX_EVENT; i++) {
150 event[i].active = false;
152 event[i].next = (i + 1 < MAX_EVENT) ? &event[i + 1] : NULL;
154 first_free_event = &event[0];
155 first_fire_event = NULL;
159 // force update timing in the first frame
160 frames_per_sec = 0.0;
162 next_frames_per_sec = FRAMES_PER_SEC;
163 next_lines_per_frame = LINES_PER_FRAME;
164 // reset before other device may call set_realtime_render()
165 memset(dev_need_mix, 0, sizeof(dev_need_mix));
168 for(int i = 0; i < MAX_SOUND_IN_BUFFERS; i++) {
169 sound_in_tmp_buffer[i] = NULL;
170 sound_in_rate[i] = 0;
171 sound_in_samples[i] = 0;
172 sound_in_channels[i] = 0;
173 sound_in_readptr[i] = 0;
174 sound_in_writeptr[i] = 0;
175 sound_in_read_size[i] = 0;
176 sound_in_write_size[i] = 0;
177 sound_in_read_mod[i] = 0;
180 initialize_done = false;
182 set_device_name(_T("Event Manager"));
190 void event_callback(int event_id, int err);
191 void update_config();
192 bool process_state(FILEIO* state_fio, bool loading);
194 // common event functions
195 int get_event_manager_id()
197 return this_device_id;
199 void set_frames_per_sec(double new_frames_per_sec)
201 next_frames_per_sec = new_frames_per_sec;
203 void set_lines_per_frame(int new_lines_per_frame)
205 if(new_lines_per_frame < MAX_LINES) {
206 next_lines_per_frame = new_lines_per_frame;
209 int get_lines_per_frame()
211 return next_lines_per_frame;
213 bool is_primary_cpu(DEVICE* device)
215 return (d_cpu[0].device == device);
217 void update_extra_event(int clock);
218 void register_event(DEVICE* device, int event_id, double usec, bool loop, int* register_id);
219 void register_event_by_clock(DEVICE* device, int event_id, uint64_t clock, bool loop, int* register_id);
220 void cancel_event(DEVICE* device, int register_id);
221 void register_frame_event(DEVICE* device);
222 void register_vline_event(DEVICE* device);
223 uint32_t get_event_remaining_clock(int register_id);
224 double get_event_remaining_usec(int register_id);
225 uint32_t get_current_clock();
226 uint32_t get_passed_clock(uint32_t prev);
227 double get_passed_usec(uint32_t prev);
228 uint32_t get_passed_clock_since_vline();
229 double get_passed_usec_since_vline();
234 int get_cur_vline_clocks()
236 return vline_clocks[cur_vline];
238 uint32_t get_cpu_pc(int index);
239 void request_skip_frames();
241 void set_realtime_render(DEVICE* device, bool flag);
242 uint64_t get_current_clock_uint64();
243 uint32_t get_cpu_clock(int index);
245 double get_frame_rate()
247 return next_frames_per_sec;
251 void initialize_sound(int rate, int samples);
252 uint16_t* create_sound(int* extra_frames);
253 int get_sound_buffer_ptr();
254 // Sound input functions
255 void clear_sound_in_source(int bank);
256 int add_sound_in_source(int rate, int samples, int channels);
257 int release_sound_in_source(int bank);
259 bool is_sound_in_source_exists(int bank);
260 int increment_sound_in_passed_data(int bank, double passed_usec);
261 int get_sound_in_buffers_count();
262 int get_sound_in_samples(int bank);
263 int get_sound_in_rate(int bank);
264 int get_sound_in_channels(int bank);
265 int16_t* get_sound_in_buf_ptr(int bank);
266 int write_sound_in_buffer(int bank, int32_t* src, int samples);
267 // Add sampled values to sample buffer;value may be -32768 to +32767.
268 int get_sound_in_latest_data(int bank, int32_t* dst, int expect_channels);
269 int get_sound_in_data(int bank, int32_t* dst, int expect_samples, int expect_rate, int expect_channels);
270 int rechannel_sound_in_data(int32_t*dst, int16_t* src, int dst_channels, int src_channels, int samples);
272 int set_context_cpu(DEVICE* device, uint32_t clocks = CPU_CLOCKS)
274 assert(dcount_cpu < MAX_CPU);
275 int index = dcount_cpu++;
276 d_cpu[index].device = (DEVICE *)device;
277 d_cpu[index].cpu_clocks = clocks;
278 d_cpu[index].accum_clocks = 0;
279 for(int k = 0; k < 6; k++) cpu_update_clocks[index][k] = d_cpu[index].update_clocks * k;
282 bool remove_context_cpu(DEVICE* device, int num)
284 if(num <= 0) return false; // Number one must not be removed.
285 if(num >= MAX_CPU) return false;
286 if(num >= dcount_cpu) return false;
287 if(dcount_cpu <= 1) return false;
288 // Note: This function is dangerous.
289 if(d_cpu[num].device != device) return false;
290 if(d_cpu[num].device == NULL) return false;
291 if(dcount_cpu == 2) {
292 d_cpu[1].device = (DEVICE *)NULL;
293 d_cpu[1].cpu_clocks = 0;
294 d_cpu[1].accum_clocks = 0;
296 for(int k = 0; k < 6; k++) cpu_update_clocks[1][k] = d_cpu[1].update_clocks * k;
298 for(int i = num; i < (dcount_cpu - 1); i++) {
299 d_cpu[i].device = d_cpu[i + 1].device;
300 d_cpu[i].cpu_clocks = d_cpu[i + 1].cpu_clocks;
301 d_cpu[i].accum_clocks = d_cpu[i + 1].accum_clocks;
303 int n = dcount_cpu - 1;
304 d_cpu[n].device = (DEVICE *)NULL;
305 d_cpu[n].cpu_clocks = 0;
306 d_cpu[n].accum_clocks = 0;
307 for(int i = 1; i < dcount_cpu; i++) {
308 for(int k = 0; k < 6; k++) cpu_update_clocks[i][k] = d_cpu[i].update_clocks * k;
310 dcount_cpu = dcount_cpu - 1;
314 void set_secondary_cpu_clock(DEVICE* device, uint32_t clocks)
316 // XXX: primary cpu clock should not be changed
317 for(int index = 1; index < dcount_cpu; index++) {
318 if(d_cpu[index].device == device) {
319 d_cpu[index].accum_clocks = 0;
320 d_cpu[index].cpu_clocks = clocks;
321 d_cpu[index].update_clocks = (int)(1024.0 * (double)d_cpu[index].cpu_clocks / (double)d_cpu[0].cpu_clocks + 0.5)
323 for(int k = 0; k < 6; k++) cpu_update_clocks[index][k] = d_cpu[index].update_clocks * k;
328 void set_context_sound(DEVICE* device)
330 assert(dcount_sound < MAX_SOUND);
331 d_sound[dcount_sound++] = device;
333 bool is_frame_skippable();
337 * Faster runncing cpu.
338 * Expect to optimize switch(...) - case to jump table.
339 * You should include real header of CPU DEVICE begin of this file.