summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2022-11-22 04:10:35 +0000
committerAidan MacDonald <amachronic@protonmail.com>2023-01-22 21:19:57 +0000
commit5b27e2255a8bbb8645f089b8e721343bba5bd396 (patch)
treebd29ddf9d2a0c07b1541ad4bace7ff4aedcb3c14
parent15c4447b6681cadba960aa9275592049afa96893 (diff)
downloadrockbox-5b27e2255a8bbb8645f089b8e721343bba5bd396.tar.gz
rockbox-5b27e2255a8bbb8645f089b8e721343bba5bd396.zip
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
-rw-r--r--apps/features.txt4
-rw-r--r--apps/gui/list.c6
-rw-r--r--apps/gui/quickscreen.c6
-rw-r--r--apps/gui/wps.c4
-rw-r--r--apps/lang/english.lang53
-rw-r--r--apps/menus/settings_menu.c9
-rw-r--r--apps/misc.c107
-rw-r--r--apps/misc.h14
-rw-r--r--apps/plugin.c1
-rw-r--r--apps/plugin.h3
-rw-r--r--apps/plugins/lrcplayer.c10
-rw-r--r--apps/plugins/mikmod/mikmod.c19
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/playmidi.c2
-rw-r--r--apps/settings.h5
-rw-r--r--apps/settings_list.c11
-rw-r--r--firmware/export/config.h4
-rwxr-xr-xmanual/configure_rockbox/system_options.tex17
17 files changed, 240 insertions, 35 deletions
diff --git a/apps/features.txt b/apps/features.txt
index 2262f7502e..bafaa11599 100644
--- a/apps/features.txt
+++ b/apps/features.txt
@@ -296,3 +296,7 @@ hibylinux
296 (CONFIG_KEYPAD == IRIVER_H10_PAD) 296 (CONFIG_KEYPAD == IRIVER_H10_PAD)
297clear_settings_on_hold 297clear_settings_on_hold
298#endif 298#endif
299
300#if defined(HAVE_PERCEPTUAL_VOLUME)
301perceptual_volume
302#endif
diff --git a/apps/gui/list.c b/apps/gui/list.c
index 83d12289f2..652279a9de 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -663,12 +663,10 @@ bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
663 663
664#ifdef HAVE_VOLUME_IN_LIST 664#ifdef HAVE_VOLUME_IN_LIST
665 case ACTION_LIST_VOLUP: 665 case ACTION_LIST_VOLUP:
666 global_settings.volume += sound_steps(SOUND_VOLUME); 666 adjust_volume(1);
667 setvol();
668 return true; 667 return true;
669 case ACTION_LIST_VOLDOWN: 668 case ACTION_LIST_VOLDOWN:
670 global_settings.volume -= sound_steps(SOUND_VOLUME); 669 adjust_volume(-1);
671 setvol();
672 return true; 670 return true;
673#endif 671#endif
674 case ACTION_STD_PREV: 672 case ACTION_STD_PREV:
diff --git a/apps/gui/quickscreen.c b/apps/gui/quickscreen.c
index 356f74b283..221dfe3111 100644
--- a/apps/gui/quickscreen.c
+++ b/apps/gui/quickscreen.c
@@ -378,14 +378,12 @@ static int gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_enter
378 else if (button == button_enter) 378 else if (button == button_enter)
379 can_quit = true; 379 can_quit = true;
380 else if (button == ACTION_QS_VOLUP) { 380 else if (button == ACTION_QS_VOLUP) {
381 global_settings.volume += sound_steps(SOUND_VOLUME); 381 adjust_volume(1);
382 setvol();
383 FOR_NB_SCREENS(i) 382 FOR_NB_SCREENS(i)
384 skin_update(CUSTOM_STATUSBAR, i, SKIN_REFRESH_NON_STATIC); 383 skin_update(CUSTOM_STATUSBAR, i, SKIN_REFRESH_NON_STATIC);
385 } 384 }
386 else if (button == ACTION_QS_VOLDOWN) { 385 else if (button == ACTION_QS_VOLDOWN) {
387 global_settings.volume -= sound_steps(SOUND_VOLUME); 386 adjust_volume(-1);
388 setvol();
389 FOR_NB_SCREENS(i) 387 FOR_NB_SCREENS(i)
390 skin_update(CUSTOM_STATUSBAR, i, SKIN_REFRESH_NON_STATIC); 388 skin_update(CUSTOM_STATUSBAR, i, SKIN_REFRESH_NON_STATIC);
391 } 389 }
diff --git a/apps/gui/wps.c b/apps/gui/wps.c
index 4b0c7c056f..fe656034b9 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -841,9 +841,9 @@ long gui_wps_show(void)
841 case ACTION_WPS_VOLUP: /* fall through */ 841 case ACTION_WPS_VOLUP: /* fall through */
842 case ACTION_WPS_VOLDOWN: 842 case ACTION_WPS_VOLDOWN:
843 if (button == ACTION_WPS_VOLUP) 843 if (button == ACTION_WPS_VOLUP)
844 global_settings.volume += sound_steps(SOUND_VOLUME); 844 adjust_volume(1);
845 else 845 else
846 global_settings.volume -= sound_steps(SOUND_VOLUME); 846 adjust_volume(-1);
847 847
848 setvol(); 848 setvol();
849 FOR_NB_SCREENS(i) 849 FOR_NB_SCREENS(i)
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 3ad2921abe..232541e33f 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -15163,7 +15163,7 @@
15163</phrase> 15163</phrase>
15164<phrase> 15164<phrase>
15165 id: LANG_DIRECT 15165 id: LANG_DIRECT
15166 desc: in the pictureflow settings 15166 desc: in the pictureflow settings, also a volume adjustment mode
15167 user: core 15167 user: core
15168 <source> 15168 <source>
15169 *: "Direct" 15169 *: "Direct"
@@ -16559,3 +16559,54 @@
16559 *: "Play Last Shuffled" 16559 *: "Play Last Shuffled"
16560 </voice> 16560 </voice>
16561</phrase> 16561</phrase>
16562<phrase>
16563 id: LANG_VOLUME_ADJUST_MODE
16564 desc: in system settings
16565 user: core
16566 <source>
16567 *: none
16568 perceptual_volume: "Volume Adjustment Mode"
16569 </source>
16570 <dest>
16571 *: none
16572 perceptual_volume: "Volume Adjustment Mode"
16573 </dest>
16574 <voice>
16575 *: none
16576 perceptual_volume: "Volume Adjustment Mode"
16577 </voice>
16578</phrase>
16579<phrase>
16580 id: LANG_VOLUME_ADJUST_NORM_STEPS
16581 desc: in system settings
16582 user: core
16583 <source>
16584 *: none
16585 perceptual_volume: "Number of Volume Steps"
16586 </source>
16587 <dest>
16588 *: none
16589 perceptual_volume: "Number of Volume Steps"
16590 </dest>
16591 <voice>
16592 *: none
16593 perceptual_volume: "Number of Volume Steps"
16594 </voice>
16595</phrase>
16596<phrase>
16597 id: LANG_PERCEPTUAL
16598 desc: in system settings -> volume adjustment mode
16599 user: core
16600 <source>
16601 *: none
16602 perceptual_volume: "Perceptual"
16603 </source>
16604 <dest>
16605 *: none
16606 perceptual_volume: "Perceptual"
16607 </dest>
16608 <voice>
16609 *: none
16610 perceptual_volume: "Perceptual"
16611 </voice>
16612</phrase>
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index 9d1314c269..bfb69a9942 100644
--- a/apps/menus/settings_menu.c
+++ b/apps/menus/settings_menu.c
@@ -338,6 +338,11 @@ MAKE_MENU(limits_menu, ID2P(LANG_LIMITS_MENU), 0, Icon_NOICON,
338 ,&default_glyphs 338 ,&default_glyphs
339 ); 339 );
340 340
341#ifdef HAVE_PERCEPTUAL_VOLUME
342/* Volume adjustment */
343MENUITEM_SETTING(volume_adjust_mode, &global_settings.volume_adjust_mode, NULL);
344MENUITEM_SETTING(volume_adjust_norm_steps, &global_settings.volume_adjust_norm_steps, NULL);
345#endif
341 346
342/* Keyclick menu */ 347/* Keyclick menu */
343MENUITEM_SETTING(keyclick, &global_settings.keyclick, NULL); 348MENUITEM_SETTING(keyclick, &global_settings.keyclick, NULL);
@@ -424,6 +429,10 @@ MAKE_MENU(system_menu, ID2P(LANG_SYSTEM),
424 &disk_menu, 429 &disk_menu,
425#endif 430#endif
426 &limits_menu, 431 &limits_menu,
432#ifdef HAVE_PERCEPTUAL_VOLUME
433 &volume_adjust_mode,
434 &volume_adjust_norm_steps,
435#endif
427#ifdef HAVE_QUICKSCREEN 436#ifdef HAVE_QUICKSCREEN
428 &shortcuts_replaces_quickscreen, 437 &shortcuts_replaces_quickscreen,
429#endif 438#endif
diff --git a/apps/misc.c b/apps/misc.c
index fd840749cb..e10fceb9af 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -824,6 +824,113 @@ void setvol(void)
824 settings_save(); 824 settings_save();
825} 825}
826 826
827#ifdef HAVE_PERCEPTUAL_VOLUME
828static short norm_tab[MAX_NORM_VOLUME_STEPS+2];
829static int norm_tab_num_steps;
830static int norm_tab_size;
831
832static void update_norm_tab(void)
833{
834 const int lim = global_settings.volume_adjust_norm_steps;
835 if (lim == norm_tab_num_steps)
836 return;
837 norm_tab_num_steps = lim;
838
839 const int min = sound_min(SOUND_VOLUME);
840 const int max = sound_max(SOUND_VOLUME);
841 const int step = sound_steps(SOUND_VOLUME);
842
843 /* Ensure the table contains the minimum volume */
844 norm_tab[0] = min;
845 norm_tab_size = 1;
846
847 for (int i = 0; i < lim; ++i)
848 {
849 int vol = from_normalized_volume(i, min, max, lim);
850 int rem = vol % step;
851
852 vol -= rem;
853 if (abs(rem) > step/2)
854 vol += rem < 0 ? -step : step;
855
856 /* Add volume step, ignoring any duplicate entries that may
857 * occur due to rounding */
858 if (vol != norm_tab[norm_tab_size-1])
859 norm_tab[norm_tab_size++] = vol;
860 }
861
862 /* Ensure the table contains the maximum volume */
863 if (norm_tab[norm_tab_size-1] != max)
864 norm_tab[norm_tab_size++] = max;
865}
866
867void set_normalized_volume(int vol)
868{
869 update_norm_tab();
870
871 if (vol < 0)
872 vol = 0;
873 if (vol >= norm_tab_size)
874 vol = norm_tab_size - 1;
875
876 global_settings.volume = norm_tab[vol];
877}
878
879int get_normalized_volume(void)
880{
881 update_norm_tab();
882
883 int a = 0, b = norm_tab_size - 1;
884 while (a != b)
885 {
886 int i = (a + b + 1) / 2;
887 if (global_settings.volume < norm_tab[i])
888 b = i - 1;
889 else
890 a = i;
891 }
892
893 return a;
894}
895#else
896void set_normalized_volume(int vol)
897{
898 global_settings.volume = vol * sound_steps(SOUND_VOLUME);
899}
900
901int get_normalized_volume(void)
902{
903 return global_settings.volume / sound_steps(SOUND_VOLUME);
904}
905#endif
906
907void adjust_volume(int steps)
908{
909#ifdef HAVE_PERCEPTUAL_VOLUME
910 adjust_volume_ex(steps, global_settings.volume_adjust_mode);
911#else
912 adjust_volume_ex(steps, VOLUME_ADJUST_DIRECT);
913#endif
914}
915
916void adjust_volume_ex(int steps, enum volume_adjust_mode mode)
917{
918 switch (mode)
919 {
920 case VOLUME_ADJUST_PERCEPTUAL:
921#ifdef HAVE_PERCEPTUAL_VOLUME
922 set_normalized_volume(get_normalized_volume() + steps);
923 break;
924#endif
925 case VOLUME_ADJUST_DIRECT:
926 default:
927 global_settings.volume += steps * sound_steps(SOUND_VOLUME);
928 break;
929 }
930
931 setvol();
932}
933
827char* strrsplt(char* str, int c) 934char* strrsplt(char* str, int c)
828{ 935{
829 char* s = strrchr(str, c); 936 char* s = strrchr(str, c);
diff --git a/apps/misc.h b/apps/misc.h
index 72b8735c8a..b7a9a5c42c 100644
--- a/apps/misc.h
+++ b/apps/misc.h
@@ -137,8 +137,22 @@ void check_bootfile(bool do_rolo);
137#endif 137#endif
138#endif 138#endif
139 139
140enum volume_adjust_mode
141{
142 VOLUME_ADJUST_DIRECT, /* adjust in units of the volume step size */
143 VOLUME_ADJUST_PERCEPTUAL, /* adjust using perceptual steps */
144};
145
146/* min/max values for global_settings.volume_adjust_norm_steps */
147#define MIN_NORM_VOLUME_STEPS 10
148#define MAX_NORM_VOLUME_STEPS 100
149
140/* check range, set volume and save settings */ 150/* check range, set volume and save settings */
141void setvol(void); 151void setvol(void);
152void set_normalized_volume(int vol);
153int get_normalized_volume(void);
154void adjust_volume(int steps);
155void adjust_volume_ex(int steps, enum volume_adjust_mode mode);
142 156
143#ifdef HAVE_LCD_COLOR 157#ifdef HAVE_LCD_COLOR
144int hex_to_rgb(const char* hex, int* color); 158int hex_to_rgb(const char* hex, int* color);
diff --git a/apps/plugin.c b/apps/plugin.c
index 00fac21b8d..cdbe340ddd 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -828,6 +828,7 @@ static const struct plugin_api rockbox_api = {
828#if defined(HAVE_TAGCACHE) 828#if defined(HAVE_TAGCACHE)
829 tagtree_subentries_do_action, 829 tagtree_subentries_do_action,
830#endif 830#endif
831 adjust_volume,
831}; 832};
832 833
833static int plugin_buffer_handle; 834static int plugin_buffer_handle;
diff --git a/apps/plugin.h b/apps/plugin.h
index 20df7e72f2..286a5e2794 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -158,7 +158,7 @@ int plugin_open(const char *plugin, const char *parameter);
158#define PLUGIN_MAGIC 0x526F634B /* RocK */ 158#define PLUGIN_MAGIC 0x526F634B /* RocK */
159 159
160/* increase this every time the api struct changes */ 160/* increase this every time the api struct changes */
161#define PLUGIN_API_VERSION 264 161#define PLUGIN_API_VERSION 265
162 162
163/* update this to latest version if a change to the api struct breaks 163/* update this to latest version if a change to the api struct breaks
164 backwards compatibility (and please take the opportunity to sort in any 164 backwards compatibility (and please take the opportunity to sort in any
@@ -954,6 +954,7 @@ struct plugin_api {
954#ifdef HAVE_TAGCACHE 954#ifdef HAVE_TAGCACHE
955 bool (*tagtree_subentries_do_action)(bool (*action_cb)(const char *file_name)); 955 bool (*tagtree_subentries_do_action)(bool (*action_cb)(const char *file_name));
956#endif 956#endif
957 void (*adjust_volume)(int steps);
957}; 958};
958 959
959/* plugin header */ 960/* plugin header */
diff --git a/apps/plugins/lrcplayer.c b/apps/plugins/lrcplayer.c
index 71e5310638..de31733671 100644
--- a/apps/plugins/lrcplayer.c
+++ b/apps/plugins/lrcplayer.c
@@ -2625,16 +2625,10 @@ static int handle_button(void)
2625 ff_rewind(0, false); 2625 ff_rewind(0, false);
2626 break; 2626 break;
2627 case ACTION_WPS_VOLDOWN: 2627 case ACTION_WPS_VOLDOWN:
2628 limit = rb->sound_min(SOUND_VOLUME); 2628 rb->adjust_volume(-1);
2629 if (--rb->global_settings->volume < limit)
2630 rb->global_settings->volume = limit;
2631 rb->sound_set(SOUND_VOLUME, rb->global_settings->volume);
2632 break; 2629 break;
2633 case ACTION_WPS_VOLUP: 2630 case ACTION_WPS_VOLUP:
2634 limit = rb->sound_max(SOUND_VOLUME); 2631 rb->adjust_volume(1);
2635 if (++rb->global_settings->volume > limit)
2636 rb->global_settings->volume = limit;
2637 rb->sound_set(SOUND_VOLUME, rb->global_settings->volume);
2638 break; 2632 break;
2639 case ACTION_WPS_CONTEXT: 2633 case ACTION_WPS_CONTEXT:
2640 ret = LRC_GOTO_EDITOR; 2634 ret = LRC_GOTO_EDITOR;
diff --git a/apps/plugins/mikmod/mikmod.c b/apps/plugins/mikmod/mikmod.c
index 6622b5fdb6..65633c0ad1 100644
--- a/apps/plugins/mikmod/mikmod.c
+++ b/apps/plugins/mikmod/mikmod.c
@@ -710,7 +710,6 @@ static void mm_errorhandler(void)
710 710
711static int playfile(char* filename) 711static int playfile(char* filename)
712{ 712{
713 int vol = 0;
714 int button; 713 int button;
715 int retval = PLUGIN_OK; 714 int retval = PLUGIN_OK;
716 bool changingpos = false; 715 bool changingpos = false;
@@ -789,13 +788,8 @@ static int playfile(char* filename)
789 } 788 }
790 break; 789 break;
791 } 790 }
792 vol = rb->global_settings->volume; 791
793 if (vol < rb->sound_max(SOUND_VOLUME)) 792 rb->adjust_volume(1);
794 {
795 vol++;
796 rb->sound_set(SOUND_VOLUME, vol);
797 rb->global_settings->volume = vol;
798 }
799 break; 793 break;
800 794
801 case ACTION_WPS_VOLDOWN: 795 case ACTION_WPS_VOLDOWN:
@@ -808,13 +802,8 @@ static int playfile(char* filename)
808 } 802 }
809 break; 803 break;
810 } 804 }
811 vol = rb->global_settings->volume; 805
812 if (vol > rb->sound_min(SOUND_VOLUME)) 806 rb->adjust_volume(-1);
813 {
814 vol--;
815 rb->sound_set(SOUND_VOLUME, vol);
816 rb->global_settings->volume = vol;
817 }
818 break; 807 break;
819 808
820 case ACTION_WPS_SKIPPREV: 809 case ACTION_WPS_SKIPPREV:
diff --git a/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c b/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c
index 1638732dc5..38f7109b13 100644
--- a/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c
+++ b/apps/plugins/sdl/SDL_mixer/timidity/playmidi.c
@@ -21,6 +21,8 @@
21 21
22#include "tables.h" 22#include "tables.h"
23 23
24/* ROCKBOX HACK: avoid a conflict with adjust_volume() in misc.h */
25#define adjust_volume adjust_midi_volume
24 26
25static int opt_expression_curve = 2; 27static int opt_expression_curve = 2;
26static int opt_volume_curve = 2; 28static int opt_volume_curve = 2;
diff --git a/apps/settings.h b/apps/settings.h
index 1ad1923c73..ca10c45d5f 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -855,6 +855,11 @@ struct user_settings
855#endif 855#endif
856 int volume_limit; /* maximum volume limit */ 856 int volume_limit; /* maximum volume limit */
857 857
858#ifdef HAVE_PERCEPTUAL_VOLUME
859 int volume_adjust_mode;
860 int volume_adjust_norm_steps;
861#endif
862
858 int surround_enabled; 863 int surround_enabled;
859 int surround_balance; 864 int surround_balance;
860 int surround_fx1; 865 int surround_fx1;
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 60ac4192fa..315f39b21f 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -40,6 +40,7 @@
40#include "powermgmt.h" 40#include "powermgmt.h"
41#include "kernel.h" 41#include "kernel.h"
42#include "open_plugin.h" 42#include "open_plugin.h"
43#include "misc.h"
43#ifdef HAVE_REMOTE_LCD 44#ifdef HAVE_REMOTE_LCD
44#include "lcd-remote.h" 45#include "lcd-remote.h"
45#endif 46#endif
@@ -1057,6 +1058,16 @@ const struct settings_list settings[] = {
1057 MAX_FILES_IN_DIR_STEP /* min */, MAX_FILES_IN_DIR_MAX, 1058 MAX_FILES_IN_DIR_STEP /* min */, MAX_FILES_IN_DIR_MAX,
1058 MAX_FILES_IN_DIR_STEP, 1059 MAX_FILES_IN_DIR_STEP,
1059 NULL, NULL, NULL), 1060 NULL, NULL, NULL),
1061#ifdef HAVE_PERCEPTUAL_VOLUME
1062 CHOICE_SETTING(0, volume_adjust_mode, LANG_VOLUME_ADJUST_MODE,
1063 VOLUME_ADJUST_DIRECT, "volume adjustment mode",
1064 "direct,perceptual", NULL, 2,
1065 ID2P(LANG_DIRECT), ID2P(LANG_PERCEPTUAL)),
1066 INT_SETTING_NOWRAP(0, volume_adjust_norm_steps, LANG_VOLUME_ADJUST_NORM_STEPS,
1067 50, "perceptual volume step count", UNIT_INT,
1068 MIN_NORM_VOLUME_STEPS, MAX_NORM_VOLUME_STEPS, 5,
1069 NULL, NULL, NULL),
1070#endif
1060/* use this setting for user code even if there's no exchangable battery 1071/* use this setting for user code even if there's no exchangable battery
1061 * support enabled */ 1072 * support enabled */
1062#if BATTERY_CAPACITY_INC > 0 1073#if BATTERY_CAPACITY_INC > 0
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 2ec0b7878f..0882cad61c 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -1319,6 +1319,10 @@ Lyre prototype 1 */
1319# define HAVE_SCREENDUMP 1319# define HAVE_SCREENDUMP
1320#endif 1320#endif
1321 1321
1322#if !defined(BOOTLOADER) && MEMORYSIZE > 2
1323# define HAVE_PERCEPTUAL_VOLUME
1324#endif
1325
1322/* null audiohw setting macro for when codec header is included for reasons 1326/* null audiohw setting macro for when codec header is included for reasons
1323 other than audio support */ 1327 other than audio support */
1324#define AUDIOHW_SETTING(name, us, nd, st, minv, maxv, defv, expr...) 1328#define AUDIOHW_SETTING(name, us, nd, st, minv, maxv, defv, expr...)
diff --git a/manual/configure_rockbox/system_options.tex b/manual/configure_rockbox/system_options.tex
index ba80a6e6e4..d4a282b445 100755
--- a/manual/configure_rockbox/system_options.tex
+++ b/manual/configure_rockbox/system_options.tex
@@ -137,6 +137,23 @@ This sub menu relates to limits in the Rockbox operating system.
137 \item LAN party computer $\rightarrow$ \dap $\rightarrow$ human 137 \item LAN party computer $\rightarrow$ \dap $\rightarrow$ human
138 \end{itemize} 138 \end{itemize}
139 } 139 }
140\opt{perceptual_volume}{
141 \subsection{Volume Adjustment Mode}
142 This setting selects the method used to adjust volume with \ButtonVolUp{} and
143 \ButtonVolDown{}. In \setting{Direct} mode each volume step changes the volume
144 by a fixed number of decibels (dB).
145
146 In \setting{Perceptual} mode, the hardware volume range is divided into a
147 number of steps, controlled by the \setting{Number of Volume Steps} option.
148 Each step changes the volume by a variable number of decibels (dB) so the
149 perceived loudness changes by about the same amount at each step. The dB
150 change is smaller at high volumes and larger at low volumes, so a large
151 range of low volumes are effectively compressed into a smaller number of
152 volume steps.
153
154 \setting{Volume Adjustment Mode} does not affect how volume is displayed by
155 themes.
156}
140\opt{quickscreen}{ 157\opt{quickscreen}{
141 \subsection{Use Shortcuts Menu Instead of Quick Screen} This option 158 \subsection{Use Shortcuts Menu Instead of Quick Screen} This option
142 activates the shortcuts menu instead of opening the quick screen when enabled. 159 activates the shortcuts menu instead of opening the quick screen when enabled.