// license:BSD-3-Clause // copyright-holders:R. Belmont, Tomasz Slanina, David Haywood /************************************ Seta custom ST-0016 chip sound emulation by R. Belmont, Tomasz Slanina, and David Haywood ************************************/ #include "emu.h" #include "st0016.h" //#define VERBOSE 1 #include "logmacro.h" // device type definition DEFINE_DEVICE_TYPE(ST0016, st0016_device, "st0016", "Seta ST0016 (Audio)") //************************************************************************** // LIVE DEVICE //************************************************************************** //------------------------------------------------- // st0016_device - constructor //------------------------------------------------- st0016_device::st0016_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, ST0016, tag, owner, clock) , device_sound_interface(mconfig, *this) , m_stream(nullptr) , m_ram_read_cb(*this) , m_vpos{ 0, 0, 0, 0, 0, 0, 0, 0 } , m_frac{ 0, 0, 0, 0, 0, 0, 0, 0 } , m_lponce{ 0, 0, 0, 0, 0, 0, 0, 0 } { std::fill(std::begin(m_regs), std::end(m_regs), 0); } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void st0016_device::device_start() { m_stream = stream_alloc(0, 2, 44100); m_ram_read_cb.resolve_safe(0); save_item(NAME(m_vpos)); save_item(NAME(m_frac)); save_item(NAME(m_lponce)); save_item(NAME(m_regs)); } //------------------------------------------------- // sound_stream_update - handle a stream update //------------------------------------------------- void st0016_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { int v, i, snum; unsigned char *slot; int32_t mix[48000*2]; int32_t *mixp; int16_t sample; int sptr, eptr, freq, lsptr, leptr; memset(mix, 0, sizeof(mix[0])*samples*2); for (v = 0; v < 8; v++) { slot = (unsigned char *)&m_regs[v * 32]; if (slot[0x16] & 0x06) { mixp = &mix[0]; sptr = slot[0x02]<<16 | slot[0x01]<<8 | slot[0x00]; eptr = slot[0x0e]<<16 | slot[0x0d]<<8 | slot[0x0c]; freq = slot[0x11]<<8 | slot[0x10]; lsptr = slot[0x06]<<16 | slot[0x05]<<8 | slot[0x04]; leptr = slot[0x0a]<<16 | slot[0x09]<<8 | slot[0x08]; for (snum = 0; snum < samples; snum++) { sample = m_ram_read_cb((sptr + m_vpos[v]) & 0x1fffff) << 8; *mixp++ += (sample * (char)slot[0x14]) >> 8; *mixp++ += (sample * (char)slot[0x15]) >> 8; m_frac[v] += freq; m_vpos[v] += (m_frac[v]>>16); m_frac[v] &= 0xffff; // stop if we're at the end if (m_lponce[v]) { // we've looped once, check loop end rather than sample end if ((m_vpos[v] + sptr) >= leptr) { m_vpos[v] = (lsptr - sptr); } } else { // not looped yet, check sample end if ((m_vpos[v] + sptr) >= eptr) { if (slot[0x16] & 0x01) // loop? { m_vpos[v] = (lsptr - sptr); m_lponce[v] = 1; } else { slot[0x16] = 0; m_vpos[v] = m_frac[v] = 0; } } } } } } mixp = &mix[0]; for (i = 0; i < samples; i++) { outputs[0][i] = (*mixp++)>>4; outputs[1][i] = (*mixp++)>>4; } } READ8_MEMBER( st0016_device::st0016_snd_r ) { return m_regs[offset]; } WRITE8_MEMBER( st0016_device::st0016_snd_w ) { int voice = offset/32; int reg = offset & 0x1f; int oldreg = m_regs[offset]; int vbase = offset & ~0x1f; m_regs[offset] = data; if ((voice < 8) && (data != oldreg)) { if ((reg == 0x16) && (data != 0)) { m_vpos[voice] = m_frac[voice] = m_lponce[voice] = 0; LOG("Key on V%02d: st %06x-%06x lp %06x-%06x frq %x flg %x\n", voice, m_regs[vbase+2]<<16 | m_regs[vbase+1]<<8 | m_regs[vbase+2], m_regs[vbase+0xe]<<16 | m_regs[vbase+0xd]<<8 | m_regs[vbase+0xc], m_regs[vbase+6]<<16 | m_regs[vbase+5]<<8 | m_regs[vbase+4], m_regs[vbase+0xa]<<16 | m_regs[vbase+0x9]<<8 | m_regs[vbase+0x8], m_regs[vbase+0x11]<<8 | m_regs[vbase+0x10], m_regs[vbase+0x16]); } } }