summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/dsp.c112
-rw-r--r--apps/dsp.h4
-rw-r--r--apps/lang/english.lang12
-rw-r--r--apps/settings.c4
-rw-r--r--apps/settings.h1
-rw-r--r--apps/settings_menu.c10
6 files changed, 140 insertions, 3 deletions
diff --git a/apps/dsp.c b/apps/dsp.c
index d0f8b6d6d1..c490ed3824 100644
--- a/apps/dsp.c
+++ b/apps/dsp.c
@@ -41,6 +41,15 @@
41#define RESAMPLE_BUF_SIZE (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ 41#define RESAMPLE_BUF_SIZE (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/
42#define DEFAULT_REPLAYGAIN 0x01000000 42#define DEFAULT_REPLAYGAIN 0x01000000
43 43
44/* These are the constants for the filters in the crossfeed */
45
46#define ATT 0x0CCCCCCDL /* 0.1 */
47#define ATT_COMP 0x73333333L /* 0.9 */
48#define LOW 0x4CCCCCCDL /* 0.6 */
49#define LOW_COMP 0x33333333L /* 0.4 */
50#define HIGH_NEG 0x9999999AL /* -0.2 */
51#define HIGH_COMP 0x66666666L /* 0.8 */
52
44#if defined(CPU_COLDFIRE) && !defined(SIMULATOR) 53#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
45 54
46/* Multiply two S.31 fractional integers and return the sign bit and the 55/* Multiply two S.31 fractional integers and return the sign bit and the
@@ -86,6 +95,20 @@
86 (t << 8) | (u & 0xff); \ 95 (t << 8) | (u & 0xff); \
87}) 96})
88 97
98
99#define ACC(acc, x, y) \
100 (void)acc; \
101 asm volatile ("mac.l %[a], %[b], %%acc0" \
102 : : [a] "i,r" (x), [b] "i,r" (y));
103#define GET_ACC(acc) \
104({ \
105 long t; \
106 (void)acc; \
107 asm volatile ("movclr.l %%acc0, %[t]" \
108 : [t] "=r" (t)); \
109 t; \
110})
111
89#else 112#else
90 113
91#define FRACMUL(x, y) (long) (((((long long) (x)) * ((long long) (y))) >> 31)) 114#define FRACMUL(x, y) (long) (((((long long) (x)) * ((long long) (y))) >> 31))
@@ -115,6 +138,7 @@ struct dsp_config
115 int frac_bits; 138 int frac_bits;
116 bool dither_enabled; 139 bool dither_enabled;
117 bool new_gain; 140 bool new_gain;
141 bool crossfeed_enabled;
118}; 142};
119 143
120struct resample_data 144struct resample_data
@@ -130,9 +154,18 @@ struct dither_data
130 long random; 154 long random;
131}; 155};
132 156
157struct crossfeed_data
158{
159 long lowpass[2];
160 long highpass[2];
161 long delay[2][13];
162 int index;
163};
164
133static struct dsp_config dsp_conf[2] IBSS_ATTR; 165static struct dsp_config dsp_conf[2] IBSS_ATTR;
134static struct dither_data dither_data[2] IBSS_ATTR; 166static struct dither_data dither_data[2] IBSS_ATTR;
135static struct resample_data resample_data[2][2] IBSS_ATTR; 167static struct resample_data resample_data[2][2] IBSS_ATTR;
168static struct crossfeed_data crossfeed_data IBSS_ATTR;
136 169
137extern int current_codec; 170extern int current_codec;
138struct dsp_config *dsp; 171struct dsp_config *dsp;
@@ -145,7 +178,6 @@ struct dsp_config *dsp;
145static long sample_buf[SAMPLE_BUF_SIZE] IBSS_ATTR; 178static long sample_buf[SAMPLE_BUF_SIZE] IBSS_ATTR;
146static long resample_buf[RESAMPLE_BUF_SIZE] IBSS_ATTR; 179static long resample_buf[RESAMPLE_BUF_SIZE] IBSS_ATTR;
147 180
148
149/* Convert at most count samples to the internal format, if needed. Returns 181/* Convert at most count samples to the internal format, if needed. Returns
150 * number of samples ready for further processing. Updates src to point 182 * number of samples ready for further processing. Updates src to point
151 * past the samples "consumed" and dst is set to point to the samples to 183 * past the samples "consumed" and dst is set to point to the samples to
@@ -410,6 +442,76 @@ static long dither_sample(long sample, long bias, long mask,
410 * the src array if gain was applied. 442 * the src array if gain was applied.
411 * Note that this must be called before the resampler. 443 * Note that this must be called before the resampler.
412 */ 444 */
445static void apply_crossfeed(long* src[], int count)
446{
447
448 if (dsp->crossfeed_enabled && src[0] != src[1])
449 {
450 long long a;
451
452 long low_left = crossfeed_data.lowpass[0];
453 long low_right = crossfeed_data.lowpass[1];
454 long high_left = crossfeed_data.highpass[0];
455 long high_right = crossfeed_data.highpass[1];
456 unsigned int index = crossfeed_data.index;
457
458 long left, right;
459
460 long * delay_l = crossfeed_data.delay[0];
461 long * delay_r = crossfeed_data.delay[1];
462
463 int i;
464
465 for (i = 0; i < count; i++)
466 {
467 /* use a low-pass filter on the signal */
468 left = src[0][i];
469 right = src[1][i];
470
471 ACC(a, LOW, low_left); ACC(a, LOW_COMP, left);
472 low_left = GET_ACC(a);
473
474 ACC(a, LOW, low_right); ACC(a, LOW_COMP, right);
475 low_right = GET_ACC(a);
476
477 /* use a high-pass filter on the signal */
478
479 ACC(a, HIGH_NEG, high_left); ACC(a, HIGH_COMP, left);
480 high_left = GET_ACC(a);
481
482 ACC(a, HIGH_NEG, high_right); ACC(a, HIGH_COMP, right);
483 high_right = GET_ACC(a);
484
485 /* New data is the high-passed signal + delayed and attenuated
486 * low-passed signal from the other channel */
487
488 ACC(a, ATT, delay_r[index]); ACC(a, ATT_COMP, high_left);
489 src[0][i] = GET_ACC(a);
490
491 ACC(a, ATT, delay_l[index]); ACC(a, ATT_COMP, high_right);
492 src[1][i] = GET_ACC(a);
493
494 /* Store the low-passed signal in the ringbuffer */
495
496 delay_l[index] = low_left;
497 delay_r[index] = low_right;
498
499 index = (index + 1) % 13;
500 }
501
502 crossfeed_data.index = index;
503 crossfeed_data.lowpass[0] = low_left;
504 crossfeed_data.lowpass[1] = low_right;
505 crossfeed_data.highpass[0] = high_left;
506 crossfeed_data.highpass[1] = high_right;
507
508 }
509}
510
511/* Apply a constant gain to the samples (e.g., for ReplayGain). May update
512 * the src array if gain was applied.
513 * Note that this must be called before the resampler.
514 */
413static void apply_gain(long* src[], int count) 515static void apply_gain(long* src[], int count)
414{ 516{
415 if (dsp->replaygain) 517 if (dsp->replaygain)
@@ -509,6 +611,7 @@ long dsp_process(char* dst, char* src[], long size)
509 size -= samples; 611 size -= samples;
510 apply_gain(tmp, samples); 612 apply_gain(tmp, samples);
511 samples = resample(tmp, samples); 613 samples = resample(tmp, samples);
614 apply_crossfeed(tmp, samples);
512 write_samples((short*) dst, tmp, samples); 615 write_samples((short*) dst, tmp, samples);
513 written += samples; 616 written += samples;
514 dst += samples * sizeof(short) * 2; 617 dst += samples * sizeof(short) * 2;
@@ -698,6 +801,13 @@ bool dsp_configure(int setting, void *value)
698 return 1; 801 return 1;
699} 802}
700 803
804void dsp_set_crossfeed(bool enable)
805{
806 if (enable)
807 memset(&crossfeed_data, 0, sizeof(crossfeed_data));
808 dsp->crossfeed_enabled = enable;
809}
810
701void dsp_set_replaygain(bool always) 811void dsp_set_replaygain(bool always)
702{ 812{
703 dsp = &dsp_conf[current_codec]; 813 dsp = &dsp_conf[current_codec];
diff --git a/apps/dsp.h b/apps/dsp.h
index fdd9a191cb..19ba6db980 100644
--- a/apps/dsp.h
+++ b/apps/dsp.h
@@ -44,7 +44,8 @@ enum {
44 DSP_SET_TRACK_GAIN, 44 DSP_SET_TRACK_GAIN,
45 DSP_SET_ALBUM_GAIN, 45 DSP_SET_ALBUM_GAIN,
46 DSP_SET_TRACK_PEAK, 46 DSP_SET_TRACK_PEAK,
47 DSP_SET_ALBUM_PEAK 47 DSP_SET_ALBUM_PEAK,
48 DSP_CROSSFEED
48}; 49};
49 50
50long dsp_process(char *dest, char *src[], long size); 51long dsp_process(char *dest, char *src[], long size);
@@ -53,5 +54,6 @@ long dsp_output_size(long size);
53int dsp_stereo_mode(void); 54int dsp_stereo_mode(void);
54bool dsp_configure(int setting, void *value); 55bool dsp_configure(int setting, void *value);
55void dsp_set_replaygain(bool always); 56void dsp_set_replaygain(bool always);
57void dsp_set_crossfeed(bool enable);
56 58
57#endif 59#endif
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 001fe4584a..1a4b88c96a 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3388,3 +3388,15 @@ desc: error message when preset list is empty
3388eng: "Screen frozen!" 3388eng: "Screen frozen!"
3389voice: "" 3389voice: ""
3390new: 3390new:
3391
3392id: LANG_CROSSFEED_ENABLE
3393desc: In the crossfeed menu
3394eng: "Enable crossfeed"
3395voice:
3396new:
3397
3398id: LANG_CROSSFEED
3399desc: in the sound settings menu
3400eng: "Crossfeed"
3401voice:
3402new:
diff --git a/apps/settings.c b/apps/settings.c
index 742b11276d..f483b8dd73 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -85,7 +85,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
85#include "dsp.h" 85#include "dsp.h"
86#endif 86#endif
87 87
88#define CONFIG_BLOCK_VERSION 30 88#define CONFIG_BLOCK_VERSION 31
89#define CONFIG_BLOCK_SIZE 512 89#define CONFIG_BLOCK_SIZE 512
90#define RTC_BLOCK_SIZE 44 90#define RTC_BLOCK_SIZE 44
91 91
@@ -444,6 +444,7 @@ static const struct bit_entry hd_bits[] =
444 {4, S_O(crossfade_fade_in_duration), 0, "crossfade fade in duration", NULL}, 444 {4, S_O(crossfade_fade_in_duration), 0, "crossfade fade in duration", NULL},
445 {4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL}, 445 {4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL},
446 {1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"}, 446 {1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"},
447 {1, S_O(crossfeed), false, "crossfeed", off_on },
447#endif 448#endif
448#ifdef HAVE_DIRCACHE 449#ifdef HAVE_DIRCACHE
449 {1, S_O(dircache), false, "dircache", off_on }, 450 {1, S_O(dircache), false, "dircache", off_on },
@@ -912,6 +913,7 @@ void settings_apply(void)
912#if CONFIG_CODEC == SWCODEC 913#if CONFIG_CODEC == SWCODEC
913 audio_set_crossfade(global_settings.crossfade); 914 audio_set_crossfade(global_settings.crossfade);
914 dsp_set_replaygain(true); 915 dsp_set_replaygain(true);
916 dsp_set_crossfeed(global_settings.crossfeed);
915#endif 917#endif
916 918
917#ifdef HAVE_SPDIF_POWER 919#ifdef HAVE_SPDIF_POWER
diff --git a/apps/settings.h b/apps/settings.h
index e605a8d1fa..d1a367cc64 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -353,6 +353,7 @@ struct user_settings
353 shuffle is on, album gain otherwise */ 353 shuffle is on, album gain otherwise */
354 int replaygain_preamp; /* scale replaygained tracks by this */ 354 int replaygain_preamp; /* scale replaygained tracks by this */
355 int beep; /* system beep volume when changing tracks etc. */ 355 int beep; /* system beep volume when changing tracks etc. */
356 bool crossfeed; /* enable crossfeed */
356#endif 357#endif
357#ifdef HAVE_DIRCACHE 358#ifdef HAVE_DIRCACHE
358 bool dircache; /* enable directory cache */ 359 bool dircache; /* enable directory cache */
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 102453033e..ce2399b1e5 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -1203,6 +1203,15 @@ static bool replaygain_settings_menu(void)
1203 return result; 1203 return result;
1204} 1204}
1205 1205
1206static bool crossfeed(void)
1207{
1208 bool result = set_bool(str(LANG_CROSSFEED_ENABLE),
1209 &global_settings.crossfeed);
1210
1211 dsp_set_crossfeed(global_settings.crossfeed);
1212 return result;
1213}
1214
1206static bool crossfade(void) 1215static bool crossfade(void)
1207{ 1216{
1208 static const struct opt_items names[] = { 1217 static const struct opt_items names[] = {
@@ -1354,6 +1363,7 @@ static bool playback_settings_menu(void)
1354#if CONFIG_CODEC == SWCODEC 1363#if CONFIG_CODEC == SWCODEC
1355 { ID2P(LANG_CROSSFADE), crossfade_settings_menu }, 1364 { ID2P(LANG_CROSSFADE), crossfade_settings_menu },
1356 { ID2P(LANG_REPLAYGAIN), replaygain_settings_menu }, 1365 { ID2P(LANG_REPLAYGAIN), replaygain_settings_menu },
1366 { ID2P(LANG_CROSSFEED), crossfeed },
1357 { ID2P(LANG_BEEP), beep }, 1367 { ID2P(LANG_BEEP), beep },
1358#endif 1368#endif
1359#ifdef HAVE_SPDIF_POWER 1369#ifdef HAVE_SPDIF_POWER