diff options
-rw-r--r-- | apps/codecs.h | 4 | ||||
-rw-r--r-- | apps/codecs/mpa.c | 2 | ||||
-rw-r--r-- | apps/codecs/spc.c | 3 | ||||
-rw-r--r-- | apps/codecs/vorbis.c | 2 | ||||
-rw-r--r-- | apps/dsp.c | 1106 | ||||
-rw-r--r-- | apps/dsp.h | 8 | ||||
-rw-r--r-- | apps/dsp_asm.h | 24 | ||||
-rw-r--r-- | apps/dsp_cf.S | 380 | ||||
-rw-r--r-- | apps/menus/playback_menu.c | 4 | ||||
-rw-r--r-- | apps/playback.c | 25 | ||||
-rw-r--r-- | apps/screens.c | 2 | ||||
-rw-r--r-- | apps/settings.c | 2 | ||||
-rw-r--r-- | firmware/export/sound.h | 1 |
13 files changed, 1060 insertions, 503 deletions
diff --git a/apps/codecs.h b/apps/codecs.h index 5d3c7039ff..3d7ead159e 100644 --- a/apps/codecs.h +++ b/apps/codecs.h | |||
@@ -90,12 +90,12 @@ | |||
90 | #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ | 90 | #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ |
91 | 91 | ||
92 | /* increase this every time the api struct changes */ | 92 | /* increase this every time the api struct changes */ |
93 | #define CODEC_API_VERSION 13 | 93 | #define CODEC_API_VERSION 14 |
94 | 94 | ||
95 | /* update this to latest version if a change to the api struct breaks | 95 | /* update this to latest version if a change to the api struct breaks |
96 | backwards compatibility (and please take the opportunity to sort in any | 96 | backwards compatibility (and please take the opportunity to sort in any |
97 | new function which are "waiting" at the end of the function table) */ | 97 | new function which are "waiting" at the end of the function table) */ |
98 | #define CODEC_MIN_API_VERSION 13 | 98 | #define CODEC_MIN_API_VERSION 14 |
99 | 99 | ||
100 | /* codec return codes */ | 100 | /* codec return codes */ |
101 | enum codec_status { | 101 | enum codec_status { |
diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c index 7bc546b1aa..6d98677892 100644 --- a/apps/codecs/mpa.c +++ b/apps/codecs/mpa.c | |||
@@ -79,8 +79,6 @@ enum codec_status codec_main(void) | |||
79 | /* Create a decoder instance */ | 79 | /* Create a decoder instance */ |
80 | 80 | ||
81 | ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS); | 81 | ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS); |
82 | ci->configure(DSP_SET_CLIP_MIN, -MAD_F_ONE); | ||
83 | ci->configure(DSP_SET_CLIP_MAX, MAD_F_ONE - 1); | ||
84 | ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, 1024*16); | 82 | ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, 1024*16); |
85 | 83 | ||
86 | next_track: | 84 | next_track: |
diff --git a/apps/codecs/spc.c b/apps/codecs/spc.c index 8d621dd677..61fd9dec72 100644 --- a/apps/codecs/spc.c +++ b/apps/codecs/spc.c | |||
@@ -712,7 +712,8 @@ static int LoadID666(unsigned char *buf) { | |||
712 | 712 | ||
713 | /**************** Codec ****************/ | 713 | /**************** Codec ****************/ |
714 | 714 | ||
715 | static int32_t samples[WAV_CHUNK_SIZE*2] IBSS_ATTR; | 715 | static int32_t samples[WAV_CHUNK_SIZE*2] |
716 | __attribute__ ((aligned (16))) IBSS_ATTR; | ||
716 | 717 | ||
717 | static struct Spc_Emu spc_emu IDATA_ATTR; | 718 | static struct Spc_Emu spc_emu IDATA_ATTR; |
718 | 719 | ||
diff --git a/apps/codecs/vorbis.c b/apps/codecs/vorbis.c index 5f08fb5eeb..7e7ef365b2 100644 --- a/apps/codecs/vorbis.c +++ b/apps/codecs/vorbis.c | |||
@@ -113,8 +113,6 @@ enum codec_status codec_main(void) | |||
113 | ogg_int64_t vf_pcmlengths[2]; | 113 | ogg_int64_t vf_pcmlengths[2]; |
114 | 114 | ||
115 | ci->configure(DSP_SET_SAMPLE_DEPTH, 24); | 115 | ci->configure(DSP_SET_SAMPLE_DEPTH, 24); |
116 | ci->configure(DSP_SET_CLIP_MAX, (1 << 24) - 1); | ||
117 | ci->configure(DSP_SET_CLIP_MIN, -((1 << 24) - 1)); | ||
118 | /* Note: These are sane defaults for these values. Perhaps | 116 | /* Note: These are sane defaults for these values. Perhaps |
119 | * they should be set differently based on quality setting | 117 | * they should be set differently based on quality setting |
120 | */ | 118 | */ |
diff --git a/apps/dsp.c b/apps/dsp.c index 577910acec..0ffaaea8d8 100644 --- a/apps/dsp.c +++ b/apps/dsp.c | |||
@@ -31,10 +31,6 @@ | |||
31 | #include "misc.h" | 31 | #include "misc.h" |
32 | #include "debug.h" | 32 | #include "debug.h" |
33 | 33 | ||
34 | #ifndef SIMULATOR | ||
35 | #include <dsp_asm.h> | ||
36 | #endif | ||
37 | |||
38 | /* 16-bit samples are scaled based on these constants. The shift should be | 34 | /* 16-bit samples are scaled based on these constants. The shift should be |
39 | * no more than 15. | 35 | * no more than 15. |
40 | */ | 36 | */ |
@@ -46,87 +42,155 @@ | |||
46 | #define RESAMPLE_BUF_COUNT (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ | 42 | #define RESAMPLE_BUF_COUNT (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/ |
47 | #define DEFAULT_GAIN 0x01000000 | 43 | #define DEFAULT_GAIN 0x01000000 |
48 | 44 | ||
49 | 45 | /* enums to index conversion properly with stereo mode and other settings */ | |
50 | enum | 46 | enum |
51 | { | 47 | { |
52 | CONVERT_LE_NATIVE_I_STEREO = STEREO_INTERLEAVED, | 48 | SAMPLE_INPUT_LE_NATIVE_I_STEREO = STEREO_INTERLEAVED, |
53 | CONVERT_LE_NATIVE_NI_STEREO = STEREO_NONINTERLEAVED, | 49 | SAMPLE_INPUT_LE_NATIVE_NI_STEREO = STEREO_NONINTERLEAVED, |
54 | CONVERT_LE_NATIVE_MONO = STEREO_MONO, | 50 | SAMPLE_INPUT_LE_NATIVE_MONO = STEREO_MONO, |
55 | CONVERT_GT_NATIVE_I_STEREO = STEREO_INTERLEAVED + STEREO_NUM_MODES, | 51 | SAMPLE_INPUT_GT_NATIVE_I_STEREO = STEREO_INTERLEAVED + STEREO_NUM_MODES, |
56 | CONVERT_GT_NATIVE_NI_STEREO = STEREO_NONINTERLEAVED + STEREO_NUM_MODES, | 52 | SAMPLE_INPUT_GT_NATIVE_NI_STEREO = STEREO_NONINTERLEAVED + STEREO_NUM_MODES, |
57 | CONVERT_GT_NATIVE_MONO = STEREO_MONO + STEREO_NUM_MODES, | 53 | SAMPLE_INPUT_GT_NATIVE_MONO = STEREO_MONO + STEREO_NUM_MODES, |
58 | CONVERT_GT_NATIVE_1ST_INDEX = STEREO_NUM_MODES | 54 | SAMPLE_INPUT_GT_NATIVE_1ST_INDEX = STEREO_NUM_MODES |
59 | }; | 55 | }; |
60 | 56 | ||
61 | struct dsp_config | 57 | enum |
62 | { | 58 | { |
63 | long codec_frequency; /* Sample rate of data coming from the codec */ | 59 | SAMPLE_OUTPUT_MONO = 0, |
64 | long frequency; /* Effective sample rate after pitch shift (if any) */ | 60 | SAMPLE_OUTPUT_STEREO, |
65 | long clip_min; | 61 | SAMPLE_OUTPUT_DITHERED_MONO, |
66 | long clip_max; | 62 | SAMPLE_OUTPUT_DITHERED_STEREO |
67 | long track_gain; | ||
68 | long album_gain; | ||
69 | long track_peak; | ||
70 | long album_peak; | ||
71 | long replaygain; | ||
72 | int sample_depth; | ||
73 | int sample_bytes; | ||
74 | int stereo_mode; | ||
75 | int num_channels; | ||
76 | int frac_bits; | ||
77 | bool dither_enabled; | ||
78 | long dither_bias; | ||
79 | long dither_mask; | ||
80 | bool new_gain; | ||
81 | bool crossfeed_enabled; | ||
82 | bool eq_enabled; | ||
83 | long eq_precut; | ||
84 | long gain; /* Note that this is in S8.23 format. */ | ||
85 | int (*convert_to_internal)(const char* src[], int32_t* dst[], int count); | ||
86 | }; | 63 | }; |
87 | 64 | ||
65 | /**************************************************************************** | ||
66 | * NOTE: Any assembly routines that use these structures must be updated | ||
67 | * if current data members are moved or changed. | ||
68 | */ | ||
69 | /* 32-bit achitecture offset */ | ||
88 | struct resample_data | 70 | struct resample_data |
89 | { | 71 | { |
90 | long phase; | 72 | long delta; /* 00h */ |
91 | long delta; | 73 | long phase; /* 04h */ |
92 | int32_t last_sample[2]; | 74 | int32_t last_sample[2]; /* 08h */ |
75 | /* 10h */ | ||
76 | }; | ||
77 | |||
78 | /* This is for passing needed data to assembly dsp routines. If another | ||
79 | * dsp parameter needs to be passed, add to the end of the structure | ||
80 | * and remove from dsp_config. | ||
81 | * If another function type becomes assembly optimized and requires dsp | ||
82 | * config info, add a pointer paramter of type "struct dsp_data *". | ||
83 | * If removing something from other than the end, reserve the spot or | ||
84 | * else update every implementation for every target. | ||
85 | * Be sure to add the offset of the new member for easy viewing as well. :) | ||
86 | * It is the first member of dsp_config and all members can be accessesed | ||
87 | * through the main aggregate but this is intended to make a safe haven | ||
88 | * for these items whereas the c part can be rearranged at will. dsp_data | ||
89 | * could even moved within dsp_config without disurbing the order. | ||
90 | */ | ||
91 | struct dsp_data | ||
92 | { | ||
93 | int output_scale; /* 00h */ | ||
94 | int num_channels; /* 04h */ | ||
95 | struct resample_data resample_data; /* 08h */ | ||
96 | int clip_min; /* 18h */ | ||
97 | int clip_max; /* 2ch */ | ||
98 | /* 30h */ | ||
93 | }; | 99 | }; |
94 | 100 | ||
101 | /* No asm...yet */ | ||
95 | struct dither_data | 102 | struct dither_data |
96 | { | 103 | { |
97 | long error[3]; | 104 | long error[3]; /* 00h */ |
98 | long random; | 105 | long random; /* 0ch */ |
106 | /* 10h */ | ||
99 | }; | 107 | }; |
100 | 108 | ||
101 | struct crossfeed_data | 109 | struct crossfeed_data |
102 | { | 110 | { |
103 | int32_t gain; /* Direct path gain */ | 111 | int32_t gain; /* 00h - Direct path gain */ |
104 | int32_t coefs[3]; /* Coefficients for the shelving filter */ | 112 | int32_t coefs[3]; /* 04h - Coefficients for the shelving filter */ |
105 | int32_t history[4]; /* Format is x[n - 1], y[n - 1] for both channels */ | 113 | int32_t history[4]; /* 10h - Format is x[n - 1], y[n - 1] for both channels */ |
106 | int32_t delay[13][2]; | 114 | int32_t delay[13][2]; /* 20h */ |
107 | int index; /* Current index into the delay line */ | 115 | int index; /* 88h - Current index into the delay line */ |
116 | /* 8ch */ | ||
108 | }; | 117 | }; |
109 | 118 | ||
110 | /* Current setup is one lowshelf filters, three peaking filters and one | 119 | /* Current setup is one lowshelf filters, three peaking filters and one |
111 | highshelf filter. Varying the number of shelving filters make no sense, | 120 | highshelf filter. Varying the number of shelving filters make no sense, |
112 | but adding peaking filters is possible. */ | 121 | but adding peaking filters is possible. */ |
113 | struct eq_state { | 122 | struct eq_state |
114 | char enabled[5]; /* Flags for active filters */ | 123 | { |
115 | struct eqfilter filters[5]; | 124 | char enabled[5]; /* 00h - Flags for active filters */ |
125 | struct eqfilter filters[5]; /* 08h - packing is 4? */ | ||
126 | /* 10ch */ | ||
116 | }; | 127 | }; |
117 | 128 | ||
118 | static struct dsp_config dsp_conf[2] IBSS_ATTR; | 129 | /* Include header with defines which functions are implemented in assembly |
119 | static struct dither_data dither_data[2] IBSS_ATTR; | 130 | code for the target */ |
120 | static struct resample_data resample_data[2] IBSS_ATTR; | 131 | #ifndef SIMULATOR |
121 | struct crossfeed_data crossfeed_data IBSS_ATTR; | 132 | #include <dsp_asm.h> |
122 | static struct eq_state eq_data; | 133 | #endif |
134 | |||
135 | #ifndef DSP_HAVE_ASM_CROSSFEED | ||
136 | static void apply_crossfeed(int32_t *buf[], int count); | ||
137 | #endif | ||
138 | /* | ||
139 | ***************************************************************************/ | ||
123 | 140 | ||
124 | static int pitch_ratio = 1000; | 141 | struct dsp_config |
125 | static int channels_mode = 0; | 142 | { |
126 | static int32_t sw_gain, sw_cross; | 143 | struct dsp_data data; /* Config members for use in asm routines */ |
144 | long codec_frequency; /* Sample rate of data coming from the codec */ | ||
145 | long frequency; /* Effective sample rate after pitch shift (if any) */ | ||
146 | int sample_depth; | ||
147 | int sample_bytes; | ||
148 | int stereo_mode; | ||
149 | int frac_bits; | ||
150 | long gain; /* Note that this is in S8.23 format. */ | ||
151 | /* Functions that change depending upon settings - NULL if stage is | ||
152 | disabled */ | ||
153 | int (*input_samples)(int count, const char *src[], int32_t *dst[]); | ||
154 | int (*resample)(int count, struct dsp_data *data, | ||
155 | int32_t *src[], int32_t *dst[]); | ||
156 | void (*output_samples)(int count, struct dsp_data *data, | ||
157 | int32_t *src[], int16_t *dst); | ||
158 | /* These will be NULL for the voice codec and is more economical that | ||
159 | way */ | ||
160 | void (*apply_crossfeed)(int32_t *src[], int count); | ||
161 | void (*channels_process)(int count, int32_t *buf[]); | ||
162 | }; | ||
127 | 163 | ||
128 | extern int current_codec; | 164 | /* General DSP config */ |
129 | static struct dsp_config *dsp; | 165 | static struct dsp_config dsp_conf[2] IBSS_ATTR; /* 0=A, 1=V */ |
166 | /* Dithering */ | ||
167 | static struct dither_data dither_data[2] IBSS_ATTR; /* 0=left, 1=right */ | ||
168 | static long dither_mask IBSS_ATTR; | ||
169 | static long dither_bias IBSS_ATTR; | ||
170 | /* Crossfeed */ | ||
171 | struct crossfeed_data crossfeed_data IBSS_ATTR; /* A */ | ||
172 | /* Equalizer */ | ||
173 | static struct eq_state eq_data; /* A/V */ | ||
174 | |||
175 | /* Settings applicable to audio codec only */ | ||
176 | static int pitch_ratio = 1000; | ||
177 | static int channels_mode; | ||
178 | long dsp_sw_gain; | ||
179 | long dsp_sw_cross; | ||
180 | static bool dither_enabled; | ||
181 | static bool eq_enabled IBSS_ATTR; | ||
182 | static long eq_precut; | ||
183 | static long track_gain; | ||
184 | static bool new_gain; | ||
185 | static long album_gain; | ||
186 | static long track_peak; | ||
187 | static long album_peak; | ||
188 | static long replaygain; | ||
189 | static bool crossfeed_enabled; | ||
190 | |||
191 | #define audio_dsp (&dsp_conf[CODEC_IDX_AUDIO]) | ||
192 | #define voice_dsp (&dsp_conf[CODEC_IDX_VOICE]) | ||
193 | static struct dsp_config *dsp IDATA_ATTR = audio_dsp; | ||
130 | 194 | ||
131 | /* The internal format is 32-bit samples, non-interleaved, stereo. This | 195 | /* The internal format is 32-bit samples, non-interleaved, stereo. This |
132 | * format is similar to the raw output from several codecs, so the amount | 196 | * format is similar to the raw output from several codecs, so the amount |
@@ -136,6 +200,38 @@ static struct dsp_config *dsp; | |||
136 | static int32_t sample_buf[SAMPLE_BUF_COUNT] IBSS_ATTR; | 200 | static int32_t sample_buf[SAMPLE_BUF_COUNT] IBSS_ATTR; |
137 | static int32_t resample_buf[RESAMPLE_BUF_COUNT] IBSS_ATTR; | 201 | static int32_t resample_buf[RESAMPLE_BUF_COUNT] IBSS_ATTR; |
138 | 202 | ||
203 | /* set a new dsp and return old one */ | ||
204 | static inline struct dsp_config * switch_dsp(struct dsp_config *_dsp) | ||
205 | { | ||
206 | struct dsp_config * old_dsp = dsp; | ||
207 | dsp = _dsp; | ||
208 | return old_dsp; | ||
209 | } | ||
210 | |||
211 | #if 0 | ||
212 | /* Clip sample to arbitrary limits where range > 0 and min + range = max */ | ||
213 | static inline long clip_sample(int32_t sample, int32_t min, int32_t range) | ||
214 | { | ||
215 | int32_t c = sample - min; | ||
216 | if ((uint32_t)c > (uint32_t)range) | ||
217 | { | ||
218 | sample -= c; | ||
219 | if (c > 0) | ||
220 | sample += range; | ||
221 | } | ||
222 | |||
223 | return sample; | ||
224 | } | ||
225 | #endif | ||
226 | |||
227 | /* Clip sample to signed 16 bit range */ | ||
228 | static inline int32_t clip_sample_16(int32_t sample) | ||
229 | { | ||
230 | if ((int16_t)sample != sample) | ||
231 | sample = 0x7fff ^ (sample >> 31); | ||
232 | return sample; | ||
233 | } | ||
234 | |||
139 | int sound_get_pitch(void) | 235 | int sound_get_pitch(void) |
140 | { | 236 | { |
141 | return pitch_ratio; | 237 | return pitch_ratio; |
@@ -156,13 +252,13 @@ void sound_set_pitch(int permille) | |||
156 | */ | 252 | */ |
157 | 253 | ||
158 | /* convert count 16-bit mono to 32-bit mono */ | 254 | /* convert count 16-bit mono to 32-bit mono */ |
159 | static int convert_lte_native_mono( | 255 | static int sample_input_lte_native_mono( |
160 | const char *src[], int32_t *dst[], int count) | 256 | int count, const char *src[], int32_t *dst[]) |
161 | { | 257 | { |
162 | count = MIN(SAMPLE_BUF_COUNT/2, count); | 258 | count = MIN(SAMPLE_BUF_COUNT/2, count); |
163 | 259 | ||
164 | const short *s = (short*) src[0]; | 260 | const int16_t *s = (int16_t *) src[0]; |
165 | const short * const send = s + count; | 261 | const int16_t * const send = s + count; |
166 | int32_t *d = dst[0] = dst[1] = sample_buf; | 262 | int32_t *d = dst[0] = dst[1] = sample_buf; |
167 | const int scale = WORD_SHIFT; | 263 | const int scale = WORD_SHIFT; |
168 | 264 | ||
@@ -178,8 +274,8 @@ static int convert_lte_native_mono( | |||
178 | } | 274 | } |
179 | 275 | ||
180 | /* convert count 16-bit interleaved stereo to 32-bit noninterleaved */ | 276 | /* convert count 16-bit interleaved stereo to 32-bit noninterleaved */ |
181 | static int convert_lte_native_interleaved_stereo( | 277 | static int sample_input_lte_native_i_stereo( |
182 | const char *src[], int32_t *dst[], int count) | 278 | int count, const char *src[], int32_t *dst[]) |
183 | { | 279 | { |
184 | count = MIN(SAMPLE_BUF_COUNT/2, count); | 280 | count = MIN(SAMPLE_BUF_COUNT/2, count); |
185 | 281 | ||
@@ -194,9 +290,9 @@ static int convert_lte_native_interleaved_stereo( | |||
194 | int32_t slr = *s++; | 290 | int32_t slr = *s++; |
195 | #ifdef ROCKBOX_LITTLE_ENDIAN | 291 | #ifdef ROCKBOX_LITTLE_ENDIAN |
196 | *dl++ = (slr >> 16) << scale; | 292 | *dl++ = (slr >> 16) << scale; |
197 | *dr++ = (int32_t)(short)slr << scale; | 293 | *dr++ = (int32_t)(int16_t)slr << scale; |
198 | #else /* ROCKBOX_BIG_ENDIAN */ | 294 | #else /* ROCKBOX_BIG_ENDIAN */ |
199 | *dl++ = (int32_t)(short)slr << scale; | 295 | *dl++ = (int32_t)(int16_t)slr << scale; |
200 | *dr++ = (slr >> 16) << scale; | 296 | *dr++ = (slr >> 16) << scale; |
201 | #endif | 297 | #endif |
202 | } | 298 | } |
@@ -208,12 +304,14 @@ static int convert_lte_native_interleaved_stereo( | |||
208 | } | 304 | } |
209 | 305 | ||
210 | /* convert count 16-bit noninterleaved stereo to 32-bit noninterleaved */ | 306 | /* convert count 16-bit noninterleaved stereo to 32-bit noninterleaved */ |
211 | static int convert_lte_native_noninterleaved_stereo( | 307 | static int sample_input_lte_native_ni_stereo( |
212 | const char *src[], int32_t *dst[], int count) | 308 | int count, const char *src[], int32_t *dst[]) |
213 | { | 309 | { |
214 | const short *sl = (short *) src[0]; | 310 | count = MIN(SAMPLE_BUF_COUNT/2, count); |
215 | const short *sr = (short *) src[1]; | 311 | |
216 | const short * const slend = sl + count; | 312 | const int16_t *sl = (int16_t *) src[0]; |
313 | const int16_t *sr = (int16_t *) src[1]; | ||
314 | const int16_t * const slend = sl + count; | ||
217 | int32_t *dl = dst[0] = sample_buf; | 315 | int32_t *dl = dst[0] = sample_buf; |
218 | int32_t *dr = dst[1] = sample_buf + SAMPLE_BUF_COUNT/2; | 316 | int32_t *dr = dst[1] = sample_buf + SAMPLE_BUF_COUNT/2; |
219 | const int scale = WORD_SHIFT; | 317 | const int scale = WORD_SHIFT; |
@@ -232,8 +330,8 @@ static int convert_lte_native_noninterleaved_stereo( | |||
232 | } | 330 | } |
233 | 331 | ||
234 | /* convert count 32-bit mono to 32-bit mono */ | 332 | /* convert count 32-bit mono to 32-bit mono */ |
235 | static int convert_gt_native_mono( | 333 | static int sample_input_gt_native_mono( |
236 | const char *src[], int32_t *dst[], int count) | 334 | int count, const char *src[], int32_t *dst[]) |
237 | { | 335 | { |
238 | count = MIN(SAMPLE_BUF_COUNT/2, count); | 336 | count = MIN(SAMPLE_BUF_COUNT/2, count); |
239 | 337 | ||
@@ -244,8 +342,8 @@ static int convert_gt_native_mono( | |||
244 | } | 342 | } |
245 | 343 | ||
246 | /* convert count 32-bit interleaved stereo to 32-bit noninterleaved stereo */ | 344 | /* convert count 32-bit interleaved stereo to 32-bit noninterleaved stereo */ |
247 | static int convert_gt_native_interleaved_stereo( | 345 | static int sample_input_gt_native_i_stereo( |
248 | const char *src[], int32_t *dst[], int count) | 346 | int count, const char *src[], int32_t *dst[]) |
249 | { | 347 | { |
250 | count = MIN(SAMPLE_BUF_COUNT/2, count); | 348 | count = MIN(SAMPLE_BUF_COUNT/2, count); |
251 | 349 | ||
@@ -270,8 +368,8 @@ static int convert_gt_native_interleaved_stereo( | |||
270 | } | 368 | } |
271 | 369 | ||
272 | /* convert 32 bit-noninterleaved stereo to 32-bit noninterleaved stereo */ | 370 | /* convert 32 bit-noninterleaved stereo to 32-bit noninterleaved stereo */ |
273 | static int convert_gt_native_noninterleaved_stereo( | 371 | static int sample_input_gt_native_ni_stereo( |
274 | const char *src[], int32_t *dst[], int count) | 372 | int count, const char *src[], int32_t *dst[]) |
275 | { | 373 | { |
276 | count = MIN(SAMPLE_BUF_COUNT/2, count); | 374 | count = MIN(SAMPLE_BUF_COUNT/2, count); |
277 | 375 | ||
@@ -283,42 +381,190 @@ static int convert_gt_native_noninterleaved_stereo( | |||
283 | return count; | 381 | return count; |
284 | } | 382 | } |
285 | 383 | ||
286 | /* set the to-native sample conversion function based on dsp sample parameters */ | 384 | /** |
287 | static void new_sample_conversion(void) | 385 | * sample_input_new_format() |
386 | * | ||
387 | * set the to-native sample conversion function based on dsp sample parameters | ||
388 | * | ||
389 | * !DSPPARAMSYNC | ||
390 | * needs syncing with changes to the following dsp parameters: | ||
391 | * * dsp->stereo_mode (A/V) | ||
392 | * * dsp->sample_depth (A/V) | ||
393 | */ | ||
394 | static void sample_input_new_format(void) | ||
288 | { | 395 | { |
289 | static int (*convert_to_internal_functions[])( | 396 | static int (* const sample_input_functions[])( |
290 | const char* src[], int32_t *dst[], int count) = | 397 | int count, const char* src[], int32_t *dst[]) = |
291 | { | 398 | { |
292 | [CONVERT_LE_NATIVE_MONO] = convert_lte_native_mono, | 399 | [SAMPLE_INPUT_LE_NATIVE_MONO] = sample_input_lte_native_mono, |
293 | [CONVERT_LE_NATIVE_I_STEREO] = convert_lte_native_interleaved_stereo, | 400 | [SAMPLE_INPUT_LE_NATIVE_I_STEREO] = sample_input_lte_native_i_stereo, |
294 | [CONVERT_LE_NATIVE_NI_STEREO] = convert_lte_native_noninterleaved_stereo, | 401 | [SAMPLE_INPUT_LE_NATIVE_NI_STEREO] = sample_input_lte_native_ni_stereo, |
295 | [CONVERT_GT_NATIVE_MONO] = convert_gt_native_mono, | 402 | [SAMPLE_INPUT_GT_NATIVE_MONO] = sample_input_gt_native_mono, |
296 | [CONVERT_GT_NATIVE_I_STEREO] = convert_gt_native_interleaved_stereo, | 403 | [SAMPLE_INPUT_GT_NATIVE_I_STEREO] = sample_input_gt_native_i_stereo, |
297 | [CONVERT_GT_NATIVE_NI_STEREO] = convert_gt_native_noninterleaved_stereo, | 404 | [SAMPLE_INPUT_GT_NATIVE_NI_STEREO] = sample_input_gt_native_ni_stereo, |
298 | }; | 405 | }; |
299 | 406 | ||
300 | int convert = dsp->stereo_mode; | 407 | int convert = dsp->stereo_mode; |
301 | 408 | ||
302 | if (dsp->sample_depth > NATIVE_DEPTH) | 409 | if (dsp->sample_depth > NATIVE_DEPTH) |
303 | convert += CONVERT_GT_NATIVE_1ST_INDEX; | 410 | convert += SAMPLE_INPUT_GT_NATIVE_1ST_INDEX; |
411 | |||
412 | dsp->input_samples = sample_input_functions[convert]; | ||
413 | } | ||
414 | |||
415 | #ifndef DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO | ||
416 | /* write mono internal format to output format */ | ||
417 | static void sample_output_mono(int count, struct dsp_data *data, | ||
418 | int32_t *src[], int16_t *dst) | ||
419 | { | ||
420 | const int32_t *s0 = src[0]; | ||
421 | const int scale = data->output_scale; | ||
422 | |||
423 | do | ||
424 | { | ||
425 | int32_t lr = clip_sample_16(*s0++ >> scale); | ||
426 | *dst++ = lr; | ||
427 | *dst++ = lr; | ||
428 | } | ||
429 | while (--count > 0); | ||
430 | } | ||
431 | #endif /* DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO */ | ||
432 | |||
433 | /* write stereo internal format to output format */ | ||
434 | #ifndef DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO | ||
435 | static void sample_output_stereo(int count, struct dsp_data *data, | ||
436 | int32_t *src[], int16_t *dst) | ||
437 | { | ||
438 | const int32_t *s0 = src[0]; | ||
439 | const int32_t *s1 = src[1]; | ||
440 | const int scale = data->output_scale; | ||
441 | |||
442 | do | ||
443 | { | ||
444 | *dst++ = clip_sample_16(*s0++ >> scale); | ||
445 | *dst++ = clip_sample_16(*s1++ >> scale); | ||
446 | } | ||
447 | while (--count > 0); | ||
448 | } | ||
449 | #endif /* DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO */ | ||
450 | |||
451 | /** | ||
452 | * The "dither" code to convert the 24-bit samples produced by libmad was | ||
453 | * taken from the coolplayer project - coolplayer.sourceforge.net | ||
454 | * | ||
455 | * This function handles mono and stereo outputs. | ||
456 | */ | ||
457 | static void sample_output_dithered(int count, struct dsp_data *data, | ||
458 | int32_t *src[], int16_t *dst) | ||
459 | { | ||
460 | const int32_t mask = dither_mask; | ||
461 | const int32_t bias = dither_bias; | ||
462 | const int scale = data->output_scale; | ||
463 | const int32_t min = data->clip_min; | ||
464 | const int32_t max = data->clip_max; | ||
465 | const int32_t range = max - min; | ||
466 | const int dinc = dsp->data.num_channels; | ||
467 | |||
468 | int ch; | ||
469 | for (ch = 0; ch < dinc; ch++) | ||
470 | { | ||
471 | struct dither_data * const dither = &dither_data[ch]; | ||
472 | int32_t *s = src[ch]; | ||
473 | int16_t *d = &dst[ch]; | ||
474 | int i; | ||
475 | |||
476 | for (i = 0; i < count; i++, s++, d += dinc) | ||
477 | { | ||
478 | int32_t output, sample; | ||
479 | int32_t random; | ||
480 | |||
481 | /* Noise shape and bias */ | ||
482 | sample = *s; | ||
483 | sample += dither->error[0] - dither->error[1] + dither->error[2]; | ||
484 | dither->error[2] = dither->error[1]; | ||
485 | dither->error[1] = dither->error[0]/2; | ||
486 | |||
487 | output = sample + bias; | ||
488 | |||
489 | /* Dither */ | ||
490 | random = dither->random*0x0019660dL + 0x3c6ef35fL; | ||
491 | output += (random & mask) - (dither->random & mask); | ||
492 | dither->random = random; | ||
493 | |||
494 | /* Clip */ | ||
495 | int32_t c = output - min; | ||
496 | if ((uint32_t)c > (uint32_t)range) | ||
497 | { | ||
498 | output -= c; | ||
499 | if (c > 0) | ||
500 | { | ||
501 | output += range; | ||
502 | if (sample > max) | ||
503 | sample = max; | ||
504 | } | ||
505 | else if (sample < min) | ||
506 | { | ||
507 | sample = min; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | output &= ~mask; | ||
512 | |||
513 | /* Error feedback */ | ||
514 | dither->error[0] = sample - output; | ||
515 | |||
516 | /* Quantize */ | ||
517 | *d = output >> scale; | ||
518 | } | ||
519 | } | ||
520 | } | ||
521 | |||
522 | /** | ||
523 | * sample_output_new_format() | ||
524 | * | ||
525 | * set the from-native to ouput sample conversion routine | ||
526 | * | ||
527 | * !DSPPARAMSYNC | ||
528 | * needs syncing with changes to the following dsp parameters: | ||
529 | * * dsp->stereo_mode (A/V) | ||
530 | * * dither_enabled (A) | ||
531 | */ | ||
532 | static void sample_output_new_format(void) | ||
533 | { | ||
534 | static void (* const sample_output_functions[])( | ||
535 | int count, struct dsp_data *data, | ||
536 | int32_t *src[], int16_t *dst) = | ||
537 | { | ||
538 | sample_output_mono, | ||
539 | sample_output_stereo, | ||
540 | sample_output_dithered, | ||
541 | sample_output_dithered | ||
542 | }; | ||
543 | |||
544 | int out = dsp->data.num_channels - 1; | ||
545 | |||
546 | if (dsp == audio_dsp && dither_enabled) | ||
547 | out += 2; | ||
304 | 548 | ||
305 | dsp->convert_to_internal = convert_to_internal_functions[convert]; | 549 | dsp->output_samples = sample_output_functions[out]; |
306 | } | 550 | } |
307 | 551 | ||
308 | static void resampler_set_delta(int frequency) | 552 | static void resampler_set_delta(int frequency) |
309 | { | 553 | { |
310 | resample_data[current_codec].delta = (unsigned long) | 554 | dsp->data.resample_data.delta = (unsigned long) |
311 | frequency * 65536LL / NATIVE_FREQUENCY; | 555 | frequency * 65536LL / NATIVE_FREQUENCY; |
312 | } | 556 | } |
313 | 557 | ||
314 | /* Linear interpolation resampling that introduces a one sample delay because | 558 | /** |
559 | * Linear interpolation resampling that introduces a one sample delay because | ||
315 | * of our inability to look into the future at the end of a frame. | 560 | * of our inability to look into the future at the end of a frame. |
316 | */ | 561 | */ |
317 | #ifndef DSP_HAVE_ASM_RESAMPLING | 562 | #ifndef DSP_HAVE_ASM_RESAMPLING |
318 | static int dsp_downsample(int channels, int count, struct resample_data *r, | 563 | static int dsp_downsample(int count, struct dsp_data *data, |
319 | int32_t **src, int32_t **dst) | 564 | int32_t *src[], int32_t *dst[]) |
320 | { | 565 | { |
321 | long delta = r->delta; | 566 | int ch = data->num_channels - 1; |
567 | long delta = data->resample_data.delta; | ||
322 | long phase, pos; | 568 | long phase, pos; |
323 | int32_t *d; | 569 | int32_t *d; |
324 | 570 | ||
@@ -328,12 +574,12 @@ static int dsp_downsample(int channels, int count, struct resample_data *r, | |||
328 | /* Just initialize things and not worry too much about the relatively | 574 | /* Just initialize things and not worry too much about the relatively |
329 | * uncommon case of not being able to spit out a sample for the frame. | 575 | * uncommon case of not being able to spit out a sample for the frame. |
330 | */ | 576 | */ |
331 | int32_t *s = src[--channels]; | 577 | int32_t *s = src[ch]; |
332 | int32_t last = r->last_sample[channels]; | 578 | int32_t last = data->resample_data.last_sample[ch]; |
333 | 579 | ||
334 | r->last_sample[channels] = s[count - 1]; | 580 | data->resample_data.last_sample[ch] = s[count - 1]; |
335 | d = dst[channels]; | 581 | d = dst[ch]; |
336 | phase = r->phase; | 582 | phase = data->resample_data.phase; |
337 | pos = phase >> 16; | 583 | pos = phase >> 16; |
338 | 584 | ||
339 | /* Do we need last sample of previous frame for interpolation? */ | 585 | /* Do we need last sample of previous frame for interpolation? */ |
@@ -348,17 +594,18 @@ static int dsp_downsample(int channels, int count, struct resample_data *r, | |||
348 | last = s[pos - 1]; | 594 | last = s[pos - 1]; |
349 | } | 595 | } |
350 | } | 596 | } |
351 | while (channels > 0); | 597 | while (--ch >= 0); |
352 | 598 | ||
353 | /* Wrap phase accumulator back to start of next frame. */ | 599 | /* Wrap phase accumulator back to start of next frame. */ |
354 | r->phase = phase - (count << 16); | 600 | data->resample_data.phase = phase - (count << 16); |
355 | return d - dst[0]; | 601 | return d - dst[0]; |
356 | } | 602 | } |
357 | 603 | ||
358 | static int dsp_upsample(int channels, int count, struct resample_data *r, | 604 | static int dsp_upsample(int count, struct dsp_data *data, |
359 | int32_t **src, int32_t **dst) | 605 | int32_t *src[], int32_t *dst[]) |
360 | { | 606 | { |
361 | long delta = r->delta; | 607 | int ch = data->num_channels - 1; |
608 | long delta = data->resample_data.delta; | ||
362 | long phase, pos; | 609 | long phase, pos; |
363 | int32_t *d; | 610 | int32_t *d; |
364 | 611 | ||
@@ -367,12 +614,12 @@ static int dsp_upsample(int channels, int count, struct resample_data *r, | |||
367 | { | 614 | { |
368 | /* Should always be able to output a sample for a ratio up to | 615 | /* Should always be able to output a sample for a ratio up to |
369 | RESAMPLE_BUF_COUNT / SAMPLE_BUF_COUNT. */ | 616 | RESAMPLE_BUF_COUNT / SAMPLE_BUF_COUNT. */ |
370 | int32_t *s = src[--channels]; | 617 | int32_t *s = src[ch]; |
371 | int32_t last = r->last_sample[channels]; | 618 | int32_t last = data->resample_data.last_sample[ch]; |
372 | 619 | ||
373 | r->last_sample[channels] = s[count - 1]; | 620 | data->resample_data.last_sample[ch] = s[count - 1]; |
374 | d = dst[channels]; | 621 | d = dst[ch]; |
375 | phase = r->phase; | 622 | phase = data->resample_data.phase; |
376 | pos = phase >> 16; | 623 | pos = phase >> 16; |
377 | 624 | ||
378 | while (pos == 0) | 625 | while (pos == 0) |
@@ -390,10 +637,10 @@ static int dsp_upsample(int channels, int count, struct resample_data *r, | |||
390 | pos = phase >> 16; | 637 | pos = phase >> 16; |
391 | } | 638 | } |
392 | } | 639 | } |
393 | while (channels > 0); | 640 | while (--ch >= 0); |
394 | 641 | ||
395 | /* Wrap phase accumulator back to start of next frame. */ | 642 | /* Wrap phase accumulator back to start of next frame. */ |
396 | r->phase = phase & 0xffff; | 643 | data->resample_data.phase = phase & 0xffff; |
397 | return d - dst[0]; | 644 | return d - dst[0]; |
398 | } | 645 | } |
399 | #endif /* DSP_HAVE_ASM_RESAMPLING */ | 646 | #endif /* DSP_HAVE_ASM_RESAMPLING */ |
@@ -402,111 +649,57 @@ static int dsp_upsample(int channels, int count, struct resample_data *r, | |||
402 | * done, to refer to the resampled data. Returns number of stereo samples | 649 | * done, to refer to the resampled data. Returns number of stereo samples |
403 | * for further processing. | 650 | * for further processing. |
404 | */ | 651 | */ |
405 | static inline int resample(int32_t *src[], int count) | 652 | static inline int resample(int count, int32_t *src[]) |
406 | { | 653 | { |
407 | long new_count = count; | 654 | if (dsp->resample) |
408 | |||
409 | if (dsp->frequency != NATIVE_FREQUENCY) | ||
410 | { | 655 | { |
411 | int32_t *dst[2] = | 656 | int32_t *dst[2] = |
412 | { | 657 | { |
413 | resample_buf, | 658 | resample_buf, |
414 | resample_buf + RESAMPLE_BUF_COUNT/2, | 659 | resample_buf + RESAMPLE_BUF_COUNT/2, |
415 | }; | 660 | }; |
416 | int channels = dsp->num_channels; | ||
417 | |||
418 | if (dsp->frequency < NATIVE_FREQUENCY) | ||
419 | new_count = dsp_upsample(channels, count, | ||
420 | &resample_data[current_codec], | ||
421 | src, dst); | ||
422 | else | ||
423 | new_count = dsp_downsample(channels, count, | ||
424 | &resample_data[current_codec], | ||
425 | src, dst); | ||
426 | 661 | ||
662 | count = dsp->resample(count, &dsp->data, src, dst); | ||
427 | src[0] = dst[0]; | 663 | src[0] = dst[0]; |
428 | src[1] = dst[channels - 1]; | 664 | src[1] = dst[dsp->data.num_channels - 1]; |
429 | } | 665 | } |
430 | 666 | ||
431 | return new_count; | 667 | return count; |
432 | } | 668 | } |
433 | 669 | ||
434 | static inline long clip_sample(int32_t sample, int32_t min, int32_t max) | 670 | static void dither_init(void) |
435 | { | 671 | { |
436 | if (sample > max) | 672 | /* Voice codec should not reset the audio codec's dither data */ |
437 | { | 673 | if (dsp != audio_dsp) |
438 | sample = max; | 674 | return; |
439 | } | ||
440 | else if (sample < min) | ||
441 | { | ||
442 | sample = min; | ||
443 | } | ||
444 | 675 | ||
445 | return sample; | 676 | memset(dither_data, 0, sizeof (dither_data)); |
677 | dither_bias = (1L << (dsp->frac_bits - NATIVE_DEPTH)); | ||
678 | dither_mask = (1L << (dsp->frac_bits + 1 - NATIVE_DEPTH)) - 1; | ||
446 | } | 679 | } |
447 | 680 | ||
448 | /* The "dither" code to convert the 24-bit samples produced by libmad was | ||
449 | * taken from the coolplayer project - coolplayer.sourceforge.net | ||
450 | */ | ||
451 | |||
452 | void dsp_dither_enable(bool enable) | 681 | void dsp_dither_enable(bool enable) |
453 | { | 682 | { |
454 | dsp->dither_enabled = enable; | 683 | /* Be sure audio dsp is current to set correct function */ |
455 | } | 684 | struct dsp_config *old_dsp = switch_dsp(audio_dsp); |
456 | 685 | dither_enabled = enable; | |
457 | static void dither_init(void) | 686 | sample_output_new_format(); |
458 | { | 687 | switch_dsp(old_dsp); |
459 | memset(dither_data, 0, sizeof(dither_data)); | ||
460 | dsp->dither_bias = (1L << (dsp->frac_bits - NATIVE_DEPTH)); | ||
461 | dsp->dither_mask = (1L << (dsp->frac_bits + 1 - NATIVE_DEPTH)) - 1; | ||
462 | } | ||
463 | |||
464 | static void dither_samples(int32_t* src, int num, struct dither_data* dither) | ||
465 | { | ||
466 | int32_t output, sample; | ||
467 | int32_t random; | ||
468 | int32_t min, max; | ||
469 | long mask = dsp->dither_mask; | ||
470 | long bias = dsp->dither_bias; | ||
471 | int i; | ||
472 | |||
473 | for (i = 0; i < num; ++i) { | ||
474 | /* Noise shape and bias */ | ||
475 | sample = src[i]; | ||
476 | sample += dither->error[0] - dither->error[1] + dither->error[2]; | ||
477 | dither->error[2] = dither->error[1]; | ||
478 | dither->error[1] = dither->error[0]/2; | ||
479 | |||
480 | output = sample + bias; | ||
481 | |||
482 | /* Dither */ | ||
483 | random = dither->random*0x0019660dL + 0x3c6ef35fL; | ||
484 | output += (random & mask) - (dither->random & mask); | ||
485 | dither->random = random; | ||
486 | |||
487 | /* Clip and quantize */ | ||
488 | min = dsp->clip_min; | ||
489 | max = dsp->clip_max; | ||
490 | if (output > max) { | ||
491 | output = max; | ||
492 | if (sample > max) | ||
493 | sample = max; | ||
494 | } else if (output < min) { | ||
495 | output = min; | ||
496 | if (sample < min) | ||
497 | sample = min; | ||
498 | } | ||
499 | output &= ~mask; | ||
500 | |||
501 | /* Error feedback */ | ||
502 | dither->error[0] = sample - output; | ||
503 | src[i] = output; | ||
504 | } | ||
505 | } | 688 | } |
506 | 689 | ||
690 | /** | ||
691 | * dsp_set_crossfeed(bool enable) | ||
692 | * | ||
693 | * !DSPPARAMSYNC | ||
694 | * needs syncing with changes to the following dsp parameters: | ||
695 | * * dsp->stereo_mode (A) | ||
696 | */ | ||
507 | void dsp_set_crossfeed(bool enable) | 697 | void dsp_set_crossfeed(bool enable) |
508 | { | 698 | { |
509 | dsp->crossfeed_enabled = enable; | 699 | crossfeed_enabled = enable; |
700 | audio_dsp->apply_crossfeed = | ||
701 | (enable && audio_dsp->data.num_channels > 1) | ||
702 | ? apply_crossfeed : NULL; | ||
510 | } | 703 | } |
511 | 704 | ||
512 | void dsp_set_crossfeed_direct_gain(int gain) | 705 | void dsp_set_crossfeed_direct_gain(int gain) |
@@ -533,7 +726,7 @@ void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) | |||
533 | * to listen to on headphones with no crossfeed. | 726 | * to listen to on headphones with no crossfeed. |
534 | */ | 727 | */ |
535 | #ifndef DSP_HAVE_ASM_CROSSFEED | 728 | #ifndef DSP_HAVE_ASM_CROSSFEED |
536 | static void apply_crossfeed(int32_t* src[], int count) | 729 | static void apply_crossfeed(int32_t *buf[], int count) |
537 | { | 730 | { |
538 | int32_t *hist_l = &crossfeed_data.history[0]; | 731 | int32_t *hist_l = &crossfeed_data.history[0]; |
539 | int32_t *hist_r = &crossfeed_data.history[2]; | 732 | int32_t *hist_r = &crossfeed_data.history[2]; |
@@ -546,9 +739,10 @@ static void apply_crossfeed(int32_t* src[], int count) | |||
546 | int32_t left, right; | 739 | int32_t left, right; |
547 | int i; | 740 | int i; |
548 | 741 | ||
549 | for (i = 0; i < count; i++) { | 742 | for (i = 0; i < count; i++) |
550 | left = src[0][i]; | 743 | { |
551 | right = src[1][i]; | 744 | left = buf[0][i]; |
745 | right = buf[1][i]; | ||
552 | 746 | ||
553 | /* Filter delayed sample from left speaker */ | 747 | /* Filter delayed sample from left speaker */ |
554 | ACC_INIT(acc, delay[di*2], coefs[0]); | 748 | ACC_INIT(acc, delay[di*2], coefs[0]); |
@@ -567,8 +761,8 @@ static void apply_crossfeed(int32_t* src[], int count) | |||
567 | delay[di*2] = left; | 761 | delay[di*2] = left; |
568 | delay[di*2 + 1] = right; | 762 | delay[di*2 + 1] = right; |
569 | /* Now add the attenuated direct sound and write to outputs */ | 763 | /* Now add the attenuated direct sound and write to outputs */ |
570 | src[0][i] = FRACMUL(left, gain) + hist_r[1]; | 764 | buf[0][i] = FRACMUL(left, gain) + hist_r[1]; |
571 | src[1][i] = FRACMUL(right, gain) + hist_l[1]; | 765 | buf[1][i] = FRACMUL(right, gain) + hist_l[1]; |
572 | 766 | ||
573 | /* Wrap delay line index if bigger than delay line size */ | 767 | /* Wrap delay line index if bigger than delay line size */ |
574 | if (++di > 12) | 768 | if (++di > 12) |
@@ -580,18 +774,19 @@ static void apply_crossfeed(int32_t* src[], int count) | |||
580 | #endif | 774 | #endif |
581 | 775 | ||
582 | /* Combine all gains to a global gain. */ | 776 | /* Combine all gains to a global gain. */ |
583 | static void set_gain(void) | 777 | static void set_gain(struct dsp_config *dsp) |
584 | { | 778 | { |
585 | dsp->gain = DEFAULT_GAIN; | 779 | dsp->gain = DEFAULT_GAIN; |
586 | 780 | ||
587 | if (dsp->replaygain) | 781 | /* Replay gain not relevant to voice */ |
782 | if (dsp == audio_dsp && replaygain) | ||
588 | { | 783 | { |
589 | dsp->gain = dsp->replaygain; | 784 | dsp->gain = replaygain; |
590 | } | 785 | } |
591 | 786 | ||
592 | if (dsp->eq_enabled && dsp->eq_precut) | 787 | if (eq_enabled && eq_precut) |
593 | { | 788 | { |
594 | dsp->gain = (long) (((int64_t) dsp->gain * dsp->eq_precut) >> 24); | 789 | dsp->gain = (long) (((int64_t) dsp->gain * eq_precut) >> 24); |
595 | } | 790 | } |
596 | 791 | ||
597 | if (dsp->gain == DEFAULT_GAIN) | 792 | if (dsp->gain == DEFAULT_GAIN) |
@@ -611,7 +806,7 @@ static void set_gain(void) | |||
611 | */ | 806 | */ |
612 | void dsp_set_eq(bool enable) | 807 | void dsp_set_eq(bool enable) |
613 | { | 808 | { |
614 | dsp->eq_enabled = enable; | 809 | eq_enabled = enable; |
615 | } | 810 | } |
616 | 811 | ||
617 | /** | 812 | /** |
@@ -621,8 +816,9 @@ void dsp_set_eq(bool enable) | |||
621 | */ | 816 | */ |
622 | void dsp_set_eq_precut(int precut) | 817 | void dsp_set_eq_precut(int precut) |
623 | { | 818 | { |
624 | dsp->eq_precut = get_replaygain_int(precut * -10); | 819 | eq_precut = get_replaygain_int(precut * -10); |
625 | set_gain(); | 820 | set_gain(audio_dsp); |
821 | set_gain(voice_dsp); /* For EQ precut */ | ||
626 | } | 822 | } |
627 | 823 | ||
628 | /** | 824 | /** |
@@ -651,9 +847,12 @@ void dsp_set_eq_coefs(int band) | |||
651 | which it should be, since we're executed from the main thread. */ | 847 | which it should be, since we're executed from the main thread. */ |
652 | 848 | ||
653 | /* Assume a band is disabled if the gain is zero */ | 849 | /* Assume a band is disabled if the gain is zero */ |
654 | if (gain == 0) { | 850 | if (gain == 0) |
851 | { | ||
655 | eq_data.enabled[band] = 0; | 852 | eq_data.enabled[band] = 0; |
656 | } else { | 853 | } |
854 | else | ||
855 | { | ||
657 | if (band == 0) | 856 | if (band == 0) |
658 | eq_ls_coefs(cutoff, q, gain, eq_data.filters[band].coefs); | 857 | eq_ls_coefs(cutoff, q, gain, eq_data.filters[band].coefs); |
659 | else if (band == 4) | 858 | else if (band == 4) |
@@ -666,24 +865,28 @@ void dsp_set_eq_coefs(int band) | |||
666 | } | 865 | } |
667 | 866 | ||
668 | /* Apply EQ filters to those bands that have got it switched on. */ | 867 | /* Apply EQ filters to those bands that have got it switched on. */ |
669 | static void eq_process(int32_t **x, unsigned num) | 868 | static void eq_process(int count, int32_t *buf[]) |
670 | { | 869 | { |
870 | static const int shifts[] = | ||
871 | { | ||
872 | EQ_SHELF_SHIFT, /* low shelf */ | ||
873 | EQ_PEAK_SHIFT, /* peaking */ | ||
874 | EQ_PEAK_SHIFT, /* peaking */ | ||
875 | EQ_PEAK_SHIFT, /* peaking */ | ||
876 | EQ_SHELF_SHIFT, /* high shelf */ | ||
877 | }; | ||
878 | unsigned int channels = dsp->data.num_channels; | ||
671 | int i; | 879 | int i; |
672 | unsigned int channels = dsp->num_channels; | ||
673 | unsigned shift; | ||
674 | 880 | ||
675 | /* filter configuration currently is 1 low shelf filter, 3 band peaking | 881 | /* filter configuration currently is 1 low shelf filter, 3 band peaking |
676 | filters and 1 high shelf filter, in that order. we need to know this | 882 | filters and 1 high shelf filter, in that order. we need to know this |
677 | so we can choose the correct shift factor. | 883 | so we can choose the correct shift factor. |
678 | */ | 884 | */ |
679 | for (i = 0; i < 5; i++) { | 885 | for (i = 0; i < 5; i++) |
680 | if (eq_data.enabled[i]) { | 886 | { |
681 | if (i == 0 || i == 4) /* shelving filters */ | 887 | if (!eq_data.enabled[i]) |
682 | shift = EQ_SHELF_SHIFT; | 888 | continue; |
683 | else | 889 | eq_filter(buf, &eq_data.filters[i], count, channels, shifts[i]); |
684 | shift = EQ_PEAK_SHIFT; | ||
685 | eq_filter(x, &eq_data.filters[i], num, channels, shift); | ||
686 | } | ||
687 | } | 890 | } |
688 | } | 891 | } |
689 | 892 | ||
@@ -691,45 +894,44 @@ static void eq_process(int32_t **x, unsigned num) | |||
691 | * the src array if gain was applied. | 894 | * the src array if gain was applied. |
692 | * Note that this must be called before the resampler. | 895 | * Note that this must be called before the resampler. |
693 | */ | 896 | */ |
694 | static void apply_gain(int32_t* _src[], int _count) | 897 | static void apply_gain(int count, int32_t *buf[]) |
695 | { | 898 | { |
696 | if (dsp->gain) | 899 | int32_t *sl, *sr; |
900 | int32_t s, *d; | ||
901 | long gain; | ||
902 | int i; | ||
903 | |||
904 | if (new_gain) | ||
697 | { | 905 | { |
698 | int32_t** src = _src; | 906 | /* Gain has changed */ |
699 | int count = _count; | 907 | dsp_set_replaygain(); |
700 | int32_t* s0 = src[0]; | 908 | if (dsp->gain == 0) |
701 | int32_t* s1 = src[1]; | 909 | return; /* No gain to apply now */ |
702 | long gain = dsp->gain; | 910 | } |
703 | int32_t s; | 911 | |
704 | int i; | 912 | sl = buf[0], sr = buf[1]; |
705 | int32_t *d; | 913 | gain = dsp->gain; |
706 | 914 | ||
707 | if (s0 != s1) | 915 | if (sl != sr) |
708 | { | 916 | { |
709 | d = &sample_buf[SAMPLE_BUF_COUNT / 2]; | 917 | d = &sample_buf[SAMPLE_BUF_COUNT / 2]; |
710 | src[1] = d; | 918 | buf[1] = d; |
711 | s = *s1++; | 919 | s = *sr++; |
712 | 920 | ||
713 | for (i = 0; i < count; i++) | ||
714 | FRACMUL_8_LOOP(s, gain, s1, d); | ||
715 | } | ||
716 | else | ||
717 | { | ||
718 | src[1] = &sample_buf[0]; | ||
719 | } | ||
720 | |||
721 | d = &sample_buf[0]; | ||
722 | src[0] = d; | ||
723 | s = *s0++; | ||
724 | |||
725 | for (i = 0; i < count; i++) | 921 | for (i = 0; i < count; i++) |
726 | FRACMUL_8_LOOP(s, gain, s0, d); | 922 | FRACMUL_8_LOOP(s, gain, sr, d); |
923 | } | ||
924 | else | ||
925 | { | ||
926 | buf[1] = &sample_buf[0]; | ||
727 | } | 927 | } |
728 | } | ||
729 | 928 | ||
730 | void channels_set(int value) | 929 | d = &sample_buf[0]; |
731 | { | 930 | buf[0] = d; |
732 | channels_mode = value; | 931 | s = *sl++; |
932 | |||
933 | for (i = 0; i < count; i++) | ||
934 | FRACMUL_8_LOOP(s, gain, sl, d); | ||
733 | } | 935 | } |
734 | 936 | ||
735 | void stereo_width_set(int value) | 937 | void stereo_width_set(int value) |
@@ -737,89 +939,119 @@ void stereo_width_set(int value) | |||
737 | long width, straight, cross; | 939 | long width, straight, cross; |
738 | 940 | ||
739 | width = value * 0x7fffff / 100; | 941 | width = value * 0x7fffff / 100; |
740 | if (value <= 100) { | 942 | |
943 | if (value <= 100) | ||
944 | { | ||
741 | straight = (0x7fffff + width) / 2; | 945 | straight = (0x7fffff + width) / 2; |
742 | cross = straight - width; | 946 | cross = straight - width; |
743 | } else { | 947 | } |
948 | else | ||
949 | { | ||
744 | /* straight = (1 + width) / (2 * width) */ | 950 | /* straight = (1 + width) / (2 * width) */ |
745 | straight = ((int64_t)(0x7fffff + width) << 22) / width; | 951 | straight = ((int64_t)(0x7fffff + width) << 22) / width; |
746 | cross = straight - 0x7fffff; | 952 | cross = straight - 0x7fffff; |
747 | } | 953 | } |
748 | sw_gain = straight << 8; | 954 | |
749 | sw_cross = cross << 8; | 955 | dsp_sw_gain = straight << 8; |
956 | dsp_sw_cross = cross << 8; | ||
750 | } | 957 | } |
751 | 958 | ||
752 | /* Implements the different channel configurations and stereo width. | 959 | /** |
753 | * We might want to combine this with the write_samples stage for efficiency, | 960 | * Implements the different channel configurations and stereo width. |
754 | * but for now we'll just let it stay as a stage of its own. | ||
755 | */ | 961 | */ |
756 | static void channels_process(int32_t **src, int num) | 962 | |
963 | /* SOUND_CHAN_STEREO mode is a noop so has no function - just outline one for | ||
964 | * completeness. */ | ||
965 | #if 0 | ||
966 | static void channels_process_sound_chan_stereo(int count, int32_t *buf[]) | ||
757 | { | 967 | { |
758 | int i; | 968 | /* The channels are each just themselves */ |
759 | int32_t *sl = src[0], *sr = src[1]; | 969 | (void)count; (void)buf; |
970 | } | ||
971 | #endif | ||
760 | 972 | ||
761 | if (channels_mode == SOUND_CHAN_STEREO) | 973 | #ifndef DSP_HAVE_ASM_SOUND_CHAN_MONO |
762 | return; | 974 | static void channels_process_sound_chan_mono(int count, int32_t *buf[]) |
763 | switch (channels_mode) { | 975 | { |
764 | case SOUND_CHAN_MONO: | 976 | int32_t *sl = buf[0], *sr = buf[1]; |
765 | for (i = 0; i < num; i++) | ||
766 | sl[i] = sr[i] = sl[i]/2 + sr[i]/2; | ||
767 | break; | ||
768 | case SOUND_CHAN_CUSTOM: | ||
769 | for (i = 0; i < num; i++) { | ||
770 | int32_t left_sample = sl[i]; | ||
771 | 977 | ||
772 | sl[i] = FRACMUL(sl[i], sw_gain) + FRACMUL(sr[i], sw_cross); | 978 | do |
773 | sr[i] = FRACMUL(sr[i], sw_gain) + FRACMUL(left_sample, sw_cross); | 979 | { |
774 | } | 980 | int32_t lr = *sl/2 + *sr/2; |
775 | break; | 981 | *sl++ = lr; |
776 | case SOUND_CHAN_MONO_LEFT: | 982 | *sr++ = lr; |
777 | for (i = 0; i < num; i++) | ||
778 | sr[i] = sl[i]; | ||
779 | break; | ||
780 | case SOUND_CHAN_MONO_RIGHT: | ||
781 | for (i = 0; i < num; i++) | ||
782 | sl[i] = sr[i]; | ||
783 | break; | ||
784 | case SOUND_CHAN_KARAOKE: | ||
785 | for (i = 0; i < num; i++) { | ||
786 | int32_t left_sample = sl[i]/2; | ||
787 | |||
788 | sl[i] = left_sample - sr[i]/2; | ||
789 | sr[i] = sr[i]/2 - left_sample; | ||
790 | } | ||
791 | break; | ||
792 | } | 983 | } |
984 | while (--count > 0); | ||
793 | } | 985 | } |
986 | #endif /* DSP_HAVE_ASM_SOUND_CHAN_MONO */ | ||
794 | 987 | ||
795 | static void write_samples(short* dst, int32_t* src[], int count) | 988 | #ifndef DSP_HAVE_ASM_SOUND_CHAN_CUSTOM |
989 | static void channels_process_sound_chan_custom(int count, int32_t *buf[]) | ||
796 | { | 990 | { |
797 | int32_t* s0 = src[0]; | 991 | const int32_t gain = dsp_sw_gain; |
798 | int32_t* s1 = src[1]; | 992 | const int32_t cross = dsp_sw_cross; |
799 | int scale = dsp->frac_bits + 1 - NATIVE_DEPTH; | 993 | int32_t *sl = buf[0], *sr = buf[1]; |
800 | 994 | ||
801 | if (dsp->dither_enabled) | 995 | do |
802 | { | 996 | { |
803 | dither_samples(src[0], count, &dither_data[0]); | 997 | int32_t l = *sl; |
804 | dither_samples(src[1], count, &dither_data[1]); | 998 | int32_t r = *sr; |
999 | *sl++ = FRACMUL(l, gain) + FRACMUL(r, cross); | ||
1000 | *sr++ = FRACMUL(r, gain) + FRACMUL(l, cross); | ||
1001 | } | ||
1002 | while (--count > 0); | ||
1003 | } | ||
1004 | #endif /* DSP_HAVE_ASM_SOUND_CHAN_CUSTOM */ | ||
805 | 1005 | ||
806 | while (count-- > 0) | 1006 | static void channels_process_sound_chan_mono_left(int count, int32_t *buf[]) |
807 | { | 1007 | { |
808 | *dst++ = (short) (*s0++ >> scale); | 1008 | /* Just copy over the other channel */ |
809 | *dst++ = (short) (*s1++ >> scale); | 1009 | memcpy(buf[1], buf[0], count * sizeof (*buf)); |
810 | } | 1010 | } |
1011 | |||
1012 | static void channels_process_sound_chan_mono_right(int count, int32_t *buf[]) | ||
1013 | { | ||
1014 | /* Just copy over the other channel */ | ||
1015 | memcpy(buf[0], buf[1], count * sizeof (*buf)); | ||
1016 | } | ||
1017 | |||
1018 | #ifndef DSP_HAVE_ASM_SOUND_CHAN_KARAOKE | ||
1019 | static void channels_process_sound_chan_karaoke(int count, int32_t *buf[]) | ||
1020 | { | ||
1021 | int32_t *sl = buf[0], *sr = buf[1]; | ||
1022 | |||
1023 | do | ||
1024 | { | ||
1025 | int32_t l = *sl/2; | ||
1026 | int32_t r = *sr/2; | ||
1027 | *sl++ = l - r; | ||
1028 | *sr++ = r - l; | ||
811 | } | 1029 | } |
812 | else | 1030 | while (--count > 0); |
1031 | } | ||
1032 | #endif /* DSP_HAVE_ASM_SOUND_CHAN_KARAOKE */ | ||
1033 | |||
1034 | void channels_set(int value) | ||
1035 | { | ||
1036 | static void (* const channels_process_functions[])( | ||
1037 | int count, int32_t *buf[]) = | ||
813 | { | 1038 | { |
814 | long min = dsp->clip_min; | 1039 | /* SOUND_CHAN_STEREO = All-purpose index for no channel processing */ |
815 | long max = dsp->clip_max; | 1040 | [SOUND_CHAN_STEREO] = NULL, |
1041 | [SOUND_CHAN_MONO] = channels_process_sound_chan_mono, | ||
1042 | [SOUND_CHAN_CUSTOM] = channels_process_sound_chan_custom, | ||
1043 | [SOUND_CHAN_MONO_LEFT] = channels_process_sound_chan_mono_left, | ||
1044 | [SOUND_CHAN_MONO_RIGHT] = channels_process_sound_chan_mono_right, | ||
1045 | [SOUND_CHAN_KARAOKE] = channels_process_sound_chan_karaoke, | ||
1046 | }; | ||
816 | 1047 | ||
817 | while (count-- > 0) | 1048 | if ((unsigned)value >= ARRAYLEN(channels_process_functions) || |
818 | { | 1049 | audio_dsp->stereo_mode == STEREO_MONO) |
819 | *dst++ = (short) (clip_sample(*s0++, min, max) >> scale); | 1050 | value = SOUND_CHAN_STEREO; |
820 | *dst++ = (short) (clip_sample(*s1++, min, max) >> scale); | 1051 | |
821 | } | 1052 | /* This doesn't apply to voice */ |
822 | } | 1053 | channels_mode = value; |
1054 | audio_dsp->channels_process = channels_process_functions[value]; | ||
823 | } | 1055 | } |
824 | 1056 | ||
825 | /* Process and convert src audio to dst based on the DSP configuration, | 1057 | /* Process and convert src audio to dst based on the DSP configuration, |
@@ -832,7 +1064,7 @@ static void write_samples(short* dst, int32_t* src[], int count) | |||
832 | */ | 1064 | */ |
833 | int dsp_process(char *dst, const char *src[], int count) | 1065 | int dsp_process(char *dst, const char *src[], int count) |
834 | { | 1066 | { |
835 | int32_t* tmp[2]; | 1067 | int32_t *tmp[2]; |
836 | int written = 0; | 1068 | int written = 0; |
837 | int samples; | 1069 | int samples; |
838 | 1070 | ||
@@ -843,27 +1075,23 @@ int dsp_process(char *dst, const char *src[], int count) | |||
843 | coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE); | 1075 | coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE); |
844 | #endif | 1076 | #endif |
845 | 1077 | ||
846 | dsp = &dsp_conf[current_codec]; | ||
847 | |||
848 | dsp_set_replaygain(false); | ||
849 | |||
850 | while (count > 0) | 1078 | while (count > 0) |
851 | { | 1079 | { |
852 | samples = dsp->convert_to_internal(src, tmp, count); | 1080 | samples = dsp->input_samples(count, src, tmp); |
853 | count -= samples; | 1081 | count -= samples; |
854 | apply_gain(tmp, samples); | 1082 | if (dsp->gain != 0) |
855 | samples = resample(tmp, samples); | 1083 | apply_gain(samples, tmp); |
856 | if (samples <= 0) | 1084 | if ((samples = resample(samples, tmp)) <= 0) |
857 | break; /* I'm pretty sure we're downsampling here */ | 1085 | break; /* I'm pretty sure we're downsampling here */ |
858 | if (dsp->crossfeed_enabled && dsp->stereo_mode != STEREO_MONO) | 1086 | if (dsp->apply_crossfeed) |
859 | apply_crossfeed(tmp, samples); | 1087 | dsp->apply_crossfeed(tmp, samples); |
860 | if (dsp->eq_enabled) | 1088 | if (eq_enabled) |
861 | eq_process(tmp, samples); | 1089 | eq_process(samples, tmp); |
862 | if (dsp->stereo_mode != STEREO_MONO) | 1090 | if (dsp->channels_process) |
863 | channels_process(tmp, samples); | 1091 | dsp->channels_process(samples, tmp); |
864 | write_samples((short*) dst, tmp, samples); | 1092 | dsp->output_samples(samples, &dsp->data, tmp, (int16_t *)dst); |
865 | written += samples; | 1093 | written += samples; |
866 | dst += samples * sizeof(short) * 2; | 1094 | dst += samples * sizeof (int16_t) * 2; |
867 | yield(); | 1095 | yield(); |
868 | } | 1096 | } |
869 | 1097 | ||
@@ -883,21 +1111,19 @@ int dsp_process(char *dst, const char *src[], int count) | |||
883 | /* dsp_input_size MUST be called afterwards */ | 1111 | /* dsp_input_size MUST be called afterwards */ |
884 | int dsp_output_count(int count) | 1112 | int dsp_output_count(int count) |
885 | { | 1113 | { |
886 | dsp = &dsp_conf[current_codec]; | 1114 | if (dsp->resample) |
887 | |||
888 | if (dsp->frequency != NATIVE_FREQUENCY) | ||
889 | { | 1115 | { |
890 | count = (int)(((unsigned long)count * NATIVE_FREQUENCY | 1116 | count = (int)(((unsigned long)count * NATIVE_FREQUENCY |
891 | + (dsp->frequency - 1)) / dsp->frequency); | 1117 | + (dsp->frequency - 1)) / dsp->frequency); |
892 | } | ||
893 | 1118 | ||
894 | /* Now we have the resampled sample count which must not exceed | 1119 | /* Now we have the resampled sample count which must not exceed |
895 | * RESAMPLE_BUF_COUNT/2 to avoid resample buffer overflow. One | 1120 | * RESAMPLE_BUF_COUNT/2 to avoid resample buffer overflow. One |
896 | * must call dsp_input_count() to get the correct input sample | 1121 | * must call dsp_input_count() to get the correct input sample |
897 | * count. | 1122 | * count. |
898 | */ | 1123 | */ |
899 | if (count > RESAMPLE_BUF_COUNT/2) | 1124 | if (count > RESAMPLE_BUF_COUNT/2) |
900 | count = RESAMPLE_BUF_COUNT/2; | 1125 | count = RESAMPLE_BUF_COUNT/2; |
1126 | } | ||
901 | 1127 | ||
902 | return count; | 1128 | return count; |
903 | } | 1129 | } |
@@ -907,17 +1133,15 @@ int dsp_output_count(int count) | |||
907 | */ | 1133 | */ |
908 | int dsp_input_count(int count) | 1134 | int dsp_input_count(int count) |
909 | { | 1135 | { |
910 | dsp = &dsp_conf[current_codec]; | ||
911 | |||
912 | /* count is now the number of resampled input samples. Convert to | 1136 | /* count is now the number of resampled input samples. Convert to |
913 | original input samples. */ | 1137 | original input samples. */ |
914 | if (dsp->frequency != NATIVE_FREQUENCY) | 1138 | if (dsp->resample) |
915 | { | 1139 | { |
916 | /* Use the real resampling delta = | 1140 | /* Use the real resampling delta = |
917 | * dsp->frequency * 65536 / NATIVE_FREQUENCY, and | 1141 | * dsp->frequency * 65536 / NATIVE_FREQUENCY, and |
918 | * round towards zero to avoid buffer overflows. */ | 1142 | * round towards zero to avoid buffer overflows. */ |
919 | count = (int)(((unsigned long)count * | 1143 | count = (int)(((unsigned long)count * |
920 | resample_data[current_codec].delta) >> 16); | 1144 | dsp->data.resample_data.delta) >> 16); |
921 | } | 1145 | } |
922 | 1146 | ||
923 | return count; | 1147 | return count; |
@@ -925,20 +1149,39 @@ int dsp_input_count(int count) | |||
925 | 1149 | ||
926 | int dsp_stereo_mode(void) | 1150 | int dsp_stereo_mode(void) |
927 | { | 1151 | { |
928 | dsp = &dsp_conf[current_codec]; | ||
929 | |||
930 | return dsp->stereo_mode; | 1152 | return dsp->stereo_mode; |
931 | } | 1153 | } |
932 | 1154 | ||
933 | bool dsp_configure(int setting, intptr_t value) | 1155 | bool dsp_configure(int setting, intptr_t value) |
934 | { | 1156 | { |
935 | dsp = &dsp_conf[current_codec]; | 1157 | void set_gain_var(long *var, long value) |
1158 | { | ||
1159 | /* Voice shouldn't mess with these */ | ||
1160 | if (dsp != audio_dsp) | ||
1161 | return; | ||
1162 | |||
1163 | *var = value; | ||
1164 | new_gain = true; | ||
1165 | } | ||
1166 | |||
1167 | void update_functions(void) | ||
1168 | { | ||
1169 | sample_input_new_format(); | ||
1170 | sample_output_new_format(); | ||
1171 | if (dsp == audio_dsp) | ||
1172 | dsp_set_crossfeed(crossfeed_enabled); | ||
1173 | } | ||
936 | 1174 | ||
937 | switch (setting) | 1175 | switch (setting) |
938 | { | 1176 | { |
1177 | case DSP_SWITCH_CODEC: | ||
1178 | if ((uintptr_t)value <= 1) | ||
1179 | switch_dsp(&dsp_conf[value]); | ||
1180 | break; | ||
1181 | |||
939 | case DSP_SET_FREQUENCY: | 1182 | case DSP_SET_FREQUENCY: |
940 | memset(&resample_data[current_codec], 0, | 1183 | memset(&dsp->data.resample_data, 0, |
941 | sizeof(struct resample_data)); | 1184 | sizeof (dsp->data.resample_data)); |
942 | /* Fall through!!! */ | 1185 | /* Fall through!!! */ |
943 | case DSP_SWITCH_FREQUENCY: | 1186 | case DSP_SWITCH_FREQUENCY: |
944 | dsp->codec_frequency = (value == 0) ? NATIVE_FREQUENCY : value; | 1187 | dsp->codec_frequency = (value == 0) ? NATIVE_FREQUENCY : value; |
@@ -946,19 +1189,20 @@ bool dsp_configure(int setting, intptr_t value) | |||
946 | if we're called from the main audio thread. Voice UI thread should | 1189 | if we're called from the main audio thread. Voice UI thread should |
947 | not need this feature. | 1190 | not need this feature. |
948 | */ | 1191 | */ |
949 | if (current_codec == CODEC_IDX_AUDIO) | 1192 | if (dsp == audio_dsp) |
950 | dsp->frequency = pitch_ratio * dsp->codec_frequency / 1000; | 1193 | dsp->frequency = pitch_ratio * dsp->codec_frequency / 1000; |
951 | else | 1194 | else |
952 | dsp->frequency = dsp->codec_frequency; | 1195 | dsp->frequency = dsp->codec_frequency; |
953 | resampler_set_delta(dsp->frequency); | ||
954 | break; | ||
955 | 1196 | ||
956 | case DSP_SET_CLIP_MIN: | 1197 | resampler_set_delta(dsp->frequency); |
957 | dsp->clip_min = value; | 1198 | |
958 | break; | 1199 | if (dsp->frequency == NATIVE_FREQUENCY) |
1200 | dsp->resample = NULL; | ||
1201 | else if (dsp->frequency < NATIVE_FREQUENCY) | ||
1202 | dsp->resample = dsp_upsample; | ||
1203 | else | ||
1204 | dsp->resample = dsp_downsample; | ||
959 | 1205 | ||
960 | case DSP_SET_CLIP_MAX: | ||
961 | dsp->clip_max = value; | ||
962 | break; | 1206 | break; |
963 | 1207 | ||
964 | case DSP_SET_SAMPLE_DEPTH: | 1208 | case DSP_SET_SAMPLE_DEPTH: |
@@ -967,69 +1211,73 @@ bool dsp_configure(int setting, intptr_t value) | |||
967 | if (dsp->sample_depth <= NATIVE_DEPTH) | 1211 | if (dsp->sample_depth <= NATIVE_DEPTH) |
968 | { | 1212 | { |
969 | dsp->frac_bits = WORD_FRACBITS; | 1213 | dsp->frac_bits = WORD_FRACBITS; |
970 | dsp->sample_bytes = sizeof(short); | 1214 | dsp->sample_bytes = sizeof (int16_t); /* samples are 16 bits */ |
971 | dsp->clip_max = ((1 << WORD_FRACBITS) - 1); | 1215 | dsp->data.clip_max = ((1 << WORD_FRACBITS) - 1); |
972 | dsp->clip_min = -((1 << WORD_FRACBITS)); | 1216 | dsp->data.clip_min = -((1 << WORD_FRACBITS)); |
973 | } | 1217 | } |
974 | else | 1218 | else |
975 | { | 1219 | { |
976 | dsp->frac_bits = value; | 1220 | dsp->frac_bits = value; |
977 | dsp->sample_bytes = 4; /* samples are 32 bits */ | 1221 | dsp->sample_bytes = sizeof (int32_t); /* samples are 32 bits */ |
978 | dsp->clip_max = (1 << value) - 1; | 1222 | dsp->data.clip_max = (1 << value) - 1; |
979 | dsp->clip_min = -(1 << value); | 1223 | dsp->data.clip_min = -(1 << value); |
980 | } | 1224 | } |
981 | 1225 | ||
982 | new_sample_conversion(); | 1226 | dsp->data.output_scale = dsp->frac_bits + 1 - NATIVE_DEPTH; |
1227 | sample_input_new_format(); | ||
983 | dither_init(); | 1228 | dither_init(); |
984 | break; | 1229 | break; |
985 | 1230 | ||
986 | case DSP_SET_STEREO_MODE: | 1231 | case DSP_SET_STEREO_MODE: |
987 | dsp->stereo_mode = value; | 1232 | dsp->stereo_mode = value; |
988 | dsp->num_channels = value == STEREO_MONO ? 1 : 2; | 1233 | dsp->data.num_channels = value == STEREO_MONO ? 1 : 2; |
989 | new_sample_conversion(); | 1234 | update_functions(); |
990 | break; | 1235 | break; |
991 | 1236 | ||
992 | case DSP_RESET: | 1237 | case DSP_RESET: |
993 | dsp->stereo_mode = STEREO_NONINTERLEAVED; | 1238 | dsp->stereo_mode = STEREO_NONINTERLEAVED; |
994 | dsp->num_channels = 2; | 1239 | dsp->data.num_channels = 2; |
995 | dsp->clip_max = ((1 << WORD_FRACBITS) - 1); | ||
996 | dsp->clip_min = -((1 << WORD_FRACBITS)); | ||
997 | dsp->track_gain = 0; | ||
998 | dsp->album_gain = 0; | ||
999 | dsp->track_peak = 0; | ||
1000 | dsp->album_peak = 0; | ||
1001 | dsp->codec_frequency = dsp->frequency = NATIVE_FREQUENCY; | ||
1002 | dsp->sample_depth = NATIVE_DEPTH; | 1240 | dsp->sample_depth = NATIVE_DEPTH; |
1003 | dsp->frac_bits = WORD_FRACBITS; | 1241 | dsp->frac_bits = WORD_FRACBITS; |
1004 | dsp->new_gain = true; | 1242 | dsp->sample_bytes = sizeof (int16_t); |
1005 | new_sample_conversion(); | 1243 | dsp->data.output_scale = dsp->frac_bits + 1 - NATIVE_DEPTH; |
1244 | dsp->data.clip_max = ((1 << WORD_FRACBITS) - 1); | ||
1245 | dsp->data.clip_min = -((1 << WORD_FRACBITS)); | ||
1246 | dsp->codec_frequency = dsp->frequency = NATIVE_FREQUENCY; | ||
1247 | |||
1248 | if (dsp == audio_dsp) | ||
1249 | { | ||
1250 | track_gain = 0; | ||
1251 | album_gain = 0; | ||
1252 | track_peak = 0; | ||
1253 | album_peak = 0; | ||
1254 | new_gain = true; | ||
1255 | } | ||
1256 | |||
1257 | update_functions(); | ||
1006 | break; | 1258 | break; |
1007 | 1259 | ||
1008 | case DSP_FLUSH: | 1260 | case DSP_FLUSH: |
1009 | memset(&resample_data[current_codec], 0, | 1261 | memset(&dsp->data.resample_data, 0, |
1010 | sizeof (struct resample_data)); | 1262 | sizeof (dsp->data.resample_data)); |
1011 | resampler_set_delta(dsp->frequency); | 1263 | resampler_set_delta(dsp->frequency); |
1012 | dither_init(); | 1264 | dither_init(); |
1013 | break; | 1265 | break; |
1014 | 1266 | ||
1015 | case DSP_SET_TRACK_GAIN: | 1267 | case DSP_SET_TRACK_GAIN: |
1016 | dsp->track_gain = (long) value; | 1268 | set_gain_var(&track_gain, value); |
1017 | dsp->new_gain = true; | ||
1018 | break; | 1269 | break; |
1019 | 1270 | ||
1020 | case DSP_SET_ALBUM_GAIN: | 1271 | case DSP_SET_ALBUM_GAIN: |
1021 | dsp->album_gain = (long) value; | 1272 | set_gain_var(&album_gain, value); |
1022 | dsp->new_gain = true; | ||
1023 | break; | 1273 | break; |
1024 | 1274 | ||
1025 | case DSP_SET_TRACK_PEAK: | 1275 | case DSP_SET_TRACK_PEAK: |
1026 | dsp->track_peak = (long) value; | 1276 | set_gain_var(&track_peak, value); |
1027 | dsp->new_gain = true; | ||
1028 | break; | 1277 | break; |
1029 | 1278 | ||
1030 | case DSP_SET_ALBUM_PEAK: | 1279 | case DSP_SET_ALBUM_PEAK: |
1031 | dsp->album_peak = (long) value; | 1280 | set_gain_var(&album_peak, value); |
1032 | dsp->new_gain = true; | ||
1033 | break; | 1281 | break; |
1034 | 1282 | ||
1035 | default: | 1283 | default: |
@@ -1039,59 +1287,51 @@ bool dsp_configure(int setting, intptr_t value) | |||
1039 | return 1; | 1287 | return 1; |
1040 | } | 1288 | } |
1041 | 1289 | ||
1042 | void dsp_set_replaygain(bool always) | 1290 | void dsp_set_replaygain(void) |
1043 | { | 1291 | { |
1044 | dsp = &dsp_conf[current_codec]; | 1292 | long gain = 0; |
1045 | |||
1046 | if (always || dsp->new_gain) | ||
1047 | { | ||
1048 | long gain = 0; | ||
1049 | 1293 | ||
1050 | dsp->new_gain = false; | 1294 | new_gain = false; |
1051 | |||
1052 | if (global_settings.replaygain || global_settings.replaygain_noclip) | ||
1053 | { | ||
1054 | bool track_mode = get_replaygain_mode(dsp->track_gain != 0, | ||
1055 | dsp->album_gain != 0) == REPLAYGAIN_TRACK; | ||
1056 | long peak = (track_mode || !dsp->album_peak) | ||
1057 | ? dsp->track_peak : dsp->album_peak; | ||
1058 | |||
1059 | if (global_settings.replaygain) | ||
1060 | { | ||
1061 | gain = (track_mode || !dsp->album_gain) | ||
1062 | ? dsp->track_gain : dsp->album_gain; | ||
1063 | 1295 | ||
1064 | if (global_settings.replaygain_preamp) | 1296 | if (global_settings.replaygain || global_settings.replaygain_noclip) |
1065 | { | 1297 | { |
1066 | long preamp = get_replaygain_int( | 1298 | bool track_mode = get_replaygain_mode(track_gain != 0, |
1067 | global_settings.replaygain_preamp * 10); | 1299 | album_gain != 0) == REPLAYGAIN_TRACK; |
1300 | long peak = (track_mode || !album_peak) ? track_peak : album_peak; | ||
1068 | 1301 | ||
1069 | gain = (long) (((int64_t) gain * preamp) >> 24); | 1302 | if (global_settings.replaygain) |
1070 | } | 1303 | { |
1071 | } | 1304 | gain = (track_mode || !album_gain) ? track_gain : album_gain; |
1072 | 1305 | ||
1073 | if (gain == 0) | 1306 | if (global_settings.replaygain_preamp) |
1074 | { | 1307 | { |
1075 | /* So that noclip can work even with no gain information. */ | 1308 | long preamp = get_replaygain_int( |
1076 | gain = DEFAULT_GAIN; | 1309 | global_settings.replaygain_preamp * 10); |
1077 | } | ||
1078 | 1310 | ||
1079 | if (global_settings.replaygain_noclip && (peak != 0) | 1311 | gain = (long) (((int64_t) gain * preamp) >> 24); |
1080 | && ((((int64_t) gain * peak) >> 24) >= DEFAULT_GAIN)) | ||
1081 | { | ||
1082 | gain = (((int64_t) DEFAULT_GAIN << 24) / peak); | ||
1083 | } | 1312 | } |
1313 | } | ||
1084 | 1314 | ||
1085 | if (gain == DEFAULT_GAIN) | 1315 | if (gain == 0) |
1086 | { | 1316 | { |
1087 | /* Nothing to do, disable processing. */ | 1317 | /* So that noclip can work even with no gain information. */ |
1088 | gain = 0; | 1318 | gain = DEFAULT_GAIN; |
1319 | } | ||
1089 | 1320 | ||
1090 | } | 1321 | if (global_settings.replaygain_noclip && (peak != 0) |
1322 | && ((((int64_t) gain * peak) >> 24) >= DEFAULT_GAIN)) | ||
1323 | { | ||
1324 | gain = (((int64_t) DEFAULT_GAIN << 24) / peak); | ||
1091 | } | 1325 | } |
1092 | 1326 | ||
1093 | /* Store in S8.23 format to simplify calculations. */ | 1327 | if (gain == DEFAULT_GAIN) |
1094 | dsp->replaygain = gain; | 1328 | { |
1095 | set_gain(); | 1329 | /* Nothing to do, disable processing. */ |
1330 | gain = 0; | ||
1331 | } | ||
1096 | } | 1332 | } |
1333 | |||
1334 | /* Store in S8.23 format to simplify calculations. */ | ||
1335 | replaygain = gain; | ||
1336 | set_gain(audio_dsp); | ||
1097 | } | 1337 | } |
diff --git a/apps/dsp.h b/apps/dsp.h index b99ac213ab..63dc68cbb4 100644 --- a/apps/dsp.h +++ b/apps/dsp.h | |||
@@ -32,14 +32,14 @@ enum | |||
32 | STEREO_NUM_MODES, | 32 | STEREO_NUM_MODES, |
33 | }; | 33 | }; |
34 | 34 | ||
35 | enum { | 35 | enum |
36 | { | ||
36 | CODEC_SET_FILEBUF_WATERMARK = 1, | 37 | CODEC_SET_FILEBUF_WATERMARK = 1, |
37 | CODEC_SET_FILEBUF_CHUNKSIZE, | 38 | CODEC_SET_FILEBUF_CHUNKSIZE, |
38 | CODEC_SET_FILEBUF_PRESEEK, | 39 | CODEC_SET_FILEBUF_PRESEEK, |
40 | DSP_SWITCH_CODEC, | ||
39 | DSP_SET_FREQUENCY, | 41 | DSP_SET_FREQUENCY, |
40 | DSP_SWITCH_FREQUENCY, | 42 | DSP_SWITCH_FREQUENCY, |
41 | DSP_SET_CLIP_MIN, | ||
42 | DSP_SET_CLIP_MAX, | ||
43 | DSP_SET_SAMPLE_DEPTH, | 43 | DSP_SET_SAMPLE_DEPTH, |
44 | DSP_SET_STEREO_MODE, | 44 | DSP_SET_STEREO_MODE, |
45 | DSP_RESET, | 45 | DSP_RESET, |
@@ -200,7 +200,7 @@ int dsp_input_count(int count); | |||
200 | int dsp_output_count(int count); | 200 | int dsp_output_count(int count); |
201 | int dsp_stereo_mode(void); | 201 | int dsp_stereo_mode(void); |
202 | bool dsp_configure(int setting, intptr_t value); | 202 | bool dsp_configure(int setting, intptr_t value); |
203 | void dsp_set_replaygain(bool always); | 203 | void dsp_set_replaygain(void); |
204 | void dsp_set_crossfeed(bool enable); | 204 | void dsp_set_crossfeed(bool enable); |
205 | void dsp_set_crossfeed_direct_gain(int gain); | 205 | void dsp_set_crossfeed_direct_gain(int gain); |
206 | void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff); | 206 | void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff); |
diff --git a/apps/dsp_asm.h b/apps/dsp_asm.h index add76a07f8..aaf7e666ec 100644 --- a/apps/dsp_asm.h +++ b/apps/dsp_asm.h | |||
@@ -24,16 +24,26 @@ | |||
24 | 24 | ||
25 | #if defined(CPU_COLDFIRE) || defined(CPU_ARM) | 25 | #if defined(CPU_COLDFIRE) || defined(CPU_ARM) |
26 | #define DSP_HAVE_ASM_CROSSFEED | 26 | #define DSP_HAVE_ASM_CROSSFEED |
27 | void apply_crossfeed(int32_t* src[], int count); | 27 | void apply_crossfeed(int32_t *src[], int count); |
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | #if defined (CPU_COLDFIRE) | 30 | #if defined (CPU_COLDFIRE) |
31 | #define DSP_HAVE_ASM_RESAMPLING | 31 | #define DSP_HAVE_ASM_RESAMPLING |
32 | int dsp_downsample(int channels, int count, void *resample_data, | 32 | int dsp_downsample(int count, struct dsp_data *data, int32_t *src[], int32_t *dst[]); |
33 | int32_t **src, int32_t **dst); | 33 | int dsp_upsample(int count, struct dsp_data *data, int32_t *src[], int32_t *dst[]); |
34 | int dsp_upsample(int channels, int count, void *resample_data, | ||
35 | int32_t **src, int32_t **dst); | ||
36 | #endif | ||
37 | 34 | ||
38 | #endif /* _DSP_ASM_H */ | 35 | #define DSP_HAVE_ASM_SOUND_CHAN_MONO |
36 | void channels_process_sound_chan_mono(int count, int32_t *buf[]); | ||
37 | #define DSP_HAVE_ASM_SOUND_CHAN_CUSTOM | ||
38 | void channels_process_sound_chan_custom(int count, int32_t *buf[]); | ||
39 | #define DSP_HAVE_ASM_SOUND_CHAN_KARAOKE | ||
40 | void channels_process_sound_chan_karaoke(int count, int32_t *buf[]); | ||
39 | 41 | ||
42 | #define DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO | ||
43 | void sample_output_mono(int count, struct dsp_data *data, | ||
44 | int32_t *src[], int16_t *dst); | ||
45 | #define DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO | ||
46 | void sample_output_stereo(int count, struct dsp_data *data, | ||
47 | int32_t *src[], int16_t *dst); | ||
48 | #endif | ||
49 | #endif /* _DSP_ASM_H */ | ||
diff --git a/apps/dsp_cf.S b/apps/dsp_cf.S index 295ef05fe0..1f8dd48cee 100644 --- a/apps/dsp_cf.S +++ b/apps/dsp_cf.S | |||
@@ -18,7 +18,7 @@ | |||
18 | ****************************************************************************/ | 18 | ****************************************************************************/ |
19 | 19 | ||
20 | /**************************************************************************** | 20 | /**************************************************************************** |
21 | * apply_crossfeed(int32_t* src[], int count) | 21 | * void apply_crossfeed(int32_t *src[], int count) |
22 | */ | 22 | */ |
23 | .section .text | 23 | .section .text |
24 | .global apply_crossfeed | 24 | .global apply_crossfeed |
@@ -88,32 +88,31 @@ apply_crossfeed: | |||
88 | .size apply_crossfeed,.cfend-apply_crossfeed | 88 | .size apply_crossfeed,.cfend-apply_crossfeed |
89 | 89 | ||
90 | /**************************************************************************** | 90 | /**************************************************************************** |
91 | * dsp_downsample(int channels, int count, struct resample_data *r, | 91 | * int dsp_downsample(int count, struct dsp_data *data, |
92 | * in32_t **src, int32_t **dst) | 92 | * in32_t *src[], int32_t *dst[]) |
93 | */ | 93 | */ |
94 | .section .text | 94 | .section .text |
95 | .global dsp_downsample | 95 | .global dsp_downsample |
96 | dsp_downsample: | 96 | dsp_downsample: |
97 | lea.l -40(%sp), %sp | save non-clobberables | 97 | lea.l -40(%sp), %sp | save non-clobberables |
98 | movem.l %d2-%d7/%a2-%a5, (%sp) | | 98 | movem.l %d2-%d7/%a2-%a5, (%sp) | |
99 | movem.l 44(%sp), %d2-%d3/%a0-%a2| %d2 = ch = channels | 99 | movem.l 44(%sp), %d2/%a0-%a2 | %d2 = count |
100 | | %d3 = count | 100 | | %a0 = data |
101 | | %a0 = r | ||
102 | | %a1 = src | 101 | | %a1 = src |
103 | | %a2 = dst | 102 | | %a2 = dst |
104 | move.l 4(%a0), %d4 | %d4 = delta = r->delta | 103 | movem.l 4(%a0), %d3-%d4 | %d3 = ch = data->num_channels |
105 | move.l #16, %d7 | %d7 = shift | 104 | | %d4 = delta = data->resample_data.delta |
105 | moveq.l #16, %d7 | %d7 = shift | ||
106 | .dschannel_loop: | 106 | .dschannel_loop: |
107 | move.l (%a0), %d5 | %d5 = phase = r->phase | 107 | move.l 12(%a0), %d5 | %d5 = phase = data->resample_data.phase |
108 | move.l -4(%a1, %d2.l*4), %a3 | %a3 = s = src[ch-1] | 108 | move.l -4(%a1, %d3.l*4), %a3 | %a3 = s = src[ch-1] |
109 | move.l -4(%a2, %d2.l*4), %a4 | %a4 = d = dst[ch-1] | 109 | move.l -4(%a2, %d3.l*4), %a4 | %a4 = d = dst[ch-1] |
110 | lea.l 4(%a0, %d2.l*4), %a5 | %a5 = &r->last_sample[ch-1] | 110 | lea.l 12(%a0, %d3.l*4), %a5 | %a5 = &data->resample_data.ast_sample[ch-1] |
111 | move.l (%a5), %d0 | %d0 = last = r->last_sample[ch-1] | 111 | move.l (%a5), %d0 | %d0 = last = data->resample_data.last_sample[ch-1] |
112 | move.l -4(%a3, %d3.l*4), %d1 | r->last_sample[ch-1] = s[count-1] | 112 | move.l -4(%a3, %d2.l*4), (%a5) | data->resample_data.last_sample[ch-1] = s[count-1] |
113 | move.l %d1, (%a5) | | ||
114 | move.l %d5, %d6 | %d6 = pos = phase >> 16 | 113 | move.l %d5, %d6 | %d6 = pos = phase >> 16 |
115 | lsr.l %d7, %d6 | | 114 | lsr.l %d7, %d6 | |
116 | cmp.l %d3, %d6 | past end of samples? | 115 | cmp.l %d2, %d6 | past end of samples? |
117 | bge.b .dsloop_skip | yes? skip loop | 116 | bge.b .dsloop_skip | yes? skip loop |
118 | tst.l %d6 | need last sample of prev. frame? | 117 | tst.l %d6 | need last sample of prev. frame? |
119 | bne.b .dsloop | no? start main loop | 118 | bne.b .dsloop | no? start main loop |
@@ -134,14 +133,14 @@ dsp_downsample: | |||
134 | move.l %d5, %d6 | pos = phase >> 16 | 133 | move.l %d5, %d6 | pos = phase >> 16 |
135 | lsr.l %d7, %d6 | | 134 | lsr.l %d7, %d6 | |
136 | move.l %d0, (%a4)+ | *d++ = %d0 | 135 | move.l %d0, (%a4)+ | *d++ = %d0 |
137 | cmp.l %d3, %d6 | pos < count? | 136 | cmp.l %d2, %d6 | pos < count? |
138 | blt.b .dsloop | yes? continue resampling | 137 | blt.b .dsloop | yes? continue resampling |
139 | .dsloop_skip: | 138 | .dsloop_skip: |
140 | subq.l #1, %d2 | ch > 0? | 139 | subq.l #1, %d3 | ch > 0? |
141 | bgt.b .dschannel_loop | yes? process next channel | 140 | bgt.b .dschannel_loop | yes? process next channel |
142 | asl.l %d7, %d3 | wrap phase to start of next frame | 141 | asl.l %d7, %d2 | wrap phase to start of next frame |
143 | sub.l %d3, %d5 | r->phase = phase - (count << 16) | 142 | sub.l %d2, %d5 | data->resample_data.phase = |
144 | move.l %d5, (%a0) | | 143 | move.l %d5, 12(%a0) | ... phase - (count << 16) |
145 | move.l %a4, %d0 | return d - d[0] | 144 | move.l %a4, %d0 | return d - d[0] |
146 | sub.l (%a2), %d0 | | 145 | sub.l (%a2), %d0 | |
147 | asr.l #2, %d0 | convert bytes->samples | 146 | asr.l #2, %d0 | convert bytes->samples |
@@ -153,31 +152,30 @@ dsp_downsample: | |||
153 | .size dsp_downsample,.dsend-dsp_downsample | 152 | .size dsp_downsample,.dsend-dsp_downsample |
154 | 153 | ||
155 | /**************************************************************************** | 154 | /**************************************************************************** |
156 | * dsp_upsample(int channels, int count, struct resample_data *r, | 155 | * int dsp_upsample(int count, struct dsp_data *dsp, |
157 | * in32_t **src, int32_t **dst) | 156 | * in32_t *src[], int32_t *dst[]) |
158 | */ | 157 | */ |
159 | .section .text | 158 | .section .text |
160 | .global dsp_upsample | 159 | .global dsp_upsample |
161 | dsp_upsample: | 160 | dsp_upsample: |
162 | lea.l -40(%sp), %sp | save non-clobberables | 161 | lea.l -40(%sp), %sp | save non-clobberables |
163 | movem.l %d2-%d7/%a2-%a5, (%sp) | | 162 | movem.l %d2-%d7/%a2-%a5, (%sp) | |
164 | movem.l 44(%sp), %d2-%d3/%a0-%a2| %d2 = ch = channels | 163 | movem.l 44(%sp), %d2/%a0-%a2 | %d2 = count |
165 | | %d3 = count | 164 | | %a0 = data |
166 | | %a0 = r | ||
167 | | %a1 = src | 165 | | %a1 = src |
168 | | %a2 = dst | 166 | | %a2 = dst |
169 | move.l 4(%a0), %d4 | %d4 = delta = r->delta | 167 | movem.l 4(%a0), %d3-%d4 | %d3 = ch = channels |
168 | | %d4 = delta = data->resample_data.delta | ||
170 | swap %d4 | swap delta to high word to use | 169 | swap %d4 | swap delta to high word to use |
171 | | carries to increment position | 170 | | carries to increment position |
172 | .uschannel_loop: | 171 | .uschannel_loop: |
173 | move.l (%a0), %d5 | %d5 = phase = r->phase | 172 | move.l 12(%a0), %d5 | %d5 = phase = data->resample_data.phase |
174 | move.l -4(%a1, %d2.l*4), %a3 | %a3 = s = src[ch-1] | 173 | move.l -4(%a1, %d3.l*4), %a3 | %a3 = s = src[ch-1] |
175 | lea.l 4(%a0, %d2.l*4), %a4 | %a4 = &r->last_sample[ch-1] | 174 | lea.l 12(%a0, %d3.l*4), %a4 | %a4 = &data->resample_data.last_sample[ch-1] |
176 | lea.l (%a3, %d3.l*4), %a5 | %a5 = src_end = &src[count] | 175 | lea.l (%a3, %d2.l*4), %a5 | %a5 = src_end = &src[count] |
177 | move.l (%a4), %d0 | %d0 = last = r->last_sample[ch-1] | 176 | move.l (%a4), %d0 | %d0 = last = data->resample_data.last_sample[ch-1] |
178 | move.l -4(%a5), %d1 | r->last_sample[ch-1] = s[count-1] | 177 | move.l -(%a5), (%a4) | data->resample_data.last_sample[ch-1] = s[count-1] |
179 | move.l %d1, (%a4) | | 178 | move.l -4(%a2, %d3.l*4), %a4 | %a4 = d = dst[ch-1] |
180 | move.l -4(%a2, %d2.l*4), %a4 | %a4 = d = dst[ch-1] | ||
181 | swap %d5 | swap phase to high word to use | 179 | swap %d5 | swap phase to high word to use |
182 | | carries to increment position | 180 | | carries to increment position |
183 | move.l %d5, %d6 | %d6 = pos = phase >> 16 | 181 | move.l %d5, %d6 | %d6 = pos = phase >> 16 |
@@ -204,13 +202,13 @@ dsp_upsample: | |||
204 | move.l %d7, (%a4)+ | *d++ = %d7 | 202 | move.l %d7, (%a4)+ | *d++ = %d7 |
205 | add.l %d4, %d5 | phase += delta | 203 | add.l %d4, %d5 | phase += delta |
206 | bcc.b .usloop_0 | load next values? | 204 | bcc.b .usloop_0 | load next values? |
207 | cmp.l %a5, %a3 | src < src_end? | 205 | cmp.l %a5, %a3 | src <= src_end? |
208 | blt.b .usloop_1 | yes? continue resampling | 206 | ble.b .usloop_1 | yes? continue resampling |
209 | .usloop_skip: | 207 | .usloop_skip: |
210 | subq.l #1, %d2 | ch > 0? | 208 | subq.l #1, %d3 | ch > 0? |
211 | bgt.b .uschannel_loop | yes? process next channel | 209 | bgt.b .uschannel_loop | yes? process next channel |
212 | swap %d5 | wrap phase to start of next frame | 210 | swap %d5 | wrap phase to start of next frame |
213 | move.l %d5, (%a0) | ...and save in r->phase | 211 | move.l %d5, 12(%a0) | ...and save in data->resample_data.phase |
214 | move.l %a4, %d0 | return d - d[0] | 212 | move.l %a4, %d0 | return d - d[0] |
215 | sub.l (%a2), %d0 | | 213 | sub.l (%a2), %d0 | |
216 | movem.l (%sp), %d2-%d7/%a2-%a5 | restore non-clobberables | 214 | movem.l (%sp), %d2-%d7/%a2-%a5 | restore non-clobberables |
@@ -219,3 +217,307 @@ dsp_upsample: | |||
219 | rts | buh-bye | 217 | rts | buh-bye |
220 | .usend: | 218 | .usend: |
221 | .size dsp_upsample,.usend-dsp_upsample | 219 | .size dsp_upsample,.usend-dsp_upsample |
220 | |||
221 | /* These routines might benefit from burst transfers but we'll keep them | ||
222 | * small for now since they're rather light weight | ||
223 | */ | ||
224 | |||
225 | /**************************************************************************** | ||
226 | * void channels_process_sound_chan_mono(int count, int32_t *buf[]) | ||
227 | * | ||
228 | * Mix left and right channels 50/50 into a center channel. | ||
229 | */ | ||
230 | .section .text | ||
231 | .global channels_process_sound_chan_mono | ||
232 | channels_process_sound_chan_mono: | ||
233 | movem.l 4(%sp), %d0/%a0 | %d0 = count, %a0 = buf | ||
234 | lea.l -12(%sp), %sp | save registers | ||
235 | move.l %macsr, %d1 | | ||
236 | movem.l %d1-%d3, (%sp) | | ||
237 | move.l #0xb0, %macsr | put emac in rounding fractional mode | ||
238 | movem.l (%a0), %a0-%a1 | get channel pointers | ||
239 | move.l #0x40000000, %d3 | %d3 = 0.5 | ||
240 | 1: | ||
241 | move.l (%a0), %d1 | L = R = l/2 + r/2 | ||
242 | mac.l %d1, %d3, (%a1), %d2, %acc0 | | ||
243 | mac.l %d2, %d3, %acc0 | | ||
244 | movclr.l %acc0, %d1 | | ||
245 | move.l %d1, (%a0)+ | output to original buffer | ||
246 | move.l %d1, (%a1)+ | | ||
247 | subq.l #1, %d0 | | ||
248 | bgt.s 1b | | ||
249 | movem.l (%sp), %d1-%d3 | restore registers | ||
250 | move.l %d1, %macsr | | ||
251 | lea.l 12(%sp), %sp | cleanup | ||
252 | rts | ||
253 | .cpmono_end: | ||
254 | .size channels_process_sound_chan_mono, .cpmono_end-channels_process_sound_chan_mono | ||
255 | |||
256 | |||
257 | /**************************************************************************** | ||
258 | * void channels_process_sound_chan_custom(int count, int32_t *buf[]) | ||
259 | * | ||
260 | * Apply stereo width (narrowing/expanding) effect. | ||
261 | */ | ||
262 | .section .text | ||
263 | .global channels_process_sound_chan_custom | ||
264 | channels_process_sound_chan_custom: | ||
265 | movem.l 4(%sp), %d0/%a0 | %d0 = count, %a0 = buf | ||
266 | lea.l -16(%sp), %sp | save registers | ||
267 | move.l %macsr, %d1 | | ||
268 | movem.l %d1-%d4, (%sp) | | ||
269 | move.l #0xb0, %macsr | put emac in rounding fractional mode | ||
270 | movem.l (%a0), %a0-%a1 | get channel pointers | ||
271 | move.l dsp_sw_gain, %d3 | load straight (mid) gain | ||
272 | move.l dsp_sw_cross, %d4 | load cross (side) gain | ||
273 | 1: | ||
274 | move.l (%a0), %d1 | | ||
275 | mac.l %d1, %d3 , (%a1), %d2, %acc0 | L = l*gain + r*cross | ||
276 | mac.l %d1, %d4 , %acc1 | R = r*gain + l*cross | ||
277 | mac.l %d2, %d4 , %acc0 | | ||
278 | mac.l %d2, %d3 , %acc1 | | ||
279 | movclr.l %acc0, %d1 | | ||
280 | movclr.l %acc1, %d2 | | ||
281 | move.l %d1, (%a0)+ | | ||
282 | move.l %d2, (%a1)+ | | ||
283 | subq.l #1, %d0 | | ||
284 | bgt.s 1b | | ||
285 | movem.l (%sp), %d1-%d4 | restore registers | ||
286 | move.l %d1, %macsr | | ||
287 | lea.l 16(%sp), %sp | cleanup | ||
288 | rts | ||
289 | .cpcustom_end: | ||
290 | .size channels_process_sound_chan_custom, .cpcustom_end-channels_process_sound_chan_custom | ||
291 | |||
292 | /**************************************************************************** | ||
293 | * void channels_process_sound_chan_karaoke(int count, int32_t *buf[]) | ||
294 | * | ||
295 | * Separate channels into side channels. | ||
296 | */ | ||
297 | .section .text | ||
298 | .global channels_process_sound_chan_karaoke | ||
299 | channels_process_sound_chan_karaoke: | ||
300 | movem.l 4(%sp), %d0/%a0 | %d0 = count, %a0 = buf | ||
301 | lea.l -16(%sp), %sp | save registers | ||
302 | move.l %macsr, %d1 | | ||
303 | movem.l %d1-%d4, (%sp) | | ||
304 | move.l #0xb0, %macsr | put emac in rounding fractional mode | ||
305 | movem.l (%a0), %a0-%a1 | get channel pointers | ||
306 | move.l #0x40000000, %d4 | %d3 = 0.5 | ||
307 | 1: | ||
308 | move.l (%a0), %d1 | | ||
309 | mac.l %d1, %d4, (%a1), %d2, %acc0 | L = l/2 - r/2 | ||
310 | mac.l %d2, %d4, %acc1 | R = r/2 - l/2 | ||
311 | movclr.l %acc0, %d1 | | ||
312 | movclr.l %acc1, %d2 | | ||
313 | move.l %d1, %d3 | | ||
314 | sub.l %d2, %d1 | | ||
315 | sub.l %d3, %d2 | | ||
316 | move.l %d1, (%a0)+ | | ||
317 | move.l %d2, (%a1)+ | | ||
318 | subq.l #1, %d0 | | ||
319 | bgt.s 1b | | ||
320 | movem.l (%sp), %d1-%d4 | restore registers | ||
321 | move.l %d1, %macsr | | ||
322 | lea.l 16(%sp), %sp | cleanup | ||
323 | rts | ||
324 | .cpkaraoke_end: | ||
325 | .size channels_process_sound_chan_karaoke, .cpkaraoke_end-channels_process_sound_chan_karaoke | ||
326 | |||
327 | /**************************************************************************** | ||
328 | * void sample_output_stereo(int count, struct dsp_data *data, | ||
329 | * int32_t *src[], int16_t *dst) | ||
330 | * | ||
331 | * Framework based on the ubiquitous Rockbox line transfer logic for | ||
332 | * Coldfire CPUs. | ||
333 | * | ||
334 | * Does emac clamping and scaling (which proved faster than the usual | ||
335 | * checks and branches - even single test clamping) and writes using | ||
336 | * line burst transfers. Also better than writing a single L-R pair per | ||
337 | * loop but a good deal more code. | ||
338 | * | ||
339 | * Attemping bursting during reads is rather futile since the source and | ||
340 | * destination alignments rarely agree and too much complication will | ||
341 | * slow us up. The parallel loads seem to do a bit better at least until | ||
342 | * a pcm buffer can always give line aligned chunk and then aligning the | ||
343 | * dest can then imply the source is aligned if the source buffers are. | ||
344 | * For now longword alignment is assumed of both the source and dest. | ||
345 | * | ||
346 | */ | ||
347 | .section .text | ||
348 | .global sample_output_stereo | ||
349 | sample_output_stereo: | ||
350 | lea.l -44(%sp), %sp | save registers | ||
351 | move.l %macsr, %d1 | do it now as at many lines will | ||
352 | movem.l %d1-%d7/%a2-%a5, (%sp) | be the far more common condition | ||
353 | move.l #0x80, %macsr | put emac unit in signed int mode | ||
354 | movem.l 48(%sp), %a0-%a2/%a4 | | ||
355 | lea.l (%a4, %a0.l*4), %a0 | %a0 = end address | ||
356 | move.l (%a1), %d1 | %a1 = multiplier: (1 << (16 - scale)) | ||
357 | sub.l #16, %d1 | | ||
358 | neg.l %d1 | | ||
359 | move.q #1, %d0 | | ||
360 | asl.l %d1, %d0 | | ||
361 | move.l %d0, %a1 | | ||
362 | movem.l (%a2), %a2-%a3 | get L/R channel pointers | ||
363 | moveq.l #28, %d0 | %d0 = second line bound | ||
364 | add.l %a4, %d0 | | ||
365 | and.l #0xfffffff0, %d0 | | ||
366 | cmp.l %a4, %d0 | at least a full line? | ||
367 | blo.w .sos_longloop_1_start | no? jump to trailing longword | ||
368 | sub.l #16, %d0 | %d1 = first line bound | ||
369 | cmp.l %a4, %d0 | any leading longwords? | ||
370 | bls.b .sos_lineloop_start | no? jump to line loop | ||
371 | .sos_longloop_0: | ||
372 | move.l (%a2)+, %d1 | read longword from L and R | ||
373 | mac.l %d1, %a1, (%a3)+, %d2, %acc0 | shift L to high word | ||
374 | mac.l %d2, %a1, %acc1 | shift R to high word | ||
375 | movclr.l %acc0, %d1 | get possibly saturated results | ||
376 | movclr.l %acc1, %d2 | | ||
377 | swap %d2 | move R to low word | ||
378 | move.w %d2, %d1 | interleave MS 16 bits of each | ||
379 | move.l %d1, (%a4)+ | ...and write both | ||
380 | cmp.l %a4, %d0 | | ||
381 | bhi.b .sos_longloop_0 | | ||
382 | .sos_lineloop_start: | ||
383 | lea.l -12(%a0), %a5 | %a5 = at or just before last line bound | ||
384 | .sos_lineloop: | ||
385 | move.l (%a2)+, %d0 | get next 4 L samples and scale | ||
386 | mac.l %d0, %a1, (%a2)+, %d1, %acc0 | with saturation | ||
387 | mac.l %d1, %a1, (%a2)+, %d2, %acc1 | | ||
388 | mac.l %d2, %a1, (%a2)+, %d3, %acc2 | | ||
389 | mac.l %d3, %a1, %acc3 | | ||
390 | movclr.l %acc0, %d0 | obtain results | ||
391 | movclr.l %acc1, %d1 | | ||
392 | movclr.l %acc2, %d2 | | ||
393 | movclr.l %acc3, %d3 | | ||
394 | move.l (%a3)+, %d4 | get next 4 R samples and scale | ||
395 | mac.l %d4, %a1, (%a3)+, %d5, %acc0 | with saturation | ||
396 | mac.l %d5, %a1, (%a3)+, %d6, %acc1 | | ||
397 | mac.l %d6, %a1, (%a3)+, %d7, %acc2 | | ||
398 | mac.l %d7, %a1, %acc3 | | ||
399 | movclr.l %acc0, %d4 | obtain results | ||
400 | movclr.l %acc1, %d5 | | ||
401 | movclr.l %acc2, %d6 | | ||
402 | movclr.l %acc3, %d7 | | ||
403 | swap %d4 | interleave most significant | ||
404 | move.w %d4, %d0 | 16 bits of L and R | ||
405 | swap %d5 | | ||
406 | move.w %d5, %d1 | | ||
407 | swap %d6 | | ||
408 | move.w %d6, %d2 | | ||
409 | swap %d7 | | ||
410 | move.w %d7, %d3 | | ||
411 | movem.l %d0-%d3, (%a4) | write four stereo samples | ||
412 | lea.l 16(%a4), %a4 | | ||
413 | cmp.l %a4, %a5 | | ||
414 | bhi.b .sos_lineloop | | ||
415 | .sos_longloop_1_start: | ||
416 | cmp.l %a4, %a0 | any longwords left? | ||
417 | bls.b .sos_done | no? finished. | ||
418 | .sos_longloop_1: | ||
419 | move.l (%a2)+, %d1 | handle trailing longwords | ||
420 | mac.l %d1, %a1, (%a3)+, %d2, %acc0 | the same way as leading ones | ||
421 | mac.l %d2, %a1, %acc1 | | ||
422 | movclr.l %acc0, %d1 | | ||
423 | movclr.l %acc1, %d2 | | ||
424 | swap %d2 | | ||
425 | move.w %d2, %d1 | | ||
426 | move.l %d1, (%a4)+ | | ||
427 | cmp.l %a4, %a0 | | ||
428 | bhi.b .sos_longloop_1 | | ||
429 | .sos_done: | ||
430 | movem.l (%sp), %d1-%d7/%a2-%a5 | restore registers | ||
431 | move.l %d1, %macsr | | ||
432 | lea.l 44(%sp), %sp | cleanup | ||
433 | rts | | ||
434 | .sos_end: | ||
435 | .size sample_output_stereo, .sos_end-sample_output_stereo | ||
436 | |||
437 | /**************************************************************************** | ||
438 | * void sample_output_mono(int count, struct dsp_data *data, | ||
439 | * int32_t *src[], int16_t *dst) | ||
440 | * | ||
441 | * Same treatment as sample_output_stereo but for one channel. | ||
442 | */ | ||
443 | .section .text | ||
444 | .global sample_output_mono | ||
445 | sample_output_mono: | ||
446 | lea.l -28(%sp), %sp | save registers | ||
447 | move.l %macsr, %d1 | do it now as at many lines will | ||
448 | movem.l %d1-%d5/%a2-%a3, (%sp) | be the far more common condition | ||
449 | move.l #0x80, %macsr | put emac unit in signed int mode | ||
450 | movem.l 32(%sp), %a0-%a3 | | ||
451 | lea.l (%a3, %a0.l*4), %a0 | %a0 = end address | ||
452 | move.l (%a1), %d1 | %d5 = multiplier: (1 << (16 - scale)) | ||
453 | sub.l #16, %d1 | | ||
454 | neg.l %d1 | | ||
455 | move.q #1, %d5 | | ||
456 | asl.l %d1, %d5 | | ||
457 | movem.l (%a2), %a2 | get source channel pointer | ||
458 | moveq.l #28, %d0 | %d0 = second line bound | ||
459 | add.l %a3, %d0 | | ||
460 | and.l #0xfffffff0, %d0 | | ||
461 | cmp.l %a3, %d0 | at least a full line? | ||
462 | blo.w .som_longloop_1_start | no? jump to trailing longword | ||
463 | sub.l #16, %d0 | %d1 = first line bound | ||
464 | cmp.l %a3, %d0 | any leading longwords? | ||
465 | bls.b .som_lineloop_start | no? jump to line loop | ||
466 | .som_longloop_0: | ||
467 | move.l (%a2)+, %d1 | read longword from L and R | ||
468 | mac.l %d1, %d5, %acc0 | shift L to high word | ||
469 | movclr.l %acc0, %d1 | get possibly saturated results | ||
470 | move.l %d1, %d2 | | ||
471 | swap %d2 | move R to low word | ||
472 | move.w %d2, %d1 | duplicate single channel into | ||
473 | move.l %d1, (%a3)+ | L and R | ||
474 | cmp.l %a3, %d0 | | ||
475 | bhi.b .som_longloop_0 | | ||
476 | .som_lineloop_start: | ||
477 | lea.l -12(%a0), %a1 | %a1 = at or just before last line bound | ||
478 | .som_lineloop: | ||
479 | move.l (%a2)+, %d0 | get next 4 L samples and scale | ||
480 | mac.l %d0, %d5, (%a2)+, %d1, %acc0 | with saturation | ||
481 | mac.l %d1, %d5, (%a2)+, %d2, %acc1 | | ||
482 | mac.l %d2, %d5, (%a2)+, %d3, %acc2 | | ||
483 | mac.l %d3, %d5, %acc3 | | ||
484 | movclr.l %acc0, %d0 | obtain results | ||
485 | movclr.l %acc1, %d1 | | ||
486 | movclr.l %acc2, %d2 | | ||
487 | movclr.l %acc3, %d3 | | ||
488 | move.l %d0, %d4 | duplicate single channel | ||
489 | swap %d4 | into L and R | ||
490 | move.w %d4, %d0 | | ||
491 | move.l %d1, %d4 | | ||
492 | swap %d4 | | ||
493 | move.w %d4, %d1 | | ||
494 | move.l %d2, %d4 | | ||
495 | swap %d4 | | ||
496 | move.w %d4, %d2 | | ||
497 | move.l %d3, %d4 | | ||
498 | swap %d4 | | ||
499 | move.w %d4, %d3 | | ||
500 | movem.l %d0-%d3, (%a3) | write four stereo samples | ||
501 | lea.l 16(%a3), %a3 | | ||
502 | cmp.l %a3, %a1 | | ||
503 | bhi.b .som_lineloop | | ||
504 | .som_longloop_1_start: | ||
505 | cmp.l %a3, %a0 | any longwords left? | ||
506 | bls.b .som_done | no? finished. | ||
507 | .som_longloop_1: | ||
508 | move.l (%a2)+, %d1 | handle trailing longwords | ||
509 | mac.l %d1, %d5, %acc0 | the same way as leading ones | ||
510 | movclr.l %acc0, %d1 | | ||
511 | move.l %d1, %d2 | | ||
512 | swap %d2 | | ||
513 | move.w %d2, %d1 | | ||
514 | move.l %d1, (%a3)+ | | ||
515 | cmp.l %a3, %a0 | | ||
516 | bhi.b .som_longloop_1 | | ||
517 | .som_done: | ||
518 | movem.l (%sp), %d1-%d5/%a2-%a3 | restore registers | ||
519 | move.l %d1, %macsr | | ||
520 | lea.l 28(%sp), %sp | cleanup | ||
521 | rts | | ||
522 | .som_end: | ||
523 | .size sample_output_mono, .som_end-sample_output_mono | ||
diff --git a/apps/menus/playback_menu.c b/apps/menus/playback_menu.c index bdc0f93c89..6345b67ace 100644 --- a/apps/menus/playback_menu.c +++ b/apps/menus/playback_menu.c | |||
@@ -109,7 +109,7 @@ int replaygain_callback(int action,const struct menu_item_ex *this_item) | |||
109 | switch (action) | 109 | switch (action) |
110 | { | 110 | { |
111 | case ACTION_EXIT_MENUITEM: /* on exit */ | 111 | case ACTION_EXIT_MENUITEM: /* on exit */ |
112 | dsp_set_replaygain(true); | 112 | dsp_set_replaygain(); |
113 | break; | 113 | break; |
114 | } | 114 | } |
115 | return action; | 115 | return action; |
@@ -208,7 +208,7 @@ int playback_callback(int action,const struct menu_item_ex *this_item) | |||
208 | && (audio_status() & AUDIO_STATUS_PLAY)) | 208 | && (audio_status() & AUDIO_STATUS_PLAY)) |
209 | { | 209 | { |
210 | #if CONFIG_CODEC == SWCODEC | 210 | #if CONFIG_CODEC == SWCODEC |
211 | dsp_set_replaygain(true); | 211 | dsp_set_replaygain(); |
212 | #endif | 212 | #endif |
213 | if (global_settings.playlist_shuffle) | 213 | if (global_settings.playlist_shuffle) |
214 | { | 214 | { |
diff --git a/apps/playback.c b/apps/playback.c index 235b3fd0a4..d09d672dff 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -276,6 +276,7 @@ static size_t high_watermark; /* High watermark for rebuffer (A/V/other) */ | |||
276 | #endif | 276 | #endif |
277 | 277 | ||
278 | /* Multiple threads */ | 278 | /* Multiple threads */ |
279 | static void set_current_codec(int codec_idx); | ||
279 | static const char *get_codec_filename(int enc_spec); /* (A-/C-/V-) */ | 280 | static const char *get_codec_filename(int enc_spec); /* (A-/C-/V-) */ |
280 | /* Set the watermark to trigger buffer fill (A/C) FIXME */ | 281 | /* Set the watermark to trigger buffer fill (A/C) FIXME */ |
281 | static void set_filebuf_watermark(int seconds); | 282 | static void set_filebuf_watermark(int seconds); |
@@ -299,7 +300,7 @@ IBSS_ATTR; | |||
299 | static const char codec_thread_name[] = "codec"; | 300 | static const char codec_thread_name[] = "codec"; |
300 | struct thread_entry *codec_thread_p; /* For modifying thread priority later. */ | 301 | struct thread_entry *codec_thread_p; /* For modifying thread priority later. */ |
301 | 302 | ||
302 | volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */ | 303 | static volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */ |
303 | 304 | ||
304 | /* Voice thread */ | 305 | /* Voice thread */ |
305 | #ifdef PLAYBACK_VOICE | 306 | #ifdef PLAYBACK_VOICE |
@@ -840,7 +841,7 @@ void audio_preinit(void) | |||
840 | logf("playback system pre-init"); | 841 | logf("playback system pre-init"); |
841 | 842 | ||
842 | filling = false; | 843 | filling = false; |
843 | current_codec = CODEC_IDX_AUDIO; | 844 | set_current_codec(CODEC_IDX_AUDIO); |
844 | playing = false; | 845 | playing = false; |
845 | paused = false; | 846 | paused = false; |
846 | audio_codec_loaded = false; | 847 | audio_codec_loaded = false; |
@@ -918,6 +919,12 @@ void voice_stop(void) | |||
918 | 919 | ||
919 | 920 | ||
920 | /* --- Routines called from multiple threads --- */ | 921 | /* --- Routines called from multiple threads --- */ |
922 | static void set_current_codec(int codec_idx) | ||
923 | { | ||
924 | current_codec = codec_idx; | ||
925 | dsp_configure(DSP_SWITCH_CODEC, codec_idx); | ||
926 | } | ||
927 | |||
921 | #ifdef PLAYBACK_VOICE | 928 | #ifdef PLAYBACK_VOICE |
922 | static void swap_codec(void) | 929 | static void swap_codec(void) |
923 | { | 930 | { |
@@ -961,7 +968,7 @@ skip_iram_swap: | |||
961 | mutex_lock(&mutex_codecthread); | 968 | mutex_lock(&mutex_codecthread); |
962 | 969 | ||
963 | /* Take control */ | 970 | /* Take control */ |
964 | current_codec = my_codec; | 971 | set_current_codec(my_codec); |
965 | 972 | ||
966 | /* Reload our IRAM and DRAM */ | 973 | /* Reload our IRAM and DRAM */ |
967 | memcpy((unsigned char *)CODEC_IRAM_ORIGIN, iram_buf[my_codec], | 974 | memcpy((unsigned char *)CODEC_IRAM_ORIGIN, iram_buf[my_codec], |
@@ -1284,7 +1291,7 @@ static void voice_thread(void) | |||
1284 | logf("Loading voice codec"); | 1291 | logf("Loading voice codec"); |
1285 | voice_codec_loaded = true; | 1292 | voice_codec_loaded = true; |
1286 | mutex_lock(&mutex_codecthread); | 1293 | mutex_lock(&mutex_codecthread); |
1287 | current_codec = CODEC_IDX_VOICE; | 1294 | set_current_codec(CODEC_IDX_VOICE); |
1288 | dsp_configure(DSP_RESET, 0); | 1295 | dsp_configure(DSP_RESET, 0); |
1289 | voice_remaining = 0; | 1296 | voice_remaining = 0; |
1290 | voice_getmore = NULL; | 1297 | voice_getmore = NULL; |
@@ -1941,7 +1948,7 @@ static void codec_thread(void) | |||
1941 | } | 1948 | } |
1942 | mutex_lock(&mutex_codecthread); | 1949 | mutex_lock(&mutex_codecthread); |
1943 | #endif | 1950 | #endif |
1944 | current_codec = CODEC_IDX_AUDIO; | 1951 | set_current_codec(CODEC_IDX_AUDIO); |
1945 | ci.stop_codec = false; | 1952 | ci.stop_codec = false; |
1946 | status = codec_load_file((const char *)ev.data, &ci); | 1953 | status = codec_load_file((const char *)ev.data, &ci); |
1947 | #ifdef PLAYBACK_VOICE | 1954 | #ifdef PLAYBACK_VOICE |
@@ -1972,7 +1979,7 @@ static void codec_thread(void) | |||
1972 | } | 1979 | } |
1973 | mutex_lock(&mutex_codecthread); | 1980 | mutex_lock(&mutex_codecthread); |
1974 | #endif | 1981 | #endif |
1975 | current_codec = CODEC_IDX_AUDIO; | 1982 | set_current_codec(CODEC_IDX_AUDIO); |
1976 | ci.stop_codec = false; | 1983 | ci.stop_codec = false; |
1977 | wrap = (size_t)&filebuf[filebuflen] - (size_t)CUR_TI->codecbuf; | 1984 | wrap = (size_t)&filebuf[filebuflen] - (size_t)CUR_TI->codecbuf; |
1978 | status = codec_load_ram(CUR_TI->codecbuf, CUR_TI->codecsize, | 1985 | status = codec_load_ram(CUR_TI->codecbuf, CUR_TI->codecsize, |
@@ -1995,7 +2002,7 @@ static void codec_thread(void) | |||
1995 | mutex_lock(&mutex_codecthread); | 2002 | mutex_lock(&mutex_codecthread); |
1996 | #endif | 2003 | #endif |
1997 | logf("loading encoder"); | 2004 | logf("loading encoder"); |
1998 | current_codec = CODEC_IDX_AUDIO; | 2005 | set_current_codec(CODEC_IDX_AUDIO); |
1999 | ci.stop_codec = false; | 2006 | ci.stop_codec = false; |
2000 | status = codec_load_file((const char *)ev.data, &ci); | 2007 | status = codec_load_file((const char *)ev.data, &ci); |
2001 | #ifdef PLAYBACK_VOICE | 2008 | #ifdef PLAYBACK_VOICE |
@@ -2702,12 +2709,12 @@ static bool audio_load_track(int offset, bool start_play, bool rebuffer) | |||
2702 | { | 2709 | { |
2703 | int last_codec = current_codec; | 2710 | int last_codec = current_codec; |
2704 | 2711 | ||
2705 | current_codec = CODEC_IDX_AUDIO; | 2712 | set_current_codec(CODEC_IDX_AUDIO); |
2706 | conf_watermark = AUDIO_DEFAULT_WATERMARK; | 2713 | conf_watermark = AUDIO_DEFAULT_WATERMARK; |
2707 | conf_filechunk = AUDIO_DEFAULT_FILECHUNK; | 2714 | conf_filechunk = AUDIO_DEFAULT_FILECHUNK; |
2708 | conf_preseek = AUDIO_REBUFFER_GUESS_SIZE; | 2715 | conf_preseek = AUDIO_REBUFFER_GUESS_SIZE; |
2709 | dsp_configure(DSP_RESET, 0); | 2716 | dsp_configure(DSP_RESET, 0); |
2710 | current_codec = last_codec; | 2717 | set_current_codec(last_codec); |
2711 | } | 2718 | } |
2712 | 2719 | ||
2713 | /* Get track metadata if we don't already have it. */ | 2720 | /* Get track metadata if we don't already have it. */ |
diff --git a/apps/screens.c b/apps/screens.c index c7841c66b3..cdd68c9e94 100644 --- a/apps/screens.c +++ b/apps/screens.c | |||
@@ -703,7 +703,7 @@ bool quick_screen_quick(int button_enter) | |||
703 | && audio_status() & AUDIO_STATUS_PLAY) | 703 | && audio_status() & AUDIO_STATUS_PLAY) |
704 | { | 704 | { |
705 | #if CONFIG_CODEC == SWCODEC | 705 | #if CONFIG_CODEC == SWCODEC |
706 | dsp_set_replaygain(true); | 706 | dsp_set_replaygain(); |
707 | #endif | 707 | #endif |
708 | if (global_settings.playlist_shuffle) | 708 | if (global_settings.playlist_shuffle) |
709 | playlist_randomise(NULL, current_tick, true); | 709 | playlist_randomise(NULL, current_tick, true); |
diff --git a/apps/settings.c b/apps/settings.c index fef77a0915..dd5e7c5ae3 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -822,7 +822,7 @@ void settings_apply(void) | |||
822 | 822 | ||
823 | #if CONFIG_CODEC == SWCODEC | 823 | #if CONFIG_CODEC == SWCODEC |
824 | audio_set_crossfade(global_settings.crossfade); | 824 | audio_set_crossfade(global_settings.crossfade); |
825 | dsp_set_replaygain(true); | 825 | dsp_set_replaygain(); |
826 | dsp_set_crossfeed(global_settings.crossfeed); | 826 | dsp_set_crossfeed(global_settings.crossfeed); |
827 | dsp_set_crossfeed_direct_gain(global_settings.crossfeed_direct_gain); | 827 | dsp_set_crossfeed_direct_gain(global_settings.crossfeed_direct_gain); |
828 | dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain, | 828 | dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain, |
diff --git a/firmware/export/sound.h b/firmware/export/sound.h index 3ad74c4859..2079a84f0f 100644 --- a/firmware/export/sound.h +++ b/firmware/export/sound.h | |||
@@ -63,6 +63,7 @@ enum { | |||
63 | SOUND_CHAN_MONO_LEFT, | 63 | SOUND_CHAN_MONO_LEFT, |
64 | SOUND_CHAN_MONO_RIGHT, | 64 | SOUND_CHAN_MONO_RIGHT, |
65 | SOUND_CHAN_KARAOKE, | 65 | SOUND_CHAN_KARAOKE, |
66 | SOUND_CHAN_NUM_MODES | ||
66 | }; | 67 | }; |
67 | 68 | ||
68 | typedef void sound_set_type(int value); | 69 | typedef void sound_set_type(int value); |