Merge pull request #165 from jdgleaver/audio-sample-pacing

Send audio samples to frontend with correct pacing
This commit is contained in:
Autechre 2021-11-30 12:03:19 +01:00 committed by GitHub
commit be3fdfd0b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 102 additions and 27 deletions

View File

@ -54,6 +54,15 @@ static int translation_caches_inited = 0;
// Usually 59.72750057 Hz, unless GBC_RATE is overclocked (for 60FPS)
#define GBA_FPS ((float) GBC_BASE_RATE) / (308 * 228 * 4)
static s16 *audio_sample_buffer = NULL;
static float audio_samples_per_frame = 0.0f;
static float audio_samples_accumulator = 0.0f;
/* Workaround for a RetroArch audio driver
* limitation: a maximum of 1024 frames
* can be written per call of audio_batch_cb() */
#define AUDIO_BATCH_FRAMES_MAX 1024
/* Maximum number of consecutive frames that
* can be skipped */
#define FRAMESKIP_MAX 30
@ -72,6 +81,7 @@ static bios_type selected_bios = auto_detect;
static retro_log_printf_t log_cb;
static retro_video_refresh_t video_cb;
static retro_audio_sample_batch_t audio_batch_cb;
static retro_input_poll_t input_poll_cb;
static retro_environment_t environ_cb;
@ -367,6 +377,45 @@ void set_fastforward_override(bool fastforward)
environ_cb(RETRO_ENVIRONMENT_SET_FASTFORWARDING_OVERRIDE, &ff_override);
}
static void audio_run(void)
{
s16 *audio_buffer_ptr;
u32 samples_to_read;
u32 samples_produced;
/* audio_samples_per_frame is decimal;
* get integer component */
samples_to_read = (u32)audio_samples_per_frame;
/* Account for fractional component */
audio_samples_accumulator += audio_samples_per_frame -
(float)samples_to_read;
if (audio_samples_accumulator >= 1.0f)
{
samples_to_read++;
audio_samples_accumulator -= 1.0f;
}
samples_produced = sound_read_samples(audio_sample_buffer, samples_to_read);
/* Workaround for a RetroArch audio driver
* limitation: a maximum of 1024 frames
* can be written per call of audio_batch_cb(),
* so we have to send samples in chunks */
audio_buffer_ptr = audio_sample_buffer;
while (samples_produced > 0)
{
u32 samples_to_write = (samples_produced > AUDIO_BATCH_FRAMES_MAX) ?
AUDIO_BATCH_FRAMES_MAX : samples_produced;
audio_batch_cb(audio_buffer_ptr, samples_to_write);
samples_produced -= samples_to_write;
audio_buffer_ptr += samples_to_write << 1;
}
}
static void video_run(void)
{
u16 *gba_screen_pixels_buf = gba_screen_pixels;
@ -457,6 +506,12 @@ void retro_get_system_av_info(struct retro_system_av_info* info)
void retro_init(void)
{
u32 audio_sample_buffer_size;
audio_samples_per_frame = (float)(GBA_SOUND_FREQUENCY) / (float)(GBA_FPS);
audio_samples_accumulator = 0.0f;
audio_sample_buffer_size = ((u32)audio_samples_per_frame + 1) * 2;
audio_sample_buffer = (s16*)malloc(audio_sample_buffer_size * sizeof(s16));
#if defined(HAVE_DYNAREC)
#if defined(MMAP_JIT_CACHE)
rom_translation_cache = map_jit_block(ROM_TRANSLATION_CACHE_SIZE + RAM_TRANSLATION_CACHE_SIZE);
@ -593,6 +648,13 @@ void retro_deinit(void)
video_post_process = NULL;
post_process_cc = false;
post_process_mix = false;
if (audio_sample_buffer)
free(audio_sample_buffer);
audio_sample_buffer = NULL;
audio_samples_per_frame = 0.0f;
audio_samples_accumulator = 0.0f;
}
static retro_time_t retro_perf_dummy_get_time_usec() { return 0; }
@ -636,6 +698,14 @@ void retro_set_video_refresh(retro_video_refresh_t cb)
{
video_cb = cb;
}
void retro_set_audio_sample(retro_audio_sample_t cb) { }
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
{
audio_batch_cb = cb;
}
void retro_set_input_poll(retro_input_poll_t cb)
{
input_poll_cb = cb;
@ -1159,7 +1229,7 @@ void retro_run(void)
execute_arm(execute_cycles);
}
render_audio();
audio_run();
video_run();
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)

55
sound.c
View File

@ -749,34 +749,39 @@ unsigned sound_write_savestate(u8 *dst)
return (unsigned int)(dst - startp);
}
#include "libretro.h"
static retro_audio_sample_batch_t audio_batch_cb;
void retro_set_audio_sample(retro_audio_sample_t cb) { }
void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; }
void render_audio(void)
u32 sound_read_samples(s16 *out, u32 frames)
{
static s16 stream_base[512];
s16 *source;
u32 i;
u32 samples_to_read = frames << 1;
/* Get total number of samples in the buffer */
u32 samples_available = (gbc_sound_buffer_index - sound_buffer_base) & BUFFER_SIZE_MASK;
/* The last 512 samples are 'in use', and cannot
* be read out yet */
samples_available = (samples_available > 512) ? (samples_available - 512) : 0;
/* Available sample count must be an even number */
samples_available = (samples_available >> 1) << 1;
while (((gbc_sound_buffer_index - sound_buffer_base) & BUFFER_SIZE_MASK) > 512)
if (samples_to_read > samples_available)
samples_to_read = samples_available;
for(i = 0; i < samples_to_read; i++)
{
source = (s16 *)(sound_buffer + sound_buffer_base);
for(i = 0; i < 512; i++)
{
s32 current_sample = source[i];
if(current_sample > 2047)
current_sample = 2047;
if(current_sample < -2048)
current_sample = -2048;
stream_base[i] = current_sample * 16;
source[i] = 0;
}
audio_batch_cb(stream_base, 256);
sound_buffer_base += 512;
sound_buffer_base &= BUFFER_SIZE_MASK;
u32 source_index = (sound_buffer_base + i) & BUFFER_SIZE_MASK;
s32 current_sample = sound_buffer[source_index];
sound_buffer[source_index] = 0;
if(current_sample > 2047)
current_sample = 2047;
if(current_sample < -2048)
current_sample = -2048;
out[i] = current_sample * 16;
}
sound_buffer_base += samples_to_read;
sound_buffer_base &= BUFFER_SIZE_MASK;
/* Function returns number of frames read */
return (samples_to_read >> 1);
}

View File

@ -108,7 +108,7 @@ void init_sound(int need_reset);
unsigned sound_write_savestate(u8 *dst);
bool sound_read_savestate(const u8 *src);
void render_audio(void);
u32 sound_read_samples(s16 *out, u32 frames);
void reset_sound(void);