Add Equalizer configuration to Sound Settings menu.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8606 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Dan Everton 2006-02-07 14:07:46 +00:00
parent 27f69db404
commit 88abdd97b2
12 changed files with 942 additions and 8 deletions

View file

@ -78,4 +78,5 @@ eq_cf.S
#elif defined(CPU_ARM) && !defined(SIMULATOR) #elif defined(CPU_ARM) && !defined(SIMULATOR)
eq_arm.S eq_arm.S
#endif #endif
eq_menu.c
#endif #endif

View file

@ -145,6 +145,7 @@ struct dsp_config
bool dither_enabled; bool dither_enabled;
bool new_gain; bool new_gain;
bool crossfeed_enabled; bool crossfeed_enabled;
bool eq_enabled;
}; };
struct resample_data struct resample_data
@ -618,6 +619,61 @@ static void apply_crossfeed(long* src[], int count)
} }
#endif #endif
#define EQ_CUTOFF_USER2REAL(x) (0xffffffff / NATIVE_FREQUENCY * (x))
#define EQ_Q_USER2REAL(x) (((x) << 16) / 10)
#define EQ_GAIN_USER2REAL(x) (((x) << 16) / 10)
/* Synchronize the EQ filters with the global settings */
void dsp_eq_update_data(bool enabled)
{
int i;
int *setting;
int gain, cutoff, q, maxgain;
dsp->eq_enabled = enabled;
setting = &global_settings.eq_band0_cutoff;
maxgain = 0;
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
/* set emac unit for dsp processing, and save old macsr, we're running in
codec thread context at this point, so can't clobber it */
unsigned long old_macsr = coldfire_get_macsr();
coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE);
#endif
/* Iterate over each band and update the appropriate filter */
for(i = 0; i < 5; i++) {
cutoff = *setting++;
q = *setting++;
gain = *setting++;
/* Keep track of maxgain for the pre-amp */
if (gain > maxgain)
maxgain = gain;
if (gain == 0) {
eq_data.enabled[i] = 0;
} else {
if (i == 0)
eq_ls_coefs(EQ_CUTOFF_USER2REAL(cutoff), EQ_Q_USER2REAL(q),
EQ_GAIN_USER2REAL(gain), eq_data.filters[0].coefs);
else if (i == 4)
eq_hs_coefs(EQ_CUTOFF_USER2REAL(cutoff), EQ_Q_USER2REAL(q),
EQ_GAIN_USER2REAL(gain), eq_data.filters[4].coefs);
else
eq_pk_coefs(EQ_CUTOFF_USER2REAL(cutoff), EQ_Q_USER2REAL(q),
EQ_GAIN_USER2REAL(gain), eq_data.filters[i].coefs);
eq_data.enabled[i] = 1;
}
}
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
/* set old macsr again */
coldfire_set_macsr(old_macsr);
#endif
}
/* Apply EQ filters to those bands that have got it switched on. */ /* Apply EQ filters to those bands that have got it switched on. */
static void eq_process(long **x, unsigned num) static void eq_process(long **x, unsigned num)
{ {
@ -745,9 +801,8 @@ long dsp_process(char* dst, char* src[], long size)
samples = resample(tmp, samples); samples = resample(tmp, samples);
if (dsp->crossfeed_enabled && dsp->stereo_mode != STEREO_MONO) if (dsp->crossfeed_enabled && dsp->stereo_mode != STEREO_MONO)
apply_crossfeed(tmp, samples); apply_crossfeed(tmp, samples);
/* TODO: Might want to wrap this with a generic eq_enabled when the if (dsp->eq_enabled)
settings are in place */ eq_process(tmp, samples);
eq_process(tmp, samples);
write_samples((short*) dst, tmp, samples); write_samples((short*) dst, tmp, samples);
written += samples; written += samples;
dst += samples * sizeof(short) * 2; dst += samples * sizeof(short) * 2;

View file

@ -54,6 +54,7 @@ int dsp_stereo_mode(void);
bool dsp_configure(int setting, void *value); bool dsp_configure(int setting, void *value);
void dsp_set_replaygain(bool always); void dsp_set_replaygain(bool always);
void dsp_set_crossfeed(bool enable); void dsp_set_crossfeed(bool enable);
void dsp_eq_update_data(bool enabled);
void sound_set_pitch(int r); void sound_set_pitch(int r);
int sound_get_pitch(void); int sound_get_pitch(void);
#endif #endif

View file

@ -32,11 +32,11 @@
*/ */
#define DIV64(x, y, z) (long)(((long long)(x) << (z))/(y)) #define DIV64(x, y, z) (long)(((long long)(x) << (z))/(y))
/* TODO: This macro requires the EMAC unit to be in fractional mode /* This macro requires the EMAC unit to be in fractional mode
when the coef generator routines are called. If this can be guaranteeed, when the coef generator routines are called. If this can't be guaranteeed,
then remove the "&& 0" below for faster coef calculation on Coldfire. then add "&& 0" below. This will use a slower coef calculation on Coldfire.
*/ */
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR) && 0 #if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
#define FRACMUL(x, y) \ #define FRACMUL(x, y) \
({ \ ({ \
long t; \ long t; \

678
apps/eq_menu.c Normal file
View file

@ -0,0 +1,678 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006 Dan Everton
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "eq_menu.h"
#include "system.h"
#include "kernel.h"
#include "lcd.h"
#include "menu.h"
#include "button.h"
#include "mp3_playback.h"
#include "settings.h"
#include "statusbar.h"
#include "screens.h"
#include "icons.h"
#include "font.h"
#include "widgets.h"
#include "lang.h"
#include "sprintf.h"
#include "talk.h"
#include "misc.h"
#include "sound.h"
#include "splash.h"
#include "dsp.h"
#include "tree.h"
#include "talk.h"
#include "screen_access.h"
#include "keyboard.h"
/* Key definitions */
#if (CONFIG_KEYPAD == IRIVER_H100_PAD || \
CONFIG_KEYPAD == IRIVER_H300_PAD)
#define EQ_BTN_NEXT_BAND BUTTON_DOWN
#define EQ_BTN_PREV_BAND BUTTON_UP
#define EQ_BTN_CHANGE_MODE BUTTON_SELECT
#define EQ_BTN_EXIT BUTTON_OFF
#elif (CONFIG_KEYPAD == IPOD_4G_PAD)
#define EQ_BTN_NEXT_BAND BUTTON_SCROLL_FWD
#define EQ_BTN_PREV_BAND BUTTON_SCROLL_BACK
#define EQ_BTN_CHANGE_MODE BUTTON_SELECT
#define EQ_BTN_EXIT BUTTON_MENU
#endif
#define EQ_CUTOFF_MIN 20
#define EQ_CUTOFF_MAX 22040
#define EQ_CUTOFF_STEP 10
#define EQ_GAIN_MIN (-240)
#define EQ_GAIN_MAX 240
#define EQ_GAIN_STEP 1
#define EQ_Q_MIN 5
#define EQ_Q_MAX 64
#define EQ_Q_STEP 1
#define EQ_USER_DIVISOR 10
static bool eq_enabled(void)
{
bool result = set_bool(str(LANG_EQUALIZER_ENABLED),
&global_settings.eq_enabled);
dsp_eq_update_data(global_settings.eq_enabled);
return result;
}
static void eq_gain_format(char* buffer, int buffer_size, int value, const char* unit)
{
int v = abs(value);
snprintf(buffer, buffer_size, "%s%d.%d %s", value < 0 ? "-" : "",
v / EQ_USER_DIVISOR, v % EQ_USER_DIVISOR, unit);
}
static void eq_q_format(char* buffer, int buffer_size, int value, const char* unit)
{
snprintf(buffer, buffer_size, "%d.%d %s", value / EQ_USER_DIVISOR, value % EQ_USER_DIVISOR, unit);
}
/* Possibly dodgy way of simplifying the code a bit. */
#define eq_make_gain_label(buf, bufsize, frequency) snprintf((buf), \
(bufsize), str(LANG_EQUALIZER_GAIN_ITEM), (frequency))
#define eq_set_cutoff(band) \
static bool eq_set_band ## band ## _cutoff(void) \
{ \
bool result = set_int(str(LANG_EQUALIZER_BAND_CUTOFF), "Hertz", UNIT_HERTZ, \
&global_settings.eq_band ## band ## _cutoff, NULL, \
EQ_CUTOFF_STEP, EQ_CUTOFF_MIN, EQ_CUTOFF_MAX, NULL); \
dsp_eq_update_data(global_settings.eq_enabled); \
return result; \
}
#define eq_set_q(band) \
static bool eq_set_band ## band ## _q(void) \
{ \
bool result = set_int(str(LANG_EQUALIZER_BAND_Q), "Q", UNIT_INT, \
&global_settings.eq_band ## band ## _q, NULL, \
EQ_Q_STEP, EQ_Q_MIN, EQ_Q_MAX, eq_q_format); \
dsp_eq_update_data(global_settings.eq_enabled); \
return result; \
}
#define eq_set_gain(band) \
static bool eq_set_band ## band ## _gain(void) \
{ \
bool result = set_int("Band " #band, str(LANG_UNIT_DB), UNIT_DB, \
&global_settings.eq_band ## band ## _gain, NULL, \
EQ_GAIN_STEP, EQ_GAIN_MIN, EQ_GAIN_MAX, eq_gain_format); \
dsp_eq_update_data(global_settings.eq_enabled); \
return result; \
}
eq_set_cutoff(0);
eq_set_cutoff(1);
eq_set_cutoff(2);
eq_set_cutoff(3);
eq_set_cutoff(4);
eq_set_q(0);
eq_set_q(1);
eq_set_q(2);
eq_set_q(3);
eq_set_q(4);
eq_set_gain(0);
eq_set_gain(1);
eq_set_gain(2);
eq_set_gain(3);
eq_set_gain(4);
static bool eq_gain_menu(void)
{
int m, i;
int *setting;
bool result;
char gain_label[5][24];
static struct menu_item items[5] = {
{ NULL, eq_set_band0_gain },
{ NULL, eq_set_band1_gain },
{ NULL, eq_set_band2_gain },
{ NULL, eq_set_band3_gain },
{ NULL, eq_set_band4_gain },
};
setting = &global_settings.eq_band0_cutoff;
/* Construct menu labels */
for(i = 0; i < 5; i++) {
eq_make_gain_label(gain_label[i], sizeof(gain_label[i]),
*setting);
items[i].desc = gain_label[i];
/* Skip to next band */
setting += 3;
}
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
NULL, NULL, NULL);
result = menu_run(m);
menu_exit(m);
return result;
}
static bool eq_set_band0(void)
{
int m;
bool result;
static const struct menu_item items[] = {
{ ID2P(LANG_EQUALIZER_BAND_CUTOFF), eq_set_band0_cutoff },
{ ID2P(LANG_EQUALIZER_BAND_Q), eq_set_band0_q },
{ ID2P(LANG_EQUALIZER_BAND_GAIN), eq_set_band0_gain },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
NULL, NULL, NULL);
result = menu_run(m);
menu_exit(m);
return result;
}
static bool eq_set_band1(void)
{
int m;
bool result;
static const struct menu_item items[] = {
{ ID2P(LANG_EQUALIZER_BAND_CUTOFF), eq_set_band1_cutoff },
{ ID2P(LANG_EQUALIZER_BAND_Q), eq_set_band1_q },
{ ID2P(LANG_EQUALIZER_BAND_GAIN), eq_set_band1_gain },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
NULL, NULL, NULL);
result = menu_run(m);
menu_exit(m);
return result;
}
static bool eq_set_band2(void)
{
int m;
bool result;
static const struct menu_item items[] = {
{ ID2P(LANG_EQUALIZER_BAND_CUTOFF), eq_set_band2_cutoff },
{ ID2P(LANG_EQUALIZER_BAND_Q), eq_set_band2_q },
{ ID2P(LANG_EQUALIZER_BAND_GAIN), eq_set_band2_gain },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
NULL, NULL, NULL);
result = menu_run(m);
menu_exit(m);
return result;
}
static bool eq_set_band3(void)
{
int m;
bool result;
static const struct menu_item items[] = {
{ ID2P(LANG_EQUALIZER_BAND_CUTOFF), eq_set_band3_cutoff },
{ ID2P(LANG_EQUALIZER_BAND_Q), eq_set_band3_q },
{ ID2P(LANG_EQUALIZER_BAND_GAIN), eq_set_band3_gain },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
NULL, NULL, NULL);
result = menu_run(m);
menu_exit(m);
return result;
}
static bool eq_set_band4(void)
{
int m;
bool result;
static const struct menu_item items[] = {
{ ID2P(LANG_EQUALIZER_BAND_CUTOFF), eq_set_band4_cutoff },
{ ID2P(LANG_EQUALIZER_BAND_Q), eq_set_band4_q },
{ ID2P(LANG_EQUALIZER_BAND_GAIN), eq_set_band4_gain },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
NULL, NULL, NULL);
result = menu_run(m);
menu_exit(m);
return result;
}
static bool eq_advanced_menu(void)
{
int m, i;
bool result;
char peak_band_label[3][32];
static struct menu_item items[] = {
{ ID2P(LANG_EQUALIZER_BAND_LOW_SHELF), eq_set_band0 },
{ NULL, eq_set_band1 },
{ NULL, eq_set_band2 },
{ NULL, eq_set_band3 },
{ ID2P(LANG_EQUALIZER_BAND_HIGH_SHELF), eq_set_band4 },
};
/* Construct menu labels */
for(i = 1; i < 4; i++) {
snprintf(peak_band_label[i-1], sizeof(peak_band_label[i-1]),
str(LANG_EQUALIZER_BAND_PEAK), i);
items[i].desc = peak_band_label[i-1];
}
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
NULL, NULL, NULL);
result = menu_run(m);
menu_exit(m);
return result;
}
#define SLIDER_KNOB_HEIGHT 6
#define SLIDER_KNOB_WIDTH 4
enum eq_slider_mode {
GAIN,
CUTOFF,
Q,
};
enum eq_type {
LOW_SHELF,
PEAK,
HIGH_SHELF
};
/* Draw a slider */
static void draw_slider(const struct screen * screen, int x, int y,
int width, int steps, int current_step)
{
int knob_x = (width / steps) * current_step + (SLIDER_KNOB_WIDTH / 2);
/* Draw groove */
screen->fillrect(x, y + 2, width, 2);
/* Draw knob */
screen->fillrect(x + knob_x, y, SLIDER_KNOB_WIDTH, SLIDER_KNOB_HEIGHT);
}
/* Draw the UI for a whole EQ band */
static int draw_eq_slider(const struct screen * screen, int x, int y,
int width, int cutoff, int q, int gain, bool selected,
enum eq_slider_mode mode, enum eq_type type)
{
char buf[26];
const char separator[2] = " ";
int steps = (abs(EQ_GAIN_MIN) + abs(EQ_GAIN_MAX)) / EQ_USER_DIVISOR;
int abs_q = abs(q);
int abs_gain = abs(gain);
int current_x, total_height, separator_width, separator_height;
int w, h;
/* Start two pixels in, one for border, one for margin */
current_x = x + 2;
/* Figure out how large our separator string is */
screen->getstringsize(separator, &separator_width, &separator_height);
/* Total height includes margins, text, and line selector */
total_height = separator_height + SLIDER_KNOB_HEIGHT + 2 + 3;
/* Print out the band label */
if (type == LOW_SHELF) {
screen->putsxy(current_x, y + 2, "LS:");
screen->getstringsize("LS:", &w, &h);
} else if (type == HIGH_SHELF) {
screen->putsxy(current_x, y + 2, "HS:");
screen->getstringsize("HS:", &w, &h);
} else {
screen->putsxy(current_x, y + 2, "PK:");
screen->getstringsize("PK:", &w, &h);
}
current_x += w;
/* Print separator */
screen->set_drawmode(DRMODE_SOLID);
screen->putsxy(current_x, y + 2, separator);
current_x += separator_width;
/* Print out gain part of status line */
snprintf(buf, sizeof(buf), "%s%2d.%ddB", gain < 0 ? "-" : " ",
abs_gain / EQ_USER_DIVISOR, abs_gain % EQ_USER_DIVISOR);
if (mode == GAIN && selected)
screen->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
screen->putsxy(current_x, y + 2, buf);
screen->getstringsize(buf, &w, &h);
current_x += w;
/* Print separator */
screen->set_drawmode(DRMODE_SOLID);
screen->putsxy(current_x, y + 2, separator);
current_x += separator_width;
/* Print out cutoff part of status line */
snprintf(buf, sizeof(buf), "%5dHz", cutoff);
if (mode == CUTOFF && selected)
screen->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
screen->putsxy(current_x, y + 2, buf);
screen->getstringsize(buf, &w, &h);
current_x += w;
/* Print separator */
screen->set_drawmode(DRMODE_SOLID);
screen->putsxy(current_x, y + 2, separator);
current_x += separator_width;
/* Print out Q part of status line */
snprintf(buf, sizeof(buf), "%d.%d Q", abs_q / EQ_USER_DIVISOR,
abs_q % EQ_USER_DIVISOR);
if (mode == Q && selected)
screen->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
screen->putsxy(current_x, y + 2, buf);
screen->getstringsize(buf, &w, &h);
current_x += w;
screen->set_drawmode(DRMODE_SOLID);
/* Draw selection box */
if (selected) {
screen->drawrect(x, y, width, total_height);
}
/* Draw horizontal slider */
draw_slider(screen, x + 3, y + h + 3, width - 6, steps,
(EQ_GAIN_MAX + gain) / EQ_USER_DIVISOR);
return total_height;
}
/* Draw's all the EQ sliders. Returns the total height of the sliders drawn */
static int draw_eq_sliders(int current_band, enum eq_slider_mode mode)
{
int i, gain, q, cutoff;
int height = 2; /* Two pixel margin */
int slider_width = screens[SCREEN_MAIN].width - 4; /* two pixel margin on each side */
int *setting = &global_settings.eq_band0_cutoff;
enum eq_type type;
for( i = 0; i < 5; ++i)
{
cutoff = *setting++;
q = *setting++;
gain = *setting++;
if (i == 0) {
type = LOW_SHELF;
} else if (i == 4) {
type = HIGH_SHELF;
} else {
type = PEAK;
}
height += draw_eq_slider(&(screens[SCREEN_MAIN]), 2, height,
slider_width, cutoff, q, gain, i == current_band, mode, type);
/* add a margin */
height += 2;
}
return height;
}
/* Provides a graphical means of editing the EQ settings */
bool eq_menu_graphical(void)
{
bool exit_request = false;
bool result = true;
bool has_changed = false;
int button;
int *setting;
int current_band, y, step, min, max, voice_unit;
enum eq_slider_mode mode;
enum eq_type current_type;
char buf[24];
screens[SCREEN_MAIN].setfont(FONT_SYSFIXED);
screens[SCREEN_MAIN].clear_display();
/* Start off editing gain on the first band */
mode = GAIN;
current_type = LOW_SHELF;
current_band = 0;
while (!exit_request) {
/* Clear the screen. The drawing routines expect this */
screens[SCREEN_MAIN].clear_display();
/* Draw equalizer band details */
y = draw_eq_sliders(current_band, mode);
/* Set pointer to the band data currently editable */
if (mode == GAIN) {
/* gain */
setting = &global_settings.eq_band0_gain;
setting += current_band * 3;
step = EQ_GAIN_STEP;
min = EQ_GAIN_MIN;
max = EQ_GAIN_MAX;
voice_unit = UNIT_DB;
snprintf(buf, sizeof(buf), str(LANG_EQUALIZER_EDIT_MODE),
str(LANG_EQUALIZER_BAND_GAIN));
screens[SCREEN_MAIN].putsxy(2, y, buf);
} else if (mode == CUTOFF) {
/* cutoff */
setting = &global_settings.eq_band0_cutoff;
setting += current_band * 3;
step = EQ_CUTOFF_STEP;
min = EQ_CUTOFF_MIN;
max = EQ_CUTOFF_MAX;
voice_unit = UNIT_HERTZ;
snprintf(buf, sizeof(buf), str(LANG_EQUALIZER_EDIT_MODE),
str(LANG_EQUALIZER_BAND_CUTOFF));
screens[SCREEN_MAIN].putsxy(2, y, buf);
} else {
/* Q */
setting = &global_settings.eq_band0_q;
setting += current_band * 3;
step = EQ_Q_STEP;
min = EQ_Q_MIN;
max = EQ_Q_MAX;
voice_unit = UNIT_INT;
snprintf(buf, sizeof(buf), str(LANG_EQUALIZER_EDIT_MODE),
str(LANG_EQUALIZER_BAND_Q));
screens[SCREEN_MAIN].putsxy(2, y, buf);
}
screens[SCREEN_MAIN].update();
button = button_get_w_tmo(HZ/10);
switch (button) {
case BUTTON_LEFT:
case BUTTON_LEFT | BUTTON_REPEAT:
*(setting) -= step;
has_changed = true;
if (*(setting) < min)
*(setting) = min;
break;
case BUTTON_RIGHT:
case BUTTON_RIGHT | BUTTON_REPEAT:
*(setting) += step;
has_changed = true;
if (*(setting) > max)
*(setting) = max;
break;
case EQ_BTN_PREV_BAND:
case EQ_BTN_PREV_BAND | BUTTON_REPEAT:
current_band--;
if (current_band < 0)
current_band = 4; /* wrap around */
break;
case EQ_BTN_NEXT_BAND:
case EQ_BTN_NEXT_BAND | BUTTON_REPEAT:
current_band++;
if (current_band > 4)
current_band = 0; /* wrap around */
break;
case EQ_BTN_CHANGE_MODE:
case EQ_BTN_CHANGE_MODE | BUTTON_REPEAT:
mode++;
if (mode > Q)
mode = GAIN; /* wrap around */
break;
case EQ_BTN_EXIT:
case EQ_BTN_EXIT | BUTTON_REPEAT:
exit_request = true;
result = false;
break;
default:
if(default_event_handler(button) == SYS_USB_CONNECTED) {
exit_request = true;
result = true;
}
break;
}
/* Update the filter if the user changed something */
if (has_changed)
dsp_eq_update_data(global_settings.eq_enabled);
}
/* Reset screen settings */
screens[SCREEN_MAIN].setfont(FONT_UI);
screens[SCREEN_MAIN].clear_display();
return result;
}
/* Preset saver.
* TODO: Can the settings system be used to do this instead?
*/
static bool eq_save_preset(void)
{
int fd, i;
char filename[MAX_PATH];
int *setting;
create_numbered_filename(filename, EQS_DIR, "eq", ".cfg", 2);
/* allow user to modify filename */
while (true) {
if (!kbd_input(filename, sizeof filename)) {
fd = creat(filename,0);
if (fd < 0)
gui_syncsplash(HZ, true, str(LANG_FAILED));
else
break;
}
else {
gui_syncsplash(HZ, true, str(LANG_RESET_DONE_CANCEL));
return false;
}
}
/* TODO: Should we really do this? */
fdprintf(fd, "eq enabled: yes\r\n");
setting = &global_settings.eq_band0_cutoff;
for(i = 0; i < 5; ++i) {
fdprintf(fd, "eq band %d cutoff: %d\r\n", i, *setting++);
fdprintf(fd, "eq band %d q: %d\r\n", i, *setting++);
fdprintf(fd, "eq band %d gain: %d\r\n", i, *setting++);
}
close(fd);
gui_syncsplash(HZ, true, (unsigned char *)"%s %s", str(LANG_SETTINGS_SAVED1),
str(LANG_SETTINGS_SAVED2));
return true;
}
/* Allows browsing of preset files */
bool eq_browse_presets(void)
{
return rockbox_browse(EQS_DIR, SHOW_CFG);
}
/* Full equalizer menu */
bool eq_menu(void)
{
int m;
bool result;
static const struct menu_item items[] = {
{ ID2P(LANG_EQUALIZER_ENABLED), eq_enabled },
{ ID2P(LANG_EQUALIZER_GRAPHICAL), eq_menu_graphical },
{ ID2P(LANG_EQUALIZER_GAIN), eq_gain_menu },
{ ID2P(LANG_EQUALIZER_ADVANCED), eq_advanced_menu },
{ ID2P(LANG_EQUALIZER_SAVE), eq_save_preset },
{ ID2P(LANG_EQUALIZER_BROWSE), eq_browse_presets },
};
m=menu_init( items, sizeof(items) / sizeof(*items), NULL,
NULL, NULL, NULL);
result = menu_run(m);
menu_exit(m);
return result;
}

28
apps/eq_menu.h Normal file
View file

@ -0,0 +1,28 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006 Dan Everton
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _EQ_MENU_H
#define _EQ_MENU_H
#include "menu.h"
bool eq_browse_presets(void);
bool eq_menu_graphical(void);
bool eq_menu(void);
#endif

View file

@ -3610,3 +3610,94 @@ desc: prompt shown when about to erase a modified dynamic playlist
eng: "Erase dynamic playlist?" eng: "Erase dynamic playlist?"
voice "" voice ""
new: new:
id: LANG_EQUALIZER
desc: in the sound settings menu
eng: "Equalizer"
voice: "Equalizer"
new:
id: LANG_EQUALIZER_ENABLED
desc: in the equalizer settings menu
eng: "Enable EQ"
voice: "Enable EQ"
new:
id: LANG_EQUALIZER_GRAPHICAL
desc: in the equalizer settings menu
eng: "Graphical EQ"
voice: "Graphical EQ"
new:
id: LANG_EQUALIZER_GAIN
desc: in the equalizer settings menu
eng: "Simple EQ Settings"
voice: "Simple EQ Settings"
new:
id: LANG_EQUALIZER_ADVANCED
desc: in the equalizer settings menu
eng: "Advanced EQ Settings"
voice: "Advanced EQ Settings"
new:
id: LANG_EQUALIZER_SAVE
desc: in the equalizer settings menu
eng: "Save EQ Preset"
voice: "Save EQ Preset"
new:
id: LANG_EQUALIZER_BROWSE
desc: in the equalizer settings menu
eng: "Browse EQ Presets"
voice: "Browse EQ Presets"
new:
id: LANG_EQUALIZER_GAIN_ITEM
desc: in the equalizer settings menu
eng: "%d Hz Band Gain"
voice: ""
new:
id: LANG_EQUALIZER_BAND_CUTOFF
desc: in the equalizer settings menu
eng: "Cutoff"
voice: "Cutoff"
new:
id: LANG_EQUALIZER_BAND_Q
desc: in the equalizer settings menu
eng: "Q"
voice: "Q"
new:
id: LANG_EQUALIZER_BAND_GAIN
desc: in the equalizer settings menu
eng: "Gain"
voice: "Gain"
new:
id: LANG_EQUALIZER_EDIT_MODE
desc: in the equalizer settings menu
eng: "Edit mode: %s"
voice: ""
new:
id: LANG_EQUALIZER_BAND_LOW_SHELF
desc: in the equalizer settings menu
eng: "Low Shelf Filter"
voice: ""
new:
id: LANG_EQUALIZER_BAND_PEAK
desc: in the equalizer settings menu
eng: "Peak Filter %d"
voice: ""
new:
id: LANG_EQUALIZER_BAND_HIGH_SHELF
desc: in the equalizer settings menu
eng: "High Shelf Filter"
voice: ""
new:

View file

@ -58,6 +58,9 @@
#include "main_menu.h" #include "main_menu.h"
#include "sound_menu.h" #include "sound_menu.h"
#include "database.h" #include "database.h"
#if CONFIG_CODEC == SWCODEC
#include "eq_menu.h"
#endif
static int context; static int context;
static char* selected_file = NULL; static char* selected_file = NULL;
@ -537,7 +540,11 @@ static int onplay_callback(int key, int menu)
int onplay(char* file, int attr, int from) int onplay(char* file, int attr, int from)
{ {
struct menu_item items[8]; /* increase this if you add entries! */ #if CONFIG_CODEC == SWCODEC
struct menu_item items[10]; /* increase this if you add entries! */
#else
struct menu_item items[8];
#endif
int m, i=0, result; int m, i=0, result;
#ifdef HAVE_LCD_COLOR #ifdef HAVE_LCD_COLOR
char *suffix; char *suffix;
@ -641,6 +648,19 @@ int onplay(char* file, int attr, int from)
i++; i++;
} }
#if CONFIG_CODEC == SWCODEC
/* Equalizer menu items */
if (context == CONTEXT_WPS)
{
items[i].desc = ID2P(LANG_EQUALIZER_GRAPHICAL);
items[i].function = eq_menu_graphical;
i++;
items[i].desc = ID2P(LANG_EQUALIZER_BROWSE);
items[i].function = eq_browse_presets;
i++;
}
#endif
/* DIY menu handling, since we want to exit after selection */ /* DIY menu handling, since we want to exit after selection */
if (i) if (i)
{ {

View file

@ -511,6 +511,28 @@ static const struct bit_entry hd_bits[] =
{1, S_O(warnon_erase_dynplaylist), false, {1, S_O(warnon_erase_dynplaylist), false,
"warn when erasing dynamic playlist", off_on }, "warn when erasing dynamic playlist", off_on },
#if CONFIG_CODEC == SWCODEC
{1, S_O(eq_enabled), false, "eq enabled", off_on },
/* 0..32768 Hz */
{15, S_O(eq_band0_cutoff), 60, "eq band 0 cutoff", NULL },
{15, S_O(eq_band1_cutoff), 200, "eq band 1 cutoff", NULL },
{15, S_O(eq_band2_cutoff), 800, "eq band 2 cutoff", NULL },
{15, S_O(eq_band3_cutoff), 4000, "eq band 3 cutoff", NULL },
{15, S_O(eq_band4_cutoff), 12000, "eq band 4 cutoff", NULL },
/* 0..64 (or 0.0 to 6.4) */
{6, S_O(eq_band0_q), 7, "eq band 0 q", NULL },
{6, S_O(eq_band1_q), 10, "eq band 1 q", NULL },
{6, S_O(eq_band2_q), 10, "eq band 2 q", NULL },
{6, S_O(eq_band3_q), 10, "eq band 3 q", NULL },
{6, S_O(eq_band4_q), 7, "eq band 4 q", NULL },
/* -240..240 (or -24db to +24db) */
{9|SIGNED, S_O(eq_band0_gain), 0, "eq band 0 gain", NULL },
{9|SIGNED, S_O(eq_band1_gain), 0, "eq band 1 gain", NULL },
{9|SIGNED, S_O(eq_band2_gain), 0, "eq band 2 gain", NULL },
{9|SIGNED, S_O(eq_band3_gain), 0, "eq band 3 gain", NULL },
{9|SIGNED, S_O(eq_band4_gain), 0, "eq band 4 gain", NULL },
#endif
/* If values are just added to the end, no need to bump the version. */ /* If values are just added to the end, no need to bump the version. */
/* new stuff to be added at the end */ /* new stuff to be added at the end */
@ -1023,6 +1045,7 @@ void settings_apply(void)
audio_set_crossfade(global_settings.crossfade); audio_set_crossfade(global_settings.crossfade);
dsp_set_replaygain(true); dsp_set_replaygain(true);
dsp_set_crossfeed(global_settings.crossfeed); dsp_set_crossfeed(global_settings.crossfeed);
dsp_eq_update_data(global_settings.eq_enabled);
#endif #endif
#ifdef HAVE_SPDIF_POWER #ifdef HAVE_SPDIF_POWER

View file

@ -39,6 +39,7 @@
#define PLUGIN_DIR ROCKBOX_DIR"/rocks" #define PLUGIN_DIR ROCKBOX_DIR"/rocks"
#define BACKDROP_DIR ROCKBOX_DIR"/backdrops" #define BACKDROP_DIR ROCKBOX_DIR"/backdrops"
#define REC_BASE_DIR "/recordings" #define REC_BASE_DIR "/recordings"
#define EQS_DIR ROCKBOX_DIR "/eqs"
#define MAX_FILENAME 20 #define MAX_FILENAME 20
@ -408,6 +409,39 @@ struct user_settings
int brightness; /* iriver h300: backlight PWM value: 2..15 int brightness; /* iriver h300: backlight PWM value: 2..15
(0 and 1 are black) */ (0 and 1 are black) */
#endif #endif
#if CONFIG_CODEC == SWCODEC
bool eq_enabled; /* Enable equalizer */
/* Order is important here, must be cutoff, q, then gain for each band.
See dsp_eq_update_data in dsp.c for why. */
/* Band 0 settings */
int eq_band0_cutoff; /* Hz */
int eq_band0_q;
int eq_band0_gain; /* +/- dB */
/* Band 1 settings */
int eq_band1_cutoff; /* Hz */
int eq_band1_q;
int eq_band1_gain; /* +/- dB */
/* Band 2 settings */
int eq_band2_cutoff; /* Hz */
int eq_band2_q;
int eq_band2_gain; /* +/- dB */
/* Band 3 settings */
int eq_band3_cutoff; /* Hz */
int eq_band3_q;
int eq_band3_gain; /* +/- dB */
/* Band 4 settings */
int eq_band4_cutoff; /* Hz */
int eq_band4_q;
int eq_band4_gain; /* +/- dB */
#endif
#ifdef HAVE_LCD_COLOR #ifdef HAVE_LCD_COLOR
unsigned char backdrop_file[MAX_FILENAME+1]; /* backdrop bitmap file */ unsigned char backdrop_file[MAX_FILENAME+1]; /* backdrop bitmap file */
#endif #endif

View file

@ -45,6 +45,7 @@
#include "splash.h" #include "splash.h"
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
#include "dsp.h" #include "dsp.h"
#include "eq_menu.h"
#endif #endif
int selected_setting; /* Used by the callback */ int selected_setting; /* Used by the callback */
@ -379,6 +380,7 @@ bool sound_menu(void)
{ ID2P(LANG_STEREO_WIDTH), stereo_width }, { ID2P(LANG_STEREO_WIDTH), stereo_width },
#if CONFIG_CODEC == SWCODEC #if CONFIG_CODEC == SWCODEC
{ ID2P(LANG_CROSSFEED), crossfeed }, { ID2P(LANG_CROSSFEED), crossfeed },
{ ID2P(LANG_EQUALIZER), eq_menu },
#endif #endif
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
{ ID2P(LANG_LOUDNESS), loudness }, { ID2P(LANG_LOUDNESS), loudness },

View file

@ -91,6 +91,7 @@ sub buildzip {
mkdir ".rockbox/wps", 0777; mkdir ".rockbox/wps", 0777;
mkdir ".rockbox/themes", 0777; mkdir ".rockbox/themes", 0777;
mkdir ".rockbox/backdrops", 0777; mkdir ".rockbox/backdrops", 0777;
mkdir ".rockbox/eqs", 0777;
my $c = 'find apps -name "*.codec" ! -empty -exec cp {} .rockbox/codecs/ \;'; my $c = 'find apps -name "*.codec" ! -empty -exec cp {} .rockbox/codecs/ \;';
print `$c`; print `$c`;