summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/sound/discrete.c
diff options
context:
space:
mode:
author Couriersud <couriersud@users.noreply.github.com>2009-08-23 19:04:41 +0000
committer Couriersud <couriersud@users.noreply.github.com>2009-08-23 19:04:41 +0000
commit20caff1c3bd07fa2541cf30e94021de6ad663a44 (patch)
tree2ee11517e09e9fe75ad4624785d76ac8034eb4a1 /src/emu/sound/discrete.c
parentdc0df4572ed47f3e926abf79add15e905e110b60 (diff)
Discrete work - this one needs a full recompile
- change the way custom modules are handled - updated drivers mario and dkong accordingly - minor change to stream input handling - no more linear lists for nodes. All node processing switched to linked lists. - module step and reset now only get a node pointer passed - Added discrete_info * pointer to node - Only nodes with a step routine actually get processed. - Fixed a bug: discrete logs did not work since some time - preliminary parallel task constants; depending on results these may vanish again. - Overall slight performance increase. dkong 940% to 960%, galaxian 740% to 790%
Diffstat (limited to 'src/emu/sound/discrete.c')
-rw-r--r--src/emu/sound/discrete.c401
1 files changed, 239 insertions, 162 deletions
diff --git a/src/emu/sound/discrete.c b/src/emu/sound/discrete.c
index fe50f12f07e..c19e83266f5 100644
--- a/src/emu/sound/discrete.c
+++ b/src/emu/sound/discrete.c
@@ -57,16 +57,14 @@
#define DISCRETE_PROFILING (0)
-
-
/*************************************
*
* Prototypes
*
*************************************/
-static void init_nodes(discrete_info *info, discrete_sound_block *block_list, const device_config *device);
-static void find_input_nodes(discrete_info *info, discrete_sound_block *block_list);
+static void init_nodes(discrete_info *info, linked_list_entry *block_list, const device_config *device);
+static void find_input_nodes(discrete_info *info);
static void setup_output_nodes(const device_config *device, discrete_info *info);
static void setup_disc_logs(discrete_info *info);
static node_description *discrete_find_node(const discrete_info *info, int node);
@@ -229,7 +227,19 @@ static const discrete_module module_list[] =
{ DSS_NULL ,"DSS_NULL" , 0 ,0 ,NULL ,NULL }
};
+/*************************************
+ *
+ * Add an entry to a list
+ *
+ *************************************/
+static void add_list(discrete_info *info, linked_list_entry ***list, void *ptr)
+{
+ **list = auto_alloc(info->device->machine, linked_list_entry);
+ (**list)->ptr = ptr;
+ (**list)->next = NULL;
+ *list = &((**list)->next);
+}
/*************************************
*
@@ -249,7 +259,7 @@ static node_description *discrete_find_node(const discrete_info *info, int node)
*
*************************************/
-static int discrete_build_list(discrete_info *info, discrete_sound_block *intf, discrete_sound_block *out, int offset)
+static void discrete_build_list(discrete_info *info, discrete_sound_block *intf, linked_list_entry ***current)
{
int node_count = 0;
@@ -258,56 +268,103 @@ static int discrete_build_list(discrete_info *info, discrete_sound_block *intf,
/* scan imported */
if (intf[node_count].type == DSO_IMPORT)
{
- offset = discrete_build_list(info, (discrete_sound_block *) intf[node_count].custom, out, offset);
+ discrete_log(info, "discrete_build_list() - DISCRETE_IMPORT @ NODE_%02d", NODE_INDEX(intf[node_count].node) );
+ discrete_build_list(info, (discrete_sound_block *) intf[node_count].custom, current);
}
else if (intf[node_count].type == DSO_REPLACE)
{
- int i;
-
+ linked_list_entry *entry;
+
node_count++;
if (intf[node_count].type == DSS_NULL)
fatalerror("discrete_build_list: DISCRETE_REPLACE at end of node_list");
- for (i = 0; i < offset; i++)
- if (out[i].type != NODE_SPECIAL )
- if (out[i].node == intf[node_count].node)
+ for (entry = info->block_list; entry != NULL; entry = entry->next)
+ {
+ discrete_sound_block *block = (discrete_sound_block *) entry->ptr;
+
+ if (block->type != NODE_SPECIAL )
+ if (block->node == intf[node_count].node)
{
- out[i] = intf[node_count];
+ entry->ptr = (void *) &intf[node_count];
+ discrete_log(info, "discrete_build_list() - DISCRETE_REPLACE @ NODE_%02d", NODE_INDEX(intf[node_count].node) );
break;
}
+ }
- if (i >= offset)
+ if (entry == NULL)
fatalerror("discrete_build_list: DISCRETE_REPLACE did not found node %d", NODE_INDEX(intf[node_count].node));
}
else if (intf[node_count].type == DSO_DELETE)
{
- int i,p,deleted;
+ int p,deleted;
+ linked_list_entry *entry, *last;
p = 0;
deleted = 0;
- for (i = 0; i < offset; i++)
+ last = NULL;
+ for (entry = info->block_list; entry != NULL; last = entry, entry = entry->next)
{
- if ((out[i].node >= intf[node_count].input_node[0]) &&
- (out[i].node <= intf[node_count].input_node[1]))
- {
- discrete_log(info, "discrete_build_list() - DISCRETE_DELETE deleted NODE_%02d", NODE_INDEX(out[i].node) );
- deleted++;
- }
- else
+ discrete_sound_block *block = (discrete_sound_block *) entry->ptr;
+
+ if ((block->node >= intf[node_count].input_node[0]) &&
+ (block->node <= intf[node_count].input_node[1]))
{
- out[p++] = out[i];
+ discrete_log(info, "discrete_build_list() - DISCRETE_DELETE deleted NODE_%02d", NODE_INDEX(block->node) );
+ if (last != NULL)
+ last->next = entry->next;
+ else
+ info->block_list = entry->next;
}
}
- offset -= deleted;
}
else
- out[offset++] = intf[node_count];
+ {
+ discrete_log(info, "discrete_build_list() - adding node %d (*current %p)\n", node_count, *current);
+ add_list(info, current, &intf[node_count]);
+ }
+
+ node_count++;
+ }
+}
+
+/*************************************
+ *
+ * Sanity check list
+ *
+ *************************************/
+
+static void discrete_sanity_check(discrete_info *info)
+{
+ linked_list_entry *entry;
+ int node_count = 0;
+
+ discrete_log(info, "discrete_start() - Doing node list sanity check");
+ for (entry = info->block_list; entry != NULL; entry = entry->next)
+ {
+ discrete_sound_block *block = (discrete_sound_block *) entry->ptr;
+
+ /* make sure we don't have too many nodes overall */
+ if (node_count > DISCRETE_MAX_NODES)
+ fatalerror("discrete_start() - Upper limit of %d nodes exceeded, have you terminated the interface block?", DISCRETE_MAX_NODES);
+
+ /* make sure the node number is in range */
+ if (block->node < NODE_START || block->node > NODE_END)
+ fatalerror("discrete_start() - Invalid node number on node %02d descriptor", block->node);
+
+ /* make sure the node type is valid */
+ if (block->type > DSO_OUTPUT)
+ fatalerror("discrete_start() - Invalid function type on NODE_%02d", NODE_INDEX(block->node) );
+
+ /* make sure this is a main node */
+ if (NODE_CHILD_NODE_NUM(block->node) > 0)
+ fatalerror("discrete_start() - Child node number on NODE_%02d", NODE_INDEX(block->node) );
node_count++;
}
- out[offset] = intf[node_count];
- return offset;
+ discrete_log(info, "discrete_start() - Sanity check counted %d nodes", node_count);
+
}
/*************************************
@@ -318,7 +375,7 @@ static int discrete_build_list(discrete_info *info, discrete_sound_block *intf,
static DEVICE_START( discrete )
{
- discrete_sound_block *intf;
+ linked_list_entry **intf;
discrete_sound_block *intf_start = (discrete_sound_block *)device->static_config;
discrete_info *info = get_safe_token(device);
char name[32];
@@ -337,50 +394,29 @@ static DEVICE_START( discrete )
/* create the logfile */
sprintf(name, "discrete%s.log", device->tag);
- if (DISCRETE_DEBUGLOG && !info->disclogfile)
+ if (DISCRETE_DEBUGLOG)
info->disclogfile = fopen(name, "w");
/* Build the final block list */
- intf = auto_alloc_array_clear(device->machine, discrete_sound_block, DISCRETE_MAX_NODES);
- discrete_build_list(info, intf_start, intf, 0);
+ info->block_list = NULL;
+ intf = &info->block_list;
+ discrete_build_list(info, intf_start, &intf);
/* first pass through the nodes: sanity check, fill in the indexed_nodes, and make a total count */
- discrete_log(info, "discrete_start() - Doing node list sanity check");
- for (info->node_count = 0; intf[info->node_count].type != DSS_NULL; info->node_count++)
- {
- /* make sure we don't have too many nodes overall */
- if (info->node_count > DISCRETE_MAX_NODES)
- fatalerror("discrete_start() - Upper limit of %d nodes exceeded, have you terminated the interface block?", DISCRETE_MAX_NODES);
-
- /* make sure the node number is in range */
- if (intf[info->node_count].node < NODE_START || intf[info->node_count].node > NODE_END)
- fatalerror("discrete_start() - Invalid node number on node %02d descriptor", info->node_count);
-
- /* make sure the node type is valid */
- if (intf[info->node_count].type > DSO_OUTPUT)
- fatalerror("discrete_start() - Invalid function type on NODE_%02d", NODE_INDEX(intf[info->node_count].node) );
-
- /* make sure this is a main node */
- if (NODE_CHILD_NODE_NUM(intf[info->node_count].node) > 0)
- fatalerror("discrete_start() - Child node number on NODE_%02d", NODE_INDEX(intf[info->node_count].node) );
- }
- info->node_count++;
- discrete_log(info, "discrete_start() - Sanity check counted %d nodes", info->node_count);
-
- /* allocate memory for the array of actual nodes */
- info->node_list = auto_alloc_array_clear(device->machine, node_description, info->node_count);
-
- /* allocate memory for the node execution order array */
- info->running_order = auto_alloc_array_clear(device->machine, node_description *, info->node_count);
+ discrete_sanity_check(info);
+
+ /* Start with empty lists */
+ info->node_list = NULL;
+ info->step_list = NULL;
/* allocate memory to hold pointers to nodes by index */
info->indexed_node = auto_alloc_array_clear(device->machine, node_description *, DISCRETE_MAX_NODES);
/* initialize the node data */
- init_nodes(info, intf, device);
+ init_nodes(info, info->block_list, device);
/* now go back and find pointers to all input nodes */
- find_input_nodes(info, intf);
+ find_input_nodes(info);
/* then set up the output nodes */
setup_output_nodes(device, info);
@@ -403,27 +439,29 @@ static DEVICE_STOP( discrete )
if (DISCRETE_PROFILING)
{
- int nodenum;
+ int count = 0;
+ linked_list_entry *entry;
osd_ticks_t total = 0;
osd_ticks_t tresh;
- printf("Total Samples: %d\n", info->total_samples);
/* calculate total time */
- for (nodenum = 0; nodenum < info->node_count; nodenum++)
+ for (entry = info->step_list; entry != NULL; entry = entry->next)
{
- node_description *node = info->running_order[nodenum];
+ node_description *node = (node_description *) entry->ptr;
/* Now step the node */
total += node->run_time;
+ count++;
}
/* print statistics */
- tresh = total / info->node_count;
- for (nodenum = 0; nodenum < info->node_count; nodenum++)
+ printf("Total Samples: %d\n", info->total_samples);
+ tresh = total / count;
+ for (entry = info->step_list; entry != NULL; entry = entry->next)
{
- node_description *node = info->running_order[nodenum];
+ node_description *node = (node_description *) entry->ptr;
if (node->run_time > tresh)
- printf("%3d: %20s %8.2f %10d\n", NODE_INDEX(node->node), node->module.name, (float) node->run_time / (float) total * 100.0, ((int) node->run_time) / info->total_samples);
+ printf("%3d: %20s %8.2f %10d\n", NODE_INDEX(node->node), node->module->name, (float) node->run_time / (float) total * 100.0, ((int) node->run_time) / info->total_samples);
}
}
@@ -457,22 +495,22 @@ static DEVICE_STOP( discrete )
static DEVICE_RESET( discrete )
{
discrete_info *info = get_safe_token(device);
- int nodenum;
+ linked_list_entry *entry;
/* loop over all nodes */
- for (nodenum = 0; nodenum < info->node_count; nodenum++)
+ for (entry = info->node_list; entry != 0; entry = entry->next)
{
- node_description *node = info->running_order[nodenum];
+ node_description *node = (node_description *) entry->ptr;
node->output[0] = 0;
/* if the node has a reset function, call it */
- if (node->module.reset)
- (*node->module.reset)(info, node);
+ if (node->module->reset)
+ (*node->module->reset)(node);
/* otherwise, just step it */
- else if (node->module.step)
- (*node->module.step)(info, node);
+ else if (node->module->step)
+ (*node->module->step)(node);
}
}
@@ -562,87 +600,120 @@ INLINE void bigselect(const device_config *device, node_description *node)
*
*************************************/
-static STREAM_UPDATE( discrete_stream_update )
+INLINE void discrete_stream_update_csv(discrete_info *info)
{
- discrete_info *info = (discrete_info *)param;
- int samplenum, nodenum, outputnum;
+ int nodenum, outputnum;
+
+ /* Dump any csv logs */
+ for (outputnum = 0; outputnum < info->num_csvlogs; outputnum++)
+ {
+ fprintf(info->disc_csv_file[outputnum], "%" I64FMT "d", ++info->sample_num);
+ for (nodenum = 0; nodenum < info->csvlog_node[outputnum]->active_inputs; nodenum++)
+ {
+ fprintf(info->disc_csv_file[outputnum], ", %f", *info->csvlog_node[outputnum]->input[nodenum]);
+ }
+ fprintf(info->disc_csv_file[outputnum], "\n");
+ }
+}
+
+INLINE void discrete_stream_update_wave(discrete_info *info)
+{
+ int outputnum;
double val;
INT16 wave_data_l, wave_data_r;
- /* Setup any input streams */
- for (nodenum = 0; nodenum < info->discrete_input_streams; nodenum++)
+ /* Dump any wave logs */
+ for (outputnum = 0; outputnum < info->num_wavelogs; outputnum++)
{
- info->input_stream_data[nodenum] = inputs[nodenum];
+ /* get nodes to be logged and apply gain, then clip to 16 bit */
+ val = (*info->wavelog_node[outputnum]->input[0]) * (*info->wavelog_node[outputnum]->input[1]);
+ val = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val;
+ wave_data_l = (INT16)val;
+ if (info->wavelog_node[outputnum]->active_inputs == 2)
+ {
+ /* DISCRETE_WAVELOG1 */
+ wav_add_data_16(info->disc_wav_file[outputnum], &wave_data_l, 1);
+ }
+ else
+ {
+ /* DISCRETE_WAVELOG2 */
+ val = (*info->wavelog_node[outputnum]->input[2]) * (*info->wavelog_node[outputnum]->input[3]);
+ val = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val;
+ wave_data_r = (INT16)val;
+
+ wav_add_data_16lr(info->disc_wav_file[outputnum], &wave_data_l, &wave_data_r, 1);
+ }
}
+}
- /* Now we must do samples iterations of the node list, one output for each step */
- for (samplenum = 0; samplenum < samples; samplenum++)
- {
+INLINE void discrete_stream_update_nodes(discrete_info *info, stream_sample_t **outputs)
+{
+ int outputnum;
+ double val;
+ linked_list_entry *entry;
+
+ if (DISCRETE_PROFILING)
info->total_samples++;
- /* loop over all nodes */
- for (nodenum = 0; nodenum < info->node_count; nodenum++)
- {
- node_description *node = info->running_order[nodenum];
- /* Now step the node */
- if (DISCRETE_PROFILING)
- node->run_time -= osd_profiling_ticks();
+ /* loop over all nodes */
+ for (entry = info->step_list; entry != NULL; entry = entry->next)
+ {
+ node_description *node = (node_description *) entry->ptr;
- if (node->module.step)
- (*node->module.step)(info, node);
- //bigselect(info->device, node);
+ /* Now step the node */
+ if (DISCRETE_PROFILING)
+ node->run_time -= osd_profiling_ticks();
- if (DISCRETE_PROFILING)
- node->run_time += osd_profiling_ticks();
+ (*node->module->step)(node);
+ //bigselect(info->device, node);
- }
+ if (DISCRETE_PROFILING)
+ node->run_time += osd_profiling_ticks();
- /* Add gain to the output and put into the buffers */
- /* Clipping will be handled by the main sound system */
- for (outputnum = 0; outputnum < info->discrete_outputs; outputnum++)
- {
- val = (*info->output_node[outputnum]->input[0]) * (*info->output_node[outputnum]->input[1]);
- outputs[outputnum][samplenum] = val;
- }
+ }
- /* Dump any csv logs */
- for (outputnum = 0; outputnum < info->num_csvlogs; outputnum++)
- {
- fprintf(info->disc_csv_file[outputnum], "%" I64FMT "d", ++info->sample_num);
- for (nodenum = 0; nodenum < info->csvlog_node[outputnum]->active_inputs; nodenum++)
- {
- fprintf(info->disc_csv_file[outputnum], ", %f", *info->csvlog_node[outputnum]->input[nodenum]);
- }
- fprintf(info->disc_csv_file[outputnum], "\n");
- }
+ /* Add gain to the output and put into the buffers */
+ /* Clipping will be handled by the main sound system */
+ for (outputnum = 0; outputnum < info->discrete_outputs; outputnum++)
+ {
+ val = (*info->output_node[outputnum]->input[0]) * (*info->output_node[outputnum]->input[1]);
+ *(outputs[outputnum]++) = val;
+ }
+}
- /* Dump any wave logs */
- for (outputnum = 0; outputnum < info->num_wavelogs; outputnum++)
- {
- /* get nodes to be logged and apply gain, then clip to 16 bit */
- val = (*info->wavelog_node[outputnum]->input[0]) * (*info->wavelog_node[outputnum]->input[1]);
- val = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val;
- wave_data_l = (INT16)val;
- if (info->wavelog_node[outputnum]->active_inputs == 2)
- {
- /* DISCRETE_WAVELOG1 */
- wav_add_data_16(info->disc_wav_file[outputnum], &wave_data_l, 1);
- }
- else
- {
- /* DISCRETE_WAVELOG2 */
- val = (*info->wavelog_node[outputnum]->input[2]) * (*info->wavelog_node[outputnum]->input[3]);
- val = (val < -32768) ? -32768 : (val > 32767) ? 32767 : val;
- wave_data_r = (INT16)val;
+static STREAM_UPDATE( discrete_stream_update )
+{
+ discrete_info *info = (discrete_info *)param;
+ stream_sample_t *outptr[DISCRETE_MAX_OUTPUTS];
+ int samplenum, nodenum, outputnum;
- wav_add_data_16lr(info->disc_wav_file[outputnum], &wave_data_l, &wave_data_r, 1);
- }
- }
+ /* Setup any output streams */
+ for (outputnum = 0; outputnum < info->discrete_outputs; outputnum++)
+ outptr[outputnum] = outputs[outputnum];
+
+ /* Setup any input streams */
+ for (nodenum = 0; nodenum < info->discrete_input_streams; nodenum++)
+ {
+ info->input_stream_data[nodenum] = inputs[nodenum];
+ }
- /* advance input streams */
- for (nodenum = 0; nodenum < info->discrete_input_streams; nodenum++)
+ if ((info->num_csvlogs > 0) || (info->num_wavelogs > 0))
+ {
+ /* Now we must do samples iterations of the node list, one output for each step */
+ for (samplenum = 0; samplenum < samples; samplenum++)
+ {
+ discrete_stream_update_nodes(info, outptr);
+ }
+ }
+ else
+ {
+ /* Now we must do samples iterations of the node list, one output for each step */
+ for (samplenum = 0; samplenum < samples; samplenum++)
{
- info->input_stream_data[nodenum]++;
+ discrete_stream_update_nodes(info, outptr);
+ discrete_stream_update_csv(info);
+ discrete_stream_update_wave(info);
+
}
}
@@ -656,24 +727,24 @@ static STREAM_UPDATE( discrete_stream_update )
*
*************************************/
-static void init_nodes(discrete_info *info, discrete_sound_block *block_list, const device_config *device)
+
+static void init_nodes(discrete_info *info, linked_list_entry *block_list, const device_config *device)
{
- int nodenum;
+ linked_list_entry **step_list = &info->step_list;
+ linked_list_entry **node_list = &info->node_list;
+ linked_list_entry *entry;
/* start with no outputs or input streams */
info->discrete_outputs = 0;
info->discrete_input_streams = 0;
/* loop over all nodes */
- for (nodenum = 0; nodenum < info->node_count; nodenum++)
+ for (entry = block_list; entry != NULL; entry = entry->next)
{
- discrete_sound_block *block = &block_list[nodenum];
- node_description *node = &info->node_list[nodenum];
+ discrete_sound_block *block = (discrete_sound_block *) entry->ptr;
+ node_description *node = auto_alloc_clear(info->device->machine, node_description);
int inputnum, modulenum;
- /* our running order just follows the order specified */
- info->running_order[nodenum] = node;
-
/* keep track of special nodes */
if (block->node == NODE_SPECIAL)
{
@@ -721,8 +792,9 @@ static void init_nodes(discrete_info *info, discrete_sound_block *block_list, co
fatalerror("init_nodes() - Unable to find discrete module type %d for NODE_%02d", block->type, NODE_INDEX(block->node));
/* static inits */
+ node->info = info;
node->node = block->node;
- node->module = module_list[modulenum];
+ node->module = &module_list[modulenum];
node->output[0] = 0.0;
node->block = block;
@@ -733,36 +805,40 @@ static void init_nodes(discrete_info *info, discrete_sound_block *block_list, co
}
node->context = NULL;
- node->name = block->name;
node->custom = block->custom;
/* setup module if custom */
if (block->type == DST_CUSTOM)
{
const discrete_custom_info *custom = (const discrete_custom_info *)node->custom;
- node->module.reset = custom->reset;
- node->module.step = custom->step;
- node->module.contextsize = custom->contextsize;
+ node->module = &custom->module;
node->custom = custom->custom;
}
/* allocate memory if necessary */
- if (node->module.contextsize)
- node->context = auto_alloc_array_clear(device->machine, UINT8, node->module.contextsize);
+ if (node->module->contextsize)
+ node->context = auto_alloc_array_clear(device->machine, UINT8, node->module->contextsize);
/* if we are an stream input node, track that */
if (block->type == DSS_INPUT_STREAM)
{
if (info->discrete_input_streams == DISCRETE_MAX_OUTPUTS)
fatalerror("init_nodes() - There can not be more then %d input stream nodes", DISCRETE_MAX_OUTPUTS);
- /* we will use the node's context pointer to point to the input stream data */
- //node->context = &info->input_stream_data[info->discrete_input_streams++];
+
node->context = NULL;
info->discrete_input_streams++;
}
+ /* add to node list */
+ add_list(info, &node_list, node);
+
+ /* our running order just follows the order specified */
+ /* does the node step ? */
+ if (node->module->step != NULL)
+ add_list(info, &step_list, node);
+
/* and register save state */
- state_save_register_device_item_array(device, nodenum, node->output);
+ state_save_register_device_item_array(device, node->node, node->output);
}
/* if no outputs, give an error */
@@ -778,15 +854,16 @@ static void init_nodes(discrete_info *info, discrete_sound_block *block_list, co
*
*************************************/
-static void find_input_nodes(discrete_info *info, discrete_sound_block *block_list)
+static void find_input_nodes(discrete_info *info)
{
- int nodenum, inputnum;
+ int inputnum;
+ linked_list_entry *entry;
/* loop over all nodes */
- for (nodenum = 0; nodenum < info->node_count; nodenum++)
+ for (entry = info->node_list; entry != NULL; entry = entry->next)
{
- node_description *node = &info->node_list[nodenum];
- discrete_sound_block *block = &block_list[nodenum];
+ node_description *node = (node_description *) entry->ptr;
+ const discrete_sound_block *block = node->block;
/* loop over all active inputs */
for (inputnum = 0; inputnum < node->active_inputs; inputnum++)
@@ -800,7 +877,7 @@ static void find_input_nodes(discrete_info *info, discrete_sound_block *block_li
if (!node_ref)
fatalerror("discrete_start - NODE_%02d referenced a non existent node NODE_%02d", NODE_INDEX(node->node), NODE_INDEX(inputnode));
- if (NODE_CHILD_NODE_NUM(inputnode) >= node_ref->module.num_output)
+ if (NODE_CHILD_NODE_NUM(inputnode) >= node_ref->module->num_output)
fatalerror("discrete_start - NODE_%02d referenced non existent output %d on node NODE_%02d", NODE_INDEX(node->node), NODE_CHILD_NODE_NUM(inputnode), NODE_INDEX(inputnode));
node->input[inputnum] = &(node_ref->output[NODE_CHILD_NODE_NUM(inputnode)]); /* Link referenced node out to input */