mirror of
https://github.com/libretro/RetroArch
synced 2025-02-06 00:39:53 +00:00
Add volume control.
It imposes no performance loss as it is performed during s16->float conversion. It is however grouped together with check_mute.
This commit is contained in:
parent
71f71c909d
commit
91edc8ff49
@ -22,10 +22,11 @@
|
||||
#endif
|
||||
|
||||
void audio_convert_s16_to_float_C(float *out,
|
||||
const int16_t *in, size_t samples)
|
||||
const int16_t *in, size_t samples, float gain)
|
||||
{
|
||||
gain = gain / 0x8000;
|
||||
for (size_t i = 0; i < samples; i++)
|
||||
out[i] = (float)in[i] / 0x8000;
|
||||
out[i] = (float)in[i] * gain;
|
||||
}
|
||||
|
||||
void audio_convert_float_to_s16_C(int16_t *out,
|
||||
@ -40,9 +41,10 @@ void audio_convert_float_to_s16_C(int16_t *out,
|
||||
|
||||
#if __SSE2__
|
||||
void audio_convert_s16_to_float_SSE2(float *out,
|
||||
const int16_t *in, size_t samples)
|
||||
const int16_t *in, size_t samples, float gain)
|
||||
{
|
||||
__m128 factor = _mm_set1_ps(1.0f / (0x7fff * 0x10000));
|
||||
float fgain = gain / (0x7fff * 0x10000);
|
||||
__m128 factor = _mm_set1_ps(fgain);
|
||||
size_t i;
|
||||
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
|
||||
{
|
||||
@ -61,7 +63,7 @@ void audio_convert_s16_to_float_SSE2(float *out,
|
||||
_mm_storeu_ps(out + 4, output[1]);
|
||||
}
|
||||
|
||||
audio_convert_s16_to_float_C(out, in, samples - i);
|
||||
audio_convert_s16_to_float_C(out, in, samples - i, gain);
|
||||
}
|
||||
|
||||
void audio_convert_float_to_s16_SSE2(int16_t *out,
|
||||
@ -84,8 +86,9 @@ void audio_convert_float_to_s16_SSE2(int16_t *out,
|
||||
}
|
||||
#elif __ALTIVEC__
|
||||
void audio_convert_s16_to_float_altivec(float *out,
|
||||
const int16_t *in, size_t samples)
|
||||
const int16_t *in, size_t samples, float gain)
|
||||
{
|
||||
const vector float gain_vec = vec_splats(gain);
|
||||
// Unaligned loads/store is a bit expensive, so we optimize for the good path (very likely).
|
||||
if (((uintptr_t)out & 15) + ((uintptr_t)in & 15) == 0)
|
||||
{
|
||||
@ -95,17 +98,17 @@ void audio_convert_s16_to_float_altivec(float *out,
|
||||
vector signed short input = vec_ld(0, in);
|
||||
vector signed int hi = vec_unpackh(input);
|
||||
vector signed int lo = vec_unpackl(input);
|
||||
vector float out_hi = vec_ctf(hi, 15);
|
||||
vector float out_lo = vec_ctf(lo, 15);
|
||||
vector float out_hi = vec_mul(vec_ctf(hi, 15), gain_vec);
|
||||
vector float out_lo = vec_mul(vec_ctf(lo, 15), gain_vec);
|
||||
|
||||
vec_st(out_hi, 0, out);
|
||||
vec_st(out_lo, 16, out);
|
||||
}
|
||||
|
||||
audio_convert_s16_to_float_C(out, in, samples - i);
|
||||
audio_convert_s16_to_float_C(out, in, samples - i, gain);
|
||||
}
|
||||
else
|
||||
audio_convert_s16_to_float_C(out, in, samples);
|
||||
audio_convert_s16_to_float_C(out, in, samples, gain);
|
||||
}
|
||||
|
||||
void audio_convert_float_to_s16_altivec(int16_t *out,
|
||||
|
@ -24,7 +24,7 @@
|
||||
#define audio_convert_float_to_s16 audio_convert_float_to_s16_SSE2
|
||||
|
||||
void audio_convert_s16_to_float_SSE2(float *out,
|
||||
const int16_t *in, size_t samples);
|
||||
const int16_t *in, size_t samples, float gain);
|
||||
|
||||
void audio_convert_float_to_s16_SSE2(int16_t *out,
|
||||
const float *in, size_t samples);
|
||||
@ -34,7 +34,7 @@ void audio_convert_float_to_s16_SSE2(int16_t *out,
|
||||
#define audio_convert_float_to_s16 audio_convert_float_to_s16_altivec
|
||||
|
||||
void audio_convert_s16_to_float_altivec(float *out,
|
||||
const int16_t *in, size_t samples);
|
||||
const int16_t *in, size_t samples, float gain);
|
||||
|
||||
void audio_convert_float_to_s16_altivec(int16_t *out,
|
||||
const float *in, size_t samples);
|
||||
@ -45,7 +45,7 @@ void audio_convert_float_to_s16_altivec(int16_t *out,
|
||||
#endif
|
||||
|
||||
void audio_convert_s16_to_float_C(float *out,
|
||||
const int16_t *in, size_t samples);
|
||||
const int16_t *in, size_t samples, float gain);
|
||||
void audio_convert_float_to_s16_C(int16_t *out,
|
||||
const float *in, size_t samples);
|
||||
|
||||
|
@ -280,6 +280,9 @@ static const float rate_control_delta = 0.006;
|
||||
static const float rate_control_delta = 0.005;
|
||||
#endif
|
||||
|
||||
// Default audio volume in dB. (0.0 dB == unity gain).
|
||||
static const float audio_volume = 0.0;
|
||||
|
||||
//////////////
|
||||
// Misc
|
||||
//////////////
|
||||
@ -391,6 +394,8 @@ static const struct retro_keybind retro_keybinds_1[] = {
|
||||
{ true, RARCH_NETPLAY_FLIP, RETROK_i, NO_BTN, AXIS_NONE },
|
||||
{ true, RARCH_SLOWMOTION, RETROK_e, NO_BTN, AXIS_NONE },
|
||||
{ true, RARCH_ENABLE_HOTKEY, RETROK_UNKNOWN, NO_BTN, AXIS_NONE },
|
||||
{ true, RARCH_VOLUME_UP, RETROK_KP_PLUS, NO_BTN, AXIS_NONE },
|
||||
{ true, RARCH_VOLUME_DOWN, RETROK_KP_MINUS, NO_BTN, AXIS_NONE },
|
||||
};
|
||||
|
||||
// Player 2-5
|
||||
|
3
driver.c
3
driver.c
@ -388,6 +388,9 @@ void init_audio(void)
|
||||
RARCH_WARN("Audio rate control was desired, but driver does not support needed features.\n");
|
||||
}
|
||||
|
||||
g_extern.audio_data.volume_db = g_settings.audio.volume;
|
||||
g_extern.audio_data.volume_gain = db_to_gain(g_settings.audio.volume);
|
||||
|
||||
#ifdef HAVE_DYLIB
|
||||
init_dsp_plugin();
|
||||
#endif
|
||||
|
2
driver.h
2
driver.h
@ -86,6 +86,8 @@ enum // RetroArch specific bind IDs.
|
||||
RARCH_NETPLAY_FLIP,
|
||||
RARCH_SLOWMOTION,
|
||||
RARCH_ENABLE_HOTKEY,
|
||||
RARCH_VOLUME_UP,
|
||||
RARCH_VOLUME_DOWN,
|
||||
|
||||
#ifdef RARCH_CONSOLE
|
||||
RARCH_CHEAT_INPUT,
|
||||
|
@ -159,6 +159,7 @@ struct settings
|
||||
|
||||
bool rate_control;
|
||||
float rate_control_delta;
|
||||
float volume; // dB scale
|
||||
} audio;
|
||||
|
||||
struct
|
||||
@ -341,6 +342,9 @@ struct global
|
||||
bool rate_control;
|
||||
double orig_src_ratio;
|
||||
size_t driver_buffer_size;
|
||||
|
||||
float volume_db;
|
||||
float volume_gain;
|
||||
} audio_data;
|
||||
|
||||
struct
|
||||
@ -679,6 +683,11 @@ static inline uint16_t swap_if_little16(uint16_t val)
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline float db_to_gain(float db)
|
||||
{
|
||||
return powf(10.0f, db / 20.0f);
|
||||
}
|
||||
|
||||
#ifdef GEKKO
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
35
retroarch.c
35
retroarch.c
@ -368,7 +368,8 @@ static bool audio_flush(const int16_t *data, size_t samples)
|
||||
struct resampler_data src_data = {0};
|
||||
RARCH_PERFORMANCE_INIT(audio_convert_s16);
|
||||
RARCH_PERFORMANCE_START(audio_convert_s16);
|
||||
audio_convert_s16_to_float(g_extern.audio_data.data, data, samples);
|
||||
audio_convert_s16_to_float(g_extern.audio_data.data, data, samples,
|
||||
g_extern.audio_data.volume_gain);
|
||||
RARCH_PERFORMANCE_STOP(audio_convert_s16);
|
||||
|
||||
#if defined(HAVE_DYLIB)
|
||||
@ -2405,6 +2406,37 @@ static void check_mute(void)
|
||||
|
||||
old_pressed = pressed;
|
||||
}
|
||||
|
||||
static void check_volume(void)
|
||||
{
|
||||
if (!g_extern.audio_active)
|
||||
return;
|
||||
|
||||
float db_change = 0.0f;
|
||||
bool pressed_up = input_key_pressed_func(RARCH_VOLUME_UP);
|
||||
bool pressed_down = input_key_pressed_func(RARCH_VOLUME_DOWN);
|
||||
if (!pressed_up && !pressed_down)
|
||||
return;
|
||||
|
||||
if (pressed_up)
|
||||
db_change += 0.5f;
|
||||
if (pressed_down)
|
||||
db_change -= 0.5f;
|
||||
|
||||
g_extern.audio_data.volume_db += db_change;
|
||||
if (g_extern.audio_data.volume_db > 12.0f)
|
||||
g_extern.audio_data.volume_db = 12.0f;
|
||||
else if (g_extern.audio_data.volume_db < -80.0f)
|
||||
g_extern.audio_data.volume_db = -80.0f;
|
||||
|
||||
char msg[256];
|
||||
snprintf(msg, sizeof(msg), "Volume: %.1f dB", g_extern.audio_data.volume_db);
|
||||
msg_queue_clear(g_extern.msg_queue);
|
||||
msg_queue_push(g_extern.msg_queue, msg, 1, 180);
|
||||
RARCH_LOG("%s\n", msg);
|
||||
|
||||
g_extern.audio_data.volume_gain = db_to_gain(g_extern.audio_data.volume_db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETPLAY
|
||||
@ -2441,6 +2473,7 @@ static void do_state_checks(void)
|
||||
#endif
|
||||
#if !defined(RARCH_PERFORMANCE_MODE)
|
||||
check_mute();
|
||||
check_volume();
|
||||
#endif
|
||||
|
||||
check_turbo();
|
||||
|
@ -186,6 +186,11 @@
|
||||
# Input rate = in_rate * (1.0 +/- audio_rate_control_delta)
|
||||
# audio_rate_control_delta = 0.005
|
||||
|
||||
# Audio volume. Volume is expressed in dB.
|
||||
# 0 dB is normal volume. No gain will be applied.
|
||||
# Gain can be controlled in runtime with input_volume_up/input_volume_down.
|
||||
# audio_volume = 0.0
|
||||
|
||||
#### Input
|
||||
|
||||
# Input driver. Depending on video driver, it might force a different input driver.
|
||||
@ -352,6 +357,11 @@
|
||||
# Alternatively, all hotkeys for keyboard could be disabled by the user.
|
||||
# input_enable_hotkey =
|
||||
|
||||
# Increases audio volume.
|
||||
# input_volume_up = kp_plus
|
||||
# Decreases audio volume.
|
||||
# input_volume_down = kp_minus
|
||||
|
||||
#### Misc
|
||||
|
||||
# Enable rewinding. This will take a performance hit when playing, so it is disabled by default.
|
||||
|
@ -200,6 +200,7 @@ void config_set_defaults(void)
|
||||
g_settings.audio.sync = audio_sync;
|
||||
g_settings.audio.rate_control = rate_control;
|
||||
g_settings.audio.rate_control_delta = rate_control_delta;
|
||||
g_settings.audio.volume = audio_volume;
|
||||
|
||||
g_settings.rewind_enable = rewind_enable;
|
||||
g_settings.rewind_buffer_size = rewind_buffer_size;
|
||||
@ -514,6 +515,7 @@ bool config_load_file(const char *path)
|
||||
CONFIG_GET_BOOL(audio.sync, "audio_sync");
|
||||
CONFIG_GET_BOOL(audio.rate_control, "audio_rate_control");
|
||||
CONFIG_GET_FLOAT(audio.rate_control_delta, "audio_rate_control_delta");
|
||||
CONFIG_GET_FLOAT(audio.volume, "audio_volume");
|
||||
|
||||
CONFIG_GET_STRING(video.driver, "video_driver");
|
||||
CONFIG_GET_STRING(audio.driver, "audio_driver");
|
||||
@ -670,6 +672,8 @@ static const struct bind_map bind_maps[MAX_PLAYERS][RARCH_BIND_LIST_END_NULL] =
|
||||
DECLARE_BIND(netplay_flip_players, RARCH_NETPLAY_FLIP),
|
||||
DECLARE_BIND(slowmotion, RARCH_SLOWMOTION),
|
||||
DECLARE_BIND(enable_hotkey, RARCH_ENABLE_HOTKEY),
|
||||
DECLARE_BIND(volume_up, RARCH_VOLUME_UP),
|
||||
DECLARE_BIND(volume_down, RARCH_VOLUME_DOWN),
|
||||
},
|
||||
|
||||
{ DECL_PLAYER(2) },
|
||||
|
@ -120,6 +120,8 @@ static struct bind binds[] = {
|
||||
MISC_BIND("Netplay player flip", netplay_flip_players),
|
||||
MISC_BIND("Slow motion", slowmotion),
|
||||
MISC_BIND("Hotkey enable", enable_hotkey),
|
||||
MISC_BIND("Volume up", volume_up),
|
||||
MISC_BIND("Volume down", volume_down),
|
||||
};
|
||||
|
||||
#define MAX_BUTTONS 32
|
||||
|
Loading…
x
Reference in New Issue
Block a user