New crossfeed complete with no volume reducing bugs. Feedback on all the

new options is appreciated. Thanks to Dan Everton for the settings/GUI
code.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9609 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Thom Johansen 2006-04-11 13:49:05 +00:00
parent 6bd1f143fa
commit 8238b49c74
10 changed files with 298 additions and 154 deletions

View File

@ -47,15 +47,6 @@
#define RESAMPLE_BUF_SIZE (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/
#define DEFAULT_REPLAYGAIN 0x01000000
/* These are the constants for the filters in the crossfeed */
#define ATT 0x0CCCCCCDL /* 0.1 */
#define ATT_COMP 0x73333333L /* 0.9 */
#define LOW 0x4CCCCCCDL /* 0.6 */
#define LOW_COMP 0x33333333L /* 0.4 */
#define HIGH_NEG -0x66666666L /* -0.2 (not unsigned!) */
#define HIGH_COMP 0x66666666L /* 0.8 */
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
/* Multiply two S.31 fractional integers and return the sign bit and the
@ -209,10 +200,11 @@ struct dither_data
struct crossfeed_data
{
int32_t lowpass[2];
int32_t highpass[2];
int32_t delay[2][13];
int index;
int32_t gain; /* Direct path gain */
int32_t coefs[3]; /* Coefficients for the shelving filter */
int32_t history[4]; /* Format is x[n - 1], y[n - 1] for both channels */
int32_t delay[13][2];
int index; /* Current index into the delay line */
};
/* Current setup is one lowshelf filters, three peaking filters and one
@ -522,71 +514,71 @@ static long dither_sample(int32_t sample, int32_t bias, int32_t mask,
return output;
}
void dsp_set_crossfeed(bool enable)
{
dsp->crossfeed_enabled = enable;
}
void dsp_set_crossfeed_direct_gain(int gain)
{
/* Work around bug in get_replaygain_int which returns 0 for 0 dB */
if (gain == 0)
crossfeed_data.gain = 0x7fffffff;
else
crossfeed_data.gain = get_replaygain_int(gain * -10) << 7;
}
void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff)
{
long g1 = get_replaygain_int(lf_gain * -10) << 3;
long g2 = get_replaygain_int(hf_gain * -10) << 3;
filter_bishelf_coefs(0xffffffff/NATIVE_FREQUENCY*cutoff, g1, g2,
crossfeed_data.coefs);
}
/* Applies crossfeed to the stereo signal in src.
* Crossfeed is a process where listening over speakers is simulated. This
* is good for old hard panned stereo records, which might be quite fatiguing
* to listen to on headphones with no crossfeed.
*/
#ifndef DSP_HAVE_ASM_CROSSFEED
static void apply_crossfeed(int32_t* src[], int count)
void apply_crossfeed(int32_t* src[], int count)
{
int32_t a; /* accumulator */
int32_t low_left = crossfeed_data.lowpass[0];
int32_t low_right = crossfeed_data.lowpass[1];
int32_t high_left = crossfeed_data.highpass[0];
int32_t high_right = crossfeed_data.highpass[1];
unsigned int index = crossfeed_data.index;
int32_t *hist_l = &crossfeed_data.history[0];
int32_t *hist_r = &crossfeed_data.history[2];
int32_t *delay = &crossfeed_data.delay[0][0];
int32_t *coefs = &crossfeed_data.coefs[0];
int32_t gain = crossfeed_data.gain;
int di = crossfeed_data.index;
int32_t acc;
int32_t left, right;
int32_t* delay_l = crossfeed_data.delay[0];
int32_t* delay_r = crossfeed_data.delay[1];
int i;
for (i = 0; i < count; i++)
{
/* use a low-pass filter on the signal */
for (i = 0; i < count; i++) {
left = src[0][i];
right = src[1][i];
ACC_INIT(a, LOW, low_left); ACC(a, LOW_COMP, left);
low_left = GET_ACC(a);
ACC_INIT(a, LOW, low_right); ACC(a, LOW_COMP, right);
low_right = GET_ACC(a);
/* use a high-pass filter on the signal */
ACC_INIT(a, HIGH_NEG, high_left); ACC(a, HIGH_COMP, left);
high_left = GET_ACC(a);
ACC_INIT(a, HIGH_NEG, high_right); ACC(a, HIGH_COMP, right);
high_right = GET_ACC(a);
/* New data is the high-passed signal + delayed and attenuated
* low-passed signal from the other channel */
ACC_INIT(a, ATT, delay_r[index]); ACC(a, ATT_COMP, high_left);
src[0][i] = GET_ACC(a);
ACC_INIT(a, ATT, delay_l[index]); ACC(a, ATT_COMP, high_right);
src[1][i] = GET_ACC(a);
/* Store the low-passed signal in the ringbuffer */
delay_l[index] = low_left;
delay_r[index] = low_right;
index = (index + 1) % 13;
ACC_INIT(acc, delay[di*2], coefs[0]);
ACC(acc, hist_l[0], coefs[1]);
ACC(acc, hist_l[1], coefs[2]);
hist_l[1] = GET_ACC(acc) << 0;
hist_l[0] = delay[di*2];
ACC_INIT(acc, delay[di*2 + 1], coefs[0]);
ACC(acc, hist_r[0], coefs[1]);
ACC(acc, hist_r[1], coefs[2]);
hist_r[1] = GET_ACC(acc) << 0;
hist_r[0] = delay[di*2 + 1];
delay[di*2] = left;
delay[di*2 + 1] = right;
src[0][i] = FRACMUL(left, gain) + hist_r[1];
src[1][i] = FRACMUL(right, gain) + hist_l[1];
if (++di > 12)
di = 0;
}
crossfeed_data.index = index;
crossfeed_data.lowpass[0] = low_left;
crossfeed_data.lowpass[1] = low_right;
crossfeed_data.highpass[0] = high_left;
crossfeed_data.highpass[1] = high_right;
crossfeed_data.index = di;
}
#endif
@ -633,13 +625,8 @@ void dsp_set_eq_coefs(int band)
if (q == 0)
q = 1;
/* The coef functions assume the EMAC unit is in fractional mode */
#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 | EMAC_ROUND);
#endif
/* NOTE: The coef functions assume the EMAC unit is in fractional mode,
which it should be, since we're executed from the main thread. */
/* Assume a band is disabled if the gain is zero */
if (gain == 0) {
@ -654,11 +641,6 @@ void dsp_set_eq_coefs(int band)
eq_data.enabled[band] = 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. */
@ -1068,13 +1050,6 @@ bool dsp_configure(int setting, void *value)
return 1;
}
void dsp_set_crossfeed(bool enable)
{
if (enable)
memset(&crossfeed_data, 0, sizeof(crossfeed_data));
dsp->crossfeed_enabled = enable;
}
void dsp_set_replaygain(bool always)
{
dsp = &dsp_conf[current_codec];

View File

@ -54,6 +54,8 @@ int dsp_stereo_mode(void);
bool dsp_configure(int setting, void *value);
void dsp_set_replaygain(bool always);
void dsp_set_crossfeed(bool enable);
void dsp_set_crossfeed_direct_gain(int gain);
void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff);
void dsp_set_eq(bool enable);
void dsp_set_eq_precut(int precut);
void dsp_set_eq_coefs(int band);

View File

@ -17,15 +17,6 @@
*
****************************************************************************/
.section .idata,"aw",@progbits
crossfeed_coefs:
.long 0x4CCCCCCD | LOW
.long 0x33333333 | LOW_COMP
.long -0x66666666 | HIGH_NEG
.long 0x66666666 | HIGH_COMP
.long 0x0CCCCCCD | ATT
.long 0x73333333 | ATT_COMP
.section .text
.global apply_crossfeed
apply_crossfeed:
@ -36,68 +27,57 @@ apply_crossfeed:
move.l (44+8, %sp), %d7 | d7 = count
lea.l crossfeed_data, %a1
lea.l crossfeed_coefs, %a6
lea.l (16, %a1), %a0 | a0 = &delay[0][0]
movem.l (%a1), %d0-%d3 | fetch filter history samples
move.l (120, %a1), %d4 | fetch delay line index
move.l (%a4), %d5 | d5 = left sample
move.l (%a5), %d6 | d6 = right sample
move.l (%a6)+, %a1 | a1 = LOW value
move.l (%a6)+, %a2 | a2 = LOW_COMP value
lea.l (8*4, %a1), %a0 | a0 = &delay[0][0]
move.l (%a1)+, %a6 | a6 = direct gain
movem.l (3*4, %a1), %d0-%d3 | fetch filter history samples
move.l (33*4, %a1), %d4 | fetch delay line index
movem.l (%a1), %a1-%a3 | load filter coefs
move.l %d4, %d5
lsl.l #3, %d5
add.l %d5, %a0 | point a0 to current delay position
| lea.l (%d4*4, %a0), %a0
| lea.l (%d4*4, %a0), %a0 | point a0 to current delay position
/* Register usage in loop:
* a0 = &delay[0][0], a1 & a2 = coefs, a3 = temp storage,
* a4 = src[0], a5 = src[1], a6 = &crossfeed_coefs[0],
* d0 = low_left, d1 = low_right,
* d2 = high_left, d3 = high_right,
* a0 = &delay[index][0], a1..a3 = b0, b1, a1 (filter coefs),
* a4 = src[0], a5 = src[1], a6 = direct gain,
* d0..d3 = history
* d4 = delay line index,
* d5 = src[0][i], d6 = src[1][i].
* d5,d6 = temp.
* d7 = count
*/
.cfloop:
| LOW*low_left + LOW_COMP*left
mac.l %a1, %d0, %acc0
mac.l %a2, %d5, %acc0
| LOW*low_right + LOW_COMP*right
mac.l %a1, %d1, (%a6)+, %a1, %acc1 | a1 = HIGH_NEG
mac.l %a2, %d6, (%a6)+, %a2, %acc1 | a2 = HIGH_COMP
movclr.l %acc0, %d0 | get low_left
movclr.l %acc1, %d1 | get low_right
| HIGH_NEG*high_left + HIGH_COMP*left
mac.l %a1, %d2, %acc0
mac.l %a2, %d5, %acc0
| HIGH_NEG*high_right + HIGH_COMP*right
mac.l %a1, %d3, (%a6)+, %a1, %acc1 | a1 = ATT
mac.l %a2, %d6, (%a6)+, %a2, %acc1 | a2 = ATT_COMP
lea.l (-6*4, %a6), %a6 | coef = &coefs[0]
move.l (%a0, %d4*4), %a3 | a3 = delay[0][idx]
move.l (52, %a0, %d4*4), %d5 | d5 = delay[1][idx]
movclr.l %acc0, %d2 | get high_left
movclr.l %acc1, %d3 | get high_right
| ATT*delay_r + ATT_COMP*high_left
mac.l %a1, %d5, (4, %a4), %d5, %acc0 | d5 = src[0][i+1]
mac.l %a2, %d2, (4, %a5), %d6, %acc0 | d6 = src[1][i+1]
| ATT*delay_l + ATT_COMP*high_right
mac.l %a1, %a3, (%a6)+, %a1, %acc1 | a1 = LOW
mac.l %a2, %d3, (%a6)+, %a2, %acc1 | a2 = LOW_COMP
| save crossfed samples to output
movclr.l %acc0, %a3
move.l %a3, (%a4)+ | src[0][i++] = out_l
movclr.l %acc1, %a3
move.l %a3, (%a5)+ | src[1][i++] = out_r
move.l %d0, (%a0, %d4*4) | delay[0][index] = low_left
move.l %d1, (52, %a0, %d4*4) | delay[1][index] = low_right */
addq.l #1, %d4 | index++ */
cmp.l #13, %d4 | if (index >= 13) {
mac.l %a2, %d0, (4, %a0), %d0, %acc0 | acc = b1*dr[n - 1] d0 = dr[n]
mac.l %a1, %d0, %acc0 | acc += b0*dr[n]
mac.l %a3, %d1, (%a4), %d5, %acc0 | acc += a1*y_l[n - 1], load left input
move.l %acc0, %d1 | get filtered delayed sample
mac.l %a6, %d5, %acc0 | acc += gain*x_l[n]
movclr.l %acc0, %d6
move.l %d6, (%a4)+ | write result
mac.l %a2, %d2, (%a0), %d2, %acc0 | acc = b1*dl[n - 1], d2 = dl[n]
move.l %d5, (%a0)+ | save left input to delay line
mac.l %a1, %d2, %acc0 | acc += b0*dl[n]
mac.l %a3, %d3, (%a5), %d5, %acc0 | acc += a1*y_r[n - 1], load right input
move.l %acc0, %d3 | get filtered delayed sample
mac.l %a6, %d5, %acc0 | acc += gain*x_r[n]
move.l %d5, (%a0)+ | save right input to delay line
movclr.l %acc0, %d6
move.l %d6, (%a5)+ | write result
addq.l #1, %d4 | index++
moveq.l #13, %d6
cmp.l %d6, %d4 | wrap index to 0 if it overflows
jlt .nowrap
clr.l %d4 | index = 0
.nowrap: | }
moveq.l #13*8, %d4
sub.l %d4, %a0 | wrap back delay line ptr as well
clr.l %d4
.nowrap:
subq.l #1, %d7
jne .cfloop
| save data back to struct
lea.l crossfeed_data, %a1
lea.l crossfeed_data + 4*4, %a1
movem.l %d0-%d3, (%a1)
move.l %d4, (120, %a1)
move.l %d4, (30*4, %a1)
movem.l (%sp), %d2-%d7/%a2-%a6
lea.l (44, %sp), %sp
rts

View File

@ -187,6 +187,34 @@ static long dbtoA(long db)
return (dbtoatab[pos] << 16) + frac*diff;
}
/* Calculate first order shelving filter coefficients.
cutoff is a value from 0 to 0x80000000, where 0 represents 0 hz and
0x80000000 represents nyquist (samplerate/2).
ad is gain at 0 hz, and an is gain at Nyquist frequency. Both are s3.27
format.
c is a pointer where the coefs will be stored. The coefs are s0.31 format.
Note that the filter is not compatible with the eq_filter routine.
*/
void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c)
{
const long one = 1 << 27;
long a0, a1;
long b0, b1;
long s, cs;
s = fsincos(cutoff, &cs) >> 4;
cs = one + (cs >> 4);
/* For max A = 4 (24 dB) */
b0 = (FRACMUL(an, cs) << 4) + (FRACMUL(ad, s) << 4);
b1 = (FRACMUL(ad, s) << 4) - (FRACMUL(an, cs) << 4);
a0 = s + cs;
a1 = s - cs;
c[0] = DIV64(b0, a0, 31);
c[1] = DIV64(b1, a0, 31);
c[2] = -DIV64(a1, a0, 31);
}
/* Calculate second order section peaking filter coefficients.
cutoff is a value from 0 to 0x80000000, where 0 represents 0 hz and
0x80000000 represents nyquist (samplerate/2).

View File

@ -33,6 +33,7 @@ struct eqfilter {
int32_t history[2][4];
};
void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c);
void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
void eq_ls_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
void eq_hs_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);

View File

@ -8408,3 +8408,69 @@
*: "pixels"
</voice>
</phrase>
<phrase>
id: LANG_CROSSFEED_DIRECT_GAIN
desc: in crossfeed settings
user:
<source>
*: "Direct Gain"
</source>
<dest>
*: "Direct Gain"
</dest>
<voice>
*: "Direct gain"
</voice>
</phrase>
<phrase>
id: LANG_CROSSFEED_CROSS_GAIN
desc: in crossfeed settings
<source>
*: "Cross Gain"
</source>
<dest>
*: "Cross Gain"
</dest>
<voice>
*: "Cross gain"
</voice>
</phrase>
<phrase>
id: LANG_CROSSFEED_HF_ATTENUATION
desc: in crossfeed settings
<source>
*: "High-Frequency Attenuation"
</source>
<dest>
*: "High-Frequency Attenuation"
</dest>
<voice>
*: "High-frequency attenuation"
</voice>
</phrase>
<phrase>
id: LANG_CROSSFEED_HF_CUTOFF
desc: in crossfeed settings
<source>
*: "High-Frequency Cutoff"
</source>
<dest>
*: "High-Frequency Cutoff"
</dest>
<voice>
*: "High-frequency cutoff"
</voice>
</phrase>
<phrase>
id: LANG_UNIT_HERTZ
desc: in sound settings
<source>
*: "Hz"
</source>
<dest>
*: "Hz"
</dest>
<voice>
*: ""
</voice>
</phrase>

View File

@ -94,7 +94,7 @@ const char rec_base_directory[] = REC_BASE_DIR;
#include "dsp.h"
#endif
#define CONFIG_BLOCK_VERSION 39
#define CONFIG_BLOCK_VERSION 40
#define CONFIG_BLOCK_SIZE 512
#define RTC_BLOCK_SIZE 44
@ -488,6 +488,10 @@ static const struct bit_entry hd_bits[] =
{4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL},
{1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"},
{1, S_O(crossfeed), false, "crossfeed", off_on },
{6, S_O(crossfeed_direct_gain), 15, "crossfeed direct gain", NULL },
{7, S_O(crossfeed_cross_gain), 60, "crossfeed cross gain", NULL },
{8, S_O(crossfeed_hf_attenuation), 160, "crossfeed hf attenuation", NULL },
{11, S_O(crossfeed_hf_cutoff), 700, "crossfeed hf cutoff", NULL },
#endif
#ifdef HAVE_DIRCACHE
{1, S_O(dircache), false, "dircache", off_on },
@ -538,6 +542,7 @@ static const struct bit_entry hd_bits[] =
"warn when erasing dynamic playlist", off_on },
#if CONFIG_CODEC == SWCODEC
{1, S_O(eq_enabled), false, "eq enabled", off_on },
{8, S_O(eq_precut), 0, "eq precut", NULL },
/* 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 },
@ -579,10 +584,6 @@ static const struct bit_entry hd_bits[] =
{1, S_O(tagcache_ram), 0, "tagcache_ram", off_on },
#endif
#if (CONFIG_CODEC == SWCODEC)
{8, S_O(eq_precut), 0, "eq precut", NULL },
#endif
/* If values are just added to the end, no need to bump the version. */
/* new stuff to be added at the end */
@ -1159,6 +1160,11 @@ void settings_apply(void)
audio_set_crossfade(global_settings.crossfade);
dsp_set_replaygain(true);
dsp_set_crossfeed(global_settings.crossfeed);
dsp_set_crossfeed_direct_gain(global_settings.crossfeed_direct_gain);
dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain,
global_settings.crossfeed_cross_gain
+ global_settings.crossfeed_hf_attenuation,
global_settings.crossfeed_hf_cutoff);
dsp_set_eq(global_settings.eq_enabled);
dsp_set_eq_precut(global_settings.eq_precut);

View File

@ -417,7 +417,13 @@ struct user_settings
shuffle is on, album gain otherwise */
int replaygain_preamp; /* scale replaygained tracks by this */
int beep; /* system beep volume when changing tracks etc. */
bool crossfeed; /* enable crossfeed */
/* Crossfeed settings */
bool crossfeed; /* enable crossfeed */
unsigned int crossfeed_direct_gain; /* - dB x 10 */
unsigned int crossfeed_cross_gain; /* - dB x 10 */
unsigned int crossfeed_hf_attenuation; /* - dB x 10 */
unsigned int crossfeed_hf_cutoff; /* Frequency in Hz */
#endif
#ifdef HAVE_DIRCACHE
bool dircache; /* enable directory cache */

View File

@ -125,7 +125,14 @@ static bool treble(void)
#endif
#if CONFIG_CODEC == SWCODEC
static bool crossfeed(void)
static void crossfeed_format(char* buffer, int buffer_size, int value,
const char* unit)
{
snprintf(buffer, buffer_size, "%s%d.%d %s", value == 0 ? " " : "-",
value / 10, value % 10, unit);
}
static bool crossfeed_enabled(void)
{
bool result = set_bool_options(str(LANG_CROSSFEED),
&global_settings.crossfeed,
@ -134,6 +141,75 @@ static bool crossfeed(void)
NULL);
dsp_set_crossfeed(global_settings.crossfeed);
return result;
}
static bool crossfeed_direct_gain(void)
{
return set_int(str(LANG_CROSSFEED_DIRECT_GAIN), str(LANG_UNIT_DB),
UNIT_DB, &global_settings.crossfeed_direct_gain,
&dsp_set_crossfeed_direct_gain, 5, 0, 60, crossfeed_format);
}
static void crossfeed_cross_gain_helper(int val)
{
dsp_set_crossfeed_cross_params(val,
val + global_settings.crossfeed_hf_attenuation,
global_settings.crossfeed_hf_cutoff);
}
static bool crossfeed_cross_gain(void)
{
return set_int(str(LANG_CROSSFEED_CROSS_GAIN), str(LANG_UNIT_DB),
UNIT_DB, &global_settings.crossfeed_cross_gain,
&crossfeed_cross_gain_helper, 5, 30, 120, crossfeed_format);
}
static void crossfeed_hf_att_helper(int val)
{
dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain,
global_settings.crossfeed_cross_gain + val,
global_settings.crossfeed_hf_cutoff);
}
static bool crossfeed_hf_attenuation(void)
{
return set_int(str(LANG_CROSSFEED_HF_ATTENUATION), str(LANG_UNIT_DB),
UNIT_DB, &global_settings.crossfeed_hf_attenuation,
&crossfeed_hf_att_helper, 5, 60, 240, crossfeed_format);
}
static void crossfeed_hf_cutoff_helper(int val)
{
dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain,
global_settings.crossfeed_cross_gain + global_settings.crossfeed_hf_attenuation, val);
}
static bool crossfeed_hf_cutoff(void)
{
return set_int(str(LANG_CROSSFEED_HF_CUTOFF), str(LANG_UNIT_HERTZ),
UNIT_HERTZ, &global_settings.crossfeed_hf_cutoff, &crossfeed_hf_cutoff_helper, 100, 500, 2000,
NULL);
}
static bool crossfeed_menu(void)
{
int m;
bool result;
static const struct menu_item items[] = {
{ ID2P(LANG_CROSSFEED), crossfeed_enabled },
{ ID2P(LANG_CROSSFEED_DIRECT_GAIN), crossfeed_direct_gain },
{ ID2P(LANG_CROSSFEED_CROSS_GAIN), crossfeed_cross_gain },
{ ID2P(LANG_CROSSFEED_HF_ATTENUATION), crossfeed_hf_attenuation },
{ ID2P(LANG_CROSSFEED_HF_CUTOFF), crossfeed_hf_cutoff },
};
m=menu_init(items, sizeof(items) / sizeof(*items), NULL,
NULL, NULL, NULL);
result = menu_run(m);
menu_exit(m);
return result;
}
#endif
@ -414,7 +490,7 @@ bool sound_menu(void)
{ ID2P(LANG_CHANNEL_MENU), chanconf },
{ ID2P(LANG_STEREO_WIDTH), stereo_width },
#if CONFIG_CODEC == SWCODEC
{ ID2P(LANG_CROSSFEED), crossfeed },
{ ID2P(LANG_CROSSFEED), crossfeed_menu },
{ ID2P(LANG_EQUALIZER), eq_menu },
#endif
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)

View File

@ -516,6 +516,10 @@ void system_init(void)
"movclr.l %%acc2, %%d0\n\t"
"movclr.l %%acc3, %%d0\n\t"
: : : "d0");
/* Set EMAC unit to saturating and rounding fractional mode, since that's
what'll be the most useful for most things which the main thread
will do. */
coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE | EMAC_ROUND);
}
void system_reboot (void)