SegaPCM: prepare to actually emulate it

This commit is contained in:
tildearrow 2023-02-09 19:11:27 -05:00
parent 00b329b896
commit 0d424c7962
4 changed files with 178 additions and 0 deletions

View File

@ -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

View File

@ -22,6 +22,7 @@
#include "../dispatch.h"
#include "../instrument.h"
#include "sound/segapcm.h"
#include <queue>
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<QueuedWrite> writes;
segapcm_device pcm;
int delay;
int pcmL, pcmR, pcmCycles;
unsigned char sampleBank;

View File

@ -0,0 +1,125 @@
// license:BSD-3-Clause
// copyright-holders:Hiromitsu Shioya, Olivier Galibert
/*********************************************************/
/* SEGA 16ch 8bit PCM */
/*********************************************************/
#include <string.h>
#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];
}

View File

@ -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 <functional>
//**************************************************************************
// 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<unsigned char(unsigned int)> 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<unsigned char(unsigned int)> read_byte;
};
#endif // MAMESOUND_SEGAPCM_H