audio improvements

This commit is contained in:
izzy2lost
2026-02-23 19:48:00 -05:00
parent 6f305476cc
commit 38337f4acb
6 changed files with 102 additions and 27 deletions
+95 -21
View File
@@ -3,10 +3,30 @@
#include "samplerate.h"
/*
* Minimal libsamplerate replacement for Android.
*
* Uses linear interpolation for sample-rate conversion. Quality is lower
* than the sinc resampler used on desktop, but the ratio is correctly
* applied so voices recorded at rates other than 48 kHz (e.g. 22050 Hz
* dialogue in Halo CE) play at the right pitch instead of chipmunk-fast.
*
* The original stub did: (void)ratio; — i.e. passed samples through
* unchanged regardless of the conversion ratio, causing every sub-48 kHz
* voice to play back at 48000/source_rate times normal speed.
*/
struct SRC_STATE {
src_callback_t cb;
void *cb_data;
int channels;
void *cb_data;
int channels;
/* Current input block (pointer owned by the callback, not by us). */
float *buf;
long buf_len; /* frames in buf */
/* Fractional read position within buf (advances by 1/ratio per output frame). */
double buf_pos;
};
SRC_STATE *src_callback_new(src_callback_t cb, int converter_type, int channels,
@@ -23,40 +43,98 @@ SRC_STATE *src_callback_new(src_callback_t cb, int converter_type, int channels,
}
return NULL;
}
state->cb = cb;
state->cb_data = cb_data;
state->cb = cb;
state->cb_data = cb_data;
state->channels = channels;
state->buf = NULL;
state->buf_len = 0;
state->buf_pos = 0.0;
return state;
}
/*
* ratio = output_sample_rate / input_sample_rate
* > 1 : upsampling (e.g. 22050 -> 48000, ratio ≈ 2.177)
* < 1 : downsampling
* = 1 : pass-through (still goes through the interpolator for simplicity)
*
* step = 1/ratio = input frames consumed per output frame produced.
*/
long src_callback_read(SRC_STATE *state, double ratio, long frames, float *data)
{
(void)ratio;
if (!state || !state->cb || !data || frames <= 0) {
if (!state || !state->cb || !data || frames <= 0 || ratio <= 0.0) {
return 0;
}
float *in = NULL;
long got = state->cb(state->cb_data, &in);
if (got <= 0 || in == NULL) {
return 0;
const double step = 1.0 / ratio;
long out = 0;
while (out < frames) {
long idx = (long)state->buf_pos;
/* Refill the input buffer when we have consumed it. */
if (state->buf == NULL || idx >= state->buf_len) {
/*
* Carry the fractional overshoot past the end of the old block
* into the start of the new block. This preserves continuity
* when ratio > 1 (step < 1) and we drain the buffer gradually.
*/
double carry = (state->buf_len > 0)
? state->buf_pos - (double)state->buf_len
: 0.0;
if (carry < 0.0) {
carry = 0.0;
}
float *new_buf = NULL;
long got = state->cb(state->cb_data, &new_buf);
if (got <= 0 || new_buf == NULL) {
break; /* source exhausted */
}
state->buf = new_buf;
state->buf_len = got;
state->buf_pos = carry;
idx = (long)state->buf_pos;
if (idx >= state->buf_len) {
break; /* carry >= new block length — shouldn't happen */
}
}
/* Linear interpolation between sample[idx] and sample[idx+1]. */
float alpha = (float)(state->buf_pos - (double)idx);
long next_idx = idx + 1;
for (int ch = 0; ch < state->channels; ch++) {
float s0 = state->buf[idx * state->channels + ch];
float s1 = (next_idx < state->buf_len)
? state->buf[next_idx * state->channels + ch]
: s0; /* hold last sample at block boundary */
data[out * state->channels + ch] = s0 + alpha * (s1 - s0);
}
state->buf_pos += step;
out++;
}
long to_copy = frames < got ? frames : got;
memcpy(data, in, sizeof(float) * to_copy * state->channels);
return to_copy;
return out;
}
int src_reset(SRC_STATE *state)
{
(void)state;
if (state) {
state->buf = NULL;
state->buf_len = 0;
state->buf_pos = 0.0;
}
return 0;
}
const char *src_strerror(int error)
{
(void)error;
return "libsamplerate stub";
return "libsamplerate stub (linear)";
}
void src_float_to_short_array(const float *in, short *out, int len)
@@ -64,14 +142,10 @@ void src_float_to_short_array(const float *in, short *out, int len)
if (!in || !out || len <= 0) {
return;
}
for (int i = 0; i < len; ++i) {
float v = in[i];
if (v > 1.0f) {
v = 1.0f;
} else if (v < -1.0f) {
v = -1.0f;
}
if (v > 1.0f) v = 1.0f;
else if (v < -1.0f) v = -1.0f;
out[i] = (short)(v * 32767.0f);
}
}
+2 -2
View File
@@ -565,7 +565,7 @@ cleanup:
struct EmulatorSettings {
int surface_scale = 1; // 1, 2, or 3
std::string tcg_thread = "multi"; // "single" or "multi"
bool use_dsp = true;
bool use_dsp = false;
bool hrtf = true;
bool cache_shaders = true;
bool hard_fpu = true;
@@ -776,7 +776,7 @@ static SetupFiles SyncSetupFiles() {
EmulatorSettings emuSettings;
emuSettings.surface_scale = GetPrefInt(env, activity, "setting_surface_scale", 1);
emuSettings.use_dsp = GetPrefBool(env, activity, "setting_use_dsp", true);
emuSettings.use_dsp = GetPrefBool(env, activity, "setting_use_dsp", false);
emuSettings.hrtf = GetPrefBool(env, activity, "setting_hrtf", true);
emuSettings.cache_shaders = GetPrefBool(env, activity, "setting_cache_shaders", true);
emuSettings.hard_fpu = GetPrefBool(env, activity, "setting_hard_fpu", true);
@@ -88,7 +88,7 @@ static void xemu_settings_apply_defaults(void)
g_config.display.setup_nvidia_profile = true;
g_config.audio.vp.num_workers = 0;
g_config.audio.use_dsp = true;
g_config.audio.use_dsp = false;
g_config.audio.hrtf = true;
g_config.audio.volume_limit = 1.0;
@@ -71,6 +71,7 @@ class MainActivity : SDLActivity(), InputManager.InputDeviceListener {
private fun hideSystemUI() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// Android 11 (API 30) and above
@Suppress("DEPRECATION")
window.setDecorFitsSystemWindows(false)
window.insetsController?.let { controller ->
controller.hide(WindowInsets.Type.systemBars())
@@ -44,7 +44,7 @@ class SettingsActivity : AppCompatActivity() {
toggleThread.check(R.id.btn_thread_multi)
}
switchDsp.isChecked = prefs.getBoolean("setting_use_dsp", true)
switchDsp.isChecked = prefs.getBoolean("setting_use_dsp", false)
switchHrtf.isChecked = prefs.getBoolean("setting_hrtf", true)
switchShaders.isChecked = prefs.getBoolean("setting_cache_shaders", true)
switchFpu.isChecked = prefs.getBoolean("setting_hard_fpu", true)
+2 -2
View File
@@ -321,8 +321,8 @@ static void monitor_init(MCPXAPUState *d)
int fifo_frames = 3;
int audio_samples = 512;
#ifdef __ANDROID__
fifo_frames = 8;
audio_samples = 1024;
fifo_frames = 16;
audio_samples = 512;
fifo_frames = getenv_int_clamped("XEMU_ANDROID_AUDIO_FIFO_FRAMES", 3, 32,
fifo_frames);
audio_samples = getenv_int_clamped("XEMU_ANDROID_AUDIO_SAMPLES", 256, 4096,