summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorThom Johansen <thomj@rockbox.org>2006-10-27 20:41:33 +0000
committerThom Johansen <thomj@rockbox.org>2006-10-27 20:41:33 +0000
commit354770088e87c3aa8720f462fe3ac8368d7de5b5 (patch)
tree58b2e4e05edca22d042e441b041174e802daf80c /apps
parent57cc28d6db6dafe2138916550aad5a9306e80f42 (diff)
downloadrockbox-354770088e87c3aa8720f462fe3ac8368d7de5b5.tar.gz
rockbox-354770088e87c3aa8720f462fe3ac8368d7de5b5.zip
Re-enable the currently unused and broken dithering and noise shaping code already in Rockbox, and make it a user option instead of a codec-controlled option. The majority of people probably will not even hear any difference with this enabled, but feedback is welcome. Save your settings!
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11368 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/codecs/a52.c1
-rw-r--r--apps/codecs/aac.c1
-rw-r--r--apps/codecs/adx.c1
-rw-r--r--apps/codecs/aiff.c1
-rw-r--r--apps/codecs/alac.c1
-rw-r--r--apps/codecs/flac.c1
-rw-r--r--apps/codecs/mpa.c1
-rw-r--r--apps/codecs/mpc.c1
-rw-r--r--apps/codecs/shorten.c1
-rw-r--r--apps/codecs/sid.c1
-rw-r--r--apps/codecs/vorbis.c1
-rw-r--r--apps/codecs/wav.c1
-rw-r--r--apps/codecs/wavpack.c1
-rw-r--r--apps/dsp.c111
-rw-r--r--apps/dsp.h2
-rw-r--r--apps/lang/english.lang14
-rw-r--r--apps/settings.c7
-rw-r--r--apps/settings.h2
-rw-r--r--apps/sound_menu.c10
19 files changed, 94 insertions, 65 deletions
diff --git a/apps/codecs/a52.c b/apps/codecs/a52.c
index 0c69c6a2c7..3d0c35d7f7 100644
--- a/apps/codecs/a52.c
+++ b/apps/codecs/a52.c
@@ -141,7 +141,6 @@ enum codec_status codec_start(struct codec_api *api)
141 ci->memset(iedata, 0, iend - iedata); 141 ci->memset(iedata, 0, iend - iedata);
142 #endif 142 #endif
143 143
144 ci->configure(DSP_DITHER, (bool *)false);
145 ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED); 144 ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED);
146 ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28); 145 ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28);
147 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (long *)(1024*128)); 146 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (long *)(1024*128));
diff --git a/apps/codecs/aac.c b/apps/codecs/aac.c
index 0c48422a53..56c2a799ec 100644
--- a/apps/codecs/aac.c
+++ b/apps/codecs/aac.c
@@ -73,7 +73,6 @@ enum codec_status codec_start(struct codec_api* api)
73 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16)); 73 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16));
74 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 74 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
75 75
76 ci->configure(DSP_DITHER, (bool *)false);
77 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED); 76 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED);
78 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(29)); 77 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(29));
79 78
diff --git a/apps/codecs/adx.c b/apps/codecs/adx.c
index 99c5f4bef7..902f3ce06b 100644
--- a/apps/codecs/adx.c
+++ b/apps/codecs/adx.c
@@ -62,7 +62,6 @@ enum codec_status codec_start(struct codec_api *api)
62 /* we only render 16 bits */ 62 /* we only render 16 bits */
63 ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)16); 63 ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)16);
64 /*ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));*/ 64 /*ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));*/
65 ci->configure(DSP_DITHER, (bool *)false);
66 65
67next_track: 66next_track:
68 DEBUGF("ADX: next_track\n"); 67 DEBUGF("ADX: next_track\n");
diff --git a/apps/codecs/aiff.c b/apps/codecs/aiff.c
index 1e7adca220..8e5a3927a0 100644
--- a/apps/codecs/aiff.c
+++ b/apps/codecs/aiff.c
@@ -83,7 +83,6 @@ enum codec_status codec_start(struct codec_api *api)
83 83
84 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 84 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
85 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); 85 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));
86 ci->configure(DSP_DITHER, (bool *)false);
87 86
88next_track: 87next_track:
89 if (codec_init(api)) { 88 if (codec_init(api)) {
diff --git a/apps/codecs/alac.c b/apps/codecs/alac.c
index 890dcdb612..06c81544cd 100644
--- a/apps/codecs/alac.c
+++ b/apps/codecs/alac.c
@@ -64,7 +64,6 @@ enum codec_status codec_start(struct codec_api* api)
64 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 64 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
65 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); 65 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
66 66
67 ci->configure(DSP_DITHER, (bool *)false);
68 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED); 67 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED);
69 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(ALAC_OUTPUT_DEPTH-1)); 68 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(ALAC_OUTPUT_DEPTH-1));
70 69
diff --git a/apps/codecs/flac.c b/apps/codecs/flac.c
index 880fd69ab2..ce54e67643 100644
--- a/apps/codecs/flac.c
+++ b/apps/codecs/flac.c
@@ -264,7 +264,6 @@ enum codec_status codec_start(struct codec_api* api)
264 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 264 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
265 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); 265 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
266 266
267 ci->configure(DSP_DITHER, (bool *)false);
268 ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED); 267 ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED);
269 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(FLAC_OUTPUT_DEPTH-1)); 268 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(FLAC_OUTPUT_DEPTH-1));
270 269
diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c
index 81604de08a..ff6090e189 100644
--- a/apps/codecs/mpa.c
+++ b/apps/codecs/mpa.c
@@ -95,7 +95,6 @@ enum codec_status codec_start(struct codec_api *api)
95 95
96 /* Create a decoder instance */ 96 /* Create a decoder instance */
97 97
98 ci->configure(DSP_DITHER, (bool *)false);
99 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(MAD_F_FRACBITS)); 98 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(MAD_F_FRACBITS));
100 ci->configure(DSP_SET_CLIP_MIN, (int *)-MAD_F_ONE); 99 ci->configure(DSP_SET_CLIP_MIN, (int *)-MAD_F_ONE);
101 ci->configure(DSP_SET_CLIP_MAX, (int *)(MAD_F_ONE - 1)); 100 ci->configure(DSP_SET_CLIP_MAX, (int *)(MAD_F_ONE - 1));
diff --git a/apps/codecs/mpc.c b/apps/codecs/mpc.c
index 563b31355a..f9622f894b 100644
--- a/apps/codecs/mpc.c
+++ b/apps/codecs/mpc.c
@@ -90,7 +90,6 @@ enum codec_status codec_start(struct codec_api *api)
90 ci->memset(iedata, 0, iend - iedata); 90 ci->memset(iedata, 0, iend - iedata);
91 #endif 91 #endif
92 92
93 ci->configure(DSP_DITHER, (bool *)false);
94 ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)(28)); 93 ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)(28));
95 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (long *)(1024*16)); 94 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (long *)(1024*16));
96 ci->configure(CODEC_SET_FILEBUF_PRESEEK, (long *)(0)); 95 ci->configure(CODEC_SET_FILEBUF_PRESEEK, (long *)(0));
diff --git a/apps/codecs/shorten.c b/apps/codecs/shorten.c
index 8d62a12f03..c571df8c7a 100644
--- a/apps/codecs/shorten.c
+++ b/apps/codecs/shorten.c
@@ -63,7 +63,6 @@ enum codec_status codec_start(struct codec_api* api)
63 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 63 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
64 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); 64 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
65 65
66 ci->configure(DSP_DITHER, (bool *)false);
67 ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED); 66 ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED);
68 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(SHN_OUTPUT_DEPTH-1)); 67 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(SHN_OUTPUT_DEPTH-1));
69 68
diff --git a/apps/codecs/sid.c b/apps/codecs/sid.c
index bdffb874f4..c95e44b426 100644
--- a/apps/codecs/sid.c
+++ b/apps/codecs/sid.c
@@ -1239,7 +1239,6 @@ enum codec_status codec_start(struct codec_api *api)
1239 1239
1240 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 1240 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
1241 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); 1241 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));
1242 ci->configure(DSP_DITHER, (bool *)false);
1243 1242
1244next_track: 1243next_track:
1245 if (codec_init(api)) { 1244 if (codec_init(api)) {
diff --git a/apps/codecs/vorbis.c b/apps/codecs/vorbis.c
index 1900364a89..0475572f19 100644
--- a/apps/codecs/vorbis.c
+++ b/apps/codecs/vorbis.c
@@ -129,7 +129,6 @@ enum codec_status codec_start(struct codec_api *api)
129 rb->memset(iedata, 0, iend - iedata); 129 rb->memset(iedata, 0, iend - iedata);
130 #endif 130 #endif
131 131
132 rb->configure(DSP_DITHER, (bool *)false);
133 rb->configure(DSP_SET_SAMPLE_DEPTH, (long *)24); 132 rb->configure(DSP_SET_SAMPLE_DEPTH, (long *)24);
134 rb->configure(DSP_SET_CLIP_MAX, (long *)((1 << 24) - 1)); 133 rb->configure(DSP_SET_CLIP_MAX, (long *)((1 << 24) - 1));
135 rb->configure(DSP_SET_CLIP_MIN, (long *)-((1 << 24) - 1)); 134 rb->configure(DSP_SET_CLIP_MIN, (long *)-((1 << 24) - 1));
diff --git a/apps/codecs/wav.c b/apps/codecs/wav.c
index 3c86e3f0c5..ba99b94616 100644
--- a/apps/codecs/wav.c
+++ b/apps/codecs/wav.c
@@ -246,7 +246,6 @@ enum codec_status codec_start(struct codec_api *api)
246 ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28); 246 ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28);
247 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 247 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
248 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); 248 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));
249 ci->configure(DSP_DITHER, (bool *)false);
250 249
251next_track: 250next_track:
252 if (codec_init(api)) { 251 if (codec_init(api)) {
diff --git a/apps/codecs/wavpack.c b/apps/codecs/wavpack.c
index 1871b46f67..de815e6b01 100644
--- a/apps/codecs/wavpack.c
+++ b/apps/codecs/wavpack.c
@@ -62,7 +62,6 @@ enum codec_status codec_start(struct codec_api* api)
62 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 62 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
63 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); 63 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
64 64
65 ci->configure(DSP_DITHER, (bool *)false);
66 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(28)); 65 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(28));
67 66
68 next_track: 67 next_track:
diff --git a/apps/dsp.c b/apps/dsp.c
index 4ea2a0c3c4..94e825c532 100644
--- a/apps/dsp.c
+++ b/apps/dsp.c
@@ -32,10 +32,6 @@
32#include <dsp_asm.h> 32#include <dsp_asm.h>
33#endif 33#endif
34 34
35/* The "dither" code to convert the 24-bit samples produced by libmad was
36 * taken from the coolplayer project - coolplayer.sourceforge.net
37 */
38
39/* 16-bit samples are scaled based on these constants. The shift should be 35/* 16-bit samples are scaled based on these constants. The shift should be
40 * no more than 15. 36 * no more than 15.
41 */ 37 */
@@ -180,6 +176,8 @@ struct dsp_config
180 int stereo_mode; 176 int stereo_mode;
181 int frac_bits; 177 int frac_bits;
182 bool dither_enabled; 178 bool dither_enabled;
179 long dither_bias;
180 long dither_mask;
183 bool new_gain; 181 bool new_gain;
184 bool crossfeed_enabled; 182 bool crossfeed_enabled;
185 bool eq_enabled; 183 bool eq_enabled;
@@ -397,7 +395,7 @@ static long upsample(int32_t **dst, int32_t **src, int count, struct resample_da
397 int i = 0, j; 395 int i = 0, j;
398 int pos; 396 int pos;
399 int num_channels = dsp->stereo_mode == STEREO_MONO ? 1 : 2; 397 int num_channels = dsp->stereo_mode == STEREO_MONO ? 1 : 2;
400 398
401 while ((pos = phase >> 16) == 0) 399 while ((pos = phase >> 16) == 0)
402 { 400 {
403 for (j = 0; j < num_channels; j++) 401 for (j = 0; j < num_channels; j++)
@@ -479,40 +477,60 @@ static inline long clip_sample(int32_t sample, int32_t min, int32_t max)
479 * taken from the coolplayer project - coolplayer.sourceforge.net 477 * taken from the coolplayer project - coolplayer.sourceforge.net
480 */ 478 */
481 479
482static long dither_sample(int32_t sample, int32_t bias, int32_t mask, 480void dsp_dither_enable(bool enable)
483 struct dither_data* dither)
484{ 481{
485 int32_t output; 482 dsp->dither_enabled = enable;
486 int32_t random; 483}
487 int32_t min;
488 int32_t max;
489
490 /* Noise shape and bias */
491
492 sample += dither->error[0] - dither->error[1] + dither->error[2];
493 dither->error[2] = dither->error[1];
494 dither->error[1] = dither->error[0] / 2;
495
496 output = sample + bias;
497
498 /* Dither */
499
500 random = dither->random * 0x0019660dL + 0x3c6ef35fL;
501 sample += (random & mask) - (dither->random & mask);
502 dither->random = random;
503
504 /* Clip and quantize */
505
506 min = dsp->clip_min;
507 max = dsp->clip_max;
508 sample = clip_sample(sample, min, max);
509 output = clip_sample(output, min, max) & ~mask;
510 484
511 /* Error feedback */ 485static void dither_init(void)
486{
487 memset(&dither_data[0], 0, sizeof(dither_data));
488 memset(&dither_data[1], 0, sizeof(dither_data));
489 dsp->dither_bias = (1L << (dsp->frac_bits - NATIVE_DEPTH));
490 dsp->dither_mask = (1L << (dsp->frac_bits + 1 - NATIVE_DEPTH)) - 1;
491}
512 492
513 dither->error[0] = sample - output; 493static void dither_samples(int32_t* src, int num, struct dither_data* dither)
494{
495 int32_t output, sample;
496 int32_t random;
497 int32_t min, max;
498 long mask = dsp->dither_mask;
499 long bias = dsp->dither_bias;
500 int i;
501
502 for (i = 0; i < num; ++i) {
503 /* Noise shape and bias */
504 sample = src[i];
505 sample += dither->error[0] - dither->error[1] + dither->error[2];
506 dither->error[2] = dither->error[1];
507 dither->error[1] = dither->error[0]/2;
508
509 output = sample + bias;
510
511 /* Dither */
512 random = dither->random*0x0019660dL + 0x3c6ef35fL;
513 output += (random & mask) - (dither->random & mask);
514 dither->random = random;
515
516 /* Clip and quantize */
517 min = dsp->clip_min;
518 max = dsp->clip_max;
519 if (output > max) {
520 output = max;
521 if (sample > max)
522 sample = max;
523 } else if (output < min) {
524 output = min;
525 if (sample < min)
526 sample = min;
527 }
528 output &= ~mask;
514 529
515 return output; 530 /* Error feedback */
531 dither->error[0] = sample - output;
532 src[i] = output;
533 }
516} 534}
517 535
518void dsp_set_crossfeed(bool enable) 536void dsp_set_crossfeed(bool enable)
@@ -740,7 +758,7 @@ static void apply_gain(int32_t* _src[], int _count)
740 758
741void channels_set(int value) 759void channels_set(int value)
742{ 760{
743 channels_mode = value; 761 channels_mode = value;
744} 762}
745 763
746void stereo_width_set(int value) 764void stereo_width_set(int value)
@@ -811,15 +829,13 @@ static void write_samples(short* dst, int32_t* src[], int count)
811 829
812 if (dsp->dither_enabled) 830 if (dsp->dither_enabled)
813 { 831 {
814 long bias = (1L << (dsp->frac_bits - NATIVE_DEPTH)); 832 dither_samples(src[0], count, &dither_data[0]);
815 long mask = (1L << scale) - 1; 833 dither_samples(src[1], count, &dither_data[1]);
816 834
817 while (count-- > 0) 835 while (count-- > 0)
818 { 836 {
819 *dst++ = (short) (dither_sample(*s0++, bias, mask, &dither_data[0]) 837 *dst++ = (short) (*s0++ >> scale);
820 >> scale); 838 *dst++ = (short) (*s1++ >> scale);
821 *dst++ = (short) (dither_sample(*s1++, bias, mask, &dither_data[1])
822 >> scale);
823 } 839 }
824 } 840 }
825 else 841 else
@@ -980,7 +996,7 @@ bool dsp_configure(int setting, void *value)
980 /* Fall through!!! */ 996 /* Fall through!!! */
981 case DSP_SWITCH_FREQUENCY: 997 case DSP_SWITCH_FREQUENCY:
982 dsp->codec_frequency = ((long) value == 0) ? NATIVE_FREQUENCY : (long) value; 998 dsp->codec_frequency = ((long) value == 0) ? NATIVE_FREQUENCY : (long) value;
983 /* Account for playback speed adjustment when settingg dsp->frequency 999 /* Account for playback speed adjustment when setting dsp->frequency
984 if we're called from the main audio thread. Voice UI thread should 1000 if we're called from the main audio thread. Voice UI thread should
985 not need this feature. 1001 not need this feature.
986 */ 1002 */
@@ -1001,7 +1017,7 @@ bool dsp_configure(int setting, void *value)
1001 1017
1002 case DSP_SET_SAMPLE_DEPTH: 1018 case DSP_SET_SAMPLE_DEPTH:
1003 dsp->sample_depth = (long) value; 1019 dsp->sample_depth = (long) value;
1004 1020
1005 if (dsp->sample_depth <= NATIVE_DEPTH) 1021 if (dsp->sample_depth <= NATIVE_DEPTH)
1006 { 1022 {
1007 dsp->frac_bits = WORD_FRACBITS; 1023 dsp->frac_bits = WORD_FRACBITS;
@@ -1017,6 +1033,7 @@ bool dsp_configure(int setting, void *value)
1017 dsp->clip_min = -(1 << (long)value); 1033 dsp->clip_min = -(1 << (long)value);
1018 } 1034 }
1019 1035
1036 dither_init();
1020 break; 1037 break;
1021 1038
1022 case DSP_SET_STEREO_MODE: 1039 case DSP_SET_STEREO_MODE:
@@ -1024,7 +1041,6 @@ bool dsp_configure(int setting, void *value)
1024 break; 1041 break;
1025 1042
1026 case DSP_RESET: 1043 case DSP_RESET:
1027 dsp->dither_enabled = false;
1028 dsp->stereo_mode = STEREO_NONINTERLEAVED; 1044 dsp->stereo_mode = STEREO_NONINTERLEAVED;
1029 dsp->clip_max = ((1 << WORD_FRACBITS) - 1); 1045 dsp->clip_max = ((1 << WORD_FRACBITS) - 1);
1030 dsp->clip_min = -((1 << WORD_FRACBITS)); 1046 dsp->clip_min = -((1 << WORD_FRACBITS));
@@ -1038,11 +1054,6 @@ bool dsp_configure(int setting, void *value)
1038 dsp->new_gain = true; 1054 dsp->new_gain = true;
1039 break; 1055 break;
1040 1056
1041 case DSP_DITHER:
1042 memset(dither_data, 0, sizeof(dither_data));
1043 dsp->dither_enabled = (bool) value;
1044 break;
1045
1046 case DSP_SET_TRACK_GAIN: 1057 case DSP_SET_TRACK_GAIN:
1047 dsp->track_gain = (long) value; 1058 dsp->track_gain = (long) value;
1048 dsp->new_gain = true; 1059 dsp->new_gain = true;
diff --git a/apps/dsp.h b/apps/dsp.h
index 4221d9e350..965eb28c5f 100644
--- a/apps/dsp.h
+++ b/apps/dsp.h
@@ -39,7 +39,6 @@ enum {
39 DSP_SET_SAMPLE_DEPTH, 39 DSP_SET_SAMPLE_DEPTH,
40 DSP_SET_STEREO_MODE, 40 DSP_SET_STEREO_MODE,
41 DSP_RESET, 41 DSP_RESET,
42 DSP_DITHER,
43 DSP_SET_TRACK_GAIN, 42 DSP_SET_TRACK_GAIN,
44 DSP_SET_ALBUM_GAIN, 43 DSP_SET_ALBUM_GAIN,
45 DSP_SET_TRACK_PEAK, 44 DSP_SET_TRACK_PEAK,
@@ -63,5 +62,6 @@ void sound_set_pitch(int r);
63int sound_get_pitch(void); 62int sound_get_pitch(void);
64void channels_set(int value); 63void channels_set(int value);
65void stereo_width_set(int value); 64void stereo_width_set(int value);
65void dsp_dither_enable(bool enable);
66 66
67#endif 67#endif
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 3305bd24aa..99cee5a2cf 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -9974,3 +9974,17 @@
9974 *: "" 9974 *: ""
9975 </voice> 9975 </voice>
9976</phrase> 9976</phrase>
9977<phrase>
9978 id: LANG_DITHERING
9979 desc: in the sound settings menu
9980 user:
9981 <source>
9982 *: "Dithering"
9983 </source>
9984 <dest>
9985 *: "Dithering"
9986 </dest>
9987 <voice>
9988 *: "Dithering"
9989 </voice>
9990</phrase>
diff --git a/apps/settings.c b/apps/settings.c
index 9d618ebcb8..da5a461d7d 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -96,7 +96,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
96#include "eq_menu.h" 96#include "eq_menu.h"
97#endif 97#endif
98 98
99#define CONFIG_BLOCK_VERSION 54 99#define CONFIG_BLOCK_VERSION 55
100#define CONFIG_BLOCK_SIZE 512 100#define CONFIG_BLOCK_SIZE 512
101#define RTC_BLOCK_SIZE 44 101#define RTC_BLOCK_SIZE 44
102 102
@@ -591,6 +591,9 @@ static const struct bit_entry hd_bits[] =
591 {9|SIGNED, S_O(eq_band2_gain), 0, "eq band 2 gain", NULL }, 591 {9|SIGNED, S_O(eq_band2_gain), 0, "eq band 2 gain", NULL },
592 {9|SIGNED, S_O(eq_band3_gain), 0, "eq band 3 gain", NULL }, 592 {9|SIGNED, S_O(eq_band3_gain), 0, "eq band 3 gain", NULL },
593 {9|SIGNED, S_O(eq_band4_gain), 0, "eq band 4 gain", NULL }, 593 {9|SIGNED, S_O(eq_band4_gain), 0, "eq band 4 gain", NULL },
594
595 /* dithering */
596 {1, S_O(dithering_enabled), false, "dithering enabled", off_on },
594#endif 597#endif
595 598
596#ifdef HAVE_DIRCACHE 599#ifdef HAVE_DIRCACHE
@@ -1274,6 +1277,8 @@ void settings_apply(void)
1274 for(i = 0; i < 5; i++) { 1277 for(i = 0; i < 5; i++) {
1275 dsp_set_eq_coefs(i); 1278 dsp_set_eq_coefs(i);
1276 } 1279 }
1280
1281 dsp_dither_enable(global_settings.dithering_enabled);
1277#endif 1282#endif
1278 1283
1279#ifdef HAVE_WM8758 1284#ifdef HAVE_WM8758
diff --git a/apps/settings.h b/apps/settings.h
index 0dca11432c..435d8e9ce2 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -435,6 +435,8 @@ struct user_settings
435 int eq_band4_cutoff; /* Hz */ 435 int eq_band4_cutoff; /* Hz */
436 int eq_band4_q; 436 int eq_band4_q;
437 int eq_band4_gain; /* +/- dB */ 437 int eq_band4_gain; /* +/- dB */
438
439 bool dithering_enabled;
438#endif 440#endif
439 441
440#ifdef HAVE_LCD_COLOR 442#ifdef HAVE_LCD_COLOR
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index a6e6a1cf55..c10ba9417e 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -219,6 +219,15 @@ static bool crossfeed_menu(void)
219 219
220 return result; 220 return result;
221} 221}
222
223static bool dithering_enable(void)
224{
225 return set_bool_options(str(LANG_DITHERING),
226 &global_settings.dithering_enabled,
227 STR(LANG_SET_BOOL_YES),
228 STR(LANG_SET_BOOL_NO),
229 dsp_dither_enable);
230}
222#endif 231#endif
223 232
224#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) 233#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
@@ -635,6 +644,7 @@ bool sound_menu(void)
635#if CONFIG_CODEC == SWCODEC 644#if CONFIG_CODEC == SWCODEC
636 { ID2P(LANG_CROSSFEED), crossfeed_menu }, 645 { ID2P(LANG_CROSSFEED), crossfeed_menu },
637 { ID2P(LANG_EQUALIZER), eq_menu }, 646 { ID2P(LANG_EQUALIZER), eq_menu },
647 { ID2P(LANG_DITHERING), dithering_enable },
638#endif 648#endif
639#ifdef HAVE_WM8758 649#ifdef HAVE_WM8758
640 { ID2P(LANG_EQUALIZER_HARDWARE), eq_hw_menu }, 650 { ID2P(LANG_EQUALIZER_HARDWARE), eq_hw_menu },