diff options
Diffstat (limited to 'apps/dsp.c')
-rw-r--r-- | apps/dsp.c | 112 |
1 files changed, 111 insertions, 1 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]; |