diff options
Diffstat (limited to 'trunk/src/emu/sound/n63701x.c')
-rw-r--r-- | trunk/src/emu/sound/n63701x.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/trunk/src/emu/sound/n63701x.c b/trunk/src/emu/sound/n63701x.c new file mode 100644 index 00000000000..0c0faae0b1b --- /dev/null +++ b/trunk/src/emu/sound/n63701x.c @@ -0,0 +1,188 @@ +/*************************************************************************** + +An Hitachi HD637A01X0 MCU programmed to act as a sample player. +Used by some Namco System 86 games. + +The MCU has internal ROM which hasn't been dumped, so here we simulate its +simple functions. + +The chip can address ROM space up to 8 block of 0x10000 bytes. At the beginning +of each block there's a table listing the start offset of each sample. +Samples are 8 bit unsigned, 0xff marks the end of the sample. 0x00 is used for +silence compression: '00 nn' must be replaced by nn+1 times '80'. + +***************************************************************************/ + +#include "emu.h" +#include "n63701x.h" + + +typedef struct +{ + int select; + int playing; + int base_addr; + int position; + int volume; + int silence_counter; +} voice; + + +typedef struct _namco_63701x namco_63701x; +struct _namco_63701x +{ + voice voices[2]; + sound_stream * stream; /* channel assigned by the mixer */ + UINT8 *rom; /* pointer to sample ROM */ +}; + + +/* volume control has three resistors: 22000, 10000 and 3300 Ohm. + 22000 is always enabled, the other two can be turned off. + Since 0x00 and 0xff samples have special meaning, the available range is + 0x01 to 0xfe, therefore 258 * (0x01 - 0x80) = 0x8002 just keeps us + inside 16 bits without overflowing. + */ +static const int vol_table[4] = { 26, 84, 200, 258 }; + + +INLINE namco_63701x *get_safe_token(device_t *device) +{ + assert(device != NULL); + assert(device->type() == NAMCO_63701X); + return (namco_63701x *)downcast<legacy_device_base *>(device)->token(); +} + + +static STREAM_UPDATE( namco_63701x_update ) +{ + namco_63701x *chip = (namco_63701x *)param; + int ch; + + for (ch = 0;ch < 2;ch++) + { + stream_sample_t *buf = outputs[ch]; + voice *v = &chip->voices[ch]; + + if (v->playing) + { + UINT8 *base = chip->rom + v->base_addr; + int pos = v->position; + int vol = vol_table[v->volume]; + int p; + + for (p = 0;p < samples;p++) + { + if (v->silence_counter) + { + v->silence_counter--; + *(buf++) = 0; + } + else + { + int data = base[(pos++) & 0xffff]; + + if (data == 0xff) /* end of sample */ + { + v->playing = 0; + break; + } + else if (data == 0x00) /* silence compression */ + { + data = base[(pos++) & 0xffff]; + v->silence_counter = data; + *(buf++) = 0; + } + else + { + *(buf++) = vol * (data - 0x80); + } + } + } + + v->position = pos; + } + else + memset(buf, 0, samples * sizeof(*buf)); + } +} + + +static DEVICE_START( namco_63701x ) +{ + namco_63701x *chip = get_safe_token(device); + + chip->rom = *device->region(); + + chip->stream = device->machine().sound().stream_alloc(*device, 0, 2, device->clock()/1000, chip, namco_63701x_update); +} + + + +WRITE8_DEVICE_HANDLER( namco_63701x_w ) +{ + namco_63701x *chip = get_safe_token(device); + int ch = offset / 2; + + if (offset & 1) + chip->voices[ch].select = data; + else + { + /* + should we stop the playing sample if voice_select[ch] == 0 ? + originally we were, but this makes us lose a sample in genpeitd, + after the continue counter reaches 0. Either we shouldn't stop + the sample, or genpeitd is returning to the title screen too soon. + */ + if (chip->voices[ch].select & 0x1f) + { + int rom_offs; + + /* update the streams */ + chip->stream->update(); + + chip->voices[ch].playing = 1; + chip->voices[ch].base_addr = 0x10000 * ((chip->voices[ch].select & 0xe0) >> 5); + rom_offs = chip->voices[ch].base_addr + 2 * ((chip->voices[ch].select & 0x1f) - 1); + chip->voices[ch].position = (chip->rom[rom_offs] << 8) + chip->rom[rom_offs+1]; + /* bits 6-7 = volume */ + chip->voices[ch].volume = data >> 6; + /* bits 0-5 = counter to indicate new sample start? we don't use them */ + + chip->voices[ch].silence_counter = 0; + } + } +} + + + + + + +/************************************************************************** + * Generic get_info + **************************************************************************/ + +DEVICE_GET_INFO( namco_63701x ) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(namco_63701x); break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( namco_63701x ); break; + case DEVINFO_FCT_STOP: /* Nothing */ break; + case DEVINFO_FCT_RESET: /* Nothing */ break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case DEVINFO_STR_NAME: strcpy(info->s, "Namco 63701X"); break; + case DEVINFO_STR_FAMILY: strcpy(info->s, "Namco custom"); break; + case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; + case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; + case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; + } +} + + +DEFINE_LEGACY_SOUND_DEVICE(NAMCO_63701X, namco_63701x); |