summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/SOURCES1
-rw-r--r--apps/dsp.c61
-rw-r--r--apps/dsp.h1
-rw-r--r--apps/eq.c8
-rw-r--r--apps/eq_menu.c678
-rw-r--r--apps/eq_menu.h28
-rw-r--r--apps/lang/english.lang91
-rw-r--r--apps/onplay.c22
-rw-r--r--apps/settings.c23
-rw-r--r--apps/settings.h34
-rw-r--r--apps/sound_menu.c2
-rwxr-xr-xtools/buildzip.pl1
12 files changed, 942 insertions, 8 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 35f78c455e..ef65789588 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -78,4 +78,5 @@ eq_cf.S
78#elif defined(CPU_ARM) && !defined(SIMULATOR) 78#elif defined(CPU_ARM) && !defined(SIMULATOR)
79eq_arm.S 79eq_arm.S
80#endif 80#endif
81eq_menu.c
81#endif 82#endif
diff --git a/apps/dsp.c b/apps/dsp.c
index 789cf72b20..e4d28bd083 100644
--- a/apps/dsp.c
+++ b/apps/dsp.c
@@ -145,6 +145,7 @@ struct dsp_config
145 bool dither_enabled; 145 bool dither_enabled;
146 bool new_gain; 146 bool new_gain;
147 bool crossfeed_enabled; 147 bool crossfeed_enabled;
148 bool eq_enabled;
148}; 149};
149 150
150struct resample_data 151struct resample_data
@@ -618,6 +619,61 @@ static void apply_crossfeed(long* src[], int count)
618} 619}
619#endif 620#endif
620 621
622#define EQ_CUTOFF_USER2REAL(x) (0xffffffff / NATIVE_FREQUENCY * (x))
623#define EQ_Q_USER2REAL(x) (((x) << 16) / 10)
624#define EQ_GAIN_USER2REAL(x) (((x) << 16) / 10)
625
626/* Synchronize the EQ filters with the global settings */
627void dsp_eq_update_data(bool enabled)
628{
629 int i;
630 int *setting;
631 int gain, cutoff, q, maxgain;
632
633 dsp->eq_enabled = enabled;
634 setting = &global_settings.eq_band0_cutoff;
635 maxgain = 0;
636
637 #if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
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);
642 #endif
643
644 /* Iterate over each band and update the appropriate filter */
645 for(i = 0; i < 5; i++) {
646 cutoff = *setting++;
647 q = *setting++;
648 gain = *setting++;
649
650 /* Keep track of maxgain for the pre-amp */
651 if (gain > maxgain)
652 maxgain = gain;
653
654 if (gain == 0) {
655 eq_data.enabled[i] = 0;
656 } else {
657 if (i == 0)
658 eq_ls_coefs(EQ_CUTOFF_USER2REAL(cutoff), EQ_Q_USER2REAL(q),
659 EQ_GAIN_USER2REAL(gain), eq_data.filters[0].coefs);
660 else if (i == 4)
661 eq_hs_coefs(EQ_CUTOFF_USER2REAL(cutoff), EQ_Q_USER2REAL(q),
662 EQ_GAIN_USER2REAL(gain), eq_data.filters[4].coefs);
663 else
664 eq_pk_coefs(EQ_CUTOFF_USER2REAL(cutoff), EQ_Q_USER2REAL(q),
665 EQ_GAIN_USER2REAL(gain), eq_data.filters[i].coefs);
666
667 eq_data.enabled[i] = 1;
668 }
669 }
670
671 #if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
672 /* set old macsr again */
673 coldfire_set_macsr(old_macsr);
674 #endif
675}
676
621/* Apply EQ filters to those bands that have got it switched on. */ 677/* Apply EQ filters to those bands that have got it switched on. */
622static void eq_process(long **x, unsigned num) 678static void eq_process(long **x, unsigned num)
623{ 679{
@@ -745,9 +801,8 @@ long dsp_process(char* dst, char* src[], long size)
745 samples = resample(tmp, samples); 801 samples = resample(tmp, samples);
746 if (dsp->crossfeed_enabled && dsp->stereo_mode != STEREO_MONO) 802 if (dsp->crossfeed_enabled && dsp->stereo_mode != STEREO_MONO)
747 apply_crossfeed(tmp, samples); 803 apply_crossfeed(tmp, samples);
748 /* TODO: Might want to wrap this with a generic eq_enabled when the 804 if (dsp->eq_enabled)
749 settings are in place */ 805 eq_process(tmp, samples);
750 eq_process(tmp, samples);
751 write_samples((short*) dst, tmp, samples); 806 write_samples((short*) dst, tmp, samples);
752 written += samples; 807 written += samples;
753 dst += samples * sizeof(short) * 2; 808 dst += samples * sizeof(short) * 2;
diff --git a/apps/dsp.h b/apps/dsp.h
index f86a4d9989..364c8d80f5 100644
--- a/apps/dsp.h
+++ b/apps/dsp.h
@@ -54,6 +54,7 @@ int dsp_stereo_mode(void);
54bool dsp_configure(int setting, void *value); 54bool dsp_configure(int setting, void *value);
55void dsp_set_replaygain(bool always); 55void dsp_set_replaygain(bool always);
56void dsp_set_crossfeed(bool enable); 56void dsp_set_crossfeed(bool enable);
57void dsp_eq_update_data(bool enabled);
57void sound_set_pitch(int r); 58void sound_set_pitch(int r);
58int sound_get_pitch(void); 59int sound_get_pitch(void);
59#endif 60#endif
diff --git a/apps/eq.c b/apps/eq.c
index 17165be541..7921028403 100644
--- a/apps/eq.c
+++ b/apps/eq.c
@@ -32,11 +32,11 @@
32 */ 32 */
33 33
34#define DIV64(x, y, z) (long)(((long long)(x) << (z))/(y)) 34#define DIV64(x, y, z) (long)(((long long)(x) << (z))/(y))
35/* TODO: This macro requires the EMAC unit to be in fractional mode 35/* This macro requires the EMAC unit to be in fractional mode
36 when the coef generator routines are called. If this can be guaranteeed, 36 when the coef generator routines are called. If this can't be guaranteeed,
37 then remove the "&& 0" below for faster coef calculation on Coldfire. 37 then add "&& 0" below. This will use a slower coef calculation on Coldfire.
38 */ 38 */
39#if defined(CPU_COLDFIRE) && !defined(SIMULATOR) && 0 39#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
40#define FRACMUL(x, y) \ 40#define FRACMUL(x, y) \
41({ \ 41({ \
42 long t; \ 42 long t; \
diff --git a/apps/eq_menu.c b/apps/eq_menu.c
new file mode 100644
index 0000000000..0e3355fcd9
--- /dev/null
+++ b/apps/eq_menu.c
@@ -0,0 +1,678 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 Dan Everton
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "config.h"
21#include <stdio.h>
22#include <stdbool.h>
23#include <string.h>
24#include "eq_menu.h"
25#include "system.h"
26#include "kernel.h"
27#include "lcd.h"
28#include "menu.h"
29#include "button.h"
30#include "mp3_playback.h"
31#include "settings.h"
32#include "statusbar.h"
33#include "screens.h"
34#include "icons.h"
35#include "font.h"
36#include "widgets.h"
37#include "lang.h"
38#include "sprintf.h"
39#include "talk.h"
40#include "misc.h"
41#include "sound.h"
42#include "splash.h"
43#include "dsp.h"
44#include "tree.h"
45#include "talk.h"
46#include "screen_access.h"
47#include "keyboard.h"
48
49/* Key definitions */
50#if (CONFIG_KEYPAD == IRIVER_H100_PAD || \
51 CONFIG_KEYPAD == IRIVER_H300_PAD)
52
53#define EQ_BTN_NEXT_BAND BUTTON_DOWN
54#define EQ_BTN_PREV_BAND BUTTON_UP
55#define EQ_BTN_CHANGE_MODE BUTTON_SELECT
56#define EQ_BTN_EXIT BUTTON_OFF
57
58#elif (CONFIG_KEYPAD == IPOD_4G_PAD)
59
60#define EQ_BTN_NEXT_BAND BUTTON_SCROLL_FWD
61#define EQ_BTN_PREV_BAND BUTTON_SCROLL_BACK
62#define EQ_BTN_CHANGE_MODE BUTTON_SELECT
63#define EQ_BTN_EXIT BUTTON_MENU
64
65#endif
66
67
68#define EQ_CUTOFF_MIN 20
69#define EQ_CUTOFF_MAX 22040
70#define EQ_CUTOFF_STEP 10
71#define EQ_GAIN_MIN (-240)
72#define EQ_GAIN_MAX 240
73#define EQ_GAIN_STEP 1
74#define EQ_Q_MIN 5
75#define EQ_Q_MAX 64
76#define EQ_Q_STEP 1
77
78#define EQ_USER_DIVISOR 10
79
80static bool eq_enabled(void)
81{
82 bool result = set_bool(str(LANG_EQUALIZER_ENABLED),
83 &global_settings.eq_enabled);
84
85 dsp_eq_update_data(global_settings.eq_enabled);
86
87 return result;
88}
89
90static void eq_gain_format(char* buffer, int buffer_size, int value, const char* unit)
91{
92 int v = abs(value);
93
94 snprintf(buffer, buffer_size, "%s%d.%d %s", value < 0 ? "-" : "",
95 v / EQ_USER_DIVISOR, v % EQ_USER_DIVISOR, unit);
96}
97
98static void eq_q_format(char* buffer, int buffer_size, int value, const char* unit)
99{
100 snprintf(buffer, buffer_size, "%d.%d %s", value / EQ_USER_DIVISOR, value % EQ_USER_DIVISOR, unit);
101}
102
103/* Possibly dodgy way of simplifying the code a bit. */
104#define eq_make_gain_label(buf, bufsize, frequency) snprintf((buf), \
105 (bufsize), str(LANG_EQUALIZER_GAIN_ITEM), (frequency))
106
107#define eq_set_cutoff(band) \
108static bool eq_set_band ## band ## _cutoff(void) \
109{ \
110 bool result = set_int(str(LANG_EQUALIZER_BAND_CUTOFF), "Hertz", UNIT_HERTZ, \
111 &global_settings.eq_band ## band ## _cutoff, NULL, \
112 EQ_CUTOFF_STEP, EQ_CUTOFF_MIN, EQ_CUTOFF_MAX, NULL); \
113 dsp_eq_update_data(global_settings.eq_enabled); \
114 return result; \
115}
116
117#define eq_set_q(band) \
118static bool eq_set_band ## band ## _q(void) \
119{ \
120 bool result = set_int(str(LANG_EQUALIZER_BAND_Q), "Q", UNIT_INT, \
121 &global_settings.eq_band ## band ## _q, NULL, \
122 EQ_Q_STEP, EQ_Q_MIN, EQ_Q_MAX, eq_q_format); \
123 dsp_eq_update_data(global_settings.eq_enabled); \
124 return result; \
125}
126
127#define eq_set_gain(band) \
128static bool eq_set_band ## band ## _gain(void) \
129{ \
130 bool result = set_int("Band " #band, str(LANG_UNIT_DB), UNIT_DB, \
131 &global_settings.eq_band ## band ## _gain, NULL, \
132 EQ_GAIN_STEP, EQ_GAIN_MIN, EQ_GAIN_MAX, eq_gain_format); \
133 dsp_eq_update_data(global_settings.eq_enabled); \
134 return result; \
135}
136
137eq_set_cutoff(0);
138eq_set_cutoff(1);
139eq_set_cutoff(2);
140eq_set_cutoff(3);
141eq_set_cutoff(4);
142
143eq_set_q(0);
144eq_set_q(1);
145eq_set_q(2);
146eq_set_q(3);
147eq_set_q(4);
148
149eq_set_gain(0);
150eq_set_gain(1);
151eq_set_gain(2);
152eq_set_gain(3);
153eq_set_gain(4);
154
155static bool eq_gain_menu(void)
156{
157 int m, i;
158 int *setting;
159 bool result;
160 char gain_label[5][24];
161 static struct menu_item items[5] = {
162 { NULL, eq_set_band0_gain },
163 { NULL, eq_set_band1_gain },
164 { NULL, eq_set_band2_gain },
165 { NULL, eq_set_band3_gain },
166 { NULL, eq_set_band4_gain },
167 };
168
169 setting = &global_settings.eq_band0_cutoff;
170
171 /* Construct menu labels */
172 for(i = 0; i < 5; i++) {
173 eq_make_gain_label(gain_label[i], sizeof(gain_label[i]),
174 *setting);
175 items[i].desc = gain_label[i];
176
177 /* Skip to next band */
178 setting += 3;
179 }
180
181 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
182 NULL, NULL, NULL);
183 result = menu_run(m);
184 menu_exit(m);
185
186 return result;
187}
188
189static bool eq_set_band0(void)
190{
191 int m;
192 bool result;
193 static const struct menu_item items[] = {
194 { ID2P(LANG_EQUALIZER_BAND_CUTOFF), eq_set_band0_cutoff },
195 { ID2P(LANG_EQUALIZER_BAND_Q), eq_set_band0_q },
196 { ID2P(LANG_EQUALIZER_BAND_GAIN), eq_set_band0_gain },
197 };
198
199 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
200 NULL, NULL, NULL);
201 result = menu_run(m);
202 menu_exit(m);
203
204 return result;
205}
206
207static bool eq_set_band1(void)
208{
209 int m;
210 bool result;
211 static const struct menu_item items[] = {
212 { ID2P(LANG_EQUALIZER_BAND_CUTOFF), eq_set_band1_cutoff },
213 { ID2P(LANG_EQUALIZER_BAND_Q), eq_set_band1_q },
214 { ID2P(LANG_EQUALIZER_BAND_GAIN), eq_set_band1_gain },
215 };
216
217 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
218 NULL, NULL, NULL);
219 result = menu_run(m);
220 menu_exit(m);
221
222 return result;
223}
224
225static bool eq_set_band2(void)
226{
227 int m;
228 bool result;
229 static const struct menu_item items[] = {
230 { ID2P(LANG_EQUALIZER_BAND_CUTOFF), eq_set_band2_cutoff },
231 { ID2P(LANG_EQUALIZER_BAND_Q), eq_set_band2_q },
232 { ID2P(LANG_EQUALIZER_BAND_GAIN), eq_set_band2_gain },
233 };
234
235 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
236 NULL, NULL, NULL);
237 result = menu_run(m);
238 menu_exit(m);
239
240 return result;
241}
242
243static bool eq_set_band3(void)
244{
245 int m;
246 bool result;
247 static const struct menu_item items[] = {
248 { ID2P(LANG_EQUALIZER_BAND_CUTOFF), eq_set_band3_cutoff },
249 { ID2P(LANG_EQUALIZER_BAND_Q), eq_set_band3_q },
250 { ID2P(LANG_EQUALIZER_BAND_GAIN), eq_set_band3_gain },
251 };
252
253 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
254 NULL, NULL, NULL);
255 result = menu_run(m);
256 menu_exit(m);
257
258 return result;
259}
260
261static bool eq_set_band4(void)
262{
263 int m;
264 bool result;
265 static const struct menu_item items[] = {
266 { ID2P(LANG_EQUALIZER_BAND_CUTOFF), eq_set_band4_cutoff },
267 { ID2P(LANG_EQUALIZER_BAND_Q), eq_set_band4_q },
268 { ID2P(LANG_EQUALIZER_BAND_GAIN), eq_set_band4_gain },
269 };
270
271 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
272 NULL, NULL, NULL);
273 result = menu_run(m);
274 menu_exit(m);
275
276 return result;
277}
278
279static bool eq_advanced_menu(void)
280{
281 int m, i;
282 bool result;
283 char peak_band_label[3][32];
284 static struct menu_item items[] = {
285 { ID2P(LANG_EQUALIZER_BAND_LOW_SHELF), eq_set_band0 },
286 { NULL, eq_set_band1 },
287 { NULL, eq_set_band2 },
288 { NULL, eq_set_band3 },
289 { ID2P(LANG_EQUALIZER_BAND_HIGH_SHELF), eq_set_band4 },
290 };
291
292 /* Construct menu labels */
293 for(i = 1; i < 4; i++) {
294 snprintf(peak_band_label[i-1], sizeof(peak_band_label[i-1]),
295 str(LANG_EQUALIZER_BAND_PEAK), i);
296 items[i].desc = peak_band_label[i-1];
297 }
298
299 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
300 NULL, NULL, NULL);
301 result = menu_run(m);
302 menu_exit(m);
303
304 return result;
305}
306
307#define SLIDER_KNOB_HEIGHT 6
308#define SLIDER_KNOB_WIDTH 4
309
310enum eq_slider_mode {
311 GAIN,
312 CUTOFF,
313 Q,
314};
315
316enum eq_type {
317 LOW_SHELF,
318 PEAK,
319 HIGH_SHELF
320};
321
322/* Draw a slider */
323static void draw_slider(const struct screen * screen, int x, int y,
324 int width, int steps, int current_step)
325{
326
327 int knob_x = (width / steps) * current_step + (SLIDER_KNOB_WIDTH / 2);
328
329 /* Draw groove */
330 screen->fillrect(x, y + 2, width, 2);
331
332 /* Draw knob */
333 screen->fillrect(x + knob_x, y, SLIDER_KNOB_WIDTH, SLIDER_KNOB_HEIGHT);
334}
335
336/* Draw the UI for a whole EQ band */
337static int draw_eq_slider(const struct screen * screen, int x, int y,
338 int width, int cutoff, int q, int gain, bool selected,
339 enum eq_slider_mode mode, enum eq_type type)
340{
341 char buf[26];
342 const char separator[2] = " ";
343 int steps = (abs(EQ_GAIN_MIN) + abs(EQ_GAIN_MAX)) / EQ_USER_DIVISOR;
344 int abs_q = abs(q);
345 int abs_gain = abs(gain);
346 int current_x, total_height, separator_width, separator_height;
347 int w, h;
348
349 /* Start two pixels in, one for border, one for margin */
350 current_x = x + 2;
351
352 /* Figure out how large our separator string is */
353 screen->getstringsize(separator, &separator_width, &separator_height);
354
355 /* Total height includes margins, text, and line selector */
356 total_height = separator_height + SLIDER_KNOB_HEIGHT + 2 + 3;
357
358 /* Print out the band label */
359 if (type == LOW_SHELF) {
360 screen->putsxy(current_x, y + 2, "LS:");
361 screen->getstringsize("LS:", &w, &h);
362 } else if (type == HIGH_SHELF) {
363 screen->putsxy(current_x, y + 2, "HS:");
364 screen->getstringsize("HS:", &w, &h);
365 } else {
366 screen->putsxy(current_x, y + 2, "PK:");
367 screen->getstringsize("PK:", &w, &h);
368 }
369 current_x += w;
370
371 /* Print separator */
372 screen->set_drawmode(DRMODE_SOLID);
373 screen->putsxy(current_x, y + 2, separator);
374 current_x += separator_width;
375
376 /* Print out gain part of status line */
377 snprintf(buf, sizeof(buf), "%s%2d.%ddB", gain < 0 ? "-" : " ",
378 abs_gain / EQ_USER_DIVISOR, abs_gain % EQ_USER_DIVISOR);
379
380 if (mode == GAIN && selected)
381 screen->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
382
383 screen->putsxy(current_x, y + 2, buf);
384 screen->getstringsize(buf, &w, &h);
385 current_x += w;
386
387 /* Print separator */
388 screen->set_drawmode(DRMODE_SOLID);
389 screen->putsxy(current_x, y + 2, separator);
390 current_x += separator_width;
391
392 /* Print out cutoff part of status line */
393 snprintf(buf, sizeof(buf), "%5dHz", cutoff);
394
395 if (mode == CUTOFF && selected)
396 screen->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
397
398 screen->putsxy(current_x, y + 2, buf);
399 screen->getstringsize(buf, &w, &h);
400 current_x += w;
401
402 /* Print separator */
403 screen->set_drawmode(DRMODE_SOLID);
404 screen->putsxy(current_x, y + 2, separator);
405 current_x += separator_width;
406
407 /* Print out Q part of status line */
408 snprintf(buf, sizeof(buf), "%d.%d Q", abs_q / EQ_USER_DIVISOR,
409 abs_q % EQ_USER_DIVISOR);
410
411 if (mode == Q && selected)
412 screen->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
413
414 screen->putsxy(current_x, y + 2, buf);
415 screen->getstringsize(buf, &w, &h);
416 current_x += w;
417
418 screen->set_drawmode(DRMODE_SOLID);
419
420 /* Draw selection box */
421 if (selected) {
422 screen->drawrect(x, y, width, total_height);
423 }
424
425 /* Draw horizontal slider */
426 draw_slider(screen, x + 3, y + h + 3, width - 6, steps,
427 (EQ_GAIN_MAX + gain) / EQ_USER_DIVISOR);
428
429 return total_height;
430}
431
432/* Draw's all the EQ sliders. Returns the total height of the sliders drawn */
433static int draw_eq_sliders(int current_band, enum eq_slider_mode mode)
434{
435 int i, gain, q, cutoff;
436 int height = 2; /* Two pixel margin */
437 int slider_width = screens[SCREEN_MAIN].width - 4; /* two pixel margin on each side */
438 int *setting = &global_settings.eq_band0_cutoff;
439 enum eq_type type;
440
441 for( i = 0; i < 5; ++i)
442 {
443 cutoff = *setting++;
444 q = *setting++;
445 gain = *setting++;
446
447 if (i == 0) {
448 type = LOW_SHELF;
449 } else if (i == 4) {
450 type = HIGH_SHELF;
451 } else {
452 type = PEAK;
453 }
454
455 height += draw_eq_slider(&(screens[SCREEN_MAIN]), 2, height,
456 slider_width, cutoff, q, gain, i == current_band, mode, type);
457
458 /* add a margin */
459 height += 2;
460 }
461
462 return height;
463}
464
465/* Provides a graphical means of editing the EQ settings */
466bool eq_menu_graphical(void)
467{
468 bool exit_request = false;
469 bool result = true;
470 bool has_changed = false;
471 int button;
472 int *setting;
473 int current_band, y, step, min, max, voice_unit;
474 enum eq_slider_mode mode;
475 enum eq_type current_type;
476 char buf[24];
477
478 screens[SCREEN_MAIN].setfont(FONT_SYSFIXED);
479 screens[SCREEN_MAIN].clear_display();
480
481 /* Start off editing gain on the first band */
482 mode = GAIN;
483 current_type = LOW_SHELF;
484 current_band = 0;
485
486 while (!exit_request) {
487 /* Clear the screen. The drawing routines expect this */
488 screens[SCREEN_MAIN].clear_display();
489
490 /* Draw equalizer band details */
491 y = draw_eq_sliders(current_band, mode);
492
493 /* Set pointer to the band data currently editable */
494 if (mode == GAIN) {
495 /* gain */
496 setting = &global_settings.eq_band0_gain;
497 setting += current_band * 3;
498
499 step = EQ_GAIN_STEP;
500 min = EQ_GAIN_MIN;
501 max = EQ_GAIN_MAX;
502 voice_unit = UNIT_DB;
503
504 snprintf(buf, sizeof(buf), str(LANG_EQUALIZER_EDIT_MODE),
505 str(LANG_EQUALIZER_BAND_GAIN));
506
507 screens[SCREEN_MAIN].putsxy(2, y, buf);
508 } else if (mode == CUTOFF) {
509 /* cutoff */
510 setting = &global_settings.eq_band0_cutoff;
511 setting += current_band * 3;
512
513 step = EQ_CUTOFF_STEP;
514 min = EQ_CUTOFF_MIN;
515 max = EQ_CUTOFF_MAX;
516 voice_unit = UNIT_HERTZ;
517
518 snprintf(buf, sizeof(buf), str(LANG_EQUALIZER_EDIT_MODE),
519 str(LANG_EQUALIZER_BAND_CUTOFF));
520
521 screens[SCREEN_MAIN].putsxy(2, y, buf);
522 } else {
523 /* Q */
524 setting = &global_settings.eq_band0_q;
525 setting += current_band * 3;
526
527 step = EQ_Q_STEP;
528 min = EQ_Q_MIN;
529 max = EQ_Q_MAX;
530 voice_unit = UNIT_INT;
531
532 snprintf(buf, sizeof(buf), str(LANG_EQUALIZER_EDIT_MODE),
533 str(LANG_EQUALIZER_BAND_Q));
534
535 screens[SCREEN_MAIN].putsxy(2, y, buf);
536 }
537
538 screens[SCREEN_MAIN].update();
539
540 button = button_get_w_tmo(HZ/10);
541
542 switch (button) {
543 case BUTTON_LEFT:
544 case BUTTON_LEFT | BUTTON_REPEAT:
545 *(setting) -= step;
546 has_changed = true;
547 if (*(setting) < min)
548 *(setting) = min;
549 break;
550
551 case BUTTON_RIGHT:
552 case BUTTON_RIGHT | BUTTON_REPEAT:
553 *(setting) += step;
554 has_changed = true;
555 if (*(setting) > max)
556 *(setting) = max;
557 break;
558
559 case EQ_BTN_PREV_BAND:
560 case EQ_BTN_PREV_BAND | BUTTON_REPEAT:
561 current_band--;
562 if (current_band < 0)
563 current_band = 4; /* wrap around */
564 break;
565
566 case EQ_BTN_NEXT_BAND:
567 case EQ_BTN_NEXT_BAND | BUTTON_REPEAT:
568 current_band++;
569 if (current_band > 4)
570 current_band = 0; /* wrap around */
571 break;
572
573 case EQ_BTN_CHANGE_MODE:
574 case EQ_BTN_CHANGE_MODE | BUTTON_REPEAT:
575 mode++;
576 if (mode > Q)
577 mode = GAIN; /* wrap around */
578 break;
579
580 case EQ_BTN_EXIT:
581 case EQ_BTN_EXIT | BUTTON_REPEAT:
582 exit_request = true;
583 result = false;
584 break;
585
586 default:
587 if(default_event_handler(button) == SYS_USB_CONNECTED) {
588 exit_request = true;
589 result = true;
590 }
591 break;
592 }
593
594 /* Update the filter if the user changed something */
595 if (has_changed)
596 dsp_eq_update_data(global_settings.eq_enabled);
597 }
598
599 /* Reset screen settings */
600 screens[SCREEN_MAIN].setfont(FONT_UI);
601 screens[SCREEN_MAIN].clear_display();
602
603 return result;
604}
605
606/* Preset saver.
607 * TODO: Can the settings system be used to do this instead?
608 */
609static bool eq_save_preset(void)
610{
611 int fd, i;
612 char filename[MAX_PATH];
613 int *setting;
614
615 create_numbered_filename(filename, EQS_DIR, "eq", ".cfg", 2);
616
617 /* allow user to modify filename */
618 while (true) {
619 if (!kbd_input(filename, sizeof filename)) {
620 fd = creat(filename,0);
621 if (fd < 0)
622 gui_syncsplash(HZ, true, str(LANG_FAILED));
623 else
624 break;
625 }
626 else {
627 gui_syncsplash(HZ, true, str(LANG_RESET_DONE_CANCEL));
628 return false;
629 }
630 }
631
632 /* TODO: Should we really do this? */
633 fdprintf(fd, "eq enabled: yes\r\n");
634
635 setting = &global_settings.eq_band0_cutoff;
636
637 for(i = 0; i < 5; ++i) {
638 fdprintf(fd, "eq band %d cutoff: %d\r\n", i, *setting++);
639 fdprintf(fd, "eq band %d q: %d\r\n", i, *setting++);
640 fdprintf(fd, "eq band %d gain: %d\r\n", i, *setting++);
641 }
642
643 close(fd);
644
645 gui_syncsplash(HZ, true, (unsigned char *)"%s %s", str(LANG_SETTINGS_SAVED1),
646 str(LANG_SETTINGS_SAVED2));
647
648 return true;
649}
650
651/* Allows browsing of preset files */
652bool eq_browse_presets(void)
653{
654 return rockbox_browse(EQS_DIR, SHOW_CFG);
655}
656
657/* Full equalizer menu */
658bool eq_menu(void)
659{
660 int m;
661 bool result;
662 static const struct menu_item items[] = {
663 { ID2P(LANG_EQUALIZER_ENABLED), eq_enabled },
664 { ID2P(LANG_EQUALIZER_GRAPHICAL), eq_menu_graphical },
665 { ID2P(LANG_EQUALIZER_GAIN), eq_gain_menu },
666 { ID2P(LANG_EQUALIZER_ADVANCED), eq_advanced_menu },
667 { ID2P(LANG_EQUALIZER_SAVE), eq_save_preset },
668 { ID2P(LANG_EQUALIZER_BROWSE), eq_browse_presets },
669 };
670
671 m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
672 NULL, NULL, NULL);
673 result = menu_run(m);
674 menu_exit(m);
675
676 return result;
677}
678
diff --git a/apps/eq_menu.h b/apps/eq_menu.h
new file mode 100644
index 0000000000..a22c1e51b8
--- /dev/null
+++ b/apps/eq_menu.h
@@ -0,0 +1,28 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 Dan Everton
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef _EQ_MENU_H
20#define _EQ_MENU_H
21
22#include "menu.h"
23
24bool eq_browse_presets(void);
25bool eq_menu_graphical(void);
26bool eq_menu(void);
27
28#endif
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index c3d458e84c..fa02e06016 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3610,3 +3610,94 @@ desc: prompt shown when about to erase a modified dynamic playlist
3610eng: "Erase dynamic playlist?" 3610eng: "Erase dynamic playlist?"
3611voice "" 3611voice ""
3612new: 3612new:
3613
3614id: LANG_EQUALIZER
3615desc: in the sound settings menu
3616eng: "Equalizer"
3617voice: "Equalizer"
3618new:
3619
3620id: LANG_EQUALIZER_ENABLED
3621desc: in the equalizer settings menu
3622eng: "Enable EQ"
3623voice: "Enable EQ"
3624new:
3625
3626id: LANG_EQUALIZER_GRAPHICAL
3627desc: in the equalizer settings menu
3628eng: "Graphical EQ"
3629voice: "Graphical EQ"
3630new:
3631
3632id: LANG_EQUALIZER_GAIN
3633desc: in the equalizer settings menu
3634eng: "Simple EQ Settings"
3635voice: "Simple EQ Settings"
3636new:
3637
3638id: LANG_EQUALIZER_ADVANCED
3639desc: in the equalizer settings menu
3640eng: "Advanced EQ Settings"
3641voice: "Advanced EQ Settings"
3642new:
3643
3644id: LANG_EQUALIZER_SAVE
3645desc: in the equalizer settings menu
3646eng: "Save EQ Preset"
3647voice: "Save EQ Preset"
3648new:
3649
3650id: LANG_EQUALIZER_BROWSE
3651desc: in the equalizer settings menu
3652eng: "Browse EQ Presets"
3653voice: "Browse EQ Presets"
3654new:
3655
3656id: LANG_EQUALIZER_GAIN_ITEM
3657desc: in the equalizer settings menu
3658eng: "%d Hz Band Gain"
3659voice: ""
3660new:
3661
3662id: LANG_EQUALIZER_BAND_CUTOFF
3663desc: in the equalizer settings menu
3664eng: "Cutoff"
3665voice: "Cutoff"
3666new:
3667
3668id: LANG_EQUALIZER_BAND_Q
3669desc: in the equalizer settings menu
3670eng: "Q"
3671voice: "Q"
3672new:
3673
3674id: LANG_EQUALIZER_BAND_GAIN
3675desc: in the equalizer settings menu
3676eng: "Gain"
3677voice: "Gain"
3678new:
3679
3680id: LANG_EQUALIZER_EDIT_MODE
3681desc: in the equalizer settings menu
3682eng: "Edit mode: %s"
3683voice: ""
3684new:
3685
3686id: LANG_EQUALIZER_BAND_LOW_SHELF
3687desc: in the equalizer settings menu
3688eng: "Low Shelf Filter"
3689voice: ""
3690new:
3691
3692id: LANG_EQUALIZER_BAND_PEAK
3693desc: in the equalizer settings menu
3694eng: "Peak Filter %d"
3695voice: ""
3696new:
3697
3698id: LANG_EQUALIZER_BAND_HIGH_SHELF
3699desc: in the equalizer settings menu
3700eng: "High Shelf Filter"
3701voice: ""
3702new:
3703
diff --git a/apps/onplay.c b/apps/onplay.c
index 17b4d1591b..9b94be0959 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -58,6 +58,9 @@
58#include "main_menu.h" 58#include "main_menu.h"
59#include "sound_menu.h" 59#include "sound_menu.h"
60#include "database.h" 60#include "database.h"
61#if CONFIG_CODEC == SWCODEC
62#include "eq_menu.h"
63#endif
61 64
62static int context; 65static int context;
63static char* selected_file = NULL; 66static char* selected_file = NULL;
@@ -537,7 +540,11 @@ static int onplay_callback(int key, int menu)
537 540
538int onplay(char* file, int attr, int from) 541int onplay(char* file, int attr, int from)
539{ 542{
540 struct menu_item items[8]; /* increase this if you add entries! */ 543#if CONFIG_CODEC == SWCODEC
544 struct menu_item items[10]; /* increase this if you add entries! */
545#else
546 struct menu_item items[8];
547#endif
541 int m, i=0, result; 548 int m, i=0, result;
542#ifdef HAVE_LCD_COLOR 549#ifdef HAVE_LCD_COLOR
543 char *suffix; 550 char *suffix;
@@ -641,6 +648,19 @@ int onplay(char* file, int attr, int from)
641 i++; 648 i++;
642 } 649 }
643 650
651#if CONFIG_CODEC == SWCODEC
652 /* Equalizer menu items */
653 if (context == CONTEXT_WPS)
654 {
655 items[i].desc = ID2P(LANG_EQUALIZER_GRAPHICAL);
656 items[i].function = eq_menu_graphical;
657 i++;
658 items[i].desc = ID2P(LANG_EQUALIZER_BROWSE);
659 items[i].function = eq_browse_presets;
660 i++;
661 }
662#endif
663
644 /* DIY menu handling, since we want to exit after selection */ 664 /* DIY menu handling, since we want to exit after selection */
645 if (i) 665 if (i)
646 { 666 {
diff --git a/apps/settings.c b/apps/settings.c
index d13f56891e..ea8c562a04 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -511,6 +511,28 @@ static const struct bit_entry hd_bits[] =
511 {1, S_O(warnon_erase_dynplaylist), false, 511 {1, S_O(warnon_erase_dynplaylist), false,
512 "warn when erasing dynamic playlist", off_on }, 512 "warn when erasing dynamic playlist", off_on },
513 513
514#if CONFIG_CODEC == SWCODEC
515 {1, S_O(eq_enabled), false, "eq enabled", off_on },
516 /* 0..32768 Hz */
517 {15, S_O(eq_band0_cutoff), 60, "eq band 0 cutoff", NULL },
518 {15, S_O(eq_band1_cutoff), 200, "eq band 1 cutoff", NULL },
519 {15, S_O(eq_band2_cutoff), 800, "eq band 2 cutoff", NULL },
520 {15, S_O(eq_band3_cutoff), 4000, "eq band 3 cutoff", NULL },
521 {15, S_O(eq_band4_cutoff), 12000, "eq band 4 cutoff", NULL },
522 /* 0..64 (or 0.0 to 6.4) */
523 {6, S_O(eq_band0_q), 7, "eq band 0 q", NULL },
524 {6, S_O(eq_band1_q), 10, "eq band 1 q", NULL },
525 {6, S_O(eq_band2_q), 10, "eq band 2 q", NULL },
526 {6, S_O(eq_band3_q), 10, "eq band 3 q", NULL },
527 {6, S_O(eq_band4_q), 7, "eq band 4 q", NULL },
528 /* -240..240 (or -24db to +24db) */
529 {9|SIGNED, S_O(eq_band0_gain), 0, "eq band 0 gain", NULL },
530 {9|SIGNED, S_O(eq_band1_gain), 0, "eq band 1 gain", NULL },
531 {9|SIGNED, S_O(eq_band2_gain), 0, "eq band 2 gain", NULL },
532 {9|SIGNED, S_O(eq_band3_gain), 0, "eq band 3 gain", NULL },
533 {9|SIGNED, S_O(eq_band4_gain), 0, "eq band 4 gain", NULL },
534#endif
535
514 /* If values are just added to the end, no need to bump the version. */ 536 /* If values are just added to the end, no need to bump the version. */
515 /* new stuff to be added at the end */ 537 /* new stuff to be added at the end */
516 538
@@ -1023,6 +1045,7 @@ void settings_apply(void)
1023 audio_set_crossfade(global_settings.crossfade); 1045 audio_set_crossfade(global_settings.crossfade);
1024 dsp_set_replaygain(true); 1046 dsp_set_replaygain(true);
1025 dsp_set_crossfeed(global_settings.crossfeed); 1047 dsp_set_crossfeed(global_settings.crossfeed);
1048 dsp_eq_update_data(global_settings.eq_enabled);
1026#endif 1049#endif
1027 1050
1028#ifdef HAVE_SPDIF_POWER 1051#ifdef HAVE_SPDIF_POWER
diff --git a/apps/settings.h b/apps/settings.h
index 3255f61ff3..6efaacbaf3 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -39,6 +39,7 @@
39#define PLUGIN_DIR ROCKBOX_DIR"/rocks" 39#define PLUGIN_DIR ROCKBOX_DIR"/rocks"
40#define BACKDROP_DIR ROCKBOX_DIR"/backdrops" 40#define BACKDROP_DIR ROCKBOX_DIR"/backdrops"
41#define REC_BASE_DIR "/recordings" 41#define REC_BASE_DIR "/recordings"
42#define EQS_DIR ROCKBOX_DIR "/eqs"
42 43
43#define MAX_FILENAME 20 44#define MAX_FILENAME 20
44 45
@@ -408,6 +409,39 @@ struct user_settings
408 int brightness; /* iriver h300: backlight PWM value: 2..15 409 int brightness; /* iriver h300: backlight PWM value: 2..15
409 (0 and 1 are black) */ 410 (0 and 1 are black) */
410#endif 411#endif
412
413#if CONFIG_CODEC == SWCODEC
414 bool eq_enabled; /* Enable equalizer */
415
416 /* Order is important here, must be cutoff, q, then gain for each band.
417 See dsp_eq_update_data in dsp.c for why. */
418
419 /* Band 0 settings */
420 int eq_band0_cutoff; /* Hz */
421 int eq_band0_q;
422 int eq_band0_gain; /* +/- dB */
423
424 /* Band 1 settings */
425 int eq_band1_cutoff; /* Hz */
426 int eq_band1_q;
427 int eq_band1_gain; /* +/- dB */
428
429 /* Band 2 settings */
430 int eq_band2_cutoff; /* Hz */
431 int eq_band2_q;
432 int eq_band2_gain; /* +/- dB */
433
434 /* Band 3 settings */
435 int eq_band3_cutoff; /* Hz */
436 int eq_band3_q;
437 int eq_band3_gain; /* +/- dB */
438
439 /* Band 4 settings */
440 int eq_band4_cutoff; /* Hz */
441 int eq_band4_q;
442 int eq_band4_gain; /* +/- dB */
443#endif
444
411#ifdef HAVE_LCD_COLOR 445#ifdef HAVE_LCD_COLOR
412 unsigned char backdrop_file[MAX_FILENAME+1]; /* backdrop bitmap file */ 446 unsigned char backdrop_file[MAX_FILENAME+1]; /* backdrop bitmap file */
413#endif 447#endif
diff --git a/apps/sound_menu.c b/apps/sound_menu.c
index e44aa68231..2bd0ff6e59 100644
--- a/apps/sound_menu.c
+++ b/apps/sound_menu.c
@@ -45,6 +45,7 @@
45#include "splash.h" 45#include "splash.h"
46#if CONFIG_CODEC == SWCODEC 46#if CONFIG_CODEC == SWCODEC
47#include "dsp.h" 47#include "dsp.h"
48#include "eq_menu.h"
48#endif 49#endif
49 50
50int selected_setting; /* Used by the callback */ 51int selected_setting; /* Used by the callback */
@@ -379,6 +380,7 @@ bool sound_menu(void)
379 { ID2P(LANG_STEREO_WIDTH), stereo_width }, 380 { ID2P(LANG_STEREO_WIDTH), stereo_width },
380#if CONFIG_CODEC == SWCODEC 381#if CONFIG_CODEC == SWCODEC
381 { ID2P(LANG_CROSSFEED), crossfeed }, 382 { ID2P(LANG_CROSSFEED), crossfeed },
383 { ID2P(LANG_EQUALIZER), eq_menu },
382#endif 384#endif
383#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) 385#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
384 { ID2P(LANG_LOUDNESS), loudness }, 386 { ID2P(LANG_LOUDNESS), loudness },
diff --git a/tools/buildzip.pl b/tools/buildzip.pl
index a9af7619db..fad73624ed 100755
--- a/tools/buildzip.pl
+++ b/tools/buildzip.pl
@@ -91,6 +91,7 @@ sub buildzip {
91 mkdir ".rockbox/wps", 0777; 91 mkdir ".rockbox/wps", 0777;
92 mkdir ".rockbox/themes", 0777; 92 mkdir ".rockbox/themes", 0777;
93 mkdir ".rockbox/backdrops", 0777; 93 mkdir ".rockbox/backdrops", 0777;
94 mkdir ".rockbox/eqs", 0777;
94 95
95 my $c = 'find apps -name "*.codec" ! -empty -exec cp {} .rockbox/codecs/ \;'; 96 my $c = 'find apps -name "*.codec" ! -empty -exec cp {} .rockbox/codecs/ \;';
96 print `$c`; 97 print `$c`;