diff options
Diffstat (limited to 'lib/rbcodec/codecs/libspc/spc_dsp_generic.c')
-rw-r--r-- | lib/rbcodec/codecs/libspc/spc_dsp_generic.c | 211 |
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 | ****************************************************************************/ | ||
23 | static inline int apply_gen_envx( struct voice_t* voice, int output ) | ||
24 | { | ||
25 | return (output * voice->envx) >> 11; | ||
26 | } | ||
27 | |||
28 | static 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 | |||
36 | static 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 | ||
47 | static 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 | ||
65 | static 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 | ||
82 | static 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 | ||
97 | static 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 */ | ||
120 | static 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 */ | ||
127 | static 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 */ | ||
167 | static 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 */ | ||
181 | static 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 */ | ||
198 | static 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 */ | ||