discrete sound system

- some more "list-ification"
- No more constraints on number of input and output nodes
- input nodes now make use of a context

Some of these changes are needed to introduce "internally buffered" input nodes going forward. These will use an internal stream to buffer all inputs so that stream_update will always calculate 20ms of samples.
This commit is contained in:
Couriersud 2009-08-29 18:30:19 +00:00
parent 98a7eb3c8d
commit 68d94c232d
3 changed files with 120 additions and 87 deletions

View File

@ -31,6 +31,18 @@ struct dss_adjustment_context
double scale;
};
struct dss_input_context
{
stream_sample_t *ptr; /* current in ptr for stream */
UINT8 data; /* data written */
double gain; /* node gain */
double offset; /* node offset */
UINT8 is_stream;
UINT8 is_buffered;
UINT32 stream_in_number;
UINT32 stream_out_number;
};
INLINE discrete_info *get_safe_token(const device_config *device)
{
assert(device != NULL);
@ -50,14 +62,14 @@ READ8_DEVICE_HANDLER(discrete_sound_r)
/* Read the node input value if allowed */
if (node)
{
UINT8 *node_data = (UINT8 *)node->context;
struct dss_input_context *context = (struct dss_input_context *)node->context;
/* Bring the system up to now */
stream_update(info->discrete_stream);
if ((node->module->type >= DSS_INPUT_DATA) && (node->module->type <= DSS_INPUT_PULSE))
{
data = *node_data;
data = context->data;
}
}
else
@ -75,8 +87,7 @@ WRITE8_DEVICE_HANDLER(discrete_sound_w)
/* Update the node input value if it's a proper input node */
if (node)
{
UINT8 *node_data = (UINT8 *)node->context;
UINT8 last_data = *node_data;
struct dss_input_context *context = (struct dss_input_context *)node->context;
UINT8 new_data = 0;
switch (node->module->type)
@ -93,15 +104,15 @@ WRITE8_DEVICE_HANDLER(discrete_sound_w)
break;
}
if (last_data != new_data)
if (context->data != new_data)
{
/* Bring the system up to now */
stream_update(info->discrete_stream);
*node_data = new_data;
context->data = new_data;
/* Update the node output here so we don't have to do it each step */
node->output[0] = *node_data * DSS_INPUT__GAIN + DSS_INPUT__OFFSET;
node->output[0] = new_data * context->gain + context->offset;
}
}
else
@ -217,33 +228,38 @@ static DISCRETE_RESET(dss_constant)
************************************************************************/
static DISCRETE_RESET(dss_input)
{
UINT8 *node_data = (UINT8 *)node->context;
struct dss_input_context *context = (struct dss_input_context *)node->context;
context->is_buffered = FALSE;
context->is_stream = FALSE;
context->gain = DSS_INPUT__GAIN;
context->offset = DSS_INPUT__OFFSET;
switch (node->module->type)
{
case DSS_INPUT_DATA:
*node_data = DSS_INPUT__INIT;
context->data = DSS_INPUT__INIT;
break;
case DSS_INPUT_LOGIC:
case DSS_INPUT_PULSE:
*node_data = (DSS_INPUT__INIT == 0) ? 0 : 1;
context->data = (DSS_INPUT__INIT == 0) ? 0 : 1;
break;
case DSS_INPUT_NOT:
*node_data = (DSS_INPUT__INIT == 0) ? 1 : 0;
context->data = (DSS_INPUT__INIT == 0) ? 1 : 0;
break;
}
node->output[0] = *node_data * DSS_INPUT__GAIN + DSS_INPUT__OFFSET;
node->output[0] = context->data * context->gain + context->offset;
}
static DISCRETE_STEP(dss_input_pulse)
{
UINT8 *node_data = (UINT8 *)node->context;
struct dss_input_context *context = (struct dss_input_context *)node->context;
/* Set a valid output */
node->output[0] = *node_data;
node->output[0] = context->data;
/* Reset the input to default for the next cycle */
/* node order is now important */
*node_data = DSS_INPUT__INIT;
context->data = DSS_INPUT__INIT;
}
@ -263,13 +279,12 @@ static DISCRETE_STEP(dss_input_pulse)
static DISCRETE_STEP(dss_input_stream)
{
/* the context pointer is set to point to the current input stream data in discrete_stream_update */
stream_sample_t **ptr = (stream_sample_t **)node->context;
stream_sample_t *data = *ptr;
struct dss_input_context *context = (struct dss_input_context *)node->context;
if (data)
if (context->ptr)
{
node->output[0] = (*data) * DSS_INPUT_STREAM__GAIN + DSS_INPUT_STREAM__OFFSET;
(*ptr)++;
node->output[0] = (*context->ptr) * context->gain + context->offset;
context->ptr++;
}
else
node->output[0] = 0;
@ -277,8 +292,13 @@ static DISCRETE_STEP(dss_input_stream)
static DISCRETE_RESET(dss_input_stream)
{
int istream = DSS_INPUT_STREAM__STREAM;
/* we will use the node's context pointer to point to the input stream data */
assert(istream < node->info->discrete_input_streams);
node->context = (discrete_info *) &node->info->input_stream_data[istream];
struct dss_input_context *context = (struct dss_input_context *)node->context;
assert(DSS_INPUT_STREAM__STREAM < linked_list_count(node->info->input_list));
context->is_buffered = FALSE;
context->is_stream = TRUE;
context->stream_in_number = DSS_INPUT_STREAM__STREAM;
context->gain = DSS_INPUT_STREAM__GAIN;
context->offset = DSS_INPUT_STREAM__OFFSET;
context->ptr = NULL;
}

View File

@ -169,6 +169,39 @@ static DISCRETE_RESET( dso_output )
/* nothing to do - just avoid being stepped */
}
/*************************************
*
* Add an entry to a list
*
*************************************/
static void linked_list_add(discrete_info *info, linked_list_entry ***list_tail_ptr, void *ptr)
{
**list_tail_ptr = auto_alloc(info->device->machine, linked_list_entry);
(**list_tail_ptr)->ptr = ptr;
(**list_tail_ptr)->next = NULL;
*list_tail_ptr = &((**list_tail_ptr)->next);
}
/*************************************
*
* Count entries in a list
*
*************************************/
static int linked_list_count(linked_list_entry *list)
{
int cnt = 0;
linked_list_entry *entry;
for (entry = list; entry != NULL; entry = entry->next)
cnt++;
return cnt;
}
/*************************************
*
* Included simulation objects
@ -191,7 +224,7 @@ static DISCRETE_RESET( dso_output )
static const discrete_module module_list[] =
{
{ DSO_OUTPUT ,"DSO_OUTPUT" , 0 ,sizeof(0) ,dso_output_reset ,dso_output_step },
{ DSO_OUTPUT ,"DSO_OUTPUT" , 0 ,0 ,dso_output_reset ,dso_output_step },
{ DSO_CSVLOG ,"DSO_CSVLOG" , 0 ,0 ,NULL ,NULL },
{ DSO_WAVELOG ,"DSO_WAVELOG" , 0 ,0 ,NULL ,NULL },
{ DSO_IMPORT ,"DSO_IMPORT" , 0 ,0 ,NULL ,NULL },
@ -207,11 +240,11 @@ static const discrete_module module_list[] =
/* from disc_inp.c */
{ DSS_ADJUSTMENT ,"DSS_ADJUSTMENT" , 1 ,sizeof(struct dss_adjustment_context) ,dss_adjustment_reset ,dss_adjustment_step },
{ DSS_CONSTANT ,"DSS_CONSTANT" , 1 ,0 ,dss_constant_reset ,NULL },
{ DSS_INPUT_DATA ,"DSS_INPUT_DATA" , 1 ,sizeof(UINT8) ,dss_input_reset ,NULL },
{ DSS_INPUT_LOGIC ,"DSS_INPUT_LOGIC" , 1 ,sizeof(UINT8) ,dss_input_reset ,NULL },
{ DSS_INPUT_NOT ,"DSS_INPUT_NOT" , 1 ,sizeof(UINT8) ,dss_input_reset ,NULL },
{ DSS_INPUT_PULSE ,"DSS_INPUT_PULSE" , 1 ,sizeof(UINT8) ,dss_input_reset ,dss_input_pulse_step },
{ DSS_INPUT_STREAM,"DSS_INPUT_STREAM", 1 ,0 ,dss_input_stream_reset,dss_input_stream_step},
{ DSS_INPUT_DATA ,"DSS_INPUT_DATA" , 1 ,sizeof(struct dss_input_context) ,dss_input_reset ,NULL },
{ DSS_INPUT_LOGIC ,"DSS_INPUT_LOGIC" , 1 ,sizeof(struct dss_input_context) ,dss_input_reset ,NULL },
{ DSS_INPUT_NOT ,"DSS_INPUT_NOT" , 1 ,sizeof(struct dss_input_context) ,dss_input_reset ,NULL },
{ DSS_INPUT_PULSE ,"DSS_INPUT_PULSE" , 1 ,sizeof(struct dss_input_context) ,dss_input_reset ,dss_input_pulse_step },
{ DSS_INPUT_STREAM,"DSS_INPUT_STREAM", 1 ,sizeof(struct dss_input_context) ,dss_input_stream_reset,dss_input_stream_step},
/* from disc_wav.c */
/* Generic modules */
@ -304,20 +337,6 @@ 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);
}
/*************************************
*
* Find a given node
@ -396,7 +415,7 @@ static void discrete_build_list(discrete_info *info, discrete_sound_block *intf,
else
{
discrete_log(info, "discrete_build_list() - adding node %d (*current %p)\n", node_count, *current);
add_list(info, current, &intf[node_count]);
linked_list_add(info, current, &intf[node_count]);
}
node_count++;
@ -482,6 +501,8 @@ static DEVICE_START( discrete )
/* Start with empty lists */
info->node_list = NULL;
info->step_list = NULL;
info->output_list = NULL;
info->input_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);
@ -494,7 +515,7 @@ static DEVICE_START( discrete )
/* then set up the output nodes */
/* initialize the stream(s) */
info->discrete_stream = stream_create(device, info->discrete_input_streams, info->discrete_outputs, info->sample_rate, info, discrete_stream_update);
info->discrete_stream = stream_create(device,linked_list_count(info->input_list), linked_list_count(info->output_list), info->sample_rate, info, discrete_stream_update);
/* allocate a queue */
@ -749,22 +770,22 @@ static STREAM_UPDATE( discrete_stream_update )
{
discrete_info *info = (discrete_info *)param;
linked_list_entry *entry;
int samplenum, nodenum, outputnum;
//int j; int left; int run;
int samplenum, outputnum;
if (samples == 0)
return;
/* Setup any output streams */
for (outputnum = 0; outputnum < info->discrete_outputs; outputnum++)
for (entry = info->output_list, outputnum = 0; entry != NULL; entry = entry->next, outputnum++)
{
info->output_node[outputnum]->context = (void *) outputs[outputnum];
((node_description *) entry->ptr)->context = (void *) outputs[outputnum];
}
/* Setup any input streams */
for (nodenum = 0; nodenum < info->discrete_input_streams; nodenum++)
for (entry = info->input_list; entry != NULL; entry = entry->next)
{
info->input_stream_data[nodenum] = inputs[nodenum];
struct dss_input_context *context = (struct dss_input_context *) ((node_description *) entry->ptr)->context;
context->ptr = (void *) inputs[context->stream_in_number];
}
for (entry = info->task_list; entry != 0; entry = entry->next)
@ -812,17 +833,15 @@ static STREAM_UPDATE( discrete_stream_update )
static void init_nodes(discrete_info *info, linked_list_entry *block_list, const device_config *device)
{
linked_list_entry **step_list = &info->step_list;
linked_list_entry **node_list = &info->node_list;
linked_list_entry **task_list = &info->task_list;
linked_list_entry **cur_task_node = NULL;
linked_list_entry *entry;
discrete_task_context *task = NULL;
/* start with no outputs or input streams */
info->discrete_outputs = 0;
info->discrete_input_streams = 0;
/* list tail pointers */
linked_list_entry **step_list = &info->step_list;
linked_list_entry **node_list = &info->node_list;
linked_list_entry **task_list = &info->task_list;
linked_list_entry **output_list = &info->output_list;
linked_list_entry **input_list = &info->input_list;
/* loop over all nodes */
for (entry = block_list; entry != NULL; entry = entry->next)
@ -854,9 +873,7 @@ static void init_nodes(discrete_info *info, linked_list_entry *block_list, const
{
/* Output Node */
case DSO_OUTPUT:
if (info->discrete_outputs == DISCRETE_MAX_OUTPUTS)
fatalerror("init_nodes() - There can not be more then %d output nodes", DISCRETE_MAX_OUTPUTS);
info->output_node[info->discrete_outputs++] = node;
linked_list_add(info, &output_list, node);
break;
/* CSVlog Node for debugging */
@ -878,7 +895,7 @@ static void init_nodes(discrete_info *info, linked_list_entry *block_list, const
if (cur_task_node != NULL)
fatalerror("init_nodes() - Nested DISCRETE_START_TASK.");
task = auto_alloc_clear(info->device->machine, discrete_task_context);
add_list(info, &task_list, task);
linked_list_add(info, &task_list, task);
cur_task_node = &task->list;
break;
@ -924,15 +941,11 @@ static void init_nodes(discrete_info *info, linked_list_entry *block_list, const
/* 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);
node->context = NULL;
info->discrete_input_streams++;
linked_list_add(info, &input_list, node);
}
/* add to node list */
add_list(info, &node_list, node);
linked_list_add(info, &node_list, node);
/* our running order just follows the order specified */
/* does the node step ? */
@ -940,9 +953,9 @@ static void init_nodes(discrete_info *info, linked_list_entry *block_list, const
{
/* do we belong to a task? */
if (cur_task_node == NULL)
add_list(info, &step_list, node);
linked_list_add(info, &step_list, node);
else
add_list(info, &cur_task_node, node);
linked_list_add(info, &cur_task_node, node);
}
if (block->type == DSO_TASK_END)
@ -956,7 +969,7 @@ static void init_nodes(discrete_info *info, linked_list_entry *block_list, const
}
/* if no outputs, give an error */
if (info->discrete_outputs == 0)
if (linked_list_count(info->output_list) == 0)
fatalerror("init_nodes() - Couldn't find an output node");
}

View File

@ -438,8 +438,12 @@
* Note: The discrete system is floating point based. So when routing a stream
* set it's gain to 100% and then use DISCRETE_INPUTX_STREAM to adjust
* it if needed.
* If you need to access a stream from a discrete task, the stream node
* must be part of that task. If a given stream is used in two tasks or
* a task and the main task, you must declare two stream nodes acccessing the
* same stream input NUM.
*
* EXAMPLES: see
* EXAMPLES: see scramble, frogger
*
***********************************************************************
=======================================================================
@ -3371,10 +3375,9 @@
#define DISCRETE_MAX_NODES 300
#define DISCRETE_MAX_INPUTS 10
#define DISCRETE_MAX_OUTPUTS 16
#define DISCRETE_MAX_WAVELOGS 10
#define DISCRETE_MAX_CSVLOGS 10
#define DISCRETE_MAX_NODE_OUTPUTS 8
#define DISCRETE_MAX_OUTPUTS 8
/*************************************
@ -3625,7 +3628,7 @@ struct _discrete_module
struct _node_description
{
int node; /* The node's index number in the node list */
double output[DISCRETE_MAX_NODE_OUTPUTS]; /* The node's last output value */
double output[DISCRETE_MAX_OUTPUTS]; /* The node's last output value */
int active_inputs; /* Number of active inputs on this node type */
int input_is_node; /* Bit Flags. 1 in bit location means input_is_node */
@ -3667,7 +3670,6 @@ struct _discrete_task_context
double *ptr;
double node_buf[2048];
double **dest;
volatile INT32 active;
};
struct _discrete_info
@ -3695,12 +3697,10 @@ struct _discrete_info
linked_list_entry *task_list; /* discrete_task_context * */
/* the input streams */
int discrete_input_streams;
stream_sample_t *input_stream_data[DISCRETE_MAX_OUTPUTS];
linked_list_entry *input_list;
/* output node tracking */
int discrete_outputs;
node_description *output_node[DISCRETE_MAX_OUTPUTS];
linked_list_entry *output_list;
/* the output stream */
sound_stream *discrete_stream;
@ -4024,10 +4024,10 @@ struct _discrete_inverter_osc_desc
*
*************************************/
#define NODE0_DEF(_x) NODE_ ## 0 ## _x = (0x40000000 + (_x) * DISCRETE_MAX_NODE_OUTPUTS), \
#define NODE0_DEF(_x) NODE_ ## 0 ## _x = (0x40000000 + (_x) * DISCRETE_MAX_OUTPUTS), \
NODE_ ## 0 ## _x ## _01, NODE_ ## 0 ## _x ## _02, NODE_ ## 0 ## _x ## _03, NODE_ ## 0 ## _x ## _04, \
NODE_ ## 0 ## _x ## _05, NODE_ ## 0 ## _x ## _06, NODE_ ## 0 ## _x ## _07
#define NODE_DEF(_x) NODE_ ## _x = (0x40000000 + (_x) * DISCRETE_MAX_NODE_OUTPUTS), \
#define NODE_DEF(_x) NODE_ ## _x = (0x40000000 + (_x) * DISCRETE_MAX_OUTPUTS), \
NODE_ ## _x ## _01, NODE_ ## _x ## _02, NODE_ ## _x ## _03, NODE_ ## _x ## _04, \
NODE_ ## _x ## _05, NODE_ ## _x ## _06, NODE_ ## _x ## _07
@ -4066,15 +4066,15 @@ enum {
/* Some Pre-defined nodes for convenience */
#define NODE(_x) (NODE_00 + (_x) * DISCRETE_MAX_NODE_OUTPUTS)
#define NODE(_x) (NODE_00 + (_x) * DISCRETE_MAX_OUTPUTS)
#define NODE_SUB(_x, _y) (NODE(_x) + (_y))
#if DISCRETE_MAX_NODE_OUTPUTS == 8
#if DISCRETE_MAX_OUTPUTS == 8
#define NODE_CHILD_NODE_NUM(_x) ((int)(_x) & 7)
#define NODE_DEFAULT_NODE(_x) ((int)(_x) & ~7)
#define NODE_INDEX(_x) (((int)(_x) - NODE_START)>>3)
#else
#error "DISCRETE_MAX_NODE_OUTPUTS != 8"
#error "DISCRETE_MAX_OUTPUTS != 8"
#endif
#define NODE_RELATIVE(_x, _y) (NODE(NODE_INDEX(_x) + (_y)))