mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 18:17:39 -04:00
Add perceptual volume adjustment
The perceived loudness change of a change in volume depends on the listening volume: at high volumes a 1 dB increment is noticeable, but at low volumes a larger increment is needed to get a comparable change in loudness. Perceptual volume adjustment accounts for this fact, and divides the hardware volume range into a number of steps. Each step changes the dB volume by a variable amount, with most of the steps concentrated at higher volumes. This makes it possible to sweep over the entire hardware volume range quickly, without losing the ability to finely adjust the volume at normal listening levels. Use "Volume Adjustment Mode" in the system settings menu to select perceptual volume mode. The number of steps used is controlled by "Number of Volume Steps". (Number of steps has no effect in direct adjustment mode.) It's still possible to set a specific dB volume level from the sound settings menu when perceptual volume is enabled, and perceptual volume does not affect the volume displayed by themes. Change-Id: I6f91fd3f7c5e2d323a914e47b5653033e92b4b3b
This commit is contained in:
parent
15c4447b66
commit
5b27e2255a
17 changed files with 240 additions and 35 deletions
107
apps/misc.c
107
apps/misc.c
|
@ -824,6 +824,113 @@ void setvol(void)
|
|||
settings_save();
|
||||
}
|
||||
|
||||
#ifdef HAVE_PERCEPTUAL_VOLUME
|
||||
static short norm_tab[MAX_NORM_VOLUME_STEPS+2];
|
||||
static int norm_tab_num_steps;
|
||||
static int norm_tab_size;
|
||||
|
||||
static void update_norm_tab(void)
|
||||
{
|
||||
const int lim = global_settings.volume_adjust_norm_steps;
|
||||
if (lim == norm_tab_num_steps)
|
||||
return;
|
||||
norm_tab_num_steps = lim;
|
||||
|
||||
const int min = sound_min(SOUND_VOLUME);
|
||||
const int max = sound_max(SOUND_VOLUME);
|
||||
const int step = sound_steps(SOUND_VOLUME);
|
||||
|
||||
/* Ensure the table contains the minimum volume */
|
||||
norm_tab[0] = min;
|
||||
norm_tab_size = 1;
|
||||
|
||||
for (int i = 0; i < lim; ++i)
|
||||
{
|
||||
int vol = from_normalized_volume(i, min, max, lim);
|
||||
int rem = vol % step;
|
||||
|
||||
vol -= rem;
|
||||
if (abs(rem) > step/2)
|
||||
vol += rem < 0 ? -step : step;
|
||||
|
||||
/* Add volume step, ignoring any duplicate entries that may
|
||||
* occur due to rounding */
|
||||
if (vol != norm_tab[norm_tab_size-1])
|
||||
norm_tab[norm_tab_size++] = vol;
|
||||
}
|
||||
|
||||
/* Ensure the table contains the maximum volume */
|
||||
if (norm_tab[norm_tab_size-1] != max)
|
||||
norm_tab[norm_tab_size++] = max;
|
||||
}
|
||||
|
||||
void set_normalized_volume(int vol)
|
||||
{
|
||||
update_norm_tab();
|
||||
|
||||
if (vol < 0)
|
||||
vol = 0;
|
||||
if (vol >= norm_tab_size)
|
||||
vol = norm_tab_size - 1;
|
||||
|
||||
global_settings.volume = norm_tab[vol];
|
||||
}
|
||||
|
||||
int get_normalized_volume(void)
|
||||
{
|
||||
update_norm_tab();
|
||||
|
||||
int a = 0, b = norm_tab_size - 1;
|
||||
while (a != b)
|
||||
{
|
||||
int i = (a + b + 1) / 2;
|
||||
if (global_settings.volume < norm_tab[i])
|
||||
b = i - 1;
|
||||
else
|
||||
a = i;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
#else
|
||||
void set_normalized_volume(int vol)
|
||||
{
|
||||
global_settings.volume = vol * sound_steps(SOUND_VOLUME);
|
||||
}
|
||||
|
||||
int get_normalized_volume(void)
|
||||
{
|
||||
return global_settings.volume / sound_steps(SOUND_VOLUME);
|
||||
}
|
||||
#endif
|
||||
|
||||
void adjust_volume(int steps)
|
||||
{
|
||||
#ifdef HAVE_PERCEPTUAL_VOLUME
|
||||
adjust_volume_ex(steps, global_settings.volume_adjust_mode);
|
||||
#else
|
||||
adjust_volume_ex(steps, VOLUME_ADJUST_DIRECT);
|
||||
#endif
|
||||
}
|
||||
|
||||
void adjust_volume_ex(int steps, enum volume_adjust_mode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case VOLUME_ADJUST_PERCEPTUAL:
|
||||
#ifdef HAVE_PERCEPTUAL_VOLUME
|
||||
set_normalized_volume(get_normalized_volume() + steps);
|
||||
break;
|
||||
#endif
|
||||
case VOLUME_ADJUST_DIRECT:
|
||||
default:
|
||||
global_settings.volume += steps * sound_steps(SOUND_VOLUME);
|
||||
break;
|
||||
}
|
||||
|
||||
setvol();
|
||||
}
|
||||
|
||||
char* strrsplt(char* str, int c)
|
||||
{
|
||||
char* s = strrchr(str, c);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue