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 }