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:
Themaister 2012-11-03 14:15:03 +01:00
parent 71f71c909d
commit 91edc8ff49
10 changed files with 85 additions and 14 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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();

View File

@ -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.

View File

@ -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) },

View File

@ -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