From 0d424c796251f1734f9e735d202eaab4218fa037 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 9 Feb 2023 19:11:27 -0500 Subject: [PATCH] SegaPCM: prepare to actually emulate it --- CMakeLists.txt | 1 + src/engine/platform/segapcm.h | 2 + src/engine/platform/sound/segapcm.cpp | 125 ++++++++++++++++++++++++++ src/engine/platform/sound/segapcm.h | 50 +++++++++++ 4 files changed, 178 insertions(+) create mode 100644 src/engine/platform/sound/segapcm.cpp create mode 100644 src/engine/platform/sound/segapcm.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c8d34898..059154f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -365,6 +365,7 @@ src/engine/platform/sound/sn76496.cpp src/engine/platform/sound/ay8910.cpp src/engine/platform/sound/saa1099.cpp src/engine/platform/sound/namco.cpp +src/engine/platform/sound/segapcm.cpp src/engine/platform/sound/gb/apu.c src/engine/platform/sound/gb/timing.c src/engine/platform/sound/pce_psg.cpp diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index a57c8084..dd776826 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -22,6 +22,7 @@ #include "../dispatch.h" #include "../instrument.h" +#include "sound/segapcm.h" #include class DivPlatformSegaPCM: public DivDispatch { @@ -59,6 +60,7 @@ class DivPlatformSegaPCM: public DivDispatch { QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {} }; std::queue writes; + segapcm_device pcm; int delay; int pcmL, pcmR, pcmCycles; unsigned char sampleBank; diff --git a/src/engine/platform/sound/segapcm.cpp b/src/engine/platform/sound/segapcm.cpp new file mode 100644 index 00000000..29bff292 --- /dev/null +++ b/src/engine/platform/sound/segapcm.cpp @@ -0,0 +1,125 @@ +// license:BSD-3-Clause +// copyright-holders:Hiromitsu Shioya, Olivier Galibert +/*********************************************************/ +/* SEGA 16ch 8bit PCM */ +/*********************************************************/ + +#include + +#include "segapcm.h" + +//------------------------------------------------- +// segapcm_device - constructor +//------------------------------------------------- + +segapcm_device::segapcm_device() + : m_bankshift(12) + , m_bankmask(0x70) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void segapcm_device::device_start() +{ + memset(m_ram,255,0x800); + memset(m_low,0,16); + memset(lastOut,0,16*2*sizeof(short)); +} + + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void segapcm_device::sound_stream_update(int* outputs) +{ + /* clear the buffers */ + outputs[0]=0; + outputs[1]=0; + + // reg function + // ------------------------------------------------ + // 0x00 ? + // 0x01 ? + // 0x02 volume left + // 0x03 volume right + // 0x04 loop address (08-15) + // 0x05 loop address (16-23) + // 0x06 end address + // 0x07 address delta + // 0x80 ? + // 0x81 ? + // 0x82 ? + // 0x83 ? + // 0x84 current address (08-15), 00-07 is internal? + // 0x85 current address (16-23) + // 0x86 bit 0: channel disable? + // bit 1: loop disable + // other bits: bank + // 0x87 ? + + /* loop over channels */ + for (int ch = 0; ch < 16; ch++) + { + uint8_t *regs = &m_ram[8*ch]; + + /* only process active channels */ + if (!(regs[0x86]&1)) + { + int offset = (regs[0x86] & m_bankmask) << m_bankshift; + uint32_t addr = (regs[0x85] << 16) | (regs[0x84] << 8) | m_low[ch]; + uint32_t loop = (regs[0x05] << 16) | (regs[0x04] << 8); + uint8_t end = regs[6] + 1; + + int8_t v; + bool fetch=true; + + /* handle looping if we've hit the end */ + if ((addr >> 16) == end) + { + if (regs[0x86] & 2) + { + regs[0x86] |= 1; + fetch=false; + } + else addr = loop; + } + + /* fetch the sample */ + if (fetch) { + v = read_byte(offset + (addr >> 8)) - 0x80; + + /* apply panning and advance */ + lastOut[ch][0]=v * (regs[2] & 0x7f); + lastOut[ch][1]=v * (regs[3] & 0x7f); + outputs[0]+=lastOut[ch][0]; + outputs[1]+=lastOut[ch][1]; + addr = (addr + regs[7]) & 0xffffff; + } else { + lastOut[ch][0]=0; + lastOut[ch][1]=0; + } + + /* store back the updated address */ + regs[0x84] = addr >> 8; + regs[0x85] = addr >> 16; + m_low[ch] = regs[0x86] & 1 ? 0 : addr; + } + } +} + + +void segapcm_device::write(unsigned int offset, uint8_t data) +{ + m_ram[offset & 0x07ff] = data; +} + + +uint8_t segapcm_device::read(unsigned int offset) +{ + return m_ram[offset & 0x07ff]; +} diff --git a/src/engine/platform/sound/segapcm.h b/src/engine/platform/sound/segapcm.h new file mode 100644 index 00000000..830cc47d --- /dev/null +++ b/src/engine/platform/sound/segapcm.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Hiromitsu Shioya, Olivier Galibert +/*********************************************************/ +/* SEGA 8bit PCM */ +/*********************************************************/ + +#ifndef MAMESOUND_SEGAPCM_H +#define MAMESOUND_SEGAPCM_H + +#include + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class segapcm_device { +public: + static constexpr int BANK_256 = 11; + static constexpr int BANK_512 = 12; + static constexpr int BANK_12M = 13; + static constexpr int BANK_MASK7 = 0x70 << 16; + static constexpr int BANK_MASKF = 0xf0 << 16; + static constexpr int BANK_MASKF8 = 0xf8 << 16; + + short lastOut[16][2]; + + segapcm_device(); + + // configuration + void set_bank(int bank) { m_bankshift = (bank & 0xf); m_bankmask = (0x70|((bank >> 16) & 0xfc)); } + void set_read(std::function r) { read_byte = r; } + + void write(unsigned int offset, uint8_t data); + uint8_t read(unsigned int offset); + + // device-level overrides + void device_start(); + + // sound stream update overrides + void sound_stream_update(int* outputs); + +private: + uint8_t m_ram[0x800]; + uint8_t m_low[16]; + int m_bankshift; + int m_bankmask; + std::function read_byte; +}; + +#endif // MAMESOUND_SEGAPCM_H