mirror of
https://github.com/libretro/RetroArch
synced 2025-02-11 06:40:48 +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
|
#endif
|
||||||
|
|
||||||
void audio_convert_s16_to_float_C(float *out,
|
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++)
|
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,
|
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__
|
#if __SSE2__
|
||||||
void audio_convert_s16_to_float_SSE2(float *out,
|
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;
|
size_t i;
|
||||||
for (i = 0; i + 8 <= samples; i += 8, in += 8, out += 8)
|
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]);
|
_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,
|
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__
|
#elif __ALTIVEC__
|
||||||
void audio_convert_s16_to_float_altivec(float *out,
|
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).
|
// 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)
|
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 short input = vec_ld(0, in);
|
||||||
vector signed int hi = vec_unpackh(input);
|
vector signed int hi = vec_unpackh(input);
|
||||||
vector signed int lo = vec_unpackl(input);
|
vector signed int lo = vec_unpackl(input);
|
||||||
vector float out_hi = vec_ctf(hi, 15);
|
vector float out_hi = vec_mul(vec_ctf(hi, 15), gain_vec);
|
||||||
vector float out_lo = vec_ctf(lo, 15);
|
vector float out_lo = vec_mul(vec_ctf(lo, 15), gain_vec);
|
||||||
|
|
||||||
vec_st(out_hi, 0, out);
|
vec_st(out_hi, 0, out);
|
||||||
vec_st(out_lo, 16, 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
|
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,
|
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
|
#define audio_convert_float_to_s16 audio_convert_float_to_s16_SSE2
|
||||||
|
|
||||||
void audio_convert_s16_to_float_SSE2(float *out,
|
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,
|
void audio_convert_float_to_s16_SSE2(int16_t *out,
|
||||||
const float *in, size_t samples);
|
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
|
#define audio_convert_float_to_s16 audio_convert_float_to_s16_altivec
|
||||||
|
|
||||||
void audio_convert_s16_to_float_altivec(float *out,
|
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,
|
void audio_convert_float_to_s16_altivec(int16_t *out,
|
||||||
const float *in, size_t samples);
|
const float *in, size_t samples);
|
||||||
@ -45,7 +45,7 @@ void audio_convert_float_to_s16_altivec(int16_t *out,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void audio_convert_s16_to_float_C(float *out,
|
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,
|
void audio_convert_float_to_s16_C(int16_t *out,
|
||||||
const float *in, size_t samples);
|
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;
|
static const float rate_control_delta = 0.005;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Default audio volume in dB. (0.0 dB == unity gain).
|
||||||
|
static const float audio_volume = 0.0;
|
||||||
|
|
||||||
//////////////
|
//////////////
|
||||||
// Misc
|
// 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_NETPLAY_FLIP, RETROK_i, NO_BTN, AXIS_NONE },
|
||||||
{ true, RARCH_SLOWMOTION, RETROK_e, 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_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
|
// 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");
|
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
|
#ifdef HAVE_DYLIB
|
||||||
init_dsp_plugin();
|
init_dsp_plugin();
|
||||||
#endif
|
#endif
|
||||||
|
2
driver.h
2
driver.h
@ -86,6 +86,8 @@ enum // RetroArch specific bind IDs.
|
|||||||
RARCH_NETPLAY_FLIP,
|
RARCH_NETPLAY_FLIP,
|
||||||
RARCH_SLOWMOTION,
|
RARCH_SLOWMOTION,
|
||||||
RARCH_ENABLE_HOTKEY,
|
RARCH_ENABLE_HOTKEY,
|
||||||
|
RARCH_VOLUME_UP,
|
||||||
|
RARCH_VOLUME_DOWN,
|
||||||
|
|
||||||
#ifdef RARCH_CONSOLE
|
#ifdef RARCH_CONSOLE
|
||||||
RARCH_CHEAT_INPUT,
|
RARCH_CHEAT_INPUT,
|
||||||
|
@ -159,6 +159,7 @@ struct settings
|
|||||||
|
|
||||||
bool rate_control;
|
bool rate_control;
|
||||||
float rate_control_delta;
|
float rate_control_delta;
|
||||||
|
float volume; // dB scale
|
||||||
} audio;
|
} audio;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
@ -341,6 +342,9 @@ struct global
|
|||||||
bool rate_control;
|
bool rate_control;
|
||||||
double orig_src_ratio;
|
double orig_src_ratio;
|
||||||
size_t driver_buffer_size;
|
size_t driver_buffer_size;
|
||||||
|
|
||||||
|
float volume_db;
|
||||||
|
float volume_gain;
|
||||||
} audio_data;
|
} audio_data;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
@ -679,6 +683,11 @@ static inline uint16_t swap_if_little16(uint16_t val)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline float db_to_gain(float db)
|
||||||
|
{
|
||||||
|
return powf(10.0f, db / 20.0f);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef GEKKO
|
#ifdef GEKKO
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#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};
|
struct resampler_data src_data = {0};
|
||||||
RARCH_PERFORMANCE_INIT(audio_convert_s16);
|
RARCH_PERFORMANCE_INIT(audio_convert_s16);
|
||||||
RARCH_PERFORMANCE_START(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);
|
RARCH_PERFORMANCE_STOP(audio_convert_s16);
|
||||||
|
|
||||||
#if defined(HAVE_DYLIB)
|
#if defined(HAVE_DYLIB)
|
||||||
@ -2405,6 +2406,37 @@ static void check_mute(void)
|
|||||||
|
|
||||||
old_pressed = pressed;
|
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
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_NETPLAY
|
#ifdef HAVE_NETPLAY
|
||||||
@ -2441,6 +2473,7 @@ static void do_state_checks(void)
|
|||||||
#endif
|
#endif
|
||||||
#if !defined(RARCH_PERFORMANCE_MODE)
|
#if !defined(RARCH_PERFORMANCE_MODE)
|
||||||
check_mute();
|
check_mute();
|
||||||
|
check_volume();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
check_turbo();
|
check_turbo();
|
||||||
|
@ -186,6 +186,11 @@
|
|||||||
# Input rate = in_rate * (1.0 +/- audio_rate_control_delta)
|
# Input rate = in_rate * (1.0 +/- audio_rate_control_delta)
|
||||||
# audio_rate_control_delta = 0.005
|
# 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
|
||||||
|
|
||||||
# Input driver. Depending on video driver, it might force a different input driver.
|
# 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.
|
# Alternatively, all hotkeys for keyboard could be disabled by the user.
|
||||||
# input_enable_hotkey =
|
# input_enable_hotkey =
|
||||||
|
|
||||||
|
# Increases audio volume.
|
||||||
|
# input_volume_up = kp_plus
|
||||||
|
# Decreases audio volume.
|
||||||
|
# input_volume_down = kp_minus
|
||||||
|
|
||||||
#### Misc
|
#### Misc
|
||||||
|
|
||||||
# Enable rewinding. This will take a performance hit when playing, so it is disabled by default.
|
# 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.sync = audio_sync;
|
||||||
g_settings.audio.rate_control = rate_control;
|
g_settings.audio.rate_control = rate_control;
|
||||||
g_settings.audio.rate_control_delta = rate_control_delta;
|
g_settings.audio.rate_control_delta = rate_control_delta;
|
||||||
|
g_settings.audio.volume = audio_volume;
|
||||||
|
|
||||||
g_settings.rewind_enable = rewind_enable;
|
g_settings.rewind_enable = rewind_enable;
|
||||||
g_settings.rewind_buffer_size = rewind_buffer_size;
|
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.sync, "audio_sync");
|
||||||
CONFIG_GET_BOOL(audio.rate_control, "audio_rate_control");
|
CONFIG_GET_BOOL(audio.rate_control, "audio_rate_control");
|
||||||
CONFIG_GET_FLOAT(audio.rate_control_delta, "audio_rate_control_delta");
|
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(video.driver, "video_driver");
|
||||||
CONFIG_GET_STRING(audio.driver, "audio_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(netplay_flip_players, RARCH_NETPLAY_FLIP),
|
||||||
DECLARE_BIND(slowmotion, RARCH_SLOWMOTION),
|
DECLARE_BIND(slowmotion, RARCH_SLOWMOTION),
|
||||||
DECLARE_BIND(enable_hotkey, RARCH_ENABLE_HOTKEY),
|
DECLARE_BIND(enable_hotkey, RARCH_ENABLE_HOTKEY),
|
||||||
|
DECLARE_BIND(volume_up, RARCH_VOLUME_UP),
|
||||||
|
DECLARE_BIND(volume_down, RARCH_VOLUME_DOWN),
|
||||||
},
|
},
|
||||||
|
|
||||||
{ DECL_PLAYER(2) },
|
{ DECL_PLAYER(2) },
|
||||||
|
@ -120,6 +120,8 @@ static struct bind binds[] = {
|
|||||||
MISC_BIND("Netplay player flip", netplay_flip_players),
|
MISC_BIND("Netplay player flip", netplay_flip_players),
|
||||||
MISC_BIND("Slow motion", slowmotion),
|
MISC_BIND("Slow motion", slowmotion),
|
||||||
MISC_BIND("Hotkey enable", enable_hotkey),
|
MISC_BIND("Hotkey enable", enable_hotkey),
|
||||||
|
MISC_BIND("Volume up", volume_up),
|
||||||
|
MISC_BIND("Volume down", volume_down),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_BUTTONS 32
|
#define MAX_BUTTONS 32
|
||||||
|
Loading…
x
Reference in New Issue
Block a user