diff options
-rw-r--r-- | apps/dsp.c | 145 | ||||
-rw-r--r-- | apps/dsp.h | 2 | ||||
-rw-r--r-- | apps/dsp_cf.S | 102 | ||||
-rw-r--r-- | apps/eq.c | 28 | ||||
-rw-r--r-- | apps/eq.h | 1 | ||||
-rw-r--r-- | apps/lang/english.lang | 66 | ||||
-rw-r--r-- | apps/settings.c | 16 | ||||
-rw-r--r-- | apps/settings.h | 8 | ||||
-rw-r--r-- | apps/sound_menu.c | 80 | ||||
-rw-r--r-- | firmware/system.c | 4 |
10 files changed, 298 insertions, 154 deletions
diff --git a/apps/dsp.c b/apps/dsp.c index 29e103afb7..b6d24824b5 100644 --- a/apps/dsp.c +++ b/apps/dsp.c | |||
@@ -47,15 +47,6 @@ | |||
47 | #define RESAMPLE_BUF_SIZE (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ | 47 | #define RESAMPLE_BUF_SIZE (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ |
48 | #define DEFAULT_REPLAYGAIN 0x01000000 | 48 | #define DEFAULT_REPLAYGAIN 0x01000000 |
49 | 49 | ||
50 | /* These are the constants for the filters in the crossfeed */ | ||
51 | |||
52 | #define ATT 0x0CCCCCCDL /* 0.1 */ | ||
53 | #define ATT_COMP 0x73333333L /* 0.9 */ | ||
54 | #define LOW 0x4CCCCCCDL /* 0.6 */ | ||
55 | #define LOW_COMP 0x33333333L /* 0.4 */ | ||
56 | #define HIGH_NEG -0x66666666L /* -0.2 (not unsigned!) */ | ||
57 | #define HIGH_COMP 0x66666666L /* 0.8 */ | ||
58 | |||
59 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) | 50 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) |
60 | 51 | ||
61 | /* Multiply two S.31 fractional integers and return the sign bit and the | 52 | /* Multiply two S.31 fractional integers and return the sign bit and the |
@@ -209,10 +200,11 @@ struct dither_data | |||
209 | 200 | ||
210 | struct crossfeed_data | 201 | struct crossfeed_data |
211 | { | 202 | { |
212 | int32_t lowpass[2]; | 203 | int32_t gain; /* Direct path gain */ |
213 | int32_t highpass[2]; | 204 | int32_t coefs[3]; /* Coefficients for the shelving filter */ |
214 | int32_t delay[2][13]; | 205 | int32_t history[4]; /* Format is x[n - 1], y[n - 1] for both channels */ |
215 | int index; | 206 | int32_t delay[13][2]; |
207 | int index; /* Current index into the delay line */ | ||
216 | }; | 208 | }; |
217 | 209 | ||
218 | /* Current setup is one lowshelf filters, three peaking filters and one | 210 | /* Current setup is one lowshelf filters, three peaking filters and one |
@@ -522,71 +514,71 @@ static long dither_sample(int32_t sample, int32_t bias, int32_t mask, | |||
522 | return output; | 514 | return output; |
523 | } | 515 | } |
524 | 516 | ||
517 | void dsp_set_crossfeed(bool enable) | ||
518 | { | ||
519 | dsp->crossfeed_enabled = enable; | ||
520 | } | ||
521 | |||
522 | void dsp_set_crossfeed_direct_gain(int gain) | ||
523 | { | ||
524 | /* Work around bug in get_replaygain_int which returns 0 for 0 dB */ | ||
525 | if (gain == 0) | ||
526 | crossfeed_data.gain = 0x7fffffff; | ||
527 | else | ||
528 | crossfeed_data.gain = get_replaygain_int(gain * -10) << 7; | ||
529 | } | ||
530 | |||
531 | void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) | ||
532 | { | ||
533 | long g1 = get_replaygain_int(lf_gain * -10) << 3; | ||
534 | long g2 = get_replaygain_int(hf_gain * -10) << 3; | ||
535 | |||
536 | filter_bishelf_coefs(0xffffffff/NATIVE_FREQUENCY*cutoff, g1, g2, | ||
537 | crossfeed_data.coefs); | ||
538 | } | ||
539 | |||
525 | /* Applies crossfeed to the stereo signal in src. | 540 | /* Applies crossfeed to the stereo signal in src. |
526 | * Crossfeed is a process where listening over speakers is simulated. This | 541 | * Crossfeed is a process where listening over speakers is simulated. This |
527 | * is good for old hard panned stereo records, which might be quite fatiguing | 542 | * is good for old hard panned stereo records, which might be quite fatiguing |
528 | * to listen to on headphones with no crossfeed. | 543 | * to listen to on headphones with no crossfeed. |
529 | */ | 544 | */ |
530 | #ifndef DSP_HAVE_ASM_CROSSFEED | 545 | #ifndef DSP_HAVE_ASM_CROSSFEED |
531 | static void apply_crossfeed(int32_t* src[], int count) | 546 | void apply_crossfeed(int32_t* src[], int count) |
532 | { | 547 | { |
533 | int32_t a; /* accumulator */ | 548 | int32_t *hist_l = &crossfeed_data.history[0]; |
534 | 549 | int32_t *hist_r = &crossfeed_data.history[2]; | |
535 | int32_t low_left = crossfeed_data.lowpass[0]; | 550 | int32_t *delay = &crossfeed_data.delay[0][0]; |
536 | int32_t low_right = crossfeed_data.lowpass[1]; | 551 | int32_t *coefs = &crossfeed_data.coefs[0]; |
537 | int32_t high_left = crossfeed_data.highpass[0]; | 552 | int32_t gain = crossfeed_data.gain; |
538 | int32_t high_right = crossfeed_data.highpass[1]; | 553 | int di = crossfeed_data.index; |
539 | unsigned int index = crossfeed_data.index; | 554 | |
540 | 555 | int32_t acc; | |
541 | int32_t left, right; | 556 | int32_t left, right; |
542 | |||
543 | int32_t* delay_l = crossfeed_data.delay[0]; | ||
544 | int32_t* delay_r = crossfeed_data.delay[1]; | ||
545 | |||
546 | int i; | 557 | int i; |
547 | 558 | ||
548 | for (i = 0; i < count; i++) | 559 | for (i = 0; i < count; i++) { |
549 | { | ||
550 | /* use a low-pass filter on the signal */ | ||
551 | left = src[0][i]; | 560 | left = src[0][i]; |
552 | right = src[1][i]; | 561 | right = src[1][i]; |
553 | 562 | ||
554 | ACC_INIT(a, LOW, low_left); ACC(a, LOW_COMP, left); | 563 | ACC_INIT(acc, delay[di*2], coefs[0]); |
555 | low_left = GET_ACC(a); | 564 | ACC(acc, hist_l[0], coefs[1]); |
556 | 565 | ACC(acc, hist_l[1], coefs[2]); | |
557 | ACC_INIT(a, LOW, low_right); ACC(a, LOW_COMP, right); | 566 | hist_l[1] = GET_ACC(acc) << 0; |
558 | low_right = GET_ACC(a); | 567 | hist_l[0] = delay[di*2]; |
559 | 568 | ACC_INIT(acc, delay[di*2 + 1], coefs[0]); | |
560 | /* use a high-pass filter on the signal */ | 569 | ACC(acc, hist_r[0], coefs[1]); |
561 | 570 | ACC(acc, hist_r[1], coefs[2]); | |
562 | ACC_INIT(a, HIGH_NEG, high_left); ACC(a, HIGH_COMP, left); | 571 | hist_r[1] = GET_ACC(acc) << 0; |
563 | high_left = GET_ACC(a); | 572 | hist_r[0] = delay[di*2 + 1]; |
564 | 573 | delay[di*2] = left; | |
565 | ACC_INIT(a, HIGH_NEG, high_right); ACC(a, HIGH_COMP, right); | 574 | delay[di*2 + 1] = right; |
566 | high_right = GET_ACC(a); | 575 | src[0][i] = FRACMUL(left, gain) + hist_r[1]; |
567 | 576 | src[1][i] = FRACMUL(right, gain) + hist_l[1]; | |
568 | /* New data is the high-passed signal + delayed and attenuated | 577 | |
569 | * low-passed signal from the other channel */ | 578 | if (++di > 12) |
570 | 579 | di = 0; | |
571 | ACC_INIT(a, ATT, delay_r[index]); ACC(a, ATT_COMP, high_left); | ||
572 | src[0][i] = GET_ACC(a); | ||
573 | |||
574 | ACC_INIT(a, ATT, delay_l[index]); ACC(a, ATT_COMP, high_right); | ||
575 | src[1][i] = GET_ACC(a); | ||
576 | |||
577 | /* Store the low-passed signal in the ringbuffer */ | ||
578 | |||
579 | delay_l[index] = low_left; | ||
580 | delay_r[index] = low_right; | ||
581 | |||
582 | index = (index + 1) % 13; | ||
583 | } | 580 | } |
584 | 581 | crossfeed_data.index = di; | |
585 | crossfeed_data.index = index; | ||
586 | crossfeed_data.lowpass[0] = low_left; | ||
587 | crossfeed_data.lowpass[1] = low_right; | ||
588 | crossfeed_data.highpass[0] = high_left; | ||
589 | crossfeed_data.highpass[1] = high_right; | ||
590 | } | 582 | } |
591 | #endif | 583 | #endif |
592 | 584 | ||
@@ -633,13 +625,8 @@ void dsp_set_eq_coefs(int band) | |||
633 | if (q == 0) | 625 | if (q == 0) |
634 | q = 1; | 626 | q = 1; |
635 | 627 | ||
636 | /* The coef functions assume the EMAC unit is in fractional mode */ | 628 | /* NOTE: The coef functions assume the EMAC unit is in fractional mode, |
637 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) | 629 | which it should be, since we're executed from the main thread. */ |
638 | /* set emac unit for dsp processing, and save old macsr, we're running in | ||
639 | codec thread context at this point, so can't clobber it */ | ||
640 | unsigned long old_macsr = coldfire_get_macsr(); | ||
641 | coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE | EMAC_ROUND); | ||
642 | #endif | ||
643 | 630 | ||
644 | /* Assume a band is disabled if the gain is zero */ | 631 | /* Assume a band is disabled if the gain is zero */ |
645 | if (gain == 0) { | 632 | if (gain == 0) { |
@@ -654,11 +641,6 @@ void dsp_set_eq_coefs(int band) | |||
654 | 641 | ||
655 | eq_data.enabled[band] = 1; | 642 | eq_data.enabled[band] = 1; |
656 | } | 643 | } |
657 | |||
658 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) | ||
659 | /* set old macsr again */ | ||
660 | coldfire_set_macsr(old_macsr); | ||
661 | #endif | ||
662 | } | 644 | } |
663 | 645 | ||
664 | /* Apply EQ filters to those bands that have got it switched on. */ | 646 | /* Apply EQ filters to those bands that have got it switched on. */ |
@@ -1068,13 +1050,6 @@ bool dsp_configure(int setting, void *value) | |||
1068 | return 1; | 1050 | return 1; |
1069 | } | 1051 | } |
1070 | 1052 | ||
1071 | void dsp_set_crossfeed(bool enable) | ||
1072 | { | ||
1073 | if (enable) | ||
1074 | memset(&crossfeed_data, 0, sizeof(crossfeed_data)); | ||
1075 | dsp->crossfeed_enabled = enable; | ||
1076 | } | ||
1077 | |||
1078 | void dsp_set_replaygain(bool always) | 1053 | void dsp_set_replaygain(bool always) |
1079 | { | 1054 | { |
1080 | dsp = &dsp_conf[current_codec]; | 1055 | dsp = &dsp_conf[current_codec]; |
diff --git a/apps/dsp.h b/apps/dsp.h index 368326d7f2..501e238a54 100644 --- a/apps/dsp.h +++ b/apps/dsp.h | |||
@@ -54,6 +54,8 @@ int dsp_stereo_mode(void); | |||
54 | bool dsp_configure(int setting, void *value); | 54 | bool dsp_configure(int setting, void *value); |
55 | void dsp_set_replaygain(bool always); | 55 | void dsp_set_replaygain(bool always); |
56 | void dsp_set_crossfeed(bool enable); | 56 | void dsp_set_crossfeed(bool enable); |
57 | void dsp_set_crossfeed_direct_gain(int gain); | ||
58 | void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff); | ||
57 | void dsp_set_eq(bool enable); | 59 | void dsp_set_eq(bool enable); |
58 | void dsp_set_eq_precut(int precut); | 60 | void dsp_set_eq_precut(int precut); |
59 | void dsp_set_eq_coefs(int band); | 61 | void dsp_set_eq_coefs(int band); |
diff --git a/apps/dsp_cf.S b/apps/dsp_cf.S index 6147ebeea7..719d1db1d5 100644 --- a/apps/dsp_cf.S +++ b/apps/dsp_cf.S | |||
@@ -17,15 +17,6 @@ | |||
17 | * | 17 | * |
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | 19 | ||
20 | .section .idata,"aw",@progbits | ||
21 | crossfeed_coefs: | ||
22 | .long 0x4CCCCCCD | LOW | ||
23 | .long 0x33333333 | LOW_COMP | ||
24 | .long -0x66666666 | HIGH_NEG | ||
25 | .long 0x66666666 | HIGH_COMP | ||
26 | .long 0x0CCCCCCD | ATT | ||
27 | .long 0x73333333 | ATT_COMP | ||
28 | |||
29 | .section .text | 20 | .section .text |
30 | .global apply_crossfeed | 21 | .global apply_crossfeed |
31 | apply_crossfeed: | 22 | apply_crossfeed: |
@@ -36,68 +27,57 @@ apply_crossfeed: | |||
36 | move.l (44+8, %sp), %d7 | d7 = count | 27 | move.l (44+8, %sp), %d7 | d7 = count |
37 | 28 | ||
38 | lea.l crossfeed_data, %a1 | 29 | lea.l crossfeed_data, %a1 |
39 | lea.l crossfeed_coefs, %a6 | 30 | lea.l (8*4, %a1), %a0 | a0 = &delay[0][0] |
40 | lea.l (16, %a1), %a0 | a0 = &delay[0][0] | 31 | move.l (%a1)+, %a6 | a6 = direct gain |
41 | movem.l (%a1), %d0-%d3 | fetch filter history samples | 32 | movem.l (3*4, %a1), %d0-%d3 | fetch filter history samples |
42 | move.l (120, %a1), %d4 | fetch delay line index | 33 | move.l (33*4, %a1), %d4 | fetch delay line index |
43 | move.l (%a4), %d5 | d5 = left sample | 34 | movem.l (%a1), %a1-%a3 | load filter coefs |
44 | move.l (%a5), %d6 | d6 = right sample | 35 | move.l %d4, %d5 |
45 | move.l (%a6)+, %a1 | a1 = LOW value | 36 | lsl.l #3, %d5 |
46 | move.l (%a6)+, %a2 | a2 = LOW_COMP value | 37 | add.l %d5, %a0 | point a0 to current delay position |
38 | | lea.l (%d4*4, %a0), %a0 | ||
39 | | lea.l (%d4*4, %a0), %a0 | point a0 to current delay position | ||
47 | /* Register usage in loop: | 40 | /* Register usage in loop: |
48 | * a0 = &delay[0][0], a1 & a2 = coefs, a3 = temp storage, | 41 | * a0 = &delay[index][0], a1..a3 = b0, b1, a1 (filter coefs), |
49 | * a4 = src[0], a5 = src[1], a6 = &crossfeed_coefs[0], | 42 | * a4 = src[0], a5 = src[1], a6 = direct gain, |
50 | * d0 = low_left, d1 = low_right, | 43 | * d0..d3 = history |
51 | * d2 = high_left, d3 = high_right, | ||
52 | * d4 = delay line index, | 44 | * d4 = delay line index, |
53 | * d5 = src[0][i], d6 = src[1][i]. | 45 | * d5,d6 = temp. |
54 | * d7 = count | 46 | * d7 = count |
55 | */ | 47 | */ |
56 | .cfloop: | 48 | .cfloop: |
57 | | LOW*low_left + LOW_COMP*left | 49 | mac.l %a2, %d0, (4, %a0), %d0, %acc0 | acc = b1*dr[n - 1] d0 = dr[n] |
58 | mac.l %a1, %d0, %acc0 | 50 | mac.l %a1, %d0, %acc0 | acc += b0*dr[n] |
59 | mac.l %a2, %d5, %acc0 | 51 | mac.l %a3, %d1, (%a4), %d5, %acc0 | acc += a1*y_l[n - 1], load left input |
60 | | LOW*low_right + LOW_COMP*right | 52 | move.l %acc0, %d1 | get filtered delayed sample |
61 | mac.l %a1, %d1, (%a6)+, %a1, %acc1 | a1 = HIGH_NEG | 53 | mac.l %a6, %d5, %acc0 | acc += gain*x_l[n] |
62 | mac.l %a2, %d6, (%a6)+, %a2, %acc1 | a2 = HIGH_COMP | 54 | movclr.l %acc0, %d6 |
63 | movclr.l %acc0, %d0 | get low_left | 55 | move.l %d6, (%a4)+ | write result |
64 | movclr.l %acc1, %d1 | get low_right | 56 | |
65 | | HIGH_NEG*high_left + HIGH_COMP*left | 57 | mac.l %a2, %d2, (%a0), %d2, %acc0 | acc = b1*dl[n - 1], d2 = dl[n] |
66 | mac.l %a1, %d2, %acc0 | 58 | move.l %d5, (%a0)+ | save left input to delay line |
67 | mac.l %a2, %d5, %acc0 | 59 | mac.l %a1, %d2, %acc0 | acc += b0*dl[n] |
68 | | HIGH_NEG*high_right + HIGH_COMP*right | 60 | mac.l %a3, %d3, (%a5), %d5, %acc0 | acc += a1*y_r[n - 1], load right input |
69 | mac.l %a1, %d3, (%a6)+, %a1, %acc1 | a1 = ATT | 61 | move.l %acc0, %d3 | get filtered delayed sample |
70 | mac.l %a2, %d6, (%a6)+, %a2, %acc1 | a2 = ATT_COMP | 62 | mac.l %a6, %d5, %acc0 | acc += gain*x_r[n] |
71 | lea.l (-6*4, %a6), %a6 | coef = &coefs[0] | 63 | move.l %d5, (%a0)+ | save right input to delay line |
72 | move.l (%a0, %d4*4), %a3 | a3 = delay[0][idx] | 64 | movclr.l %acc0, %d6 |
73 | move.l (52, %a0, %d4*4), %d5 | d5 = delay[1][idx] | 65 | move.l %d6, (%a5)+ | write result |
74 | movclr.l %acc0, %d2 | get high_left | 66 | |
75 | movclr.l %acc1, %d3 | get high_right | 67 | addq.l #1, %d4 | index++ |
76 | | ATT*delay_r + ATT_COMP*high_left | 68 | moveq.l #13, %d6 |
77 | mac.l %a1, %d5, (4, %a4), %d5, %acc0 | d5 = src[0][i+1] | 69 | cmp.l %d6, %d4 | wrap index to 0 if it overflows |
78 | mac.l %a2, %d2, (4, %a5), %d6, %acc0 | d6 = src[1][i+1] | ||
79 | | ATT*delay_l + ATT_COMP*high_right | ||
80 | mac.l %a1, %a3, (%a6)+, %a1, %acc1 | a1 = LOW | ||
81 | mac.l %a2, %d3, (%a6)+, %a2, %acc1 | a2 = LOW_COMP | ||
82 | |||
83 | | save crossfed samples to output | ||
84 | movclr.l %acc0, %a3 | ||
85 | move.l %a3, (%a4)+ | src[0][i++] = out_l | ||
86 | movclr.l %acc1, %a3 | ||
87 | move.l %a3, (%a5)+ | src[1][i++] = out_r | ||
88 | move.l %d0, (%a0, %d4*4) | delay[0][index] = low_left | ||
89 | move.l %d1, (52, %a0, %d4*4) | delay[1][index] = low_right */ | ||
90 | addq.l #1, %d4 | index++ */ | ||
91 | cmp.l #13, %d4 | if (index >= 13) { | ||
92 | jlt .nowrap | 70 | jlt .nowrap |
93 | clr.l %d4 | index = 0 | 71 | moveq.l #13*8, %d4 |
94 | .nowrap: | } | 72 | sub.l %d4, %a0 | wrap back delay line ptr as well |
73 | clr.l %d4 | ||
74 | .nowrap: | ||
95 | subq.l #1, %d7 | 75 | subq.l #1, %d7 |
96 | jne .cfloop | 76 | jne .cfloop |
97 | | save data back to struct | 77 | | save data back to struct |
98 | lea.l crossfeed_data, %a1 | 78 | lea.l crossfeed_data + 4*4, %a1 |
99 | movem.l %d0-%d3, (%a1) | 79 | movem.l %d0-%d3, (%a1) |
100 | move.l %d4, (120, %a1) | 80 | move.l %d4, (30*4, %a1) |
101 | movem.l (%sp), %d2-%d7/%a2-%a6 | 81 | movem.l (%sp), %d2-%d7/%a2-%a6 |
102 | lea.l (44, %sp), %sp | 82 | lea.l (44, %sp), %sp |
103 | rts | 83 | rts |
@@ -187,6 +187,34 @@ static long dbtoA(long db) | |||
187 | return (dbtoatab[pos] << 16) + frac*diff; | 187 | return (dbtoatab[pos] << 16) + frac*diff; |
188 | } | 188 | } |
189 | 189 | ||
190 | /* Calculate first order shelving filter coefficients. | ||
191 | cutoff is a value from 0 to 0x80000000, where 0 represents 0 hz and | ||
192 | 0x80000000 represents nyquist (samplerate/2). | ||
193 | ad is gain at 0 hz, and an is gain at Nyquist frequency. Both are s3.27 | ||
194 | format. | ||
195 | c is a pointer where the coefs will be stored. The coefs are s0.31 format. | ||
196 | Note that the filter is not compatible with the eq_filter routine. | ||
197 | */ | ||
198 | void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) | ||
199 | { | ||
200 | const long one = 1 << 27; | ||
201 | long a0, a1; | ||
202 | long b0, b1; | ||
203 | long s, cs; | ||
204 | s = fsincos(cutoff, &cs) >> 4; | ||
205 | cs = one + (cs >> 4); | ||
206 | |||
207 | /* For max A = 4 (24 dB) */ | ||
208 | b0 = (FRACMUL(an, cs) << 4) + (FRACMUL(ad, s) << 4); | ||
209 | b1 = (FRACMUL(ad, s) << 4) - (FRACMUL(an, cs) << 4); | ||
210 | a0 = s + cs; | ||
211 | a1 = s - cs; | ||
212 | |||
213 | c[0] = DIV64(b0, a0, 31); | ||
214 | c[1] = DIV64(b1, a0, 31); | ||
215 | c[2] = -DIV64(a1, a0, 31); | ||
216 | } | ||
217 | |||
190 | /* Calculate second order section peaking filter coefficients. | 218 | /* Calculate second order section peaking filter coefficients. |
191 | cutoff is a value from 0 to 0x80000000, where 0 represents 0 hz and | 219 | cutoff is a value from 0 to 0x80000000, where 0 represents 0 hz and |
192 | 0x80000000 represents nyquist (samplerate/2). | 220 | 0x80000000 represents nyquist (samplerate/2). |
@@ -33,6 +33,7 @@ struct eqfilter { | |||
33 | int32_t history[2][4]; | 33 | int32_t history[2][4]; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c); | ||
36 | void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); | 37 | void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); |
37 | void eq_ls_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); | 38 | void eq_ls_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); |
38 | void eq_hs_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); | 39 | void eq_hs_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); |
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 0a70910457..a388884d69 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -8408,3 +8408,69 @@ | |||
8408 | *: "pixels" | 8408 | *: "pixels" |
8409 | </voice> | 8409 | </voice> |
8410 | </phrase> | 8410 | </phrase> |
8411 | <phrase> | ||
8412 | id: LANG_CROSSFEED_DIRECT_GAIN | ||
8413 | desc: in crossfeed settings | ||
8414 | user: | ||
8415 | <source> | ||
8416 | *: "Direct Gain" | ||
8417 | </source> | ||
8418 | <dest> | ||
8419 | *: "Direct Gain" | ||
8420 | </dest> | ||
8421 | <voice> | ||
8422 | *: "Direct gain" | ||
8423 | </voice> | ||
8424 | </phrase> | ||
8425 | <phrase> | ||
8426 | id: LANG_CROSSFEED_CROSS_GAIN | ||
8427 | desc: in crossfeed settings | ||
8428 | <source> | ||
8429 | *: "Cross Gain" | ||
8430 | </source> | ||
8431 | <dest> | ||
8432 | *: "Cross Gain" | ||
8433 | </dest> | ||
8434 | <voice> | ||
8435 | *: "Cross gain" | ||
8436 | </voice> | ||
8437 | </phrase> | ||
8438 | <phrase> | ||
8439 | id: LANG_CROSSFEED_HF_ATTENUATION | ||
8440 | desc: in crossfeed settings | ||
8441 | <source> | ||
8442 | *: "High-Frequency Attenuation" | ||
8443 | </source> | ||
8444 | <dest> | ||
8445 | *: "High-Frequency Attenuation" | ||
8446 | </dest> | ||
8447 | <voice> | ||
8448 | *: "High-frequency attenuation" | ||
8449 | </voice> | ||
8450 | </phrase> | ||
8451 | <phrase> | ||
8452 | id: LANG_CROSSFEED_HF_CUTOFF | ||
8453 | desc: in crossfeed settings | ||
8454 | <source> | ||
8455 | *: "High-Frequency Cutoff" | ||
8456 | </source> | ||
8457 | <dest> | ||
8458 | *: "High-Frequency Cutoff" | ||
8459 | </dest> | ||
8460 | <voice> | ||
8461 | *: "High-frequency cutoff" | ||
8462 | </voice> | ||
8463 | </phrase> | ||
8464 | <phrase> | ||
8465 | id: LANG_UNIT_HERTZ | ||
8466 | desc: in sound settings | ||
8467 | <source> | ||
8468 | *: "Hz" | ||
8469 | </source> | ||
8470 | <dest> | ||
8471 | *: "Hz" | ||
8472 | </dest> | ||
8473 | <voice> | ||
8474 | *: "" | ||
8475 | </voice> | ||
8476 | </phrase> | ||
diff --git a/apps/settings.c b/apps/settings.c index cbd39335f1..1316969726 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -94,7 +94,7 @@ const char rec_base_directory[] = REC_BASE_DIR; | |||
94 | #include "dsp.h" | 94 | #include "dsp.h" |
95 | #endif | 95 | #endif |
96 | 96 | ||
97 | #define CONFIG_BLOCK_VERSION 39 | 97 | #define CONFIG_BLOCK_VERSION 40 |
98 | #define CONFIG_BLOCK_SIZE 512 | 98 | #define CONFIG_BLOCK_SIZE 512 |
99 | #define RTC_BLOCK_SIZE 44 | 99 | #define RTC_BLOCK_SIZE 44 |
100 | 100 | ||
@@ -488,6 +488,10 @@ static const struct bit_entry hd_bits[] = | |||
488 | {4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL}, | 488 | {4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL}, |
489 | {1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"}, | 489 | {1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"}, |
490 | {1, S_O(crossfeed), false, "crossfeed", off_on }, | 490 | {1, S_O(crossfeed), false, "crossfeed", off_on }, |
491 | {6, S_O(crossfeed_direct_gain), 15, "crossfeed direct gain", NULL }, | ||
492 | {7, S_O(crossfeed_cross_gain), 60, "crossfeed cross gain", NULL }, | ||
493 | {8, S_O(crossfeed_hf_attenuation), 160, "crossfeed hf attenuation", NULL }, | ||
494 | {11, S_O(crossfeed_hf_cutoff), 700, "crossfeed hf cutoff", NULL }, | ||
491 | #endif | 495 | #endif |
492 | #ifdef HAVE_DIRCACHE | 496 | #ifdef HAVE_DIRCACHE |
493 | {1, S_O(dircache), false, "dircache", off_on }, | 497 | {1, S_O(dircache), false, "dircache", off_on }, |
@@ -538,6 +542,7 @@ static const struct bit_entry hd_bits[] = | |||
538 | "warn when erasing dynamic playlist", off_on }, | 542 | "warn when erasing dynamic playlist", off_on }, |
539 | #if CONFIG_CODEC == SWCODEC | 543 | #if CONFIG_CODEC == SWCODEC |
540 | {1, S_O(eq_enabled), false, "eq enabled", off_on }, | 544 | {1, S_O(eq_enabled), false, "eq enabled", off_on }, |
545 | {8, S_O(eq_precut), 0, "eq precut", NULL }, | ||
541 | /* 0..32768 Hz */ | 546 | /* 0..32768 Hz */ |
542 | {15, S_O(eq_band0_cutoff), 60, "eq band 0 cutoff", NULL }, | 547 | {15, S_O(eq_band0_cutoff), 60, "eq band 0 cutoff", NULL }, |
543 | {15, S_O(eq_band1_cutoff), 200, "eq band 1 cutoff", NULL }, | 548 | {15, S_O(eq_band1_cutoff), 200, "eq band 1 cutoff", NULL }, |
@@ -579,10 +584,6 @@ static const struct bit_entry hd_bits[] = | |||
579 | {1, S_O(tagcache_ram), 0, "tagcache_ram", off_on }, | 584 | {1, S_O(tagcache_ram), 0, "tagcache_ram", off_on }, |
580 | #endif | 585 | #endif |
581 | 586 | ||
582 | #if (CONFIG_CODEC == SWCODEC) | ||
583 | {8, S_O(eq_precut), 0, "eq precut", NULL }, | ||
584 | #endif | ||
585 | |||
586 | /* If values are just added to the end, no need to bump the version. */ | 587 | /* If values are just added to the end, no need to bump the version. */ |
587 | /* new stuff to be added at the end */ | 588 | /* new stuff to be added at the end */ |
588 | 589 | ||
@@ -1159,6 +1160,11 @@ void settings_apply(void) | |||
1159 | audio_set_crossfade(global_settings.crossfade); | 1160 | audio_set_crossfade(global_settings.crossfade); |
1160 | dsp_set_replaygain(true); | 1161 | dsp_set_replaygain(true); |
1161 | dsp_set_crossfeed(global_settings.crossfeed); | 1162 | dsp_set_crossfeed(global_settings.crossfeed); |
1163 | dsp_set_crossfeed_direct_gain(global_settings.crossfeed_direct_gain); | ||
1164 | dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain, | ||
1165 | global_settings.crossfeed_cross_gain | ||
1166 | + global_settings.crossfeed_hf_attenuation, | ||
1167 | global_settings.crossfeed_hf_cutoff); | ||
1162 | 1168 | ||
1163 | dsp_set_eq(global_settings.eq_enabled); | 1169 | dsp_set_eq(global_settings.eq_enabled); |
1164 | dsp_set_eq_precut(global_settings.eq_precut); | 1170 | dsp_set_eq_precut(global_settings.eq_precut); |
diff --git a/apps/settings.h b/apps/settings.h index 1266fed1c4..8a657999e2 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -417,7 +417,13 @@ struct user_settings | |||
417 | shuffle is on, album gain otherwise */ | 417 | shuffle is on, album gain otherwise */ |
418 | int replaygain_preamp; /* scale replaygained tracks by this */ | 418 | int replaygain_preamp; /* scale replaygained tracks by this */ |
419 | int beep; /* system beep volume when changing tracks etc. */ | 419 | int beep; /* system beep volume when changing tracks etc. */ |
420 | bool crossfeed; /* enable crossfeed */ | 420 | |
421 | /* Crossfeed settings */ | ||
422 | bool crossfeed; /* enable crossfeed */ | ||
423 | unsigned int crossfeed_direct_gain; /* - dB x 10 */ | ||
424 | unsigned int crossfeed_cross_gain; /* - dB x 10 */ | ||
425 | unsigned int crossfeed_hf_attenuation; /* - dB x 10 */ | ||
426 | unsigned int crossfeed_hf_cutoff; /* Frequency in Hz */ | ||
421 | #endif | 427 | #endif |
422 | #ifdef HAVE_DIRCACHE | 428 | #ifdef HAVE_DIRCACHE |
423 | bool dircache; /* enable directory cache */ | 429 | bool dircache; /* enable directory cache */ |
diff --git a/apps/sound_menu.c b/apps/sound_menu.c index 2e45f76621..1d389f30de 100644 --- a/apps/sound_menu.c +++ b/apps/sound_menu.c | |||
@@ -125,7 +125,14 @@ static bool treble(void) | |||
125 | #endif | 125 | #endif |
126 | 126 | ||
127 | #if CONFIG_CODEC == SWCODEC | 127 | #if CONFIG_CODEC == SWCODEC |
128 | static bool crossfeed(void) | 128 | static void crossfeed_format(char* buffer, int buffer_size, int value, |
129 | const char* unit) | ||
130 | { | ||
131 | snprintf(buffer, buffer_size, "%s%d.%d %s", value == 0 ? " " : "-", | ||
132 | value / 10, value % 10, unit); | ||
133 | } | ||
134 | |||
135 | static bool crossfeed_enabled(void) | ||
129 | { | 136 | { |
130 | bool result = set_bool_options(str(LANG_CROSSFEED), | 137 | bool result = set_bool_options(str(LANG_CROSSFEED), |
131 | &global_settings.crossfeed, | 138 | &global_settings.crossfeed, |
@@ -134,6 +141,75 @@ static bool crossfeed(void) | |||
134 | NULL); | 141 | NULL); |
135 | 142 | ||
136 | dsp_set_crossfeed(global_settings.crossfeed); | 143 | dsp_set_crossfeed(global_settings.crossfeed); |
144 | |||
145 | return result; | ||
146 | } | ||
147 | |||
148 | static bool crossfeed_direct_gain(void) | ||
149 | { | ||
150 | return set_int(str(LANG_CROSSFEED_DIRECT_GAIN), str(LANG_UNIT_DB), | ||
151 | UNIT_DB, &global_settings.crossfeed_direct_gain, | ||
152 | &dsp_set_crossfeed_direct_gain, 5, 0, 60, crossfeed_format); | ||
153 | } | ||
154 | |||
155 | static void crossfeed_cross_gain_helper(int val) | ||
156 | { | ||
157 | dsp_set_crossfeed_cross_params(val, | ||
158 | val + global_settings.crossfeed_hf_attenuation, | ||
159 | global_settings.crossfeed_hf_cutoff); | ||
160 | } | ||
161 | |||
162 | static bool crossfeed_cross_gain(void) | ||
163 | { | ||
164 | return set_int(str(LANG_CROSSFEED_CROSS_GAIN), str(LANG_UNIT_DB), | ||
165 | UNIT_DB, &global_settings.crossfeed_cross_gain, | ||
166 | &crossfeed_cross_gain_helper, 5, 30, 120, crossfeed_format); | ||
167 | } | ||
168 | |||
169 | static void crossfeed_hf_att_helper(int val) | ||
170 | { | ||
171 | dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain, | ||
172 | global_settings.crossfeed_cross_gain + val, | ||
173 | global_settings.crossfeed_hf_cutoff); | ||
174 | } | ||
175 | |||
176 | static bool crossfeed_hf_attenuation(void) | ||
177 | { | ||
178 | return set_int(str(LANG_CROSSFEED_HF_ATTENUATION), str(LANG_UNIT_DB), | ||
179 | UNIT_DB, &global_settings.crossfeed_hf_attenuation, | ||
180 | &crossfeed_hf_att_helper, 5, 60, 240, crossfeed_format); | ||
181 | } | ||
182 | |||
183 | static void crossfeed_hf_cutoff_helper(int val) | ||
184 | { | ||
185 | dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain, | ||
186 | global_settings.crossfeed_cross_gain + global_settings.crossfeed_hf_attenuation, val); | ||
187 | } | ||
188 | |||
189 | static bool crossfeed_hf_cutoff(void) | ||
190 | { | ||
191 | return set_int(str(LANG_CROSSFEED_HF_CUTOFF), str(LANG_UNIT_HERTZ), | ||
192 | UNIT_HERTZ, &global_settings.crossfeed_hf_cutoff, &crossfeed_hf_cutoff_helper, 100, 500, 2000, | ||
193 | NULL); | ||
194 | } | ||
195 | |||
196 | static bool crossfeed_menu(void) | ||
197 | { | ||
198 | int m; | ||
199 | bool result; | ||
200 | static const struct menu_item items[] = { | ||
201 | { ID2P(LANG_CROSSFEED), crossfeed_enabled }, | ||
202 | { ID2P(LANG_CROSSFEED_DIRECT_GAIN), crossfeed_direct_gain }, | ||
203 | { ID2P(LANG_CROSSFEED_CROSS_GAIN), crossfeed_cross_gain }, | ||
204 | { ID2P(LANG_CROSSFEED_HF_ATTENUATION), crossfeed_hf_attenuation }, | ||
205 | { ID2P(LANG_CROSSFEED_HF_CUTOFF), crossfeed_hf_cutoff }, | ||
206 | }; | ||
207 | |||
208 | m=menu_init(items, sizeof(items) / sizeof(*items), NULL, | ||
209 | NULL, NULL, NULL); | ||
210 | result = menu_run(m); | ||
211 | menu_exit(m); | ||
212 | |||
137 | return result; | 213 | return result; |
138 | } | 214 | } |
139 | #endif | 215 | #endif |
@@ -414,7 +490,7 @@ bool sound_menu(void) | |||
414 | { ID2P(LANG_CHANNEL_MENU), chanconf }, | 490 | { ID2P(LANG_CHANNEL_MENU), chanconf }, |
415 | { ID2P(LANG_STEREO_WIDTH), stereo_width }, | 491 | { ID2P(LANG_STEREO_WIDTH), stereo_width }, |
416 | #if CONFIG_CODEC == SWCODEC | 492 | #if CONFIG_CODEC == SWCODEC |
417 | { ID2P(LANG_CROSSFEED), crossfeed }, | 493 | { ID2P(LANG_CROSSFEED), crossfeed_menu }, |
418 | { ID2P(LANG_EQUALIZER), eq_menu }, | 494 | { ID2P(LANG_EQUALIZER), eq_menu }, |
419 | #endif | 495 | #endif |
420 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | 496 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) |
diff --git a/firmware/system.c b/firmware/system.c index 7eaefb1d77..8bdd821e60 100644 --- a/firmware/system.c +++ b/firmware/system.c | |||
@@ -516,6 +516,10 @@ void system_init(void) | |||
516 | "movclr.l %%acc2, %%d0\n\t" | 516 | "movclr.l %%acc2, %%d0\n\t" |
517 | "movclr.l %%acc3, %%d0\n\t" | 517 | "movclr.l %%acc3, %%d0\n\t" |
518 | : : : "d0"); | 518 | : : : "d0"); |
519 | /* Set EMAC unit to saturating and rounding fractional mode, since that's | ||
520 | what'll be the most useful for most things which the main thread | ||
521 | will do. */ | ||
522 | coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE | EMAC_ROUND); | ||
519 | } | 523 | } |
520 | 524 | ||
521 | void system_reboot (void) | 525 | void system_reboot (void) |