1 #include "driver.h"
2 #include <stdio.h>
3 #include <stdarg.h>
4 #include <math.h>
5 
6 /************************************************************************/
7 /*                                                                      */
8 /*  MAME - Discrete sound system emulation library                      */
9 /*                                                                      */
10 /*  Written by Keith Wilkins (mame@esplexo.co.uk)                       */
11 /*                                                                      */
12 /*  (c) K.Wilkins 2000                                                  */
13 /*                                                                      */
14 /*  Coding started in November 2000                                     */
15 /*  KW - Added Sawtooth waveforms  Feb2003                              */
16 /*                                                                      */
17 /************************************************************************/
18 /*                                                                      */
19 /* SEE DISCRETE.H for documentation on usage                            */
20 /*                                                                      */
21 /************************************************************************/
22 /*                                                                      */
23 /* Each sound primative DSS_xxxx or DST_xxxx has its own implementation */
24 /* file. All discrete sound primatives MUST implement the following     */
25 /* API:                                                                 */
26 /*                                                                      */
27 /* dsX_NAME_init() returns pointer to context or -1 for failure         */
28 /* dsX_NAME_step(inputs, context,float timestep)  - Perform time step   */
29 /*                                                  return output value */
30 /* dsX_NAME_kill(context) - Free context memory and return              */
31 /* dsX_NAME_reset(context) - Reset to initial state                     */
32 /*                                                                      */
33 /* Core software takes care of traversing the netlist in the correct    */
34 /* order                                                                */
35 /*                                                                      */
36 /* discrete_sh_start()       - Read Node list, initialise & reset       */
37 /* discrete_sh_stop()        - Shutdown discrete sound system           */
38 /* discrete_sh_reset()       - Put sound system back to time 0          */
39 /* discrete_sh_update()      - Update streams to current time           */
40 /* discrete_stream_update()  - This does the real update to the sim     */
41 /*                                                                      */
42 /************************************************************************/
43 /*                                                                      */
44 /* Context -  Memory pointer (void)                                     */
45 /*            Last output value                                         */
46 /*            Next object in list (Doubly linked?? or Array of struct)  */
47 /*                                                                      */
48 /* Initialisation -                                                     */
49 /*     Parse table into linked object list                              */
50 /*     Based on blocking/input tree sort list, perhaps the best         */
51 /*     solution is to traverse the netlist backwards to work out the    */
52 /*     dependancies, how will this react to feedback loops.             */
53 /*     Call init in order                                               */
54 /*                                                                      */
55 /* Runtime - Use streams interface and callback to update channels      */
56 /*     Calc number of steps and deltaT                                  */
57 /*       Traverse list with step for each object                        */
58 /*       Store output/s in streaming buffer                             */
59 /*     Repeat until all steps done                                      */
60 /*                                                                      */
61 /* Shutdown -                                                           */
62 /*     Tranverse list                                                   */
63 /*       Call _kill for each item                                       */
64 /*     Free core memory array list.                                     */
65 /*                                                                      */
66 /************************************************************************/
67 
68 static int init_ok=0;
69 static struct node_description **running_order=NULL;
70 static int node_count=0;
71 static struct node_description *node_list=NULL;
72 static struct node_description *output_node=NULL;
73 static int discrete_stream=0;
74 static int discrete_stereo=0;
75 
76 /* Include simulation objects */
77 #include "disc_wav.c"		/* Wave sources   - SINE/SQUARE/NOISE/etc */
78 #include "disc_mth.c"		/* Math Devices   - ADD/GAIN/etc */
79 #include "disc_inp.c"		/* Input Devices  - INPUT/CONST/etc */
80 #include "disc_flt.c"		/* Filter Devices - RCF/HPF/LPF */
81 #include "disc_dev.c"		/* Popular Devices - NE555/etc */
82 #include "disc_out.c"		/* Output devices */
83 
84 /************************************************************************/
85 /*                                                                      */
86 /*        Define the call tables for running the simulation,            */
87 /*        add your new node types into here to allow them to be         */
88 /*        called within the simulation environment.                     */
89 /*                                                                      */
90 /************************************************************************/
91 struct discrete_module module_list[]=
92 {
93 	{ DSS_INPUT       ,"DSS_INPUT"       ,dss_input_init       ,dss_input_kill       ,dss_input_reset       ,dss_input_step       },
94 	{ DSS_CONSTANT    ,"DSS_CONSTANT"    ,NULL                 ,NULL                 ,NULL                  ,dss_constant_step    },
95 	{ DSS_ADJUSTMENT  ,"DSS_ADJUSTMENT"  ,dss_adjustment_init  ,dss_adjustment_kill  ,dss_adjustment_reset  ,dss_adjustment_step  },
96 	{ DSS_SQUAREWAVE  ,"DSS_SQUAREWAVE"  ,dss_squarewave_init  ,dss_squarewave_kill  ,dss_squarewave_reset  ,dss_squarewave_step  },
97 	{ DSS_SINEWAVE    ,"DSS_SINEWAVE"    ,dss_sinewave_init    ,dss_sinewave_kill    ,dss_sinewave_reset    ,dss_sinewave_step    },
98 	{ DSS_NOISE       ,"DSS_NOISE"       ,dss_noise_init       ,dss_noise_kill       ,dss_noise_reset       ,dss_noise_step       },
99 	{ DSS_LFSR_NOISE  ,"DSS_LFSR_NOISE"  ,dss_lfsr_init        ,dss_lfsr_kill        ,dss_lfsr_reset        ,dss_lfsr_step        },
100 	{ DSS_TRIANGLEWAVE,"DSS_TRIANGLEWAVE",dss_trianglewave_init,dss_trianglewave_kill,dss_trianglewave_reset,dss_trianglewave_step},
101 	{ DSS_SAWTOOTHWAVE,"DSS_SAWTOOTHWAVE",dss_sawtoothwave_init,dss_sawtoothwave_kill,dss_sawtoothwave_reset,dss_sawtoothwave_step},
102 
103 	{ DST_GAIN        ,"DST_GAIN"        ,NULL                 ,NULL                 ,NULL                  ,dst_gain_step        },
104 	{ DST_DIVIDE      ,"DST_DIVIDE"      ,NULL                 ,NULL                 ,NULL                  ,dst_divide_step      },
105 	{ DST_ADDER       ,"DST_ADDER"       ,NULL                 ,NULL                 ,NULL                  ,dst_adder_step       },
106 	{ DST_SWITCH      ,"DST_SWITCH"      ,NULL                 ,NULL                 ,NULL                  ,dst_switch_step      },
107 	{ DST_RCFILTER    ,"DST_RCFILTER"    ,dst_rcfilter_init    ,NULL                 ,dst_rcfilter_reset    ,dst_rcfilter_step    },
108 	{ DST_RCDISC      ,"DST_RCDISC"      ,dst_rcdisc_init      ,dst_rcdisc_kill      ,dst_rcdisc_reset      ,dst_rcdisc_step      },
109 	{ DST_RCDISC2     ,"DST_RCDISC2"     ,dst_rcdisc2_init     ,dst_rcdisc2_kill     ,dst_rcdisc2_reset     ,dst_rcdisc2_step     },
110 	{ DST_RAMP        ,"DST_RAMP"        ,dst_ramp_init        ,dst_ramp_kill        ,dst_ramp_reset        ,dst_ramp_step        },
111 	{ DST_CLAMP       ,"DST_CLAMP"       ,NULL                 ,NULL                 ,NULL                  ,dst_clamp_step       },
112 	{ DST_LADDER      ,"DST_LADDER"      ,dst_ladder_init      ,dst_ladder_kill      ,dst_ladder_reset      ,dst_ladder_step      },
113 	{ DST_ONESHOT     ,"DST_ONESHOT"     ,dst_oneshot_init     ,dst_oneshot_kill     ,dst_oneshot_reset     ,dst_oneshot_step     },
114 	{ DST_SAMPHOLD    ,"DST_SAMPHOLD"    ,dst_samphold_init    ,dst_samphold_kill    ,dst_samphold_reset    ,dst_samphold_step    },
115 
116 	{ DST_LOGIC_INV   ,"DST_LOGIC_INV"   ,NULL                 ,NULL                 ,NULL                  ,dst_logic_inv_step   },
117 	{ DST_LOGIC_AND   ,"DST_LOGIC_AND"   ,NULL                 ,NULL                 ,NULL                  ,dst_logic_and_step   },
118 	{ DST_LOGIC_NAND  ,"DST_LOGIC_NAND"  ,NULL                 ,NULL                 ,NULL                  ,dst_logic_nand_step  },
119 	{ DST_LOGIC_OR    ,"DST_LOGIC_OR"    ,NULL                 ,NULL                 ,NULL                  ,dst_logic_or_step    },
120 	{ DST_LOGIC_NOR   ,"DST_LOGIC_NOR"   ,NULL                 ,NULL                 ,NULL                  ,dst_logic_nor_step   },
121 	{ DST_LOGIC_XOR   ,"DST_LOGIC_XOR"   ,NULL                 ,NULL                 ,NULL                  ,dst_logic_xor_step   },
122 	{ DST_LOGIC_NXOR  ,"DST_LOGIC_NXOR"  ,NULL                 ,NULL                 ,NULL                  ,dst_logic_nxor_step  },
123 
124 /*	{ DSD_NE555       ,"DSD_NE555"       ,dsd_ne555_init       ,dsd_ne555_kill       ,dsd_ne555_reset       ,dsd_ne555_step       }, */
125 
126 	{ DSO_OUTPUT      ,"DSO_OUTPUT"      ,dso_output_init      ,NULL                 ,NULL                  ,dso_output_step      },
127 	{ DSS_NULL        ,"DSS_NULL"        ,NULL                 ,NULL                 ,NULL                  ,NULL                 }
128 };
129 
130 
find_node(int node)131 static struct node_description* find_node(int node)
132 {
133 	int loop;
134 	for(loop=0;loop<node_count;loop++)
135 	{
136 		if(node_list[loop].node==node) return &node_list[loop];
137 	}
138 	return NULL;
139 }
140 
discrete_stream_update_stereo(int ch,INT16 ** buffer,int length)141 static void discrete_stream_update_stereo(int ch, INT16 **buffer, int length)
142 {
143 	/* Now we must do length iterations of the node list, one output for each step */
144 	int loop,loop2;
145 	struct node_description *node;
146 
147 	for(loop=0;loop<length;loop++)
148 	{
149 		for(loop2=0;loop2<node_count;loop2++)
150 		{
151 			/* Pick the first node to process */
152 			node=running_order[loop2];
153 
154 			/* Work out what nodes/inputs are required, dont process NO CONNECT nodes */
155 			/* these are ones that are connected to NODE_LIST[0]                      */
156 			if(node->input_node0 && (node->input_node0)->node!=NODE_NC) node->input0=(node->input_node0)->output;
157 			if(node->input_node1 && (node->input_node1)->node!=NODE_NC) node->input1=(node->input_node1)->output;
158 			if(node->input_node2 && (node->input_node2)->node!=NODE_NC) node->input2=(node->input_node2)->output;
159 			if(node->input_node3 && (node->input_node3)->node!=NODE_NC) node->input3=(node->input_node3)->output;
160 			if(node->input_node4 && (node->input_node4)->node!=NODE_NC) node->input4=(node->input_node4)->output;
161 			if(node->input_node5 && (node->input_node5)->node!=NODE_NC) node->input5=(node->input_node5)->output;
162 
163 			/* Now step the node */
164 			if(module_list[node->module].step) (*module_list[node->module].step)(node);
165 		}
166 
167 		/* Now put the output into the buffers */
168 		buffer[0][loop]=((struct dso_output_context*)(output_node->context))->left;
169 		buffer[1][loop]=((struct dso_output_context*)(output_node->context))->right;
170 	}
171 }
172 
discrete_stream_update_mono(int ch,INT16 * buffer,int length)173 static void discrete_stream_update_mono(int ch,INT16 *buffer, int length)
174 {
175 	/* Now we must do length iterations of the node list, one output for each step */
176 	int loop,loop2;
177 	struct node_description *node;
178 
179 	for(loop=0;loop<length;loop++)
180 	{
181 		for(loop2=0;loop2<node_count;loop2++)
182 		{
183 			/* Pick the first node to process */
184 			node=running_order[loop2];
185 
186 			/* Work out what nodes/inputs are required, dont process NO CONNECT nodes */
187 			/* these are ones that are connected to NODE_LIST[0]                      */
188 			if(node->input_node0 && (node->input_node0)->node!=NODE_NC) node->input0=(node->input_node0)->output;
189 			if(node->input_node1 && (node->input_node1)->node!=NODE_NC) node->input1=(node->input_node1)->output;
190 			if(node->input_node2 && (node->input_node2)->node!=NODE_NC) node->input2=(node->input_node2)->output;
191 			if(node->input_node3 && (node->input_node3)->node!=NODE_NC) node->input3=(node->input_node3)->output;
192 			if(node->input_node4 && (node->input_node4)->node!=NODE_NC) node->input4=(node->input_node4)->output;
193 			if(node->input_node5 && (node->input_node5)->node!=NODE_NC) node->input5=(node->input_node5)->output;
194 
195 			/* Now step the node */
196 			if(module_list[node->module].step) (*module_list[node->module].step)(node);
197 		}
198 
199 		/* Now put the output into the buffer */
200 		buffer[loop]=(((struct dso_output_context*)(output_node->context))->left+((struct dso_output_context*)(output_node->context))->right)/2;
201 	}
202 }
203 
discrete_sh_start(const struct MachineSound * msound)204 int discrete_sh_start (const struct MachineSound *msound)
205 {
206 	struct discrete_sound_block *intf;
207 	int loop=0,loop2=0,search=0,failed=0;
208 
209 	/* Initialise */
210 	intf = msound->sound_interface;
211 	node_count=0;
212 
213 	/* Sanity check and node count */
214 	while(1)
215 	{
216 		/* Check the node parameter is a valid node */
217 		if(intf[node_count].node<NODE_START || intf[node_count].node>NODE_END)
218 		{
219 			logerror("discrete_sh_start() - Invalid node number on node %02d descriptor\n",node_count);
220 			return 1;
221 		}
222 		if(intf[node_count].type>DSO_OUTPUT)
223 		{
224 			logerror("discrete_sh_start() - Invalid function type on node %02d descriptor\n",node_count);
225 			return 1;
226 		}
227 
228 		/* Node count must include the NULL node as well */
229 		if(intf[node_count].type==DSS_NULL)
230 		{
231 			node_count++;
232 			break;
233 		}
234 
235 		node_count++;
236 
237 		/* Sanity check */
238 		if(node_count>DISCRETE_MAX_NODES)
239 		{
240 			logerror("discrete_sh_start() - Upper limit of 255 nodes exceeded, have you terminated the interface block.");
241 			return 1;
242 		}
243 	}
244 
245 	/* Allocate memory for the context array and the node execution order array */
246 	if((running_order=(struct node_description**)malloc(node_count*sizeof(struct node_description*)))==NULL)
247 	{
248 		logerror("discrete_sh_start() - Failed to allocate running order array.\n");
249 		return 1;
250 	}
251 	else
252 	{
253 		/* Initialise memory */
254 		memset(running_order,0,node_count*sizeof(struct node_description*));
255 	}
256 
257 	if((node_list=(struct node_description*)malloc(node_count*sizeof(struct node_description)))==NULL)
258 	{
259 		logerror("discrete_sh_start() - Failed to allocate context list array.\n");
260 		return 1;
261 	}
262 	else
263 	{
264 		/* Initialise memory */
265 		memset(node_list,0,node_count*sizeof(struct node_description));
266 	}
267 
268 	/* Work out the execution order */
269 	/* FAKE IT FOR THE MOMENT, EXECUTE IN ORDER */
270 	for(loop=0;loop<node_count;loop++)
271 	{
272 		running_order[loop]=&node_list[loop];
273 	}
274 
275 	/* Configure the input node pointers, the find_node function wont work without the node ID setup beforehand */
276 	for(loop=0;loop<node_count;loop++) node_list[loop].node=intf[loop].node;
277 	failed=0;
278 
279 	/* Duplicate node number test */
280 	for(loop=0;loop<node_count;loop++)
281 	{
282 		for(loop2=0;loop2<node_count;loop2++)
283 		{
284 			if(node_list[loop].node==node_list[loop2].node && loop!=loop2)
285 			{
286 				logerror("discrete_sh_start - Node NODE_%02d defined more than once\n",node_list[loop].node-NODE_00);
287 				failed=1;
288 			}
289 		}
290 	}
291 
292 	/* Initialise and start all of the objects */
293 	for(loop=0;loop<node_count;loop++)
294 	{
295 		/* Configure the input node pointers */
296 		node_list[loop].node=intf[loop].node;
297 		node_list[loop].output=0;
298 		node_list[loop].input0=intf[loop].initial0;
299 		node_list[loop].input1=intf[loop].initial1;
300 		node_list[loop].input2=intf[loop].initial2;
301 		node_list[loop].input3=intf[loop].initial3;
302 		node_list[loop].input4=intf[loop].initial4;
303 		node_list[loop].input5=intf[loop].initial5;
304 		node_list[loop].input_node0=find_node(intf[loop].input_node0);
305 		node_list[loop].input_node1=find_node(intf[loop].input_node1);
306 		node_list[loop].input_node2=find_node(intf[loop].input_node2);
307 		node_list[loop].input_node3=find_node(intf[loop].input_node3);
308 		node_list[loop].input_node4=find_node(intf[loop].input_node4);
309 		node_list[loop].input_node5=find_node(intf[loop].input_node5);
310 		node_list[loop].name=intf[loop].name;
311 		node_list[loop].custom=intf[loop].custom;
312 
313 		/* Check that all referenced nodes have actually been found */
314 		if(node_list[loop].input_node0==NULL && intf[loop].input_node0>=NODE_START && intf[loop].input_node0<=NODE_END)
315 		{
316 			logerror("discrete_sh_start - Node NODE_%02d referenced a non existant node NODE_%02d\n",node_list[loop].node-NODE_00,intf[loop].input_node0-NODE_00);
317 			failed=1;
318 		}
319 		if(node_list[loop].input_node1==NULL && intf[loop].input_node1>=NODE_START && intf[loop].input_node1<=NODE_END)
320 		{
321 			logerror("discrete_sh_start - Node NODE_%02d referenced a non existant node NODE_%02d\n",node_list[loop].node-NODE_00,intf[loop].input_node1-NODE_00);
322 			failed=1;
323 		}
324 		if(node_list[loop].input_node2==NULL && intf[loop].input_node2>=NODE_START && intf[loop].input_node2<=NODE_END)
325 		{
326 			logerror("discrete_sh_start - Node NODE_%02d referenced a non existant node NODE_%02d\n",node_list[loop].node-NODE_00,intf[loop].input_node2-NODE_00);
327 			failed=1;
328 		}
329 		if(node_list[loop].input_node3==NULL && intf[loop].input_node3>=NODE_START && intf[loop].input_node3<=NODE_END)
330 		{
331 			logerror("discrete_sh_start - Node NODE_%02d referenced a non existant node NODE_%02d\n",node_list[loop].node-NODE_00,intf[loop].input_node3-NODE_00);
332 			failed=1;
333 		}
334 		if(node_list[loop].input_node4==NULL && intf[loop].input_node4>=NODE_START && intf[loop].input_node4<=NODE_END)
335 		{
336 			logerror("discrete_sh_start - Node NODE_%02d referenced a non existant node NODE_%02d\n",node_list[loop].node-NODE_00,intf[loop].input_node4-NODE_00);
337 			failed=1;
338 		}
339 		if(node_list[loop].input_node5==NULL && intf[loop].input_node5>=NODE_START && intf[loop].input_node5<=NODE_END)
340 		{
341 			logerror("discrete_sh_start - Node NODE_%02d referenced a non existant node NODE_%02d\n",node_list[loop].node-NODE_00,intf[loop].input_node5-NODE_00);
342 			failed=1;
343 		}
344 
345 		/* Try to find the simulation module in the module list table */
346 		search=0;
347 		while(1)
348 		{
349 			if(module_list[search].type==intf[loop].type)
350 			{
351 				node_list[loop].module=search;
352 				if(module_list[search].init)
353 					if(((*module_list[search].init)(&node_list[loop]))==1) failed=1;
354 				break;
355 			}
356 			else if(module_list[search].type==DSS_NULL)
357 			{
358 				if(intf[loop].type==DSS_NULL) break;
359 				else
360 				{
361 					logerror("discrete_sh_start() - Invalid DSS/DST/DSO module type specified in interface, item %02d\n",loop+1);
362 					failed=1;
363 					break;
364 				}
365 			}
366 			search++;
367 		}
368 	}
369 	/* Setup the output node */
370 	if((output_node=find_node(NODE_OP))==NULL)
371 	{
372 		logerror("discrete_sh_start() - Counldnt find an output node");
373 		failed=1;
374 	}
375 
376 	/* Different setup for Mono/Stereo systems */
377 	if ((Machine->drv->sound_attributes&SOUND_SUPPORTS_STEREO) == SOUND_SUPPORTS_STEREO)
378 	{
379 		int vol[2];
380 		const char *stereo_names[2] = { "Discrete Left", "Discrete Right" };
381 		vol[0] = output_node->input2;
382 		vol[1] = output_node->input2;
383 		/* Initialise a stereo, stream, we always use stereo even if only a mono system */
384 		discrete_stream=stream_init_multi(2,stereo_names,vol,Machine->sample_rate,0,discrete_stream_update_stereo);
385 		discrete_stereo=1;
386 	}
387 	else
388 	{
389 		int vol;
390 		vol = output_node->input2;
391 		/* Initialise a stereo, stream, we always use stereo even if only a mono system */
392 		discrete_stream=stream_init("Discrete Sound",vol,Machine->sample_rate,0,discrete_stream_update_mono);
393 	}
394 
395 	if(discrete_stream==-1)
396 	{
397 		logerror("discrete_sh_start - Stream init returned an error\n");
398 		failed=1;
399 	}
400 
401 	/* Report success or fail */
402 	if(!failed) init_ok=1;
403 	return failed;
404 }
405 
discrete_sh_stop(void)406 void discrete_sh_stop (void)
407 {
408 	int loop=0;
409 	if(!init_ok) return;
410 
411 	for(loop=0;loop<node_count;loop++)
412 	{
413     	/* Destruct all of the objects */
414 		if(module_list[node_list[loop].module].kill) (*module_list[node_list[loop].module].kill)(&node_list[loop]);
415 	}
416 	if(node_list) free(node_list);
417 	if(running_order) free(running_order);
418 	node_count=0;
419 	node_list=NULL;
420 	running_order=NULL;
421 }
422 
discrete_sh_reset(void)423 void discrete_sh_reset (void)
424 {
425 	/* Reset all of the objects */
426 	int loop=0;
427 
428 	if(!init_ok) return;
429 
430 	for(loop=0;loop<node_count;loop++)
431 	{
432 		if(module_list[node_list[loop].module].reset) (*module_list[node_list[loop].module].reset)(&node_list[loop]);
433 	}
434 }
435 
discrete_sh_update(void)436 void discrete_sh_update(void)
437 {
438 	if(!init_ok) return;
439 
440 	/* Bring stream upto the present time */
441 	stream_update(discrete_stream, 0);
442 }
443