From 354770088e87c3aa8720f462fe3ac8368d7de5b5 Mon Sep 17 00:00:00 2001 From: Thom Johansen Date: Fri, 27 Oct 2006 20:41:33 +0000 Subject: 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 --- apps/codecs/a52.c | 1 - apps/codecs/aac.c | 1 - apps/codecs/adx.c | 1 - apps/codecs/aiff.c | 1 - apps/codecs/alac.c | 1 - apps/codecs/flac.c | 1 - apps/codecs/mpa.c | 1 - apps/codecs/mpc.c | 1 - apps/codecs/shorten.c | 1 - apps/codecs/sid.c | 1 - apps/codecs/vorbis.c | 1 - apps/codecs/wav.c | 1 - apps/codecs/wavpack.c | 1 - apps/dsp.c | 111 +++++++++++++++++++++++++++---------------------- apps/dsp.h | 2 +- apps/lang/english.lang | 14 +++++++ apps/settings.c | 7 +++- apps/settings.h | 2 + apps/sound_menu.c | 10 +++++ 19 files changed, 94 insertions(+), 65 deletions(-) (limited to 'apps') 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) ci->memset(iedata, 0, iend - iedata); #endif - ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28); 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) ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16)); ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); - ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(29)); 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) /* we only render 16 bits */ ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)16); /*ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));*/ - ci->configure(DSP_DITHER, (bool *)false); next_track: 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) ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); - ci->configure(DSP_DITHER, (bool *)false); next_track: 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) ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); - ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(ALAC_OUTPUT_DEPTH-1)); 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) ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); - ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(FLAC_OUTPUT_DEPTH-1)); 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) /* Create a decoder instance */ - ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(MAD_F_FRACBITS)); ci->configure(DSP_SET_CLIP_MIN, (int *)-MAD_F_ONE); 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) ci->memset(iedata, 0, iend - iedata); #endif - ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)(28)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (long *)(1024*16)); 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) ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); - ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_SET_STEREO_MODE, (long *)STEREO_NONINTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(SHN_OUTPUT_DEPTH-1)); 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) ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); - ci->configure(DSP_DITHER, (bool *)false); next_track: 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) rb->memset(iedata, 0, iend - iedata); #endif - rb->configure(DSP_DITHER, (bool *)false); rb->configure(DSP_SET_SAMPLE_DEPTH, (long *)24); rb->configure(DSP_SET_CLIP_MAX, (long *)((1 << 24) - 1)); 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) ci->configure(DSP_SET_SAMPLE_DEPTH, (long *)28); ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); - ci->configure(DSP_DITHER, (bool *)false); next_track: 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) ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); - ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(28)); 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 @@ #include #endif -/* The "dither" code to convert the 24-bit samples produced by libmad was - * taken from the coolplayer project - coolplayer.sourceforge.net - */ - /* 16-bit samples are scaled based on these constants. The shift should be * no more than 15. */ @@ -180,6 +176,8 @@ struct dsp_config int stereo_mode; int frac_bits; bool dither_enabled; + long dither_bias; + long dither_mask; bool new_gain; bool crossfeed_enabled; bool eq_enabled; @@ -397,7 +395,7 @@ static long upsample(int32_t **dst, int32_t **src, int count, struct resample_da int i = 0, j; int pos; int num_channels = dsp->stereo_mode == STEREO_MONO ? 1 : 2; - + while ((pos = phase >> 16) == 0) { 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) * taken from the coolplayer project - coolplayer.sourceforge.net */ -static long dither_sample(int32_t sample, int32_t bias, int32_t mask, - struct dither_data* dither) +void dsp_dither_enable(bool enable) { - int32_t output; - int32_t random; - int32_t min; - int32_t max; - - /* Noise shape and bias */ - - sample += dither->error[0] - dither->error[1] + dither->error[2]; - dither->error[2] = dither->error[1]; - dither->error[1] = dither->error[0] / 2; - - output = sample + bias; - - /* Dither */ - - random = dither->random * 0x0019660dL + 0x3c6ef35fL; - sample += (random & mask) - (dither->random & mask); - dither->random = random; - - /* Clip and quantize */ - - min = dsp->clip_min; - max = dsp->clip_max; - sample = clip_sample(sample, min, max); - output = clip_sample(output, min, max) & ~mask; + dsp->dither_enabled = enable; +} - /* Error feedback */ +static void dither_init(void) +{ + memset(&dither_data[0], 0, sizeof(dither_data)); + memset(&dither_data[1], 0, sizeof(dither_data)); + dsp->dither_bias = (1L << (dsp->frac_bits - NATIVE_DEPTH)); + dsp->dither_mask = (1L << (dsp->frac_bits + 1 - NATIVE_DEPTH)) - 1; +} - dither->error[0] = sample - output; +static void dither_samples(int32_t* src, int num, struct dither_data* dither) +{ + int32_t output, sample; + int32_t random; + int32_t min, max; + long mask = dsp->dither_mask; + long bias = dsp->dither_bias; + int i; + + for (i = 0; i < num; ++i) { + /* Noise shape and bias */ + sample = src[i]; + sample += dither->error[0] - dither->error[1] + dither->error[2]; + dither->error[2] = dither->error[1]; + dither->error[1] = dither->error[0]/2; + + output = sample + bias; + + /* Dither */ + random = dither->random*0x0019660dL + 0x3c6ef35fL; + output += (random & mask) - (dither->random & mask); + dither->random = random; + + /* Clip and quantize */ + min = dsp->clip_min; + max = dsp->clip_max; + if (output > max) { + output = max; + if (sample > max) + sample = max; + } else if (output < min) { + output = min; + if (sample < min) + sample = min; + } + output &= ~mask; - return output; + /* Error feedback */ + dither->error[0] = sample - output; + src[i] = output; + } } void dsp_set_crossfeed(bool enable) @@ -740,7 +758,7 @@ static void apply_gain(int32_t* _src[], int _count) void channels_set(int value) { - channels_mode = value; + channels_mode = value; } void stereo_width_set(int value) @@ -811,15 +829,13 @@ static void write_samples(short* dst, int32_t* src[], int count) if (dsp->dither_enabled) { - long bias = (1L << (dsp->frac_bits - NATIVE_DEPTH)); - long mask = (1L << scale) - 1; + dither_samples(src[0], count, &dither_data[0]); + dither_samples(src[1], count, &dither_data[1]); while (count-- > 0) { - *dst++ = (short) (dither_sample(*s0++, bias, mask, &dither_data[0]) - >> scale); - *dst++ = (short) (dither_sample(*s1++, bias, mask, &dither_data[1]) - >> scale); + *dst++ = (short) (*s0++ >> scale); + *dst++ = (short) (*s1++ >> scale); } } else @@ -980,7 +996,7 @@ bool dsp_configure(int setting, void *value) /* Fall through!!! */ case DSP_SWITCH_FREQUENCY: dsp->codec_frequency = ((long) value == 0) ? NATIVE_FREQUENCY : (long) value; - /* Account for playback speed adjustment when settingg dsp->frequency + /* Account for playback speed adjustment when setting dsp->frequency if we're called from the main audio thread. Voice UI thread should not need this feature. */ @@ -1001,7 +1017,7 @@ bool dsp_configure(int setting, void *value) case DSP_SET_SAMPLE_DEPTH: dsp->sample_depth = (long) value; - + if (dsp->sample_depth <= NATIVE_DEPTH) { dsp->frac_bits = WORD_FRACBITS; @@ -1017,6 +1033,7 @@ bool dsp_configure(int setting, void *value) dsp->clip_min = -(1 << (long)value); } + dither_init(); break; case DSP_SET_STEREO_MODE: @@ -1024,7 +1041,6 @@ bool dsp_configure(int setting, void *value) break; case DSP_RESET: - dsp->dither_enabled = false; dsp->stereo_mode = STEREO_NONINTERLEAVED; dsp->clip_max = ((1 << WORD_FRACBITS) - 1); dsp->clip_min = -((1 << WORD_FRACBITS)); @@ -1038,11 +1054,6 @@ bool dsp_configure(int setting, void *value) dsp->new_gain = true; break; - case DSP_DITHER: - memset(dither_data, 0, sizeof(dither_data)); - dsp->dither_enabled = (bool) value; - break; - case DSP_SET_TRACK_GAIN: dsp->track_gain = (long) value; 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 { DSP_SET_SAMPLE_DEPTH, DSP_SET_STEREO_MODE, DSP_RESET, - DSP_DITHER, DSP_SET_TRACK_GAIN, DSP_SET_ALBUM_GAIN, DSP_SET_TRACK_PEAK, @@ -63,5 +62,6 @@ void sound_set_pitch(int r); int sound_get_pitch(void); void channels_set(int value); void stereo_width_set(int value); +void dsp_dither_enable(bool enable); #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 @@ *: "" + + id: LANG_DITHERING + desc: in the sound settings menu + user: + + *: "Dithering" + + + *: "Dithering" + + + *: "Dithering" + + 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; #include "eq_menu.h" #endif -#define CONFIG_BLOCK_VERSION 54 +#define CONFIG_BLOCK_VERSION 55 #define CONFIG_BLOCK_SIZE 512 #define RTC_BLOCK_SIZE 44 @@ -591,6 +591,9 @@ static const struct bit_entry hd_bits[] = {9|SIGNED, S_O(eq_band2_gain), 0, "eq band 2 gain", NULL }, {9|SIGNED, S_O(eq_band3_gain), 0, "eq band 3 gain", NULL }, {9|SIGNED, S_O(eq_band4_gain), 0, "eq band 4 gain", NULL }, + + /* dithering */ + {1, S_O(dithering_enabled), false, "dithering enabled", off_on }, #endif #ifdef HAVE_DIRCACHE @@ -1274,6 +1277,8 @@ void settings_apply(void) for(i = 0; i < 5; i++) { dsp_set_eq_coefs(i); } + + dsp_dither_enable(global_settings.dithering_enabled); #endif #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 int eq_band4_cutoff; /* Hz */ int eq_band4_q; int eq_band4_gain; /* +/- dB */ + + bool dithering_enabled; #endif #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) return result; } + +static bool dithering_enable(void) +{ + return set_bool_options(str(LANG_DITHERING), + &global_settings.dithering_enabled, + STR(LANG_SET_BOOL_YES), + STR(LANG_SET_BOOL_NO), + dsp_dither_enable); +} #endif #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) @@ -635,6 +644,7 @@ bool sound_menu(void) #if CONFIG_CODEC == SWCODEC { ID2P(LANG_CROSSFEED), crossfeed_menu }, { ID2P(LANG_EQUALIZER), eq_menu }, + { ID2P(LANG_DITHERING), dithering_enable }, #endif #ifdef HAVE_WM8758 { ID2P(LANG_EQUALIZER_HARDWARE), eq_hw_menu }, -- cgit v1.2.3