1 /************************************************************************/
2 /*                                                                      */
3 /*  MAME - Discrete sound system emulation library                      */
4 /*                                                                      */
5 /*  Written by Keith Wilkins (mame@esplexo.co.uk)                       */
6 /*                                                                      */
7 /*  (c) K.Wilkins 2000                                                  */
8 /*                                                                      */
9 /************************************************************************/
10 /*                                                                      */
11 /* DST_FILTER1           - Generic 1st order filter                     */
12 /* DST_FILTER2           - Generic 2nd order filter                     */
13 /* DST_RCFILTER          - Simple RC filter & also lowpass filter       */
14 /* DST_RCDISC            - Simple discharing RC                         */
15 /*                                                                      */
16 /************************************************************************/
17 
18 /************************************************************************/
19 /*                                                                      */
20 /* DST_FILTER1 - Generic 1st order filter                               */
21 /*                                                                      */
22 /* input[0]    - Enable input value                                     */
23 /* input[1]    - input value                                            */
24 /* input[2]    - Frequency value (initialisation only)                  */
25 /* input[3]    - Filter type (initialisation only)                      */
26 /* input[4]    - NOT USED                                               */
27 /* input[5]    - NOT USED                                               */
28 /*                                                                      */
29 /************************************************************************/
30 
31 struct dss_filter1_context
32 {
33 	double x1;		/* x[k-1], previous input value */
34 	double y1;		/* y[k-1], previous output value */
35 	double a1;		/* digital filter coefficients, denominator */
36 	double b0, b1;	/* digital filter coefficients, numerator */
37 };
38 
calculate_filter1_coefficients(double fc,double type,double * a1,double * b0,double * b1)39 static void calculate_filter1_coefficients(double fc, double type,
40                                            double *a1, double *b0, double *b1)
41 {
42 	double den, w, two_over_T;
43 
44 	/* calculate digital filter coefficents */
45     /*w = 2.0*M_PI*fc; no pre-warping */
46     w = Machine->sample_rate*2.0*tan(M_PI*fc/Machine->sample_rate); /* pre-warping */
47 	two_over_T = 2.0*Machine->sample_rate;
48 
49     den = w + two_over_T;
50     *a1 = (w - two_over_T)/den;
51     if (type == DISC_FILTER_LOWPASS)
52 	{
53     	*b0 = *b1 = w/den;
54 	}
55 	else if (type == DISC_FILTER_HIGHPASS)
56     {
57 		*b0 = two_over_T/den;
58     	*b1 = *b0;
59 	}
60 	else
61 	{
62 		discrete_log("calculate_filter1_coefficients() - Invalid filter type for 1st order filter.");
63 	}
64 }
65 
dst_filter1_step(struct node_description * node)66 int dst_filter1_step(struct node_description *node)
67 {
68 	struct dss_filter1_context *context;
69 	double gain = 1.0;
70 
71 	context=(struct dss_filter1_context*)node->context;
72 	if (node->input[0] == 0.0)
73 	{
74 		gain = 0.0;
75 	}
76 
77 	node->output = -context->a1*context->y1 + context->b0*gain*node->input[1] + context->b1*context->x1;
78 
79 	context->x1 = gain*node->input[1];
80 	context->y1 = node->output;
81 
82 	return 0;
83 }
84 
dst_filter1_reset(struct node_description * node)85 int dst_filter1_reset(struct node_description *node)
86 {
87 	node->output=0;
88 	return 0;
89 }
90 
dst_filter1_init(struct node_description * node)91 int dst_filter1_init(struct node_description *node)
92 {
93 	struct dss_filter1_context *context;
94 
95 	/* Allocate memory for the context array and the node execution order array */
96 	if((node->context=malloc(sizeof(struct dss_filter1_context)))==NULL)
97 	{
98 		discrete_log("dss_filter1_init() - Failed to allocate local context memory.");
99 		return 1;
100 	}
101 	else
102 	{
103 		/* Initialise memory */
104 		memset(node->context,0,sizeof(struct dss_filter1_context));
105 	}
106 	context=(struct dss_filter1_context*)node->context;
107 
108 	calculate_filter1_coefficients(node->input[2], node->input[3],
109 								   &context->a1, &context->b0, &context->b1);
110 
111 	/* Initialise the object */
112 	dst_filter1_reset(node);
113 	return 0;
114 }
115 
116 /************************************************************************/
117 /*                                                                      */
118 /* DST_FILTER2 - Generic 2nd order filter                               */
119 /*                                                                      */
120 /* input[0]    - Enable input value                                     */
121 /* input[1]    - input value                                            */
122 /* input[2]    - Frequency value (initialisation only)                  */
123 /* input[3]    - Damping value (initialisation only)                    */
124 /* input[4]    - Filter type (initialisation only) 						*/
125 /* input[5]    - NOT USED                                               */
126 /*                                                                      */
127 /************************************************************************/
128 
129 struct dss_filter2_context
130 {
131 	double x1, x2;		/* x[k-1], x[k-2], previous 2 input values */
132 	double y1, y2;		/* y[k-1], y[k-2], previous 2 output values */
133 	double a1, a2;		/* digital filter coefficients, denominator */
134 	double b0, b1, b2;	/* digital filter coefficients, numerator */
135 };
136 
calculate_filter2_coefficients(double fc,double d,double type,double * a1,double * a2,double * b0,double * b1,double * b2)137 static void calculate_filter2_coefficients(double fc, double d, double type,
138                                            double *a1, double *a2,
139                                            double *b0, double *b1, double *b2)
140 {
141 	double w;	/* cutoff freq, in radians/sec */
142 	double w_squared;
143 	double den;	/* temp variable */
144 	double two_over_T = 2*Machine->sample_rate;
145 	double two_over_T_squared = two_over_T * two_over_T;
146 
147 	/* calculate digital filter coefficents */
148     /*w = 2.0*M_PI*fc; no pre-warping */
149     w = Machine->sample_rate*2.0*tan(M_PI*fc/Machine->sample_rate); /* pre-warping */
150 	w_squared = w*w;
151 
152     den = two_over_T_squared + d*w*two_over_T + w_squared;
153 
154     *a1 = 2.0*(-two_over_T_squared + w_squared)/den;
155     *a2 = (two_over_T_squared - d*w*two_over_T + w_squared)/den;
156 
157     if (type == DISC_FILTER_LOWPASS)
158 	{
159     	*b0 = *b2 = w_squared/den;
160     	*b1 = 2.0*(*b0);
161 	}
162 	else if (type == DISC_FILTER_BANDPASS)
163     {
164 		*b0 = w*two_over_T/den;
165     	*b1 = 0.0;
166     	*b2 = -(*b0);
167 	}
168 	else if (type == DISC_FILTER_HIGHPASS)
169     {
170 		*b0 = *b2 = two_over_T_squared/den;
171     	*b1 = -2.0*(*b0);
172 	}
173 	else
174 	{
175 		discrete_log("calculate_filter2_coefficients() - Invalid filter type for 2nd order filter.");
176 	}
177 }
178 
dst_filter2_step(struct node_description * node)179 int dst_filter2_step(struct node_description *node)
180 {
181 	struct dss_filter2_context *context;
182 	double gain = 1.0;
183 
184 	context=(struct dss_filter2_context*)node->context;
185 	if (node->input[0] == 0.0)
186 	{
187 		gain = 0.0;
188 	}
189 
190 	node->output = -context->a1*context->y1 - context->a2*context->y2 +
191 	                context->b0*gain*node->input[1] + context->b1*context->x1 + context->b2*context->x2;
192 
193 	context->x2 = context->x1;
194 	context->x1 = gain*node->input[1];
195 	context->y2 = context->y1;
196 	context->y1 = node->output;
197 
198 	return 0;
199 }
200 
dst_filter2_reset(struct node_description * node)201 int dst_filter2_reset(struct node_description *node)
202 {
203 	node->output=0;
204 	return 0;
205 }
206 
dst_filter2_init(struct node_description * node)207 int dst_filter2_init(struct node_description *node)
208 {
209 	struct dss_filter2_context *context;
210 
211 	/* Allocate memory for the context array and the node execution order array */
212 	if((node->context=malloc(sizeof(struct dss_filter2_context)))==NULL)
213 	{
214 		discrete_log("dss_filter2_init() - Failed to allocate local context memory.");
215 		return 1;
216 	}
217 	else
218 	{
219 		/* Initialise memory */
220 		memset(node->context,0,sizeof(struct dss_filter2_context));
221 	}
222 	context=(struct dss_filter2_context*)node->context;
223 
224 	calculate_filter2_coefficients(node->input[2], node->input[3], node->input[4],
225 								   &context->a1, &context->a2,
226 								   &context->b0, &context->b1, &context->b2);
227 
228 	/* Initialise the object */
229 	dst_filter2_reset(node);
230 	return 0;
231 }
232 
233 
234 struct dss_rcdisc_context
235 {
236         int state;
237         double t;           // time
238         double step;
239 	double exponent0;
240 	double exponent1;
241 };
242 
243 /************************************************************************/
244 /*                                                                      */
245 /* DST_RCFILTER - Usage of node_description values for RC filter        */
246 /*                                                                      */
247 /* input[0]    - Enable input value                                     */
248 /* input[1]    - input value                                            */
249 /* input[2]    - Resistor value (initialisation only)                   */
250 /* input[3]    - Capacitor Value (initialisation only)                  */
251 /* input[4]    - NOT USED                                               */
252 /* input[5]    - Pre-calculated value for exponent                      */
253 /*                                                                      */
254 /************************************************************************/
dst_rcfilter_step(struct node_description * node)255 int dst_rcfilter_step(struct node_description *node)
256 {
257 	/************************************************************************/
258 	/* Next Value = PREV + (INPUT_VALUE - PREV)*(1-(EXP(-TIMEDELTA/RC)))    */
259 	/************************************************************************/
260 
261 	if(node->input[0])
262 	{
263 		node->output=node->output+((node->input[1]-node->output)*node->input[5]);
264 	}
265 	else
266 	{
267 		node->output=0;
268 	}
269 	return 0;
270 }
271 
dst_rcfilter_reset(struct node_description * node)272 int dst_rcfilter_reset(struct node_description *node)
273 {
274 	node->output=0;
275 	return 0;
276 }
277 
dst_rcfilter_init(struct node_description * node)278 int dst_rcfilter_init(struct node_description *node)
279 {
280 	node->input[5]=-1.0/(node->input[2]*node->input[3]*Machine->sample_rate);
281 	node->input[5]=1-exp(node->input[5]);
282 	/* Initialise the object */
283 	dst_rcfilter_reset(node);
284 	return 0;
285 }
286 
287 /************************************************************************/
288 /*                                                                      */
289 /* DST_RCDISC -   Usage of node_description values for RC discharge     */
290 /*                (inverse slope of DST_RCFILTER)                       */
291 /*                                                                      */
292 /* input[0]    - Enable input value                                     */
293 /* input[1]    - input value                                            */
294 /* input[2]    - Resistor value (initialisation only)                   */
295 /* input[3]    - Capacitor Value (initialisation only)                  */
296 /* input[4]    - NOT USED                                               */
297 /* input[5]    - NOT_USED                                               */
298 /*                                                                      */
299 /************************************************************************/
300 
dst_rcdisc_step(struct node_description * node)301 int dst_rcdisc_step(struct node_description *node)
302 {
303 	struct dss_rcdisc_context *context;
304 	context=(struct dss_rcdisc_context*)node->context;
305 
306 	switch (context->state) {
307 		case 0:     /* waiting for trigger  */
308 			if(node->input[0]) {
309 				context->state = 1;
310 				context->t = 0;
311 			}
312 			node->output=0;
313 			break;
314 
315 		case 1:
316 			if (node->input[0]) {
317 				node->output=node->input[1] * exp(context->t / context->exponent0);
318 				context->t += context->step;
319                 } else {
320 					context->state = 0;
321 			}
322 		}
323 
324 	return 0;
325 }
326 
dst_rcdisc_reset(struct node_description * node)327 int dst_rcdisc_reset(struct node_description *node)
328 {
329 	struct dss_rcdisc_context *context;
330 	context=(struct dss_rcdisc_context*)node->context;
331 
332 	node->output=0;
333 
334 	context->state = 0;
335 	context->t = 0;
336 	context->step = 1.0 / Machine->sample_rate;
337 	context->exponent0=-1.0 * node->input[2]*node->input[3];
338 
339 	return 0;
340 }
341 
dst_rcdisc_init(struct node_description * node)342 int dst_rcdisc_init(struct node_description *node)
343 {
344 	/* Allocate memory for the context array and the node execution order array */
345 	if((node->context=malloc(sizeof(struct dss_rcdisc_context)))==NULL)
346 	{
347 		discrete_log("dss_rcdisc_init() - Failed to allocate local context memory.");
348 		return 1;
349 	}
350 	else
351 	{
352 		/* Initialise memory */
353 		memset(node->context,0,sizeof(struct dss_rcdisc_context));
354 	}
355 
356 	/* Initialise the object */
357 	dst_rcdisc_reset(node);
358 	return 0;
359 }
360 
361 
362 /************************************************************************/
363 /*                                                                      */
364 /* DST_RCDISC2 -  Usage of node_description values for RC discharge     */
365 /*                Has switchable charge resistor/input                  */
366 /*                                                                      */
367 /* input[0]    - Switch input value                                     */
368 /* input[1]    - input[0] value                                         */
369 /* input[2]    - Resistor0 value (initialisation only)                  */
370 /* input[3]    - input[1] value                                         */
371 /* input[4]    - Resistor1 value (initialisation only)                  */
372 /* input[5]    - Capacitor Value (initialisation only)                  */
373 /*                                                                      */
374 /************************************************************************/
375 
376 
dst_rcdisc2_step(struct node_description * node)377 int dst_rcdisc2_step(struct node_description *node)
378 {
379 	double diff;
380 	struct dss_rcdisc_context *context;
381 	context=(struct dss_rcdisc_context*)node->context;
382 
383 	/* Works differently to other as we always on, no enable */
384 	/* exponential based in differnce between input/output   */
385 
386 	diff = ((node->input[0]==0)?node->input[1]:node->input[3])-node->output;
387 	diff = diff -(diff * exp(context->step / ((node->input[0]==0)?context->exponent0:context->exponent1)));
388 	node->output+=diff;
389 	return 0;
390 }
391 
dst_rcdisc2_reset(struct node_description * node)392 int dst_rcdisc2_reset(struct node_description *node)
393 {
394 	struct dss_rcdisc_context *context;
395 	context=(struct dss_rcdisc_context*)node->context;
396 
397 	node->output=0;
398 
399 	context->state = 0;
400 	context->t = 0;
401 	context->step = 1.0 / Machine->sample_rate;
402 	context->exponent0=-1.0 * node->input[2]*node->input[5];
403 	context->exponent1=-1.0 * node->input[4]*node->input[5];
404 
405 	return 0;
406 }
407 
dst_rcdisc2_init(struct node_description * node)408 int dst_rcdisc2_init(struct node_description *node)
409 {
410 	/* Allocate memory for the context array and the node execution order array */
411 	if((node->context=malloc(sizeof(struct dss_rcdisc_context)))==NULL)
412 	{
413 		discrete_log("dss_rcdisc2_init() - Failed to allocate local context memory.");
414 		return 1;
415 	}
416 	else
417 	{
418 		/* Initialise memory */
419 		memset(node->context,0,sizeof(struct dss_rcdisc_context));
420 	}
421 
422 	/* Initialise the object */
423 	dst_rcdisc2_reset(node);
424 	return 0;
425 }
426 
427 /* !!!!!!!!!!! NEW FILTERS for testing !!!!!!!!!!!!!!!!!!!!! */
428 
429 
430 /************************************************************************/
431 /*                                                                      */
432 /* DST_RCFILTER - Usage of node_description values for RC filter        */
433 /*                                                                      */
434 /* input[0]    - Enable input value                                     */
435 /* input[1]    - input value                                            */
436 /* input[2]    - Resistor value (initialisation only)                   */
437 /* input[3]    - Capacitor Value (initialisation only)                  */
438 /* input[4]    - NOT USED                                               */
439 /* input[5]    - NOT USED                                               */
440 /*                                                                      */
441 /************************************************************************/
442 
dst_rcfilterN_init(struct node_description * node)443 int dst_rcfilterN_init(struct node_description *node)
444 {
445 	double f=1.0/(2*M_PI*node->input[2]*node->input[3]);
446 
447 	node->input[2] = f;
448 	node->input[3] = DISC_FILTER_LOWPASS;
449 
450 	/* Use first order filter */
451 	return dst_filter1_init(node);
452 }
453 
454 
455 /************************************************************************/
456 /*                                                                      */
457 /* DST_RCDISC -   Usage of node_description values for RC discharge     */
458 /*                (inverse slope of DST_RCFILTER)                       */
459 /*                                                                      */
460 /* input[0]    - Enable input value                                     */
461 /* input[1]    - input value                                            */
462 /* input[2]    - Resistor value (initialisation only)                   */
463 /* input[3]    - Capacitor Value (initialisation only)                  */
464 /* input[4]    - NOT USED                                               */
465 /* input[5]    - NOT_USED                                               */
466 /*                                                                      */
467 /************************************************************************/
468 
dst_rcdiscN_init(struct node_description * node)469 int dst_rcdiscN_init(struct node_description *node)
470 {
471 	double f=1.0/(2*M_PI*node->input[2]*node->input[3]);
472 
473 	node->input[2] = f;
474 	node->input[3] = DISC_FILTER_LOWPASS;
475 
476 	/* Use first order filter */
477 	return dst_filter1_init(node);
478 }
479 
dst_rcdiscN_step(struct node_description * node)480 int dst_rcdiscN_step(struct node_description *node)
481 {
482 	struct dss_filter1_context *context;
483 	double gain = 1.0;
484 	context=(struct dss_filter1_context*)node->context;
485 
486 	if (node->input[0] == 0.0)
487 	{
488 		gain = 0.0;
489 	}
490 
491 	/* A rise in the input signal results in an instant charge, */
492 	/* else discharge through the RC to zero */
493 	if (gain*node->input[1] > context->x1)
494 		node->output = gain*node->input[1];
495 	else
496 		node->output = -context->a1*context->y1;
497 
498 	context->x1 = gain*node->input[1];
499 	context->y1 = node->output;
500 
501 	return 0;
502 }
503 
504 
505 /************************************************************************/
506 /*                                                                      */
507 /* DST_RCDISC2 -  Usage of node_description values for RC discharge     */
508 /*                Has switchable charge resistor/input                  */
509 /*                                                                      */
510 /* input[0]    - Switch input value                                     */
511 /* input[1]    - input[0] value                                         */
512 /* input[2]    - Resistor0 value (initialisation only)                  */
513 /* input[3]    - input[1] value                                         */
514 /* input[4]    - Resistor1 value (initialisation only)                  */
515 /* input[5]    - Capacitor Value (initialisation only)                  */
516 /*                                                                      */
517 /************************************************************************/
518 
519 struct dss_rcdisc2_context
520 {
521 	double x1;		/* x[k-1], last input value */
522 	double y1;		/* y[k-1], last output value */
523 	double a1_0, b0_0, b1_0;	/* digital filter coefficients, filter #1 */
524 	double a1_1, b0_1, b1_1;	/* digital filter coefficients, filter #2 */
525 };
526 
dst_rcdisc2N_step(struct node_description * node)527 int dst_rcdisc2N_step(struct node_description *node)
528 {
529 	struct dss_rcdisc2_context *context;
530 	double input = ((node->input[0]==0)?node->input[1]:node->input[3]);
531 	context=(struct dss_rcdisc2_context*)node->context;
532 
533 	if (node->input[0] == 0)
534 		node->output = -context->a1_0*context->y1 + context->b0_0*input + context->b1_0*context->x1;
535 	else
536 		node->output = -context->a1_1*context->y1 + context->b0_1*input + context->b1_1*context->x1;
537 
538 	context->x1 = input;
539 	context->y1 = node->output;
540 
541 	return 0;
542 }
543 
dst_rcdisc2N_reset(struct node_description * node)544 int dst_rcdisc2N_reset(struct node_description *node)
545 {
546 	node->output=0;
547 	return 0;
548 }
549 
dst_rcdisc2N_init(struct node_description * node)550 int dst_rcdisc2N_init(struct node_description *node)
551 {
552 	struct dss_rcdisc2_context *context;
553 	double f1,f2;
554 
555 	/* Allocate memory for the context array and the node execution order array */
556 	if((node->context=malloc(sizeof(struct dss_rcdisc2_context)))==NULL)
557 	{
558 		discrete_log("dst_rcdisc2_init() - Failed to allocate local context memory.");
559 		return 1;
560 	}
561 	else
562 	{
563 		/* Initialise memory */
564 		memset(node->context,0,sizeof(struct dss_rcdisc2_context));
565 	}
566 	context=(struct dss_rcdisc2_context*)node->context;
567 
568 	f1=1.0/(2*M_PI*node->input[2]*node->input[5]);
569 	f2=1.0/(2*M_PI*node->input[4]*node->input[5]);
570 
571 	calculate_filter1_coefficients(f1, DISC_FILTER_LOWPASS, &context->a1_0, &context->b0_0, &context->b1_0);
572 	calculate_filter1_coefficients(f2, DISC_FILTER_LOWPASS, &context->a1_1, &context->b0_1, &context->b1_1);
573 
574 	/* Initialise the object */
575 	dst_rcdisc2_reset(node);
576 
577 	return 0;
578 }
579 
580