/************************************************************************
*
* MAME - Discrete sound system emulation library
*
* Written by Keith Wilkins (mame@esplexo.co.uk)
*
* (c) K.Wilkins 2000
*
***********************************************************************
*
* DSS_ADJUSTMENT - UI Mapped adjustable input
* DSS_CONSTANT - Node based constant - Do we need this ???
* DSS_INPUT_x - Input devices
* DSS_INPUT_STREAM - Connects external streams to the discrete system
*
************************************************************************/
#define DSS_INPUT__GAIN DISCRETE_INPUT(0)
#define DSS_INPUT__OFFSET DISCRETE_INPUT(1)
#define DSS_INPUT__INIT DISCRETE_INPUT(2)
struct dss_adjustment_context
{
const input_port_config *port;
INT32 lastpval;
INT32 pmin;
double pscale;
double min;
double scale;
};
struct dss_input_context
{
stream_sample_t *ptr; /* current in ptr for stream */
double gain; /* node gain */
double offset; /* node offset */
UINT8 data; /* data written */
UINT8 is_stream;
UINT8 is_buffered;
UINT32 stream_in_number;
/* the buffer stream */
sound_stream *buffer_stream;
};
INLINE discrete_info *get_safe_token(const device_config *device)
{
assert(device != NULL);
assert(device->token != NULL);
assert(device->type == SOUND);
assert(sound_get_type(device) == SOUND_DISCRETE);
return (discrete_info *)device->token;
}
READ8_DEVICE_HANDLER(discrete_sound_r)
{
discrete_info *info = get_safe_token(device);
node_description *node = discrete_find_node(info, offset);
UINT8 data = 0;
/* Read the node input value if allowed */
if (node)
{
/* Bring the system up to now */
stream_update(info->discrete_stream);
data = (UINT8) node->output[NODE_CHILD_NODE_NUM(offset)];
}
else
fatalerror("discrete_sound_r read from non-existent NODE_%02d\n", offset-NODE_00);
return data;
}
WRITE8_DEVICE_HANDLER(discrete_sound_w)
{
discrete_info *info = get_safe_token(device);
node_description *node = discrete_find_node(info, offset);
/* Update the node input value if it's a proper input node */
if (node)
{
struct dss_input_context *context = (struct dss_input_context *)node->context;
UINT8 new_data = 0;
switch (node->module->type)
{
case DSS_INPUT_DATA:
case DSS_INPUT_BUFFER:
new_data = data;
break;
case DSS_INPUT_LOGIC:
case DSS_INPUT_PULSE:
new_data = data ? 1 : 0;
break;
case DSS_INPUT_NOT:
new_data = data ? 0 : 1;
break;
}
if (context->data != new_data)
{
if (context->is_buffered)
{
/* Bring the system up to now */
stream_update(context->buffer_stream);
context->data = new_data;
}
else
{
/* Bring the system up to now */
stream_update(info->discrete_stream);
context->data = new_data;
/* Update the node output here so we don't have to do it each step */
node->output[0] = new_data * context->gain + context->offset;
}
}
}
else
{
discrete_log(info, "discrete_sound_w write to non-existent NODE_%02d\n", offset-NODE_00);
}
}
/************************************************************************
*
* DSS_ADJUSTMENT - UI Adjustable constant node to emulate trimmers
*
* input[0] - Enable
* input[1] - Minimum value
* input[2] - Maximum value
* input[3] - Log/Linear 0=Linear !0=Log
* input[4] - Input Port number
* input[5] -
* input[6] -
*
************************************************************************/
#define DSS_ADJUSTMENT__MIN DISCRETE_INPUT(0)
#define DSS_ADJUSTMENT__MAX DISCRETE_INPUT(1)
#define DSS_ADJUSTMENT__LOG DISCRETE_INPUT(2)
#define DSS_ADJUSTMENT__PORT DISCRETE_INPUT(3)
#define DSS_ADJUSTMENT__PMIN DISCRETE_INPUT(4)
#define DSS_ADJUSTMENT__PMAX DISCRETE_INPUT(5)
static DISCRETE_STEP(dss_adjustment)
{
struct dss_adjustment_context *context = (struct dss_adjustment_context *)node->context;
INT32 rawportval = input_port_read_direct(context->port);
/* only recompute if the value changed from last time */
if (UNEXPECTED(rawportval != context->lastpval))
{
double portval = (double)(rawportval - context->pmin) * context->pscale;
double scaledval = portval * context->scale + context->min;
context->lastpval = rawportval;
if (DSS_ADJUSTMENT__LOG == 0)
node->output[0] = scaledval;
else
node->output[0] = pow(10, scaledval);
}
}
static DISCRETE_RESET(dss_adjustment)
{
struct dss_adjustment_context *context = (struct dss_adjustment_context *)node->context;
double min, max;
if (node->custom)
{
context->port = input_port_by_tag(node->info->device->machine->portconfig, (const char *)node->custom);
if (context->port == NULL)
fatalerror("DISCRETE_ADJUSTMENT_TAG - NODE_%d has invalid tag", NODE_BLOCKINDEX(node));
}
else
context->port = input_port_by_index(node->info->device->machine->portconfig, DSS_ADJUSTMENT__PORT);
context->lastpval = 0x7fffffff;
context->pmin = DSS_ADJUSTMENT__PMIN;
context->pscale = 1.0 / (double)(DSS_ADJUSTMENT__PMAX - DSS_ADJUSTMENT__PMIN);
/* linear scale */
if (DSS_ADJUSTMENT__LOG == 0)
{
context->min = DSS_ADJUSTMENT__MIN;
context->scale = DSS_ADJUSTMENT__MAX - DSS_ADJUSTMENT__MIN;
}
/* logarithmic scale */
else
{
/* force minimum and maximum to be > 0 */
min = (DSS_ADJUSTMENT__MIN > 0) ? DSS_ADJUSTMENT__MIN : 1;
max = (DSS_ADJUSTMENT__MAX > 0) ? DSS_ADJUSTMENT__MAX : 1;
context->min = log10(min);
context->scale = log10(max) - log10(min);
}
DISCRETE_STEP_CALL(dss_adjustment);
}
/************************************************************************
*
* DSS_CONSTANT - This is a constant.
*
* input[0] - Constant value
*
************************************************************************/
#define DSS_CONSTANT__INIT DISCRETE_INPUT(0)
static DISCRETE_RESET(dss_constant)
{
node->output[0]= DSS_CONSTANT__INIT;
}
/************************************************************************
*
* DSS_INPUT_x - Receives input from discrete_sound_w
*
* input[0] - Gain value
* input[1] - Offset value
* input[2] - Starting Position
* input[3] - Current data value
*
************************************************************************/
static DISCRETE_RESET(dss_input)
{
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:
context->data = DSS_INPUT__INIT;
break;
case DSS_INPUT_LOGIC:
case DSS_INPUT_PULSE:
context->data = (DSS_INPUT__INIT == 0) ? 0 : 1;
break;
case DSS_INPUT_NOT:
context->data = (DSS_INPUT__INIT == 0) ? 1 : 0;
break;
}
node->output[0] = context->data * context->gain + context->offset;
}
static DISCRETE_STEP(dss_input_pulse)
{
struct dss_input_context *context = (struct dss_input_context *)node->context;
/* Set a valid output */
node->output[0] = context->data;
/* Reset the input to default for the next cycle */
/* node order is now important */
context->data = DSS_INPUT__INIT;
}
/************************************************************************
*
* DSS_INPUT_STREAM - Receives input from a routed stream
*
* input[0] - Input stream number
* input[1] - Gain value
* input[2] - Offset value
*
************************************************************************/
#define DSS_INPUT_STREAM__STREAM DISCRETE_INPUT(0)
#define DSS_INPUT_STREAM__GAIN DISCRETE_INPUT(1)
#define DSS_INPUT_STREAM__OFFSET DISCRETE_INPUT(2)
static DISCRETE_STEP(dss_input_stream)
{
/* the context pointer is set to point to the current input stream data in discrete_stream_update */
struct dss_input_context *context = (struct dss_input_context *)node->context;
if (EXPECTED(context->ptr))
{
node->output[0] = (*context->ptr) * context->gain + context->offset;
context->ptr++;
}
else
node->output[0] = 0;
}
static DISCRETE_RESET(dss_input_stream)
{
struct dss_input_context *context = (struct dss_input_context *)node->context;
context->ptr = NULL;
context->data = 0;
}
static DISCRETE_START(dss_input_stream)
{
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_stream = TRUE;
/* Stream out number is set during start */
context->stream_in_number = DSS_INPUT_STREAM__STREAM;
context->gain = DSS_INPUT_STREAM__GAIN;
context->offset = DSS_INPUT_STREAM__OFFSET;
context->ptr = NULL;
//context->data = 0;
if (node->block->type == DSS_INPUT_BUFFER)
{
context->is_buffered = TRUE;
context->buffer_stream = stream_create(node->info->device, 0, 1, node->info->sample_rate, (void *) node, buffer_stream_update);
stream_set_input(node->info->discrete_stream, context->stream_in_number,
context->buffer_stream, 0, 1.0);
}
else
{
context->is_buffered = FALSE;
context->buffer_stream = NULL;
}
}