diff options
-rw-r--r-- | apps/dsp.c | 112 | ||||
-rw-r--r-- | apps/dsp.h | 4 | ||||
-rw-r--r-- | apps/lang/english.lang | 12 | ||||
-rw-r--r-- | apps/settings.c | 4 | ||||
-rw-r--r-- | apps/settings.h | 1 | ||||
-rw-r--r-- | apps/settings_menu.c | 10 |
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 | ||
120 | struct resample_data | 144 | struct resample_data |
@@ -130,9 +154,18 @@ struct dither_data | |||
130 | long random; | 154 | long random; |
131 | }; | 155 | }; |
132 | 156 | ||
157 | struct crossfeed_data | ||
158 | { | ||
159 | long lowpass[2]; | ||
160 | long highpass[2]; | ||
161 | long delay[2][13]; | ||
162 | int index; | ||
163 | }; | ||
164 | |||
133 | static struct dsp_config dsp_conf[2] IBSS_ATTR; | 165 | static struct dsp_config dsp_conf[2] IBSS_ATTR; |
134 | static struct dither_data dither_data[2] IBSS_ATTR; | 166 | static struct dither_data dither_data[2] IBSS_ATTR; |
135 | static struct resample_data resample_data[2][2] IBSS_ATTR; | 167 | static struct resample_data resample_data[2][2] IBSS_ATTR; |
168 | static struct crossfeed_data crossfeed_data IBSS_ATTR; | ||
136 | 169 | ||
137 | extern int current_codec; | 170 | extern int current_codec; |
138 | struct dsp_config *dsp; | 171 | struct dsp_config *dsp; |
@@ -145,7 +178,6 @@ struct dsp_config *dsp; | |||
145 | static long sample_buf[SAMPLE_BUF_SIZE] IBSS_ATTR; | 178 | static long sample_buf[SAMPLE_BUF_SIZE] IBSS_ATTR; |
146 | static long resample_buf[RESAMPLE_BUF_SIZE] IBSS_ATTR; | 179 | static 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 | */ |
445 | static 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 | */ | ||
413 | static void apply_gain(long* src[], int count) | 515 | static 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 | ||
804 | void dsp_set_crossfeed(bool enable) | ||
805 | { | ||
806 | if (enable) | ||
807 | memset(&crossfeed_data, 0, sizeof(crossfeed_data)); | ||
808 | dsp->crossfeed_enabled = enable; | ||
809 | } | ||
810 | |||
701 | void dsp_set_replaygain(bool always) | 811 | void 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 | ||
50 | long dsp_process(char *dest, char *src[], long size); | 51 | long dsp_process(char *dest, char *src[], long size); |
@@ -53,5 +54,6 @@ long dsp_output_size(long size); | |||
53 | int dsp_stereo_mode(void); | 54 | int dsp_stereo_mode(void); |
54 | bool dsp_configure(int setting, void *value); | 55 | bool dsp_configure(int setting, void *value); |
55 | void dsp_set_replaygain(bool always); | 56 | void dsp_set_replaygain(bool always); |
57 | void 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 | |||
3388 | eng: "Screen frozen!" | 3388 | eng: "Screen frozen!" |
3389 | voice: "" | 3389 | voice: "" |
3390 | new: | 3390 | new: |
3391 | |||
3392 | id: LANG_CROSSFEED_ENABLE | ||
3393 | desc: In the crossfeed menu | ||
3394 | eng: "Enable crossfeed" | ||
3395 | voice: | ||
3396 | new: | ||
3397 | |||
3398 | id: LANG_CROSSFEED | ||
3399 | desc: in the sound settings menu | ||
3400 | eng: "Crossfeed" | ||
3401 | voice: | ||
3402 | new: | ||
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 | ||
1206 | static 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 | |||
1206 | static bool crossfade(void) | 1215 | static 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 |