summaryrefslogtreecommitdiff
path: root/lib/rbcodec/dsp/eq.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2013-05-23 13:58:51 -0400
committerMichael Sevakis <jethead71@rockbox.org>2013-07-06 04:22:04 +0200
commitd37bf24d9011addbfbd40942a4e9bbf26de7df00 (patch)
treedafb7eaeb494081668a4841d490fce2bfbb2438d /lib/rbcodec/dsp/eq.c
parent00faabef5e902008172e08d3bcd77683cbafef51 (diff)
downloadrockbox-d37bf24d9011addbfbd40942a4e9bbf26de7df00.tar.gz
rockbox-d37bf24d9011addbfbd40942a4e9bbf26de7df00.zip
Enable setting of global output samplerate on certain targets.
Replaces the NATIVE_FREQUENCY constant with a configurable frequency. The user may select 48000Hz if the hardware supports it. The default is still 44100Hz and the minimum is 44100Hz. The setting is located in the playback settings, under "Frequency". "Frequency" was duplicated in english.lang for now to avoid having to fix every .lang file for the moment and throwing everything out of sync because of the new play_frequency feature in features.txt. The next cleanup should combine it with the one included for recording and generalize the ID label. If the hardware doesn't support 48000Hz, no setting will be available. On particular hardware where very high rates are practical and desireable, the upper bound can be extended by patching. The PCM mixer can be configured to play at the full hardware frequency range. The DSP core can configure to the hardware minimum up to the maximum playback setting (some buffers must be reserved according to the maximum rate). If only 44100Hz is supported or possible on a given target for playback, using the DSP and mixer at other samperates is possible if the hardware offers them. Change-Id: I6023cf0c0baa8bc6292b6919b4dd3618a6a25622 Reviewed-on: http://gerrit.rockbox.org/479 Reviewed-by: Michael Sevakis <jethead71@rockbox.org> Tested-by: Michael Sevakis <jethead71@rockbox.org>
Diffstat (limited to 'lib/rbcodec/dsp/eq.c')
-rw-r--r--lib/rbcodec/dsp/eq.c77
1 files changed, 55 insertions, 22 deletions
diff --git a/lib/rbcodec/dsp/eq.c b/lib/rbcodec/dsp/eq.c
index 94cb61deec..e4d7bf5e02 100644
--- a/lib/rbcodec/dsp/eq.c
+++ b/lib/rbcodec/dsp/eq.c
@@ -25,6 +25,7 @@
25#include "dsp_filter.h" 25#include "dsp_filter.h"
26#include "dsp_proc_entry.h" 26#include "dsp_proc_entry.h"
27#include "dsp_core.h" 27#include "dsp_core.h"
28#include "dsp_misc.h"
28#include "eq.h" 29#include "eq.h"
29#include "pga.h" 30#include "pga.h"
30#include "replaygain.h" 31#include "replaygain.h"
@@ -42,6 +43,9 @@
42#error Band count must be greater than or equal to 3 43#error Band count must be greater than or equal to 3
43#endif 44#endif
44 45
46/* Cached band settings */
47static struct eq_band_setting settings[EQ_NUM_BANDS];
48
45static struct eq_state 49static struct eq_state
46{ 50{
47 uint32_t enabled; /* Mask of enabled bands */ 51 uint32_t enabled; /* Mask of enabled bands */
@@ -49,16 +53,48 @@ static struct eq_state
49 struct dsp_filter filters[EQ_NUM_BANDS]; /* Data for each filter */ 53 struct dsp_filter filters[EQ_NUM_BANDS]; /* Data for each filter */
50} eq_data IBSS_ATTR; 54} eq_data IBSS_ATTR;
51 55
56#define FOR_EACH_ENB_BAND(b) \
57 for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++)
58
52/* Clear histories of all enabled bands */ 59/* Clear histories of all enabled bands */
53static void eq_flush(void) 60static void eq_flush(void)
54{ 61{
55 if (eq_data.enabled == 0) 62 if (eq_data.enabled == 0)
56 return; /* Not initialized yet/no bands on */ 63 return; /* Not initialized yet/no bands on */
57 64
58 for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++) 65 FOR_EACH_ENB_BAND(b)
59 filter_flush(&eq_data.filters[*b]); 66 filter_flush(&eq_data.filters[*b]);
60} 67}
61 68
69static void update_band_filter(int band, unsigned int fout)
70{
71 /* Convert user settings to format required by coef generator
72 functions */
73 typeof (filter_pk_coefs) *coef_gen = filter_pk_coefs;
74
75 /* Only first and last bands are not peaking filters */
76 if (band == 0)
77 coef_gen = filter_ls_coefs;
78 else if (band == EQ_NUM_BANDS-1)
79 coef_gen = filter_hs_coefs;
80
81 const struct eq_band_setting *setting = &settings[band];
82 struct dsp_filter *filter = &eq_data.filters[band];
83
84 coef_gen(fp_div(setting->cutoff, fout, 32), setting->q ?: 1,
85 setting->gain, filter);
86}
87
88/* Resync all bands to a new DSP output frequency */
89static void update_samplerate(unsigned int fout)
90{
91 if (eq_data.enabled == 0)
92 return; /* Not initialized yet/no bands on */
93
94 FOR_EACH_ENB_BAND(b)
95 update_band_filter(*b, fout);
96}
97
62/** DSP interface **/ 98/** DSP interface **/
63 99
64/* Set the precut gain value */ 100/* Set the precut gain value */
@@ -73,11 +109,14 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting)
73 if (band < 0 || band >= EQ_NUM_BANDS) 109 if (band < 0 || band >= EQ_NUM_BANDS)
74 return; 110 return;
75 111
112 settings[band] = *setting; /* cache setting */
113
114 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
115
76 /* NOTE: The coef functions assume the EMAC unit is in fractional mode, 116 /* NOTE: The coef functions assume the EMAC unit is in fractional mode,
77 which it should be, since we're executed from the main thread. */ 117 which it should be, since we're executed from the main thread. */
78 118
79 uint32_t mask = eq_data.enabled; 119 uint32_t mask = eq_data.enabled;
80 struct dsp_filter *filter = &eq_data.filters[band];
81 120
82 /* Assume a band is disabled if the gain is zero */ 121 /* Assume a band is disabled if the gain is zero */
83 mask &= ~BIT_N(band); 122 mask &= ~BIT_N(band);
@@ -85,33 +124,19 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting)
85 if (setting->gain != 0) 124 if (setting->gain != 0)
86 { 125 {
87 mask |= BIT_N(band); 126 mask |= BIT_N(band);
88 127 update_band_filter(band, dsp_get_output_frequency(dsp));
89 /* Convert user settings to format required by coef generator
90 functions */
91 void (* coef_gen)(unsigned long cutoff, unsigned long Q, long db,
92 struct dsp_filter *f) = filter_pk_coefs;
93
94 /* Only first and last bands are not peaking filters */
95 if (band == 0)
96 coef_gen = filter_ls_coefs;
97 else if (band == EQ_NUM_BANDS-1)
98 coef_gen = filter_hs_coefs;
99
100 coef_gen(0xffffffff / NATIVE_FREQUENCY * setting->cutoff,
101 setting->q ?: 1, setting->gain, filter);
102 } 128 }
103 129
104 if (mask == eq_data.enabled) 130 if (mask == eq_data.enabled)
105 return; /* No change in band-enable state */ 131 return; /* No change in band-enable state */
106 132
107 if (mask & BIT_N(band)) 133 if (mask & BIT_N(band))
108 filter_flush(filter); /* Coming online */ 134 filter_flush(&eq_data.filters[band]); /* Coming online */
109 135
110 eq_data.enabled = mask; 136 eq_data.enabled = mask;
111 137
112 /* Only be active if there are bands to process - if EQ is off, then 138 /* Only be active if there are bands to process - if EQ is off, then
113 this call has no effect */ 139 this call has no effect */
114 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
115 dsp_proc_activate(dsp, DSP_PROC_EQUALIZER, mask != 0); 140 dsp_proc_activate(dsp, DSP_PROC_EQUALIZER, mask != 0);
116 141
117 /* Prepare list of enabled bands for efficient iteration */ 142 /* Prepare list of enabled bands for efficient iteration */
@@ -125,6 +150,11 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting)
125void dsp_eq_enable(bool enable) 150void dsp_eq_enable(bool enable)
126{ 151{
127 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); 152 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
153 bool enabled = dsp_proc_enabled(dsp, DSP_PROC_EQUALIZER);
154
155 if (enable == enabled)
156 return;
157
128 dsp_proc_enable(dsp, DSP_PROC_EQUALIZER, enable); 158 dsp_proc_enable(dsp, DSP_PROC_EQUALIZER, enable);
129 159
130 if (enable && eq_data.enabled != 0) 160 if (enable && eq_data.enabled != 0)
@@ -139,7 +169,7 @@ static void eq_process(struct dsp_proc_entry *this,
139 int count = buf->remcount; 169 int count = buf->remcount;
140 unsigned int channels = buf->format.num_channels; 170 unsigned int channels = buf->format.num_channels;
141 171
142 for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++) 172 FOR_EACH_ENB_BAND(b)
143 filter_process(&eq_data.filters[*b], buf->p32, count, channels); 173 filter_process(&eq_data.filters[*b], buf->p32, count, channels);
144 174
145 (void)this; 175 (void)this;
@@ -154,10 +184,9 @@ static intptr_t eq_configure(struct dsp_proc_entry *this,
154 switch (setting) 184 switch (setting)
155 { 185 {
156 case DSP_PROC_INIT: 186 case DSP_PROC_INIT:
157 if (value != 0)
158 break; /* Already enabled */
159
160 this->process = eq_process; 187 this->process = eq_process;
188 /* Wouldn't have been getting frequency updates */
189 update_samplerate(dsp_get_output_frequency(dsp));
161 /* Fall-through */ 190 /* Fall-through */
162 case DSP_PROC_CLOSE: 191 case DSP_PROC_CLOSE:
163 pga_enable_gain(PGA_EQ_PRECUT, setting == DSP_PROC_INIT); 192 pga_enable_gain(PGA_EQ_PRECUT, setting == DSP_PROC_INIT);
@@ -166,6 +195,10 @@ static intptr_t eq_configure(struct dsp_proc_entry *this,
166 case DSP_FLUSH: 195 case DSP_FLUSH:
167 eq_flush(); 196 eq_flush();
168 break; 197 break;
198
199 case DSP_SET_OUT_FREQUENCY:
200 update_samplerate(value);
201 break;
169 } 202 }
170 203
171 return 0; 204 return 0;