summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/dsp.c71
-rw-r--r--apps/dsp.h7
-rw-r--r--apps/eq.c60
-rw-r--r--apps/eq.h7
-rw-r--r--apps/menus/sound_menu.c10
-rw-r--r--apps/settings.c7
6 files changed, 132 insertions, 30 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 */
122struct eq_state 123struct 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;
171struct crossfeed_data crossfeed_data IBSS_ATTR; /* A */ 172struct crossfeed_data crossfeed_data IBSS_ATTR; /* A */
172/* Equalizer */ 173/* Equalizer */
173static struct eq_state eq_data; /* A/V */ 174static struct eq_state eq_data; /* A/V */
175#ifdef HAVE_SW_TONE_CONTROLS
176static int prescale;
177static int bass;
178static int treble;
179/* Filter struct for software bass/treble controls */
180static struct eqfilter tone_filter;
181#endif
174 182
175/* Settings applicable to audio codec only */ 183/* Settings applicable to audio codec only */
176static int pitch_ratio = 1000; 184static int pitch_ratio = 1000;
@@ -704,11 +712,7 @@ void dsp_set_crossfeed(bool enable)
704 712
705void dsp_set_crossfeed_direct_gain(int gain) 713void 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
714void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) 718void 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
993static 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
1000int 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
989static void channels_process_sound_chan_custom(int count, int32_t *buf[]) 1023static 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
54enum {
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);
209void dsp_set_eq_coefs(int band); 215void dsp_set_eq_coefs(int band);
210void sound_set_pitch(int r); 216void sound_set_pitch(int r);
211int sound_get_pitch(void); 217int sound_get_pitch(void);
218int dsp_callback(int msg, intptr_t param);
212void channels_set(int value); 219void channels_set(int value);
213void stereo_width_set(int value); 220void stereo_width_set(int value);
214void dsp_dither_enable(bool enable); 221void dsp_dither_enable(bool enable);
diff --git a/apps/eq.c b/apps/eq.c
index 588c23f89f..1d74db790e 100644
--- a/apps/eq.c
+++ b/apps/eq.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.
@@ -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 */
130void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c) 130void 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 */
162void 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 */
168void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c) 220void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c)
diff --git a/apps/eq.h b/apps/eq.h
index 095c8e82f0..83d235959d 100644
--- a/apps/eq.h
+++ b/apps/eq.h
@@ -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
36void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c); 37void filter_shelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c);
38void filter_bishelf_coefs(unsigned long cutoff_low, unsigned long cutoff_high,
39 long A_low, long A_high, long A, int32_t *c);
37void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); 40void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
38void eq_ls_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); 41void eq_ls_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
39void eq_hs_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c); 42void 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
57MENUITEM_SETTING(volume, &global_settings.volume, soundmenu_callback); 57MENUITEM_SETTING(volume, &global_settings.volume, soundmenu_callback);
58 58MENUITEM_SETTING(bass, &global_settings.bass, soundmenu_callback);
59#ifndef HAVE_TLV320 59MENUITEM_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
64MENUITEM_SETTING(balance, &global_settings.balance, soundmenu_callback); 60MENUITEM_SETTING(balance, &global_settings.balance, soundmenu_callback);
65MENUITEM_SETTING(channel_config, &global_settings.channel_config, soundmenu_callback); 61MENUITEM_SETTING(channel_config, &global_settings.channel_config, soundmenu_callback);
66MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, soundmenu_callback); 62MENUITEM_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
100MAKE_MENU(sound_settings, ID2P(LANG_SOUND_SETTINGS), NULL, bitmap_icons_6x8[Icon_Audio], 96MAKE_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
643void sound_settings_apply(void) 643void 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