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