- Added the ability to the HC55516 emulator to take an external osciallator

- Updated Mouse Trap to use the new interface
This commit is contained in:
Zsolt Vasvari 2008-01-20 15:05:31 +00:00
parent cb6dbf5369
commit 34a413510d
3 changed files with 141 additions and 72 deletions

View File

@ -3,9 +3,11 @@
#include "hc55516.h"
#include <math.h>
#include "cpuintrf.h"
/* default to 4x oversampling */
#define DEFAULT_SAMPLE_RATE (48000 * 4)
#define SAMPLE_RATE (48000 * 4)
#define INTEGRATOR_LEAK_TC 0.001
@ -19,10 +21,11 @@
struct hc55516_data
{
sound_stream *channel;
int sample_rate;
int clock; /* 0 = software driven, non-0 = oscillator */
UINT8 last_clock;
UINT8 databit;
UINT8 new_databit;
UINT8 shiftreg;
INT16 curr_value;
@ -56,11 +59,12 @@ static void *hc55516_start(int sndindex, int clock, const void *config)
leak = pow(exp(-1), 1.0 / (INTEGRATOR_LEAK_TC * 16000.0));
/* create the stream */
chip->sample_rate = clock ? clock : DEFAULT_SAMPLE_RATE;
chip->channel = stream_create(0, 1, chip->sample_rate, chip, hc55516_update);
chip->clock = clock;
chip->channel = stream_create(0, 1, SAMPLE_RATE, chip, hc55516_update);
state_save_register_item("hc55516", sndindex, chip->last_clock);
state_save_register_item("hc55516", sndindex, chip->databit);
state_save_register_item("hc55516", sndindex, chip->new_databit);
state_save_register_item("hc55516", sndindex, chip->shiftreg);
state_save_register_item("hc55516", sndindex, chip->curr_value);
state_save_register_item("hc55516", sndindex, chip->next_value);
@ -73,23 +77,79 @@ static void *hc55516_start(int sndindex, int clock, const void *config)
}
INLINE int current_clock_edge(struct hc55516_data *chip)
{
return ((UINT64)chip->update_count * chip->clock * 2 / SAMPLE_RATE) & 0x01;
}
static void process_bit(struct hc55516_data *chip)
{
double integrator = chip->integrator, temp;
/* move the estimator up or down a step based on the bit */
if (chip->databit)
{
chip->shiftreg = ((chip->shiftreg << 1) | 1) & 7;
integrator += chip->filter;
}
else
{
chip->shiftreg = (chip->shiftreg << 1) & 7;
integrator -= chip->filter;
}
/* simulate leakage */
integrator *= leak;
/* if we got all 0's or all 1's in the last n bits, bump the step up */
if (chip->shiftreg == 0 || chip->shiftreg == 7)
{
chip->filter = FILTER_MAX - ((FILTER_MAX - chip->filter) * charge);
if (chip->filter > FILTER_MAX)
chip->filter = FILTER_MAX;
}
/* simulate decay */
else
{
chip->filter *= decay;
if (chip->filter < FILTER_MIN)
chip->filter = FILTER_MIN;
}
/* compute the sample as a 32-bit word */
temp = integrator * SAMPLE_GAIN;
chip->integrator = integrator;
/* compress the sample range to fit better in a 16-bit word */
if (temp < 0)
chip->next_value = (int)(temp / (-temp * (1.0 / 32768.0) + 1.0));
else
chip->next_value = (int)(temp / (temp * (1.0 / 32768.0) + 1.0));
}
static void hc55516_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length)
{
struct hc55516_data *chip = param;
stream_sample_t *buffer = _buffer[0];
INT32 data, slope;
int i;
INT32 data, slope;
/* zero-length? bail */
if (length == 0)
return;
/* track how many samples we've updated without a clock */
chip->update_count += length;
if (chip->update_count > chip->sample_rate / 32)
if (chip->clock == 0)
{
chip->update_count = chip->sample_rate;
chip->next_value = 0;
/* track how many samples we've updated without a clock */
chip->update_count += length;
if (chip->update_count > SAMPLE_RATE / 32)
{
chip->update_count = SAMPLE_RATE;
chip->next_value = 0;
}
}
/* compute the interpolation slope */
@ -97,9 +157,37 @@ static void hc55516_update(void *param, stream_sample_t **inputs, stream_sample_
slope = ((INT32)chip->next_value - data) / length;
chip->curr_value = chip->next_value;
/* reset the sample count */
for (i = 0; i < length; i++, data += slope)
*buffer++ = data;
if (chip->clock != 0)
{
int edge = current_clock_edge(chip);
/* external oscillator */
for (i = 0; i < length; i++, data += slope)
{
int new_edge;
*buffer++ = data;
chip->update_count++;
new_edge = current_clock_edge(chip);
/* pull in next data bit on falling edge of the clock */
if (edge && !new_edge)
{
chip->databit = chip->new_databit;
process_bit(chip);
}
edge = new_edge;
}
}
/* software driven clock */
else
for (i = 0; i < length; i++, data += slope)
*buffer++ = data;
}
@ -108,6 +196,8 @@ void hc55516_clock_w(int num, int state)
struct hc55516_data *chip = sndti_token(SOUND_HC55516, num);
int clock = state & 1, diffclock;
assert(chip->clock == 0);
/* update the clock */
diffclock = clock ^ chip->last_clock;
chip->last_clock = clock;
@ -115,54 +205,13 @@ void hc55516_clock_w(int num, int state)
/* speech clock changing (active on rising edge) */
if (diffclock && clock)
{
double integrator = chip->integrator, temp;
/* update the output buffer before changing the registers */
stream_update(chip->channel);
/* clear the update count */
chip->update_count = 0;
/* move the estimator up or down a step based on the bit */
if (chip->databit)
{
chip->shiftreg = ((chip->shiftreg << 1) | 1) & 7;
integrator += chip->filter;
}
else
{
chip->shiftreg = (chip->shiftreg << 1) & 7;
integrator -= chip->filter;
}
/* simulate leakage */
integrator *= leak;
/* if we got all 0's or all 1's in the last n bits, bump the step up */
if (chip->shiftreg == 0 || chip->shiftreg == 7)
{
chip->filter = FILTER_MAX - ((FILTER_MAX - chip->filter) * charge);
if (chip->filter > FILTER_MAX)
chip->filter = FILTER_MAX;
}
/* simulate decay */
else
{
chip->filter *= decay;
if (chip->filter < FILTER_MIN)
chip->filter = FILTER_MIN;
}
/* compute the sample as a 32-bit word */
temp = integrator * SAMPLE_GAIN;
chip->integrator = integrator;
/* compress the sample range to fit better in a 16-bit word */
if (temp < 0)
chip->next_value = (int)(temp / (-temp * (1.0 / 32768.0) + 1.0));
else
chip->next_value = (int)(temp / (temp * (1.0 / 32768.0) + 1.0));
/* update the output buffer before changing the registers */
stream_update(chip->channel);
process_bit(chip);
}
}
@ -170,7 +219,14 @@ void hc55516_clock_w(int num, int state)
void hc55516_digit_w(int num, int data)
{
struct hc55516_data *chip = sndti_token(SOUND_HC55516, num);
chip->databit = data & 1;
if (chip->clock != 0)
{
stream_update(chip->channel);
chip->new_databit = data & 1;
}
else
chip->databit = data & 1;
}
@ -194,17 +250,32 @@ void hc55516_digit_clock_clear_w(int num, int data)
}
int hc55516_clock_edge_r(int num)
{
struct hc55516_data *chip = sndti_token(SOUND_HC55516, num);
assert(chip->clock != 0);
stream_update(chip->channel);
return current_clock_edge(chip);
}
WRITE8_HANDLER( hc55516_0_digit_w ) { hc55516_digit_w(0,data); }
WRITE8_HANDLER( hc55516_0_clock_w ) { hc55516_clock_w(0,data); }
WRITE8_HANDLER( hc55516_0_clock_clear_w ) { hc55516_clock_clear_w(0,data); }
WRITE8_HANDLER( hc55516_0_clock_set_w ) { hc55516_clock_set_w(0,data); }
WRITE8_HANDLER( hc55516_0_digit_clock_clear_w ) { hc55516_digit_clock_clear_w(0,data); }
READ8_HANDLER ( hc55516_0_clock_edge_r ) { return hc55516_clock_edge_r(0); }
WRITE8_HANDLER( hc55516_1_digit_w ) { hc55516_digit_w(1,data); }
WRITE8_HANDLER( hc55516_1_clock_w ) { hc55516_clock_w(1,data); }
WRITE8_HANDLER( hc55516_1_clock_clear_w ) { hc55516_clock_clear_w(1,data); }
WRITE8_HANDLER( hc55516_1_clock_set_w ) { hc55516_clock_set_w(1,data); }
WRITE8_HANDLER( hc55516_1_digit_clock_clear_w ) { hc55516_digit_clock_clear_w(1,data); }
READ8_HANDLER ( hc55516_1_clock_edge_r ) { return hc55516_clock_edge_r(1); }
@ -237,8 +308,8 @@ void hc55516_get_info(void *token, UINT32 state, sndinfo *info)
/* --- the following bits of info are returned as NULL-terminated strings --- */
case SNDINFO_STR_NAME: info->s = "HC55516"; break;
case SNDINFO_STR_CORE_FAMILY: info->s = "Gaelco custom"; break;
case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break;
case SNDINFO_STR_CORE_FAMILY: info->s = "CVSD"; break;
case SNDINFO_STR_CORE_VERSION: info->s = "2.0"; break;
case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break;
case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright Nicola Salmoria and the MAME Team"; break;
}

View File

@ -15,17 +15,21 @@ void hc55516_clock_set_w(int num, int data);
/* clears the clock state and sets the databit */
void hc55516_digit_clock_clear_w(int num, int data);
int hc55516_clock_edge_r(int num);
WRITE8_HANDLER( hc55516_0_digit_w );
WRITE8_HANDLER( hc55516_0_clock_w );
WRITE8_HANDLER( hc55516_0_clock_clear_w );
WRITE8_HANDLER( hc55516_0_clock_set_w );
WRITE8_HANDLER( hc55516_0_digit_clock_clear_w );
READ8_HANDLER ( hc55516_0_clock_edge_r );
WRITE8_HANDLER( hc55516_1_digit_w );
WRITE8_HANDLER( hc55516_1_clock_w );
WRITE8_HANDLER( hc55516_1_clock_clear_w );
WRITE8_HANDLER( hc55516_1_clock_set_w );
WRITE8_HANDLER( hc55516_1_digit_clock_clear_w );
READ8_HANDLER ( hc55516_1_clock_edge_r );
#endif

View File

@ -27,7 +27,8 @@
#define SH8253_CLOCK (CRYSTAL_OSC/2)
#define SH6840_CLOCK (CRYSTAL_OSC/4)
#define SH6532_CLOCK (CRYSTAL_OSC/4)
#define CVSD_CLOCK_FREQ (1.0 / (0.693 * (RES_K(2.4) + 2.0 * RES_K(20)) * CAP_P(2200)))
#define CVSD_CLOCK (1.0 / (0.693 * (RES_K(2.4) + 2.0 * RES_K(20)) * CAP_P(2200)))
#define CVSD_Z80_CLOCK (CRYSTAL_OSC/2)
#define BASE_VOLUME (32767 / 6)
enum
@ -834,10 +835,7 @@ MACHINE_DRIVER_END
static WRITE8_HANDLER( mtrap_voiceio_w )
{
if (!(offset & 0x10))
{
hc55516_digit_clock_clear_w(0,data);
hc55516_clock_set_w(0,data);
}
hc55516_digit_w(0, data & 1);
if (!(offset & 0x20))
riot_portb_data = data & 1;
@ -856,12 +854,8 @@ static READ8_HANDLER( mtrap_voiceio_r )
}
if (!(offset & 0x40))
{
attotime curtime = timer_get_time();
int clock_pulse = curtime.attoseconds / HZ_TO_ATTOSECONDS(2 * CVSD_CLOCK_FREQ);
return hc55516_clock_edge_r(0) << 7;
return (clock_pulse & 1) << 7;
}
return 0;
}
@ -880,12 +874,12 @@ ADDRESS_MAP_END
MACHINE_DRIVER_START( mtrap_cvsd_audio )
MDRV_CPU_ADD(Z80, 3579545/2)
MDRV_CPU_ADD(Z80, CVSD_Z80_CLOCK)
MDRV_CPU_PROGRAM_MAP(cvsd_map,0)
MDRV_CPU_IO_MAP(cvsd_iomap,0)
/* audio hardware */
MDRV_SOUND_ADD(HC55516, 0)
MDRV_SOUND_ADD(HC55516, CVSD_CLOCK)
MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.80)
MACHINE_DRIVER_END