summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libspc/spc_dsp_generic.c
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2013-05-18 01:45:03 -0400
committerMichael Sevakis <jethead71@rockbox.org>2013-05-21 00:02:14 -0400
commit87021f7c0ac4620eafd185ff11905ee643f72b6c (patch)
tree03ae48f3d999cd8743af40cc5df933f64f6df2d2 /lib/rbcodec/codecs/libspc/spc_dsp_generic.c
parenta17d6de5bc727b0bb55764ecef2605ae689e8dab (diff)
downloadrockbox-87021f7c0ac4620eafd185ff11905ee643f72b6c.tar.gz
rockbox-87021f7c0ac4620eafd185ff11905ee643f72b6c.zip
SPC Codec: Refactor for CPU and clean up some things.
CPU optimization gets its own files in which to fill-in optimizable routines. Some pointless #if 0's for profiling need removal. Those macros are empty if not profiling. Force some functions that are undesirable to be force-inlined by the compiler to be not inlined. Change-Id: Ia7b7e45380d7efb20c9b1a4d52e05db3ef6bbaab
Diffstat (limited to 'lib/rbcodec/codecs/libspc/spc_dsp_generic.c')
-rw-r--r--lib/rbcodec/codecs/libspc/spc_dsp_generic.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libspc/spc_dsp_generic.c b/lib/rbcodec/codecs/libspc/spc_dsp_generic.c
new file mode 100644
index 0000000000..60e79f8763
--- /dev/null
+++ b/lib/rbcodec/codecs/libspc/spc_dsp_generic.c
@@ -0,0 +1,211 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Adam Gashlin (hcs)
11 * Copyright (C) 2004-2007 Shay Green (blargg)
12 * Copyright (C) 2002 Brad Martin
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23static inline int apply_gen_envx( struct voice_t* voice, int output )
24{
25 return (output * voice->envx) >> 11;
26}
27
28static inline int apply_gen_volume( struct voice_t* voice, int output,
29 int* amp_0, int* amp_1 )
30{
31 *amp_0 = voice->volume [0] * output;
32 *amp_1 = voice->volume [1] * output;
33 return output;
34}
35
36static inline int apply_gen_amp( struct voice_t* voice, int output,
37 int* amp_0, int* amp_1)
38{
39 output = apply_gen_envx( voice, output );
40 output = apply_gen_volume( voice, output, amp_0, amp_1 );
41 return output;
42}
43
44#if !SPC_NOINTERP
45
46#ifndef SPC_GAUSSIAN_FAST_INTERP
47static inline int gaussian_fast_interp( int16_t const* samples,
48 int32_t position,
49 int16_t const* fwd,
50 int16_t const* rev )
51{
52 samples += position >> 12;
53 return (fwd [0] * samples [0] +
54 fwd [1] * samples [1] +
55 rev [1] * samples [2] +
56 rev [0] * samples [3]) >> 11;
57}
58#endif /* SPC_GAUSSIAN_FAST_INTERP */
59
60#ifndef SPC_GAUSSIAN_FAST_AMP
61#define gaussian_fast_amp apply_amp
62#endif /* SPC_GAUSSIAN_FAST_AMP */
63
64#ifndef SPC_GAUSSIAN_SLOW_INTERP
65static inline int gaussian_slow_interp( int16_t const* samples,
66 int32_t position,
67 int16_t const* fwd,
68 int16_t const* rev )
69{
70 int output;
71 samples += position >> 12;
72 output = (fwd [0] * samples [0]) & ~0xFFF;
73 output = (output + fwd [1] * samples [1]) & ~0xFFF;
74 output = (output + rev [1] * samples [2]) >> 12;
75 output = (int16_t) (output * 2);
76 output += ((rev [0] * samples [3]) >> 12) * 2;
77 return CLAMP16( output );
78}
79#endif /* SPC_GAUSSIAN_SLOW_INTERP */
80
81#ifndef SPC_GAUSSIAN_SLOW_AMP
82static inline int gaussian_slow_amp( struct voice_t* voice, int output,
83 int *amp_0, int *amp_1 )
84{
85 output = apply_gen_envx( voice, output ) & ~1;
86 output = apply_gen_volume( voice, output, amp_0, amp_1 );
87 return output;
88}
89#endif /* SPC_GAUSSIAN_SLOW_AMP */
90
91#define interp gaussian_slow_interp
92#define apply_amp gaussian_slow_amp
93
94#else /* SPC_NOINTERP */
95
96#ifndef SPC_LINEAR_INTERP
97static inline int linear_interp( int16_t const* samples, int32_t position )
98{
99 int32_t fraction = position & 0xfff;
100 int16_t const* pos = (samples + (position >> 12)) + 1;
101 return pos[0] + ((fraction * (pos[1] - pos[0])) >> 12);
102}
103#endif /* SPC_LINEAR_INTERP */
104
105#define interp( samp, pos, fwd, rev ) \
106 linear_interp( (samp), (pos) )
107
108#ifndef SPC_LINEAR_AMP
109#define linear_amp apply_gen_amp
110#endif /* SPC_LINEAR_AMP */
111
112#define apply_amp linear_amp
113#endif /* SPC_NOINTERP */
114
115
116#if !SPC_NOECHO
117
118#ifndef SPC_DSP_ECHO_APPLY
119/* Init FIR filter */
120static inline void echo_init( struct Spc_Dsp* this )
121{
122 this->fir.pos = 0;
123 ci->memset( this->fir.buf, 0, sizeof this->fir.buf );
124}
125
126/* Apply FIR filter */
127static inline void echo_apply(struct Spc_Dsp* this,
128 uint8_t* const echo_ptr, int* out_0, int* out_1)
129{
130 int fb_0 = GET_LE16SA( echo_ptr );
131 int fb_1 = GET_LE16SA( echo_ptr + 2 );
132
133 /* Keep last 8 samples */
134 int (* const fir_ptr) [2] = this->fir.buf + this->fir.pos;
135 this->fir.pos = (this->fir.pos + 1) & (FIR_BUF_HALF - 1);
136
137 fir_ptr [ 0] [0] = fb_0;
138 fir_ptr [ 0] [1] = fb_1;
139 /* duplicate at +8 eliminates wrap checking below */
140 fir_ptr [FIR_BUF_HALF] [0] = fb_0;
141 fir_ptr [FIR_BUF_HALF] [1] = fb_1;
142
143 fb_0 *= this->fir.coeff [0];
144 fb_1 *= this->fir.coeff [0];
145
146 #define DO_PT( i ) \
147 fb_0 += fir_ptr [i] [0] * this->fir.coeff [i]; \
148 fb_1 += fir_ptr [i] [1] * this->fir.coeff [i];
149
150 DO_PT( 1 )
151 DO_PT( 2 )
152 DO_PT( 3 )
153 DO_PT( 4 )
154 DO_PT( 5 )
155 DO_PT( 6 )
156 DO_PT( 7 )
157
158 #undef DO_PT
159
160 *out_0 = fb_0;
161 *out_1 = fb_1;
162}
163#endif /* SPC_DSP_ECHO_APPLY */
164
165#ifndef SPC_DSP_ECHO_FEEDBACK
166/* Feedback into echo buffer */
167static inline void echo_feedback( struct Spc_Dsp* this, uint8_t *echo_ptr,
168 int echo_0, int echo_1, int fb_0, int fb_1 )
169{
170 int e0 = (echo_0 >> 7) + ((fb_0 * this->r.g.echo_feedback) >> 14);
171 int e1 = (echo_1 >> 7) + ((fb_1 * this->r.g.echo_feedback) >> 14);
172 e0 = CLAMP16( e0 );
173 SET_LE16A( echo_ptr , e0 );
174 e1 = CLAMP16( e1 );
175 SET_LE16A( echo_ptr + 2, e1 );
176}
177#endif /* SPC_DSP_ECHO_FEEDBACK */
178
179#ifndef SPC_DSP_GENERATE_OUTPUT
180/* Generate final output */
181static inline void echo_output( struct Spc_Dsp* this, int global_muting,
182 int global_vol_0, int global_vol_1, int chans_0, int chans_1,
183 int fb_0, int fb_1, int* out_0, int* out_1 )
184{
185 *out_0 = (chans_0 * global_vol_0 + fb_0 * this->r.g.echo_volume_0)
186 >> global_muting;
187 *out_1 = (chans_1 * global_vol_1 + fb_1 * this->r.g.echo_volume_1)
188 >> global_muting;
189}
190#endif /* SPC_DSP_GENERATE_OUTPUT */
191
192#define mix_output echo_output
193
194#else /* SPC_NOECHO */
195
196#ifndef SPC_DSP_GENERATE_OUTPUT
197/* Generate final output */
198static inline void noecho_output( struct Spc_Dsp* this, int global_muting,
199 int global_vol_0, int global_vol_1, int chans_0, int chans_1,
200 int* out_0, int* out_1 )
201{
202 *out_0 = (chans_0 * global_vol_0) >> global_muting;
203 *out_1 = (chans_1 * global_vol_1) >> global_muting;
204 (void)this;
205}
206#endif /* SPC_DSP_GENERATE_OUTPUT */
207
208#define mix_output(this, gm, gv0, gv1, ch0, ch1, fb_0, fb_1, o0, o1) \
209 noecho_output( (this), (gm), (gv0), (gv1), (ch0), (ch1), (o0), (o1) )
210
211#endif /* !SPC_NOECHO */