Mercurial > repos > blastem
comparison blastem.c @ 2640:c30e5548154f
Get sync to audio working in emscripten
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 26 Feb 2025 22:55:42 -0800 |
parents | c768bbd912f1 |
children | 99297d5f4c5d |
comparison
equal
deleted
inserted
replaced
2639:0046305e3fa8 | 2640:c30e5548154f |
---|---|
30 #ifndef DISABLE_NUKLEAR | 30 #ifndef DISABLE_NUKLEAR |
31 #include "nuklear_ui/blastem_nuklear.h" | 31 #include "nuklear_ui/blastem_nuklear.h" |
32 #endif | 32 #endif |
33 #ifdef __EMSCRIPTEN__ | 33 #ifdef __EMSCRIPTEN__ |
34 #include <emscripten.h> | 34 #include <emscripten.h> |
35 #include "render_audio.h" | |
35 #endif | 36 #endif |
36 | 37 |
37 #include "version.inc" | 38 #include "version.inc" |
38 | 39 |
39 #ifdef __ANDROID__ | 40 #ifdef __ANDROID__ |
140 persist_save_registered = 1; | 141 persist_save_registered = 1; |
141 } | 142 } |
142 } | 143 } |
143 } | 144 } |
144 | 145 |
145 void apply_updated_config(void) | |
146 { | |
147 render_config_updated(); | |
148 set_bindings(); | |
149 update_pad_bindings(); | |
150 if (current_system && current_system->config_updated) { | |
151 current_system->config_updated(current_system); | |
152 } | |
153 } | |
154 | |
155 static system_media cart, lock_on; | |
156 static void on_drag_drop(char *filename) | |
157 { | |
158 if (current_system) { | |
159 if (current_system->next_rom) { | |
160 free(current_system->next_rom); | |
161 } | |
162 current_system->next_rom = strdup(filename); | |
163 system_request_exit(current_system, 1); | |
164 if (menu_system && menu_system->type == SYSTEM_GENESIS) { | |
165 genesis_context *gen = (genesis_context *)menu_system; | |
166 if (gen->extra) { | |
167 menu_context *menu = gen->extra; | |
168 menu->external_game_load = 1; | |
169 } | |
170 } | |
171 cart.chain = NULL; | |
172 } else { | |
173 init_system_with_media(filename, SYSTEM_UNKNOWN); | |
174 } | |
175 #ifndef DISABLE_NUKLEAR | |
176 if (is_nuklear_active()) { | |
177 show_play_view(); | |
178 } | |
179 #endif | |
180 } | |
181 | |
182 const system_media *current_media(void) | |
183 { | |
184 return &cart; | |
185 } | |
186 | |
187 void reload_media(void) | |
188 { | |
189 if (!current_system || !cart.orig_path) { | |
190 return; | |
191 } | |
192 if (current_system->next_rom) { | |
193 free(current_system->next_rom); | |
194 } | |
195 current_system->next_rom = cart.orig_path; | |
196 cart.orig_path = NULL; | |
197 if (cart.chain) { | |
198 load_media(cart.chain->orig_path, cart.chain, NULL); | |
199 } | |
200 system_request_exit(current_system, 1); | |
201 } | |
202 | |
203 void lockon_media(char *lock_on_path) | |
204 { | |
205 free(lock_on.dir); | |
206 free(lock_on.name); | |
207 free(lock_on.extension); | |
208 free(lock_on.orig_path); | |
209 if (lock_on_path) { | |
210 if (!current_system || !current_system->lockon_change) { | |
211 cart.chain = NULL; | |
212 reload_media(); | |
213 } | |
214 cart.chain = &lock_on; | |
215 load_media(lock_on_path, &lock_on, NULL); | |
216 if (current_system && current_system->lockon_change) { | |
217 current_system->lockon_change(current_system, &lock_on); | |
218 } | |
219 } else { | |
220 lock_on.dir = NULL; | |
221 lock_on.name = NULL; | |
222 lock_on.extension = NULL; | |
223 lock_on.orig_path = NULL; | |
224 cart.chain = NULL; | |
225 } | |
226 } | |
227 | |
228 static uint32_t opts = 0; | |
229 static uint8_t force_region = 0; | |
230 void init_system_with_media(char *path, system_type force_stype) | |
231 { | |
232 if (game_system) { | |
233 if (game_system->persist_save) { | |
234 game_system->persist_save(game_system); | |
235 } | |
236 //swap to game context arena and mark all allocated pages in it free | |
237 if (current_system == menu_system) { | |
238 current_system->arena = set_current_arena(game_system->arena); | |
239 } | |
240 mark_all_free(); | |
241 game_system->free_context(game_system); | |
242 } else if(current_system) { | |
243 //start a new arena and save old one in suspended system context | |
244 current_system->arena = start_new_arena(); | |
245 } | |
246 free(cart.dir); | |
247 free(cart.name); | |
248 free(cart.extension); | |
249 free(cart.orig_path); | |
250 system_type stype = SYSTEM_UNKNOWN; | |
251 if (!(cart.size = load_media(path, &cart, &stype))) { | |
252 fatal_error("Failed to open %s for reading\n", path); | |
253 } | |
254 | |
255 if (force_stype != SYSTEM_UNKNOWN) { | |
256 stype = force_stype; | |
257 } | |
258 if (stype == SYSTEM_UNKNOWN) { | |
259 stype = detect_system_type(&cart); | |
260 } | |
261 if (stype == SYSTEM_UNKNOWN) { | |
262 fatal_error("Failed to detect system type for %s\n", path); | |
263 } | |
264 //allocate new system context | |
265 game_system = alloc_config_system(stype, &cart, opts, force_region); | |
266 if (!game_system) { | |
267 fatal_error("Failed to configure emulated machine for %s\n", path); | |
268 } | |
269 if (menu_system) { | |
270 menu_system->next_context = game_system; | |
271 } | |
272 game_system->next_context = menu_system; | |
273 setup_saves(&cart, game_system); | |
274 update_title(game_system->info.name); | |
275 } | |
276 | |
277 static uint8_t menu; | 146 static uint8_t menu; |
278 static uint8_t use_nuklear; | 147 static uint8_t use_nuklear; |
279 #ifdef __EMSCRIPTEN__ | 148 #ifdef __EMSCRIPTEN__ |
280 void handle_frame_presented(void) | 149 void handle_frame_presented(void) |
281 { | 150 { |
307 was_menu = 0; | 176 was_menu = 0; |
308 ui_exit(); | 177 ui_exit(); |
309 #endif | 178 #endif |
310 } | 179 } |
311 if (current_system) { | 180 if (current_system) { |
181 if (system_started && render_is_audio_sync()) { | |
182 if (all_sources_ready()) { | |
183 return; | |
184 } | |
185 } | |
312 if (current_system->next_rom) { | 186 if (current_system->next_rom) { |
313 char *next_rom = current_system->next_rom; | 187 char *next_rom = current_system->next_rom; |
314 current_system->next_rom = NULL; | 188 current_system->next_rom = NULL; |
315 init_system_with_media(next_rom, 0); | 189 init_system_with_media(next_rom, 0); |
316 system_started = 0; | 190 system_started = 0; |
328 } | 202 } |
329 } | 203 } |
330 } | 204 } |
331 | 205 |
332 } | 206 } |
333 #endif | 207 |
208 void setup_main_loop(void) | |
209 { | |
210 //can't use render_is_audio_sync since we haven't called render_init/render_config_updated yet | |
211 char *sync = tern_find_path_default(config, "system\0sync_source\0", (tern_val){.ptrval = "audio"}, TVAL_PTR).ptrval; | |
212 emscripten_cancel_main_loop(); | |
213 if (!strcmp("video", sync)) { | |
214 render_set_audio_full_fun(NULL); | |
215 render_set_frame_presented_fun(handle_frame_presented); | |
216 emscripten_set_main_loop(browser_main_loop, 0, 0); | |
217 } else { | |
218 render_set_frame_presented_fun(NULL); | |
219 render_set_audio_full_fun(handle_frame_presented); | |
220 emscripten_set_main_loop(browser_main_loop, 1, 0); //dummy fps value, will be overridden by a call to emscripten_set_main_loop_timing | |
221 } | |
222 } | |
223 #endif | |
224 | |
225 void apply_updated_config(void) | |
226 { | |
227 #ifdef __EMSCRIPTEN__ | |
228 setup_main_loop(); | |
229 #endif | |
230 render_config_updated(); | |
231 set_bindings(); | |
232 update_pad_bindings(); | |
233 if (current_system && current_system->config_updated) { | |
234 current_system->config_updated(current_system); | |
235 } | |
236 } | |
237 | |
238 static system_media cart, lock_on; | |
239 static void on_drag_drop(char *filename) | |
240 { | |
241 if (current_system) { | |
242 if (current_system->next_rom) { | |
243 free(current_system->next_rom); | |
244 } | |
245 current_system->next_rom = strdup(filename); | |
246 system_request_exit(current_system, 1); | |
247 if (menu_system && menu_system->type == SYSTEM_GENESIS) { | |
248 genesis_context *gen = (genesis_context *)menu_system; | |
249 if (gen->extra) { | |
250 menu_context *menu = gen->extra; | |
251 menu->external_game_load = 1; | |
252 } | |
253 } | |
254 cart.chain = NULL; | |
255 } else { | |
256 init_system_with_media(filename, SYSTEM_UNKNOWN); | |
257 } | |
258 #ifndef DISABLE_NUKLEAR | |
259 if (is_nuklear_active()) { | |
260 show_play_view(); | |
261 } | |
262 #endif | |
263 } | |
264 | |
265 const system_media *current_media(void) | |
266 { | |
267 return &cart; | |
268 } | |
269 | |
270 void reload_media(void) | |
271 { | |
272 if (!current_system || !cart.orig_path) { | |
273 return; | |
274 } | |
275 if (current_system->next_rom) { | |
276 free(current_system->next_rom); | |
277 } | |
278 current_system->next_rom = cart.orig_path; | |
279 cart.orig_path = NULL; | |
280 if (cart.chain) { | |
281 load_media(cart.chain->orig_path, cart.chain, NULL); | |
282 } | |
283 system_request_exit(current_system, 1); | |
284 } | |
285 | |
286 void lockon_media(char *lock_on_path) | |
287 { | |
288 free(lock_on.dir); | |
289 free(lock_on.name); | |
290 free(lock_on.extension); | |
291 free(lock_on.orig_path); | |
292 if (lock_on_path) { | |
293 if (!current_system || !current_system->lockon_change) { | |
294 cart.chain = NULL; | |
295 reload_media(); | |
296 } | |
297 cart.chain = &lock_on; | |
298 load_media(lock_on_path, &lock_on, NULL); | |
299 if (current_system && current_system->lockon_change) { | |
300 current_system->lockon_change(current_system, &lock_on); | |
301 } | |
302 } else { | |
303 lock_on.dir = NULL; | |
304 lock_on.name = NULL; | |
305 lock_on.extension = NULL; | |
306 lock_on.orig_path = NULL; | |
307 cart.chain = NULL; | |
308 } | |
309 } | |
310 | |
311 static uint32_t opts = 0; | |
312 static uint8_t force_region = 0; | |
313 void init_system_with_media(char *path, system_type force_stype) | |
314 { | |
315 if (game_system) { | |
316 if (game_system->persist_save) { | |
317 game_system->persist_save(game_system); | |
318 } | |
319 //swap to game context arena and mark all allocated pages in it free | |
320 if (current_system == menu_system) { | |
321 current_system->arena = set_current_arena(game_system->arena); | |
322 } | |
323 mark_all_free(); | |
324 game_system->free_context(game_system); | |
325 } else if(current_system) { | |
326 //start a new arena and save old one in suspended system context | |
327 current_system->arena = start_new_arena(); | |
328 } | |
329 free(cart.dir); | |
330 free(cart.name); | |
331 free(cart.extension); | |
332 free(cart.orig_path); | |
333 system_type stype = SYSTEM_UNKNOWN; | |
334 if (!(cart.size = load_media(path, &cart, &stype))) { | |
335 fatal_error("Failed to open %s for reading\n", path); | |
336 } | |
337 | |
338 if (force_stype != SYSTEM_UNKNOWN) { | |
339 stype = force_stype; | |
340 } | |
341 if (stype == SYSTEM_UNKNOWN) { | |
342 stype = detect_system_type(&cart); | |
343 } | |
344 if (stype == SYSTEM_UNKNOWN) { | |
345 fatal_error("Failed to detect system type for %s\n", path); | |
346 } | |
347 //allocate new system context | |
348 game_system = alloc_config_system(stype, &cart, opts, force_region); | |
349 if (!game_system) { | |
350 fatal_error("Failed to configure emulated machine for %s\n", path); | |
351 } | |
352 if (menu_system) { | |
353 menu_system->next_context = game_system; | |
354 } | |
355 game_system->next_context = menu_system; | |
356 setup_saves(&cart, game_system); | |
357 update_title(game_system->info.name); | |
358 } | |
334 | 359 |
335 char *parse_addr_port(char *arg) | 360 char *parse_addr_port(char *arg) |
336 { | 361 { |
337 while (*arg && *arg != ':') { | 362 while (*arg && *arg != ':') { |
338 ++arg; | 363 ++arg; |
548 char *config_fullscreen = tern_find_path(config, "video\0fullscreen\0", TVAL_PTR).ptrval; | 573 char *config_fullscreen = tern_find_path(config, "video\0fullscreen\0", TVAL_PTR).ptrval; |
549 if (config_fullscreen && !strcmp("on", config_fullscreen)) { | 574 if (config_fullscreen && !strcmp("on", config_fullscreen)) { |
550 fullscreen = !fullscreen; | 575 fullscreen = !fullscreen; |
551 } | 576 } |
552 #ifdef __EMSCRIPTEN__ | 577 #ifdef __EMSCRIPTEN__ |
553 config = tern_insert_path(config, "system\0sync_source\0", (tern_val){.ptrval = strdup("video")}, TVAL_PTR); | |
554 config = tern_insert_path(config, "ui\0initial_path\0", (tern_val){.ptrval = strdup("/roms")}, TVAL_PTR); | 578 config = tern_insert_path(config, "ui\0initial_path\0", (tern_val){.ptrval = strdup("/roms")}, TVAL_PTR); |
555 render_set_frame_presented_fun(handle_frame_presented); | 579 setup_main_loop(); |
556 emscripten_set_main_loop(browser_main_loop, 0, 0); | |
557 #endif | 580 #endif |
558 if (!headless) { | 581 if (!headless) { |
559 if (reader_addr) { | 582 if (reader_addr) { |
560 render_set_external_sync(1); | 583 render_set_external_sync(1); |
561 } | 584 } |