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