summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-02-24 17:06:36 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-02-24 17:06:36 +0000
commitd4e904bf3557c63fb358d2d8e91bb103ca369e1a (patch)
tree2405fea04069c5d13286438d38ef7c246bb75075
parentdbf772bae969703972a672a866f07edc9a9031a5 (diff)
downloadrockbox-d4e904bf3557c63fb358d2d8e91bb103ca369e1a.tar.gz
rockbox-d4e904bf3557c63fb358d2d8e91bb103ca369e1a.zip
SWCODEC: Dsp speed optimizations. Changes for more modularity. Removal of some usless stuff. Some assembly routines for Coldfire with speed in mind over size for the outputs but the channel modes remain compact. Miscellaneous coldfire asm updates to accomodate the changes. Codec API structure version has to increase so do a full update.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12472 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs.h4
-rw-r--r--apps/codecs/mpa.c2
-rw-r--r--apps/codecs/spc.c3
-rw-r--r--apps/codecs/vorbis.c2
-rw-r--r--apps/dsp.c1106
-rw-r--r--apps/dsp.h8
-rw-r--r--apps/dsp_asm.h24
-rw-r--r--apps/dsp_cf.S380
-rw-r--r--apps/menus/playback_menu.c4
-rw-r--r--apps/playback.c25
-rw-r--r--apps/screens.c2
-rw-r--r--apps/settings.c2
-rw-r--r--firmware/export/sound.h1
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 */
101enum codec_status { 101enum 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
86next_track: 84next_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
715static int32_t samples[WAV_CHUNK_SIZE*2] IBSS_ATTR; 715static int32_t samples[WAV_CHUNK_SIZE*2]
716 __attribute__ ((aligned (16))) IBSS_ATTR;
716 717
717static struct Spc_Emu spc_emu IDATA_ATTR; 718static 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 */
50enum 46enum
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
61struct dsp_config 57enum
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 */
88struct resample_data 70struct 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 */
91struct 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 */
95struct dither_data 102struct 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
101struct crossfeed_data 109struct 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. */
113struct eq_state { 122struct 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
118static struct dsp_config dsp_conf[2] IBSS_ATTR; 129/* Include header with defines which functions are implemented in assembly
119static struct dither_data dither_data[2] IBSS_ATTR; 130 code for the target */
120static struct resample_data resample_data[2] IBSS_ATTR; 131#ifndef SIMULATOR
121struct crossfeed_data crossfeed_data IBSS_ATTR; 132#include <dsp_asm.h>
122static struct eq_state eq_data; 133#endif
134
135#ifndef DSP_HAVE_ASM_CROSSFEED
136static void apply_crossfeed(int32_t *buf[], int count);
137#endif
138/*
139 ***************************************************************************/
123 140
124static int pitch_ratio = 1000; 141struct dsp_config
125static int channels_mode = 0; 142{
126static 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
128extern int current_codec; 164/* General DSP config */
129static struct dsp_config *dsp; 165static struct dsp_config dsp_conf[2] IBSS_ATTR; /* 0=A, 1=V */
166/* Dithering */
167static struct dither_data dither_data[2] IBSS_ATTR; /* 0=left, 1=right */
168static long dither_mask IBSS_ATTR;
169static long dither_bias IBSS_ATTR;
170/* Crossfeed */
171struct crossfeed_data crossfeed_data IBSS_ATTR; /* A */
172/* Equalizer */
173static struct eq_state eq_data; /* A/V */
174
175/* Settings applicable to audio codec only */
176static int pitch_ratio = 1000;
177static int channels_mode;
178 long dsp_sw_gain;
179 long dsp_sw_cross;
180static bool dither_enabled;
181static bool eq_enabled IBSS_ATTR;
182static long eq_precut;
183static long track_gain;
184static bool new_gain;
185static long album_gain;
186static long track_peak;
187static long album_peak;
188static long replaygain;
189static bool crossfeed_enabled;
190
191#define audio_dsp (&dsp_conf[CODEC_IDX_AUDIO])
192#define voice_dsp (&dsp_conf[CODEC_IDX_VOICE])
193static 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;
136static int32_t sample_buf[SAMPLE_BUF_COUNT] IBSS_ATTR; 200static int32_t sample_buf[SAMPLE_BUF_COUNT] IBSS_ATTR;
137static int32_t resample_buf[RESAMPLE_BUF_COUNT] IBSS_ATTR; 201static int32_t resample_buf[RESAMPLE_BUF_COUNT] IBSS_ATTR;
138 202
203/* set a new dsp and return old one */
204static 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 */
213static 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 */
228static 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
139int sound_get_pitch(void) 235int 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 */
159static int convert_lte_native_mono( 255static 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 */
181static int convert_lte_native_interleaved_stereo( 277static 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 */
211static int convert_lte_native_noninterleaved_stereo( 307static 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 */
235static int convert_gt_native_mono( 333static 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 */
247static int convert_gt_native_interleaved_stereo( 345static 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 */
273static int convert_gt_native_noninterleaved_stereo( 371static 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/**
287static 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 */
394static 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 */
417static 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
435static 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 */
457static 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 */
532static 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
308static void resampler_set_delta(int frequency) 552static 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
318static int dsp_downsample(int channels, int count, struct resample_data *r, 563static 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
358static int dsp_upsample(int channels, int count, struct resample_data *r, 604static 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 */
405static inline int resample(int32_t *src[], int count) 652static 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
434static inline long clip_sample(int32_t sample, int32_t min, int32_t max) 670static 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
452void dsp_dither_enable(bool enable) 681void 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;
457static 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
464static 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 */
507void dsp_set_crossfeed(bool enable) 697void 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
512void dsp_set_crossfeed_direct_gain(int gain) 705void 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
536static void apply_crossfeed(int32_t* src[], int count) 729static 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. */
583static void set_gain(void) 777static 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 */
612void dsp_set_eq(bool enable) 807void 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 */
622void dsp_set_eq_precut(int precut) 817void 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. */
669static void eq_process(int32_t **x, unsigned num) 868static 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 */
694static void apply_gain(int32_t* _src[], int _count) 897static 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
730void 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
735void stereo_width_set(int value) 937void 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 */
756static 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
966static 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; 974static 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
795static void write_samples(short* dst, int32_t* src[], int count) 988#ifndef DSP_HAVE_ASM_SOUND_CHAN_CUSTOM
989static 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) 1006static 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
1012static 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
1019static 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
1034void 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 */
833int dsp_process(char *dst, const char *src[], int count) 1065int 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 */
884int dsp_output_count(int count) 1112int 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 */
908int dsp_input_count(int count) 1134int 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
926int dsp_stereo_mode(void) 1150int 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
933bool dsp_configure(int setting, intptr_t value) 1155bool 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
1042void dsp_set_replaygain(bool always) 1290void 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
35enum { 35enum
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);
200int dsp_output_count(int count); 200int dsp_output_count(int count);
201int dsp_stereo_mode(void); 201int dsp_stereo_mode(void);
202bool dsp_configure(int setting, intptr_t value); 202bool dsp_configure(int setting, intptr_t value);
203void dsp_set_replaygain(bool always); 203void dsp_set_replaygain(void);
204void dsp_set_crossfeed(bool enable); 204void dsp_set_crossfeed(bool enable);
205void dsp_set_crossfeed_direct_gain(int gain); 205void dsp_set_crossfeed_direct_gain(int gain);
206void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff); 206void 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
27void apply_crossfeed(int32_t* src[], int count); 27void 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
32int dsp_downsample(int channels, int count, void *resample_data, 32int dsp_downsample(int count, struct dsp_data *data, int32_t *src[], int32_t *dst[]);
33 int32_t **src, int32_t **dst); 33int dsp_upsample(int count, struct dsp_data *data, int32_t *src[], int32_t *dst[]);
34int 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
36void channels_process_sound_chan_mono(int count, int32_t *buf[]);
37#define DSP_HAVE_ASM_SOUND_CHAN_CUSTOM
38void channels_process_sound_chan_custom(int count, int32_t *buf[]);
39#define DSP_HAVE_ASM_SOUND_CHAN_KARAOKE
40void channels_process_sound_chan_karaoke(int count, int32_t *buf[]);
39 41
42#define DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO
43void sample_output_mono(int count, struct dsp_data *data,
44 int32_t *src[], int16_t *dst);
45#define DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO
46void 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
96dsp_downsample: 96dsp_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
161dsp_upsample: 160dsp_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
232channels_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
2401:
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
264channels_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
2731:
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
299channels_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
3071:
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
349sample_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
445sample_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 */
279static void set_current_codec(int codec_idx);
279static const char *get_codec_filename(int enc_spec); /* (A-/C-/V-) */ 280static 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 */
281static void set_filebuf_watermark(int seconds); 282static void set_filebuf_watermark(int seconds);
@@ -299,7 +300,7 @@ IBSS_ATTR;
299static const char codec_thread_name[] = "codec"; 300static const char codec_thread_name[] = "codec";
300struct thread_entry *codec_thread_p; /* For modifying thread priority later. */ 301struct thread_entry *codec_thread_p; /* For modifying thread priority later. */
301 302
302volatile int current_codec IDATA_ATTR; /* Current codec (normal/voice) */ 303static 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 --- */
922static 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
922static void swap_codec(void) 929static 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
68typedef void sound_set_type(int value); 69typedef void sound_set_type(int value);