diff options
-rw-r--r-- | apps/dsp.c | 71 | ||||
-rw-r--r-- | apps/dsp.h | 7 | ||||
-rw-r--r-- | apps/eq.c | 60 | ||||
-rw-r--r-- | apps/eq.h | 7 | ||||
-rw-r--r-- | apps/menus/sound_menu.c | 10 | ||||
-rw-r--r-- | apps/settings.c | 7 | ||||
-rw-r--r-- | firmware/export/config-iaudiox5.h | 3 | ||||
-rw-r--r-- | firmware/export/sound.h | 2 | ||||
-rw-r--r-- | firmware/sound.c | 53 |
9 files changed, 175 insertions, 45 deletions
diff --git a/apps/dsp.c b/apps/dsp.c index 0ffaaea8d8..f306069a87 100644 --- a/apps/dsp.c +++ b/apps/dsp.c | |||
@@ -116,9 +116,10 @@ struct crossfeed_data | |||
116 | /* 8ch */ | 116 | /* 8ch */ |
117 | }; | 117 | }; |
118 | 118 | ||
119 | /* Current setup is one lowshelf filters, three peaking filters and one | 119 | /* Current setup is one lowshelf filters three peaking filters and one |
120 | highshelf filter. Varying the number of shelving filters make no sense, | 120 | * highshelf filter. Varying the number of shelving filters make no sense, |
121 | but adding peaking filters is possible. */ | 121 | * but adding peaking filters is possible. |
122 | */ | ||
122 | struct eq_state | 123 | struct eq_state |
123 | { | 124 | { |
124 | char enabled[5]; /* 00h - Flags for active filters */ | 125 | char enabled[5]; /* 00h - Flags for active filters */ |
@@ -171,6 +172,13 @@ static long dither_bias IBSS_ATTR; | |||
171 | struct crossfeed_data crossfeed_data IBSS_ATTR; /* A */ | 172 | struct crossfeed_data crossfeed_data IBSS_ATTR; /* A */ |
172 | /* Equalizer */ | 173 | /* Equalizer */ |
173 | static struct eq_state eq_data; /* A/V */ | 174 | static struct eq_state eq_data; /* A/V */ |
175 | #ifdef HAVE_SW_TONE_CONTROLS | ||
176 | static int prescale; | ||
177 | static int bass; | ||
178 | static int treble; | ||
179 | /* Filter struct for software bass/treble controls */ | ||
180 | static struct eqfilter tone_filter; | ||
181 | #endif | ||
174 | 182 | ||
175 | /* Settings applicable to audio codec only */ | 183 | /* Settings applicable to audio codec only */ |
176 | static int pitch_ratio = 1000; | 184 | static int pitch_ratio = 1000; |
@@ -704,11 +712,7 @@ void dsp_set_crossfeed(bool enable) | |||
704 | 712 | ||
705 | void dsp_set_crossfeed_direct_gain(int gain) | 713 | void dsp_set_crossfeed_direct_gain(int gain) |
706 | { | 714 | { |
707 | /* Work around bug in get_replaygain_int which returns 0 for 0 dB */ | 715 | crossfeed_data.gain = get_replaygain_int(gain * -10) << 7; |
708 | if (gain == 0) | ||
709 | crossfeed_data.gain = 0x7fffffff; | ||
710 | else | ||
711 | crossfeed_data.gain = get_replaygain_int(gain * -10) << 7; | ||
712 | } | 716 | } |
713 | 717 | ||
714 | void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) | 718 | void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) |
@@ -716,8 +720,8 @@ void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) | |||
716 | long g1 = get_replaygain_int(lf_gain * -10) << 3; | 720 | long g1 = get_replaygain_int(lf_gain * -10) << 3; |
717 | long g2 = get_replaygain_int(hf_gain * -10) << 3; | 721 | long g2 = get_replaygain_int(hf_gain * -10) << 3; |
718 | 722 | ||
719 | filter_bishelf_coefs(0xffffffff/NATIVE_FREQUENCY*cutoff, g1, g2, | 723 | filter_shelf_coefs(0xffffffff/NATIVE_FREQUENCY*cutoff, g1, g2, |
720 | crossfeed_data.coefs); | 724 | crossfeed_data.coefs); |
721 | } | 725 | } |
722 | 726 | ||
723 | /* Applies crossfeed to the stereo signal in src. | 727 | /* Applies crossfeed to the stereo signal in src. |
@@ -985,6 +989,36 @@ static void channels_process_sound_chan_mono(int count, int32_t *buf[]) | |||
985 | } | 989 | } |
986 | #endif /* DSP_HAVE_ASM_SOUND_CHAN_MONO */ | 990 | #endif /* DSP_HAVE_ASM_SOUND_CHAN_MONO */ |
987 | 991 | ||
992 | #ifdef HAVE_SW_TONE_CONTROLS | ||
993 | static void set_tone_controls(void) | ||
994 | { | ||
995 | filter_bishelf_coefs(0xffffffff/NATIVE_FREQUENCY*200, | ||
996 | 0xffffffff/NATIVE_FREQUENCY*3500, | ||
997 | bass, treble, -prescale, tone_filter.coefs); | ||
998 | } | ||
999 | |||
1000 | int dsp_callback(int msg, intptr_t param) | ||
1001 | { | ||
1002 | switch (msg) { | ||
1003 | case DSP_CALLBACK_SET_PRESCALE: | ||
1004 | prescale = param; | ||
1005 | set_tone_controls(); | ||
1006 | break; | ||
1007 | /* prescaler is always set after calling any of these, so we wait with | ||
1008 | * calculating coefs until the above case is hit. | ||
1009 | */ | ||
1010 | case DSP_CALLBACK_SET_BASS: | ||
1011 | bass = param; | ||
1012 | break; | ||
1013 | case DSP_CALLBACK_SET_TREBLE: | ||
1014 | treble = param; | ||
1015 | default: | ||
1016 | break; | ||
1017 | } | ||
1018 | return 0; | ||
1019 | } | ||
1020 | #endif | ||
1021 | |||
988 | #ifndef DSP_HAVE_ASM_SOUND_CHAN_CUSTOM | 1022 | #ifndef DSP_HAVE_ASM_SOUND_CHAN_CUSTOM |
989 | static void channels_process_sound_chan_custom(int count, int32_t *buf[]) | 1023 | static void channels_process_sound_chan_custom(int count, int32_t *buf[]) |
990 | { | 1024 | { |
@@ -1068,12 +1102,12 @@ int dsp_process(char *dst, const char *src[], int count) | |||
1068 | int written = 0; | 1102 | int written = 0; |
1069 | int samples; | 1103 | int samples; |
1070 | 1104 | ||
1071 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) | 1105 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) |
1072 | /* set emac unit for dsp processing, and save old macsr, we're running in | 1106 | /* set emac unit for dsp processing, and save old macsr, we're running in |
1073 | codec thread context at this point, so can't clobber it */ | 1107 | codec thread context at this point, so can't clobber it */ |
1074 | unsigned long old_macsr = coldfire_get_macsr(); | 1108 | unsigned long old_macsr = coldfire_get_macsr(); |
1075 | coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE); | 1109 | coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE); |
1076 | #endif | 1110 | #endif |
1077 | 1111 | ||
1078 | while (count > 0) | 1112 | while (count > 0) |
1079 | { | 1113 | { |
@@ -1085,8 +1119,17 @@ int dsp_process(char *dst, const char *src[], int count) | |||
1085 | break; /* I'm pretty sure we're downsampling here */ | 1119 | break; /* I'm pretty sure we're downsampling here */ |
1086 | if (dsp->apply_crossfeed) | 1120 | if (dsp->apply_crossfeed) |
1087 | dsp->apply_crossfeed(tmp, samples); | 1121 | dsp->apply_crossfeed(tmp, samples); |
1122 | /* TODO: EQ and tone controls need separate structs for audio and voice | ||
1123 | * DSP processing thanks to filter history. isn't really audible now, but | ||
1124 | * might be the day we start handling voice more delicately. | ||
1125 | */ | ||
1088 | if (eq_enabled) | 1126 | if (eq_enabled) |
1089 | eq_process(samples, tmp); | 1127 | eq_process(samples, tmp); |
1128 | #ifdef HAVE_SW_TONE_CONTROLS | ||
1129 | if ((bass | treble) != 0) | ||
1130 | eq_filter(tmp, &tone_filter, samples, dsp->data.num_channels, | ||
1131 | FILTER_BISHELF_SHIFT); | ||
1132 | #endif | ||
1090 | if (dsp->channels_process) | 1133 | if (dsp->channels_process) |
1091 | dsp->channels_process(samples, tmp); | 1134 | dsp->channels_process(samples, tmp); |
1092 | dsp->output_samples(samples, &dsp->data, tmp, (int16_t *)dst); | 1135 | dsp->output_samples(samples, &dsp->data, tmp, (int16_t *)dst); |
@@ -1095,10 +1138,10 @@ int dsp_process(char *dst, const char *src[], int count) | |||
1095 | yield(); | 1138 | yield(); |
1096 | } | 1139 | } |
1097 | 1140 | ||
1098 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) | 1141 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) |
1099 | /* set old macsr again */ | 1142 | /* set old macsr again */ |
1100 | coldfire_set_macsr(old_macsr); | 1143 | coldfire_set_macsr(old_macsr); |
1101 | #endif | 1144 | #endif |
1102 | return written; | 1145 | return written; |
1103 | } | 1146 | } |
1104 | 1147 | ||
diff --git a/apps/dsp.h b/apps/dsp.h index 63dc68cbb4..03118e8c31 100644 --- a/apps/dsp.h +++ b/apps/dsp.h | |||
@@ -51,6 +51,12 @@ enum | |||
51 | DSP_CROSSFEED | 51 | DSP_CROSSFEED |
52 | }; | 52 | }; |
53 | 53 | ||
54 | enum { | ||
55 | DSP_CALLBACK_SET_PRESCALE = 0, | ||
56 | DSP_CALLBACK_SET_BASS, | ||
57 | DSP_CALLBACK_SET_TREBLE | ||
58 | }; | ||
59 | |||
54 | /* A bunch of fixed point assembler helper macros */ | 60 | /* A bunch of fixed point assembler helper macros */ |
55 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) | 61 | #if defined(CPU_COLDFIRE) && !defined(SIMULATOR) |
56 | /* These macros use the Coldfire EMAC extension and need the MACSR flags set | 62 | /* These macros use the Coldfire EMAC extension and need the MACSR flags set |
@@ -209,6 +215,7 @@ void dsp_set_eq_precut(int precut); | |||
209 | void dsp_set_eq_coefs(int band); | 215 | void dsp_set_eq_coefs(int band); |
210 | void sound_set_pitch(int r); | 216 | void sound_set_pitch(int r); |
211 | int sound_get_pitch(void); | 217 | int sound_get_pitch(void); |
218 | int dsp_callback(int msg, intptr_t param); | ||
212 | void channels_set(int value); | 219 | void channels_set(int value); |
213 | void stereo_width_set(int value); | 220 | void stereo_width_set(int value); |
214 | void dsp_dither_enable(bool enable); | 221 | void dsp_dither_enable(bool enable); |
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2006 Thom Johansen | 10 | * Copyright (C) 2006-2007 Thom Johansen |
11 | * | 11 | * |
12 | * All files in this archive are subject to the GNU General Public License. | 12 | * All files in this archive are subject to the GNU General Public License. |
13 | * See the file COPYING in the source tree root for full license agreement. | 13 | * See the file COPYING in the source tree root for full license agreement. |
@@ -127,7 +127,7 @@ static long fsincos(unsigned long phase, long *cos) { | |||
127 | * @param an gain at Nyquist frequency. s3.27 fixed point. | 127 | * @param an gain at Nyquist frequency. s3.27 fixed point. |
128 | * @param c pointer to coefficient storage. The coefs are s0.31 format. | 128 | * @param c pointer to coefficient storage. The coefs are s0.31 format. |
129 | */ | 129 | */ |
130 | void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) | 130 | void filter_shelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) |
131 | { | 131 | { |
132 | const long one = 1 << 27; | 132 | const long one = 1 << 27; |
133 | long a0, a1; | 133 | long a0, a1; |
@@ -137,7 +137,7 @@ void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) | |||
137 | cs = one + (cs >> 4); | 137 | cs = one + (cs >> 4); |
138 | 138 | ||
139 | /* For max A = 4 (24 dB) */ | 139 | /* For max A = 4 (24 dB) */ |
140 | b0 = FRACMUL_SHL(an, cs, 4) + FRACMUL_SHL(ad, s, 4); | 140 | b0 = FRACMUL_SHL(ad, s, 4) + FRACMUL_SHL(an, cs, 4); |
141 | b1 = FRACMUL_SHL(ad, s, 4) - FRACMUL_SHL(an, cs, 4); | 141 | b1 = FRACMUL_SHL(ad, s, 4) - FRACMUL_SHL(an, cs, 4); |
142 | a0 = s + cs; | 142 | a0 = s + cs; |
143 | a1 = s - cs; | 143 | a1 = s - cs; |
@@ -147,6 +147,58 @@ void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) | |||
147 | c[2] = -DIV64(a1, a0, 31); | 147 | c[2] = -DIV64(a1, a0, 31); |
148 | } | 148 | } |
149 | 149 | ||
150 | /** | ||
151 | * Calculate second order section filter consisting of one low-shelf and one | ||
152 | * high-shelf section. | ||
153 | * @param cutoff_low low-shelf midpoint frequency. See eq_pk_coefs for format. | ||
154 | * @param cutoff_high high-shelf midpoint frequency. | ||
155 | * @param A_low decibel value multiplied by ten, describing gain/attenuation of | ||
156 | * low-shelf part. Max value is 24 dB. | ||
157 | * @param A_high decibel value multiplied by ten, describing gain/attenuation of | ||
158 | * high-shelf part. Max value is 24 dB. | ||
159 | * @param A decibel value multiplied by ten, describing additional overall gain. | ||
160 | * @param c pointer to coefficient storage. Coefficients are s4.27 format. | ||
161 | */ | ||
162 | void filter_bishelf_coefs(unsigned long cutoff_low, unsigned long cutoff_high, | ||
163 | long A_low, long A_high, long A, int32_t *c) | ||
164 | { | ||
165 | long sin1, cos2; /* s0.31 */ | ||
166 | long cos1, sin2; /* s3.28 */ | ||
167 | int32_t b0, b1, b2, b3; /* s3.28 */ | ||
168 | int32_t a0, a1, a2, a3; | ||
169 | const long gd = get_replaygain_int(A_low*5) << 4; /* 10^(db/40), s3.28 */ | ||
170 | const long gn = get_replaygain_int(A_high*5) << 4; /* 10^(db/40), s3.28 */ | ||
171 | const long g = get_replaygain_int(A*10) << 7; /* 10^(db/20), s0.31 */ | ||
172 | |||
173 | sin1 = fsincos(cutoff_low/2, &cos1); | ||
174 | sin2 = fsincos(cutoff_high/2, &cos2) >> 3; | ||
175 | cos1 >>= 3; | ||
176 | |||
177 | /* lowshelf filter, ranges listed are for all possible cutoffs */ | ||
178 | b0 = FRACMUL(sin1, gd) + cos1; /* 0.25 .. 4.10 */ | ||
179 | b1 = FRACMUL(sin1, gd) - cos1; /* -1 .. 3.98 */ | ||
180 | a0 = DIV64(sin1, gd, 25) + cos1; /* 0.25 .. 4.10 */ | ||
181 | a1 = DIV64(sin1, gd, 25) - cos1; /* -1 .. 3.98 */ | ||
182 | |||
183 | /* highshelf filter */ | ||
184 | b2 = sin2 + FRACMUL(cos2, gn); /* 0.25 .. 4.10 */ | ||
185 | b3 = sin2 - FRACMUL(cos2, gn); /* -3.98 .. 1 */ | ||
186 | a2 = sin2 + DIV64(cos2, gn, 25); /* 0.25 .. 4.10 */ | ||
187 | a3 = sin2 - DIV64(cos2, gn, 25); /* -3.98 .. 1 */ | ||
188 | |||
189 | /* now we cascade the two first order filters to one second order filter | ||
190 | * which can be used by eq_filter(). these resulting coefficients have a | ||
191 | * really wide numerical range, so we use a fixed point format which will | ||
192 | * work for the selected cutoff frequencies (in dsp.c) only. | ||
193 | */ | ||
194 | const int32_t rcp_a0 = DIV64(1, FRACMUL(a0, a2), 53); /* s3.28 */ | ||
195 | *c++ = FRACMUL(g, FRACMUL_SHL(FRACMUL(b0, b2), rcp_a0, 5)); | ||
196 | *c++ = FRACMUL(g, FRACMUL_SHL(FRACMUL(b0, b3) + FRACMUL(b1, b2), rcp_a0, 5)); | ||
197 | *c++ = FRACMUL(g, FRACMUL_SHL(FRACMUL(b1, b3), rcp_a0, 5)); | ||
198 | *c++ = -FRACMUL_SHL(FRACMUL(a0, a3) + FRACMUL(a1, a2), rcp_a0, 5); | ||
199 | *c++ = -FRACMUL_SHL(FRACMUL(a1, a3), rcp_a0, 5); | ||
200 | } | ||
201 | |||
150 | /* Coef calculation taken from Audio-EQ-Cookbook.txt by Robert Bristow-Johnson. | 202 | /* Coef calculation taken from Audio-EQ-Cookbook.txt by Robert Bristow-Johnson. |
151 | * Slightly faster calculation can be done by deriving forms which use tan() | 203 | * Slightly faster calculation can be done by deriving forms which use tan() |
152 | * instead of cos() and sin(), but the latter are far easier to use when doing | 204 | * instead of cos() and sin(), but the latter are far easier to use when doing |
@@ -162,7 +214,7 @@ void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) | |||
162 | * @param Q Q factor value multiplied by ten. Lower bound is artificially set | 214 | * @param Q Q factor value multiplied by ten. Lower bound is artificially set |
163 | * at 0.5. | 215 | * at 0.5. |
164 | * @param db decibel value multiplied by ten, describing gain/attenuation at | 216 | * @param db decibel value multiplied by ten, describing gain/attenuation at |
165 | * peak freq. | 217 | * peak freq. Max value is 24 dB. |
166 | * @param c pointer to coefficient storage. Coefficients are s3.28 format. | 218 | * @param c pointer to coefficient storage. Coefficients are s3.28 format. |
167 | */ | 219 | */ |
168 | void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c) | 220 | void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c) |
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright (C) 2006 Thom Johansen | 10 | * Copyright (C) 2006-2007 Thom Johansen |
11 | * | 11 | * |
12 | * All files in this archive are subject to the GNU General Public License. | 12 | * All files in this archive are subject to the GNU General Public License. |
13 | * See the file COPYING in the source tree root for full license agreement. | 13 | * See the file COPYING in the source tree root for full license agreement. |
@@ -25,6 +25,7 @@ | |||
25 | /* These depend on the fixed point formats used by the different filter types | 25 | /* These depend on the fixed point formats used by the different filter types |
26 | and need to be changed when they change. | 26 | and need to be changed when they change. |
27 | */ | 27 | */ |
28 | #define FILTER_BISHELF_SHIFT 5 | ||
28 | #define EQ_PEAK_SHIFT 4 | 29 | #define EQ_PEAK_SHIFT 4 |
29 | #define EQ_SHELF_SHIFT 6 | 30 | #define EQ_SHELF_SHIFT 6 |
30 | 31 | ||
@@ -33,7 +34,9 @@ struct eqfilter { | |||
33 | int32_t history[2][4]; | 34 | int32_t history[2][4]; |
34 | }; | 35 | }; |
35 | 36 | ||
36 | void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c); | 37 | void filter_shelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c); |
38 | void filter_bishelf_coefs(unsigned long cutoff_low, unsigned long cutoff_high, | ||
39 | long A_low, long A_high, long A, int32_t *c); | ||
37 | void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); | 40 | void eq_pk_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); | 41 | void eq_ls_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); | 42 | void eq_hs_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); |
diff --git a/apps/menus/sound_menu.c b/apps/menus/sound_menu.c index 9dc9579b0e..287b3ec904 100644 --- a/apps/menus/sound_menu.c +++ b/apps/menus/sound_menu.c | |||
@@ -55,12 +55,8 @@ int soundmenu_callback(int action,const struct menu_item_ex *this_item) | |||
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | MENUITEM_SETTING(volume, &global_settings.volume, soundmenu_callback); | 57 | MENUITEM_SETTING(volume, &global_settings.volume, soundmenu_callback); |
58 | 58 | MENUITEM_SETTING(bass, &global_settings.bass, soundmenu_callback); | |
59 | #ifndef HAVE_TLV320 | 59 | MENUITEM_SETTING(treble, &global_settings.treble, soundmenu_callback); |
60 | MENUITEM_SETTING(bass, &global_settings.bass, soundmenu_callback); | ||
61 | MENUITEM_SETTING(treble, &global_settings.treble, soundmenu_callback); | ||
62 | #endif | ||
63 | |||
64 | MENUITEM_SETTING(balance, &global_settings.balance, soundmenu_callback); | 60 | MENUITEM_SETTING(balance, &global_settings.balance, soundmenu_callback); |
65 | MENUITEM_SETTING(channel_config, &global_settings.channel_config, soundmenu_callback); | 61 | MENUITEM_SETTING(channel_config, &global_settings.channel_config, soundmenu_callback); |
66 | MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, soundmenu_callback); | 62 | MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, soundmenu_callback); |
@@ -99,9 +95,7 @@ MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, soundmenu_callback | |||
99 | 95 | ||
100 | MAKE_MENU(sound_settings, ID2P(LANG_SOUND_SETTINGS), NULL, bitmap_icons_6x8[Icon_Audio], | 96 | MAKE_MENU(sound_settings, ID2P(LANG_SOUND_SETTINGS), NULL, bitmap_icons_6x8[Icon_Audio], |
101 | &volume, | 97 | &volume, |
102 | #ifndef HAVE_TLV320 | ||
103 | &bass,&treble, | 98 | &bass,&treble, |
104 | #endif | ||
105 | &balance,&channel_config,&stereo_width | 99 | &balance,&channel_config,&stereo_width |
106 | #if CONFIG_CODEC == SWCODEC | 100 | #if CONFIG_CODEC == SWCODEC |
107 | ,&crossfeed_menu, &equalizer_menu, &dithering_enabled | 101 | ,&crossfeed_menu, &equalizer_menu, &dithering_enabled |
diff --git a/apps/settings.c b/apps/settings.c index dd5e7c5ae3..cc5ab12d6f 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -642,6 +642,9 @@ void settings_apply_pm_range(void) | |||
642 | 642 | ||
643 | void sound_settings_apply(void) | 643 | void sound_settings_apply(void) |
644 | { | 644 | { |
645 | #ifdef HAVE_SW_TONE_CONTROLS | ||
646 | sound_set_dsp_callback(dsp_callback); | ||
647 | #endif | ||
645 | sound_set(SOUND_BASS, global_settings.bass); | 648 | sound_set(SOUND_BASS, global_settings.bass); |
646 | sound_set(SOUND_TREBLE, global_settings.treble); | 649 | sound_set(SOUND_TREBLE, global_settings.treble); |
647 | sound_set(SOUND_BALANCE, global_settings.balance); | 650 | sound_set(SOUND_BALANCE, global_settings.balance); |
@@ -967,7 +970,7 @@ bool set_sound(const unsigned char * string, | |||
967 | talkunit = UNIT_PERCENT; | 970 | talkunit = UNIT_PERCENT; |
968 | else if (*unit == 'H') | 971 | else if (*unit == 'H') |
969 | talkunit = UNIT_HERTZ; | 972 | talkunit = UNIT_HERTZ; |
970 | if(!numdec) | 973 | if (!numdec) |
971 | #if CONFIG_CODEC == SWCODEC | 974 | #if CONFIG_CODEC == SWCODEC |
972 | /* We need to hijack this one and send it off to apps/dsp.c instead of | 975 | /* We need to hijack this one and send it off to apps/dsp.c instead of |
973 | firmware/sound.c */ | 976 | firmware/sound.c */ |
@@ -975,7 +978,7 @@ bool set_sound(const unsigned char * string, | |||
975 | return set_int(string, unit, talkunit, variable, &stereo_width_set, | 978 | return set_int(string, unit, talkunit, variable, &stereo_width_set, |
976 | steps, min, max, NULL ); | 979 | steps, min, max, NULL ); |
977 | else | 980 | else |
978 | #endif | 981 | #endif |
979 | return set_int(string, unit, talkunit, variable, sound_callback, | 982 | return set_int(string, unit, talkunit, variable, sound_callback, |
980 | steps, min, max, NULL ); | 983 | steps, min, max, NULL ); |
981 | else | 984 | else |
diff --git a/firmware/export/config-iaudiox5.h b/firmware/export/config-iaudiox5.h index 6aeaab0431..ba9e95398f 100644 --- a/firmware/export/config-iaudiox5.h +++ b/firmware/export/config-iaudiox5.h | |||
@@ -84,6 +84,9 @@ | |||
84 | 84 | ||
85 | #define HAVE_TLV320 | 85 | #define HAVE_TLV320 |
86 | 86 | ||
87 | /* TLV320 has no tone controls, so we use the software ones */ | ||
88 | #define HAVE_SW_TONE_CONTROLS | ||
89 | |||
87 | #ifndef SIMULATOR | 90 | #ifndef SIMULATOR |
88 | 91 | ||
89 | /* Define this if your LCD can set contrast */ | 92 | /* Define this if your LCD can set contrast */ |
diff --git a/firmware/export/sound.h b/firmware/export/sound.h index 2079a84f0f..192384031d 100644 --- a/firmware/export/sound.h +++ b/firmware/export/sound.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #ifndef SOUND_H | 19 | #ifndef SOUND_H |
20 | #define SOUND_H | 20 | #define SOUND_H |
21 | 21 | ||
22 | #include <inttypes.h> | ||
22 | #ifdef HAVE_UDA1380 | 23 | #ifdef HAVE_UDA1380 |
23 | #include "uda1380.h" | 24 | #include "uda1380.h" |
24 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8751) | 25 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8751) |
@@ -76,6 +77,7 @@ int sound_max(int setting); | |||
76 | int sound_default(int setting); | 77 | int sound_default(int setting); |
77 | sound_set_type* sound_get_fn(int setting); | 78 | sound_set_type* sound_get_fn(int setting); |
78 | 79 | ||
80 | void sound_set_dsp_callback(int (*func)(int, intptr_t)); | ||
79 | void sound_set_volume(int value); | 81 | void sound_set_volume(int value); |
80 | void sound_set_balance(int value); | 82 | void sound_set_balance(int value); |
81 | void sound_set_bass(int value); | 83 | void sound_set_bass(int value); |
diff --git a/firmware/sound.c b/firmware/sound.c index c3679d41f2..a2b4e96e81 100644 --- a/firmware/sound.c +++ b/firmware/sound.c | |||
@@ -87,6 +87,11 @@ static const struct sound_settings_info sound_settings_table[] = { | |||
87 | [SOUND_BASS] = {"dB", 0, 1, -15, 15, 7, sound_set_bass}, | 87 | [SOUND_BASS] = {"dB", 0, 1, -15, 15, 7, sound_set_bass}, |
88 | [SOUND_TREBLE] = {"dB", 0, 1, -15, 15, 7, sound_set_treble}, | 88 | [SOUND_TREBLE] = {"dB", 0, 1, -15, 15, 7, sound_set_treble}, |
89 | #endif | 89 | #endif |
90 | /* Override any other potentially existing treble/bass controllers if wanted */ | ||
91 | #ifdef HAVE_SW_TONE_CONTROLS | ||
92 | [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0, sound_set_bass}, | ||
93 | [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0, sound_set_treble}, | ||
94 | #endif | ||
90 | [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0, sound_set_balance}, | 95 | [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0, sound_set_balance}, |
91 | [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0, sound_set_channels}, | 96 | [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0, sound_set_channels}, |
92 | [SOUND_STEREO_WIDTH] = {"%", 0, 1, 0, 255, 100, sound_set_stereo_width}, | 97 | [SOUND_STEREO_WIDTH] = {"%", 0, 1, 0, 255, 100, sound_set_stereo_width}, |
@@ -166,6 +171,22 @@ sound_set_type* sound_get_fn(int setting) | |||
166 | return NULL; | 171 | return NULL; |
167 | } | 172 | } |
168 | 173 | ||
174 | #ifdef HAVE_SW_TONE_CONTROLS | ||
175 | /* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */ | ||
176 | enum { | ||
177 | DSP_CALLBACK_SET_PRESCALE = 0, | ||
178 | DSP_CALLBACK_SET_BASS, | ||
179 | DSP_CALLBACK_SET_TREBLE | ||
180 | }; | ||
181 | |||
182 | static int (*dsp_callback)(int, intptr_t) = NULL; | ||
183 | |||
184 | void sound_set_dsp_callback(int (*func)(int, intptr_t)) | ||
185 | { | ||
186 | dsp_callback = func; | ||
187 | } | ||
188 | #endif | ||
189 | |||
169 | #ifndef SIMULATOR | 190 | #ifndef SIMULATOR |
170 | #if CONFIG_CODEC == MAS3507D /* volume/balance/treble/bass interdependency */ | 191 | #if CONFIG_CODEC == MAS3507D /* volume/balance/treble/bass interdependency */ |
171 | #define VOLUME_MIN -780 | 192 | #define VOLUME_MIN -780 |
@@ -293,10 +314,9 @@ int current_bass = 0; /* -150..+150 0..+240 */ | |||
293 | 314 | ||
294 | static void set_prescaled_volume(void) | 315 | static void set_prescaled_volume(void) |
295 | { | 316 | { |
296 | int prescale = 0; | 317 | int prescale; |
297 | int l, r; | 318 | int l, r; |
298 | 319 | ||
299 | #ifndef HAVE_TLV320 | ||
300 | prescale = MAX(current_bass, current_treble); | 320 | prescale = MAX(current_bass, current_treble); |
301 | if (prescale < 0) | 321 | if (prescale < 0) |
302 | prescale = 0; /* no need to prescale if we don't boost | 322 | prescale = 0; /* no need to prescale if we don't boost |
@@ -307,13 +327,12 @@ static void set_prescaled_volume(void) | |||
307 | * instead (might cause clipping). */ | 327 | * instead (might cause clipping). */ |
308 | if (current_volume + prescale > VOLUME_MAX) | 328 | if (current_volume + prescale > VOLUME_MAX) |
309 | prescale = VOLUME_MAX - current_volume; | 329 | prescale = VOLUME_MAX - current_volume; |
310 | #endif | 330 | |
311 | 331 | #if defined(HAVE_SW_TONE_CONTROLS) | |
312 | #if CONFIG_CODEC == MAS3507D | 332 | dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale); |
333 | #elif CONFIG_CODEC == MAS3507D | ||
313 | mas_writereg(MAS_REG_KPRESCALE, prescale_table[prescale/10]); | 334 | mas_writereg(MAS_REG_KPRESCALE, prescale_table[prescale/10]); |
314 | #elif defined(HAVE_UDA1380) | 335 | #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \ |
315 | audiohw_set_mixer_vol(tenthdb2mixer(-prescale), tenthdb2mixer(-prescale)); | ||
316 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
317 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) | 336 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) |
318 | audiohw_set_mixer_vol(tenthdb2mixer(-prescale), tenthdb2mixer(-prescale)); | 337 | audiohw_set_mixer_vol(tenthdb2mixer(-prescale), tenthdb2mixer(-prescale)); |
319 | #endif | 338 | #endif |
@@ -338,9 +357,7 @@ static void set_prescaled_volume(void) | |||
338 | 357 | ||
339 | #if CONFIG_CODEC == MAS3507D | 358 | #if CONFIG_CODEC == MAS3507D |
340 | dac_volume(tenthdb2reg(l), tenthdb2reg(r), false); | 359 | dac_volume(tenthdb2reg(l), tenthdb2reg(r), false); |
341 | #elif defined(HAVE_UDA1380) | 360 | #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \ |
342 | audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r)); | ||
343 | #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \ | ||
344 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) | 361 | || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) |
345 | audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r)); | 362 | audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r)); |
346 | #if defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8751) | 363 | #if defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8751) |
@@ -484,12 +501,15 @@ void sound_set_balance(int value) | |||
484 | #endif | 501 | #endif |
485 | } | 502 | } |
486 | 503 | ||
487 | #ifndef HAVE_TLV320 | ||
488 | void sound_set_bass(int value) | 504 | void sound_set_bass(int value) |
489 | { | 505 | { |
490 | if(!audio_is_initialized) | 506 | if(!audio_is_initialized) |
491 | return; | 507 | return; |
492 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | 508 | #if defined(HAVE_SW_TONE_CONTROLS) |
509 | current_bass = value * 10; | ||
510 | dsp_callback(DSP_CALLBACK_SET_BASS, current_bass); | ||
511 | set_prescaled_volume(); | ||
512 | #elif (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
493 | unsigned tmp = ((unsigned)(value * 8) & 0xff) << 8; | 513 | unsigned tmp = ((unsigned)(value * 8) & 0xff) << 8; |
494 | mas_codec_writereg(0x14, tmp); | 514 | mas_codec_writereg(0x14, tmp); |
495 | #elif CONFIG_CODEC == MAS3507D | 515 | #elif CONFIG_CODEC == MAS3507D |
@@ -515,7 +535,11 @@ void sound_set_treble(int value) | |||
515 | { | 535 | { |
516 | if(!audio_is_initialized) | 536 | if(!audio_is_initialized) |
517 | return; | 537 | return; |
518 | #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | 538 | #if defined(HAVE_SW_TONE_CONTROLS) |
539 | current_treble = value * 10; | ||
540 | dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble); | ||
541 | set_prescaled_volume(); | ||
542 | #elif (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) | ||
519 | unsigned tmp = ((unsigned)(value * 8) & 0xff) << 8; | 543 | unsigned tmp = ((unsigned)(value * 8) & 0xff) << 8; |
520 | mas_codec_writereg(0x15, tmp); | 544 | mas_codec_writereg(0x15, tmp); |
521 | #elif CONFIG_CODEC == MAS3507D | 545 | #elif CONFIG_CODEC == MAS3507D |
@@ -536,7 +560,6 @@ void sound_set_treble(int value) | |||
536 | (void)value; | 560 | (void)value; |
537 | #endif | 561 | #endif |
538 | } | 562 | } |
539 | #endif /* HAVE_TLV320 */ | ||
540 | 563 | ||
541 | void sound_set_channels(int value) | 564 | void sound_set_channels(int value) |
542 | { | 565 | { |