diff options
-rw-r--r-- | config.c | 1 | ||||
-rw-r--r-- | main.c | 8 | ||||
-rw-r--r-- | menu.c | 6 | ||||
-rw-r--r-- | options.c | 1 | ||||
-rw-r--r-- | options.h | 1 | ||||
-rw-r--r-- | plat_sdl.c | 71 |
6 files changed, 77 insertions, 11 deletions
@@ -25,6 +25,7 @@ static const struct { CE_NUM(show_fps), CE_NUM(show_cpu), CE_NUM(limit_frames), + CE_NUM(enable_drc), CE_NUM(audio_buffer_size), CE_NUM(scale_size), CE_NUM(scale_filter), @@ -31,6 +31,8 @@ static int last_screenshot = 0; static uint32_t vsyncs; static uint32_t renders; +#define UNDERRUN_THRESHOLD 0.5 + static void toggle_fast_forward(int force_off) { static int frameskip_style_was; @@ -198,6 +200,7 @@ void set_defaults(void) show_hud = 1; limit_frames = 1; enable_audio = 1; + enable_drc = 1; audio_buffer_size = 5; scale_size = SCALE_SIZE_NONE; scale_filter = SCALE_FILTER_NEAREST; @@ -496,7 +499,10 @@ static void adjust_audio(void) { if (current_core.retro_audio_buffer_status) { float occupancy = 1.0 - plat_sound_capacity(); - current_core.retro_audio_buffer_status(true, (int)(occupancy * 100), occupancy < 0.50); + if (enable_drc) + occupancy = MIN(1.0, occupancy * 2.0); + + current_core.retro_audio_buffer_status(true, (int)(occupancy * 100), occupancy < UNDERRUN_THRESHOLD); } } @@ -484,6 +484,7 @@ static const char h_restore_def[] = "Switches back to default settings"; static const char h_show_fps[] = "Shows frames and vsyncs per second"; static const char h_show_cpu[] = "Shows CPU usage"; +static const char h_enable_drc[] = "Dynamically adjusts audio rate for smoother video"; static const char h_audio_buffer_size[] = "The size of the audio buffer, in frames. Higher\n" @@ -511,6 +512,7 @@ static menu_entry e_menu_video_options[] = mee_enum_h ("Screen size", 0, scale_size, men_scale_size, h_scale_size), mee_enum_h ("Filter", 0, scale_filter, men_scale_filter, h_scale_filter), mee_range_h ("Audio buffer", 0, audio_buffer_size, 1, 15, h_audio_buffer_size), + mee_onoff_h ("Audio adjustment", 0, enable_drc, 1, h_enable_drc), mee_end, }; @@ -519,7 +521,7 @@ static int menu_loop_video_options(int id, int keys) static int sel = 0; me_loop(e_menu_video_options, &sel); - scale_update_scaler(); + plat_reinit(); return 0; } @@ -676,7 +678,7 @@ void menu_loop(void) me_enable(e_menu_main, MA_MAIN_SAVE_STATE, state_allowed()); me_enable(e_menu_main, MA_MAIN_LOAD_STATE, state_allowed()); me_enable(e_menu_main, MA_MAIN_CHEATS, cheats != NULL); - + me_enable(e_menu_main, MA_MAIN_DISC_CTRL, needs_disc_ctrl); if (override) @@ -11,6 +11,7 @@ int show_cpu; int show_hud; int limit_frames; int enable_audio; +int enable_drc; unsigned audio_buffer_size; enum scale_size scale_size; enum scale_filter scale_filter; @@ -8,6 +8,7 @@ extern int show_cpu; extern int show_hud; extern int limit_frames; extern int enable_audio; +extern int enable_drc; extern unsigned audio_buffer_size; extern enum scale_size scale_size; extern enum scale_filter scale_filter; @@ -18,6 +18,8 @@ struct audio_state { struct audio_frame *buf; int in_sample_rate; int out_sample_rate; + int sample_rate_adj; + int adj_out_sample_rate; }; struct audio_state audio; @@ -25,11 +27,16 @@ struct audio_state audio; static void plat_sound_select_resampler(void); void (*plat_sound_write)(const struct audio_frame *data, int frames); +#define DRC_MAX_ADJUSTMENT 0.003 +#define DRC_ADJ_BELOW 0.4 +#define DRC_ADJ_ABOVE 0.6 + static char msg[HUD_LEN]; static unsigned msg_priority = 0; static unsigned msg_expire = 0; static bool frame_dirty = false; +static int frame_time = 1000000 / 60; static void video_expire_msg(void) { @@ -65,16 +72,16 @@ static int audio_resample_nearest(struct audio_frame data) { static int diff = 0; int consumed = 0; - if (diff < audio.out_sample_rate) { + if (diff < audio.adj_out_sample_rate) { audio.buf[audio.buf_w++] = data; if (audio.buf_w >= audio.buf_len) audio.buf_w = 0; diff += audio.in_sample_rate; } - if (diff >= audio.out_sample_rate) { + if (diff >= audio.adj_out_sample_rate) { consumed++; - diff -= audio.out_sample_rate; + diff -= audio.adj_out_sample_rate; } return consumed; @@ -233,9 +240,25 @@ void plat_video_process(const void *data, unsigned width, unsigned height, size_ void plat_video_flip(void) { - if (frame_dirty) + static unsigned int next_frame_time_us = 0; + + if (frame_dirty) { + unsigned int time = plat_get_ticks_us(); + + if (limit_frames && enable_drc && time < next_frame_time_us) { + usleep(next_frame_time_us - time); + } + + if (!next_frame_time_us) + next_frame_time_us = time; + fb_flip(); + do { + next_frame_time_us += frame_time; + } while (next_frame_time_us < time); + } + frame_dirty = false; } @@ -324,6 +347,9 @@ static int plat_sound_init(void) audio.in_sample_rate = sample_rate; audio.out_sample_rate = received.freq; + audio.sample_rate_adj = audio.out_sample_rate * DRC_MAX_ADJUSTMENT; + audio.adj_out_sample_rate = audio.out_sample_rate; + plat_sound_select_resampler(); plat_sound_resize_buffer(); @@ -347,12 +373,22 @@ float plat_sound_capacity(void) } #define BATCH_SIZE 100 -void plat_sound_write_resample(const struct audio_frame *data, int frames, int (*resample)(struct audio_frame data)) +void plat_sound_write_resample(const struct audio_frame *data, int frames, int (*resample)(struct audio_frame data), bool drc) { int consumed = 0; if (audio.buf_len == 0) return; + if (drc) { + if (plat_sound_capacity() < DRC_ADJ_BELOW) { + audio.adj_out_sample_rate = audio.out_sample_rate - audio.sample_rate_adj; + } else if (plat_sound_capacity() > DRC_ADJ_ABOVE) { + audio.adj_out_sample_rate = audio.out_sample_rate + audio.sample_rate_adj; + } else { + audio.adj_out_sample_rate = audio.out_sample_rate; + } + } + SDL_LockAudio(); while (frames > 0) { @@ -382,12 +418,17 @@ void plat_sound_write_resample(const struct audio_frame *data, int frames, int ( void plat_sound_write_passthrough(const struct audio_frame *data, int frames) { - plat_sound_write_resample(data, frames, audio_resample_passthrough); + plat_sound_write_resample(data, frames, audio_resample_passthrough, false); } void plat_sound_write_nearest(const struct audio_frame *data, int frames) { - plat_sound_write_resample(data, frames, audio_resample_nearest); + plat_sound_write_resample(data, frames, audio_resample_nearest, false); +} + +void plat_sound_write_drc(const struct audio_frame *data, int frames) +{ + plat_sound_write_resample(data, frames, audio_resample_nearest, true); } void plat_sound_resize_buffer(void) { @@ -398,6 +439,10 @@ void plat_sound_resize_buffer(void) { ? current_audio_buffer_size * audio.in_sample_rate / frame_rate : 0; + /* Dynamic adjustment keeps buffer 50% full, need double size */ + if (enable_drc) + audio.buf_len *= 2; + if (audio.buf_len == 0) { SDL_UnlockAudio(); return; @@ -422,7 +467,10 @@ void plat_sound_resize_buffer(void) { static void plat_sound_select_resampler(void) { - if (audio.in_sample_rate == audio.out_sample_rate) { + if (enable_drc) { + PA_INFO("Using audio adjustment (in: %d, out: %d-%d)\n", audio.in_sample_rate, audio.out_sample_rate - audio.sample_rate_adj, audio.out_sample_rate + audio.sample_rate_adj); + plat_sound_write = plat_sound_write_drc; + } else if (audio.in_sample_rate == audio.out_sample_rate) { PA_INFO("Using passthrough resampler (in: %d, out: %d)\n", audio.in_sample_rate, audio.out_sample_rate); plat_sound_write = plat_sound_write_passthrough; } else { @@ -479,7 +527,14 @@ int plat_reinit(void) PA_ERROR("SDL sound failed to init: %s\n", SDL_GetError()); return -1; } + } else { + plat_sound_resize_buffer(); + plat_sound_select_resampler(); } + + if (frame_rate != 0) + frame_time = 1000000 / frame_rate; + scale_update_scaler(); return 0; } |