diff options
Diffstat (limited to 'src/emu/sound/segapcm.c')
-rw-r--r-- | src/emu/sound/segapcm.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/src/emu/sound/segapcm.c b/src/emu/sound/segapcm.c new file mode 100644 index 00000000000..7fa6a215fa7 --- /dev/null +++ b/src/emu/sound/segapcm.c @@ -0,0 +1,160 @@ +/*********************************************************/ +/* SEGA 16ch 8bit PCM */ +/*********************************************************/ + +#include "sndintrf.h" +#include "streams.h" +#include "segapcm.h" + +struct segapcm +{ + UINT8 *ram; + UINT8 low[16]; + const UINT8 *rom; + int bankshift; + int bankmask; + sound_stream * stream; +}; + +static void SEGAPCM_update(void *param, stream_sample_t **inputs, stream_sample_t **buffer, int length) +{ + struct segapcm *spcm = param; + int ch; + + /* clear the buffers */ + memset(buffer[0], 0, length*sizeof(*buffer[0])); + memset(buffer[1], 0, length*sizeof(*buffer[1])); + + /* loop over channels */ + for (ch = 0; ch < 16; ch++) + + /* only process active channels */ + if (!(spcm->ram[0x86+8*ch] & 1)) + { + UINT8 *base = spcm->ram+8*ch; + UINT8 flags = base[0x86]; + const UINT8 *rom = spcm->rom + ((flags & spcm->bankmask) << spcm->bankshift); + UINT32 addr = (base[5] << 16) | (base[4] << 8) | spcm->low[ch]; + UINT16 loop = (base[0x85] << 8) | base[0x84]; + UINT8 end = base[6] + 1; + UINT8 delta = base[7]; + UINT8 voll = base[2]; + UINT8 volr = base[3]; + int i; + + /* loop over samples on this channel */ + for (i = 0; i < length; i++) + { + INT8 v = 0; + + /* handle looping if we've hit the end */ + if ((addr >> 16) == end) + { + if (!(flags & 2)) + addr = loop << 8; + else + { + flags |= 1; + break; + } + } + + /* fetch the sample */ + v = rom[addr >> 8] - 0x80; + + /* apply panning and advance */ + buffer[0][i] += v * voll; + buffer[1][i] += v * volr; + addr += delta; + } + + /* store back the updated address and info */ + base[0x86] = flags; + base[4] = addr >> 8; + base[5] = addr >> 16; + spcm->low[ch] = flags & 1 ? 0 : addr; + } +} + +static void *segapcm_start(int sndindex, int clock, const void *config) +{ + const struct SEGAPCMinterface *intf = config; + int mask, rom_mask; + struct segapcm *spcm; + + spcm = auto_malloc(sizeof(*spcm)); + memset(spcm, 0, sizeof(*spcm)); + + spcm->rom = (const UINT8 *)memory_region(intf->region); + spcm->ram = auto_malloc(0x800); + + memset(spcm->ram, 0xff, 0x800); + + spcm->bankshift = (UINT8)(intf->bank); + mask = intf->bank >> 16; + if(!mask) + mask = BANK_MASK7>>16; + + for(rom_mask = 1; rom_mask < memory_region_length(intf->region); rom_mask *= 2); + rom_mask--; + + spcm->bankmask = mask & (rom_mask >> spcm->bankshift); + + spcm->stream = stream_create(0, 2, clock / 128, spcm, SEGAPCM_update); + + state_save_register_item_array("segapcm", sndindex, spcm->low); + state_save_register_item_pointer("segapcm", sndindex, spcm->ram, 0x800); + + return spcm; +} + + +WRITE8_HANDLER( SegaPCM_w ) +{ + struct segapcm *spcm = sndti_token(SOUND_SEGAPCM, 0); + stream_update(spcm->stream); + spcm->ram[offset & 0x07ff] = data; +} + +READ8_HANDLER( SegaPCM_r ) +{ + struct segapcm *spcm = sndti_token(SOUND_SEGAPCM, 0); + stream_update(spcm->stream); + return spcm->ram[offset & 0x07ff]; +} + + + +/************************************************************************** + * Generic get_info + **************************************************************************/ + +static void segapcm_set_info(void *token, UINT32 state, sndinfo *info) +{ + switch (state) + { + /* no parameters to set */ + } +} + + +void segapcm_get_info(void *token, UINT32 state, sndinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case SNDINFO_PTR_SET_INFO: info->set_info = segapcm_set_info; break; + case SNDINFO_PTR_START: info->start = segapcm_start; break; + case SNDINFO_PTR_STOP: /* Nothing */ break; + case SNDINFO_PTR_RESET: /* Nothing */ break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case SNDINFO_STR_NAME: info->s = "Sega PCM"; break; + case SNDINFO_STR_CORE_FAMILY: info->s = "Sega custom"; break; + case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break; + case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break; + case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break; + } +} |