1 // Based on MAME driver by Derrick Renaud, Couriersud
2
3 #include "burnint.h"
4 #include "flt_rc.h"
5
6 #include <math.h>
7
8 #define FLT_RC_NUM 16
9
10 struct flt_rc_info
11 {
12 INT32 type;
13 double R1;
14 double R2;
15 double R3;
16 double C;
17
18 struct {
19 INT32 k;
20 INT32 memory;
21 INT32 type;
22 } state;
23
24 double src_gain;
25 double gain;
26 INT16 limit;
27 INT32 src_stereo;
28 INT32 output_dir;
29 INT32 add_signal;
30 };
31
32 static struct flt_rc_info flt_rc_table[FLT_RC_NUM];
33
34 static INT32 num_filters;
35
36 #define FLT_CLIP(A) ((A) < -ptr->limit ? -ptr->limit : (A) > ptr->limit ? ptr->limit : (A))
37
filter_rc_update(INT32 num,INT16 * src,INT16 * pSoundBuf,INT32 length)38 void filter_rc_update(INT32 num, INT16 *src, INT16 *pSoundBuf, INT32 length)
39 {
40 #if defined FBA_DEBUG
41 if (!DebugSnd_FilterRCInitted) bprintf(PRINT_ERROR, _T("filter_rc_update called without init\n"));
42 if (num > num_filters) bprintf(PRINT_ERROR, _T("filter_rc_update called with invalid num %i\n"), num);
43 #endif
44
45 struct flt_rc_info *ptr;
46
47 ptr = &flt_rc_table[num];
48
49 INT32 memory = ptr->state.memory;
50 INT16 value;
51
52 switch (ptr->state.type) {
53 case FLT_RC_LOWPASS: {
54 while (length--) {
55 if (ptr->state.k == 0x10000) {
56 memory = (INT32)(*src++ * ptr->src_gain); // filter disabled
57 } else {
58 memory += (((INT32)((*src++ * ptr->src_gain)) - memory) * ptr->state.k) / 0x10000; // enabled
59 }
60
61 if (ptr->src_stereo) src++;
62
63 INT32 nLeftSample = 0, nRightSample = 0;
64
65 if ((ptr->output_dir & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
66 nLeftSample += (INT32)(memory * ptr->gain);
67 }
68
69 if ((ptr->output_dir & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
70 nRightSample += (INT32)(memory * ptr->gain);
71 }
72
73 if (ptr->output_dir & (FLT_RC_PANNEDLEFT + FLT_RC_PANNEDRIGHT)) { // panned slightly right or left (used in gyruss)
74 nLeftSample += (INT32)(memory * ((ptr->output_dir & FLT_RC_PANNEDRIGHT) ? (ptr->gain / 3) : (ptr->gain)));
75 nRightSample += (INT32)(memory * ((ptr->output_dir & FLT_RC_PANNEDLEFT ) ? (ptr->gain / 3) : (ptr->gain)));
76 }
77
78 nLeftSample = FLT_CLIP(nLeftSample);
79 nRightSample = FLT_CLIP(nRightSample);
80
81 if (ptr->add_signal) {
82 pSoundBuf[0] = BURN_SND_CLIP(pSoundBuf[0] + nLeftSample);
83 pSoundBuf[1] = BURN_SND_CLIP(pSoundBuf[1] + nRightSample);
84 } else {
85 pSoundBuf[0] = nLeftSample;
86 pSoundBuf[1] = nRightSample;
87 }
88 pSoundBuf += 2;
89 }
90 break;
91 }
92
93 case FLT_RC_HIGHPASS:
94 case FLT_RC_AC: {
95 while (length--) {
96 if (ptr->state.k == 0x0) {
97 value = (INT32)(*src * ptr->src_gain); // filter disabled
98 } else {
99 value = (INT32)(*src * ptr->src_gain) - memory; // enabled
100 }
101
102 INT32 nLeftSample = 0, nRightSample = 0;
103
104 if ((ptr->output_dir & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
105 nLeftSample += (INT32)(value * ptr->gain);
106 }
107
108 if ((ptr->output_dir & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
109 nRightSample += (INT32)(value * ptr->gain);
110 }
111
112 if (ptr->output_dir & (FLT_RC_PANNEDLEFT + FLT_RC_PANNEDRIGHT)) { // panned slightly right or left (used in gyruss)
113 nLeftSample += (INT32)(value * ((ptr->output_dir & FLT_RC_PANNEDRIGHT) ? (ptr->gain / 3) : (ptr->gain)));
114 nRightSample += (INT32)(value * ((ptr->output_dir & FLT_RC_PANNEDLEFT ) ? (ptr->gain / 3) : (ptr->gain)));
115 }
116
117 nLeftSample = FLT_CLIP(nLeftSample);
118 nRightSample = FLT_CLIP(nRightSample);
119
120 if (ptr->add_signal) {
121 pSoundBuf[0] = BURN_SND_CLIP(pSoundBuf[0] + nLeftSample);
122 pSoundBuf[1] = BURN_SND_CLIP(pSoundBuf[1] + nRightSample);
123 } else {
124 pSoundBuf[0] = nLeftSample;
125 pSoundBuf[1] = nRightSample;
126 }
127 pSoundBuf += 2;
128 memory += (((INT32)(*src++ * ptr->src_gain) - memory) * ptr->state.k) / 0x10000;
129 if (ptr->src_stereo) src++;
130 }
131 break;
132 }
133 }
134
135 ptr->state.memory = memory;
136 }
137
set_RC_info(INT32 num,INT32 type,double R1,double R2,double R3,double C)138 static void set_RC_info(INT32 num, INT32 type, double R1, double R2, double R3, double C)
139 {
140 double Req = 0.00;
141
142 struct flt_rc_info *ptr;
143
144 ptr = &flt_rc_table[num];
145
146 ptr->state.type = type;
147
148 switch (ptr->state.type) {
149 case FLT_RC_LOWPASS: {
150 if (C == 0.0) {
151 /* filter disabled */
152 ptr->state.k = 0x10000;
153 return;
154 }
155 Req = (R1 * (R2 + R3)) / (R1 + R2 + R3);
156 break;
157 }
158
159 case FLT_RC_HIGHPASS:
160 case FLT_RC_AC: {
161 if (C == 0.0) {
162 /* filter disabled */
163 ptr->state.k = 0x0;
164 ptr->state.memory = 0x0;
165 return;
166 }
167 Req = R1;
168 break;
169 }
170
171 default:
172 bprintf(PRINT_IMPORTANT, _T("filter_rc_setRC: Wrong filter type %d\n"), ptr->state.type);
173 }
174
175 /* Cut Frequency = 1/(2*Pi*Req*C) */
176 /* k = (1-(EXP(-TIMEDELTA/RC))) */
177 ptr->state.k = (INT32)(0x10000 - 0x10000 * (exp(-1 / (Req * C) / nBurnSoundRate)));
178 }
179
filter_rc_set_RC(INT32 num,INT32 type,double R1,double R2,double R3,double C)180 void filter_rc_set_RC(INT32 num, INT32 type, double R1, double R2, double R3, double C)
181 {
182 #if defined FBA_DEBUG
183 if (!DebugSnd_FilterRCInitted) bprintf(PRINT_ERROR, _T("filter_rc_set_RC called without init\n"));
184 if (num > num_filters) bprintf(PRINT_ERROR, _T("filter_rc_set_RC called with invalid num %i\n"), num);
185 #endif
186
187 set_RC_info(num, type, R1, R2, R3, C);
188 }
189
filter_rc_init(INT32 num,INT32 type,double R1,double R2,double R3,double C,INT32 add_signal)190 void filter_rc_init(INT32 num, INT32 type, double R1, double R2, double R3, double C, INT32 add_signal)
191 {
192 #if defined FBA_DEBUG
193 if (num >= FLT_RC_NUM) bprintf (PRINT_ERROR, _T("filter_rc_init called for too many chips (%d)! Change FLT_RC_NUM (%d)!\n"), num, FLT_RC_NUM);
194 #endif
195
196 DebugSnd_FilterRCInitted = 1;
197
198 num_filters = num + 1;
199
200 set_RC_info(num, type, R1, R2, R3, C);
201
202 struct flt_rc_info *ptr;
203
204 ptr = &flt_rc_table[num];
205
206 ptr->src_gain = 1.00;
207 ptr->src_stereo = 0; // mostly used with ay8910 mono input, so default to off for stereo
208 ptr->gain = 1.00;
209 ptr->limit = 0x7fff;
210 ptr->output_dir = BURN_SND_ROUTE_BOTH;
211 ptr->add_signal = add_signal;
212 }
213
filter_rc_set_src_gain(INT32 num,double gain)214 void filter_rc_set_src_gain(INT32 num, double gain)
215 {
216 #if defined FBA_DEBUG
217 if (!DebugSnd_FilterRCInitted) bprintf(PRINT_ERROR, _T("filter_rc_set_src_gain called without init\n"));
218 if (num > num_filters) bprintf(PRINT_ERROR, _T("filter_rc_set_src_gain called with invalid num %i\n"), num);
219 #endif
220
221 struct flt_rc_info *ptr;
222
223 ptr = &flt_rc_table[num];
224
225 ptr->src_gain = gain;
226 }
227
filter_rc_set_src_stereo(INT32 num)228 void filter_rc_set_src_stereo(INT32 num)
229 { // allows for processing a mono (but stereo) stream
230 #if defined FBA_DEBUG
231 if (!DebugSnd_FilterRCInitted) bprintf(PRINT_ERROR, _T("filter_rc_set_src_stereo called without init\n"));
232 if (num > num_filters) bprintf(PRINT_ERROR, _T("filter_rc_set_src_stereo called with invalid num %i\n"), num);
233 #endif
234
235 struct flt_rc_info *ptr;
236
237 ptr = &flt_rc_table[num];
238
239 ptr->src_stereo = 1;
240 }
241
filter_rc_set_route(INT32 num,double nVolume,INT32 nRouteDir)242 void filter_rc_set_route(INT32 num, double nVolume, INT32 nRouteDir)
243 {
244 #if defined FBA_DEBUG
245 if (!DebugSnd_FilterRCInitted) bprintf(PRINT_ERROR, _T("filter_rc_set_route called without init\n"));
246 if (num > num_filters) bprintf(PRINT_ERROR, _T("filter_rc_set_route called with invalid num %i\n"), num);
247 #endif
248
249 struct flt_rc_info *ptr;
250
251 ptr = &flt_rc_table[num];
252
253 ptr->gain = nVolume;
254 ptr->output_dir = nRouteDir;
255 }
256
filter_rc_set_limit(INT32 num,double nVolume)257 void filter_rc_set_limit(INT32 num, double nVolume)
258 {
259 #if defined FBA_DEBUG
260 if (!DebugSnd_FilterRCInitted) bprintf(PRINT_ERROR, _T("filter_rc_set_limit called without init\n"));
261 if (num > num_filters) bprintf(PRINT_ERROR, _T("filter_rc_set_limit called with invalid num %i\n"), num);
262 #endif
263
264 struct flt_rc_info *ptr;
265
266 ptr = &flt_rc_table[num];
267
268 ptr->limit = (INT16)((double)nVolume * 0x7fff);
269 //bprintf(0, _T("limiter is +-%X. (%f)\n"), ptr->limit, nVolume);
270 }
271
filter_rc_exit()272 void filter_rc_exit()
273 {
274 #if defined FBA_DEBUG
275 if (!DebugSnd_FilterRCInitted) bprintf(PRINT_ERROR, _T("filter_rc_exit called without init\n"));
276 #endif
277
278 if (!DebugSnd_FilterRCInitted) return;
279
280 for (INT32 i = 0; i < FLT_RC_NUM; i++) {
281 struct flt_rc_info *ptr;
282
283 ptr = &flt_rc_table[i];
284
285 memset(ptr, 0, sizeof(flt_rc_info));
286 }
287
288 num_filters = 0;
289
290 DebugSnd_FilterRCInitted = 0;
291 }
292