add (Partial) GA20 support
This commit is contained in:
parent
7a91996e3a
commit
d5f44557c2
12 changed files with 877 additions and 5 deletions
175
src/engine/platform/sound/ga20/iremga20.cpp
Normal file
175
src/engine/platform/sound/ga20/iremga20.cpp
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
// license:BSD-3-Clause
|
||||
// copyright-holders:Acho A. Tang,R. Belmont, Valley Bell
|
||||
/*********************************************************
|
||||
|
||||
Irem GA20 PCM Sound Chip
|
||||
80 pin QFP, label NANAO GA20 (Nanao Corporation was Irem's parent company)
|
||||
|
||||
TODO:
|
||||
- It's not currently known whether this chip is stereo.
|
||||
- Is sample position base(regs 0,1) used while sample is playing, or
|
||||
latched at key on? We've always emulated it the latter way.
|
||||
gunforc2 seems to be the only game updating the address regs sometimes
|
||||
while a sample is playing, but it doesn't seem intentional.
|
||||
- What is the 2nd sample address for? Is it end(cut-off) address, or
|
||||
loop start address? Every game writes a value that's past sample end.
|
||||
- All games write either 0 or 2 to reg #6, do other bits have any function?
|
||||
|
||||
|
||||
Revisions:
|
||||
|
||||
04-15-2002 Acho A. Tang
|
||||
- rewrote channel mixing
|
||||
- added prelimenary volume and sample rate emulation
|
||||
|
||||
05-30-2002 Acho A. Tang
|
||||
- applied hyperbolic gain control to volume and used
|
||||
a musical-note style progression in sample rate
|
||||
calculation(still very inaccurate)
|
||||
|
||||
02-18-2004 R. Belmont
|
||||
- sample rate calculation reverse-engineered.
|
||||
Thanks to Fujix, Yasuhiro Ogawa, the Guru, and Tormod
|
||||
for real PCB samples that made this possible.
|
||||
|
||||
02-03-2007 R. Belmont
|
||||
- Cleaned up faux x86 assembly.
|
||||
|
||||
09-25-2018 Valley Bell & co
|
||||
- rewrote channel update to make data 0 act as sample terminator
|
||||
|
||||
|
||||
DISCLAIMER
|
||||
- This file is modified for suitable in furnace.
|
||||
- modified by cam900
|
||||
|
||||
*********************************************************/
|
||||
|
||||
#include "iremga20.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// iremga20_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
iremga20_device::iremga20_device(iremga20_intf &intf) :
|
||||
m_regs{0},
|
||||
m_channel{channel_def(), channel_def(), channel_def(), channel_def()},
|
||||
m_intf(intf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void iremga20_device::device_reset()
|
||||
{
|
||||
memset(m_regs, 0, 0x20 * sizeof(u8));
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
m_channel[i].rate = 0;
|
||||
m_channel[i].pos = 0;
|
||||
m_channel[i].counter = 0;
|
||||
m_channel[i].end = 0;
|
||||
m_channel[i].volume = 0;
|
||||
m_channel[i].play = false;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// sound_stream_update - handle a stream update
|
||||
//-------------------------------------------------
|
||||
|
||||
void iremga20_device::sound_stream_update(short** outputs, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
s32 sampleout = 0;
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
channel_def &ch = m_channel[j];
|
||||
if (ch.play)
|
||||
{
|
||||
int sample = m_intf.read_byte(ch.pos);
|
||||
if (sample == 0x00) // check for sample end marker
|
||||
ch.play = false;
|
||||
else
|
||||
{
|
||||
sampleout += (sample - 0x80) * (s32)ch.volume;
|
||||
ch.counter--;
|
||||
if (ch.counter <= ch.rate)
|
||||
{
|
||||
ch.pos++;
|
||||
ch.counter = 0x100;
|
||||
}
|
||||
}
|
||||
}
|
||||
outputs[j][i] = sampleout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void iremga20_device::write(u32 offset, u8 data)
|
||||
{
|
||||
offset &= 0x1f;
|
||||
m_regs[offset] = data;
|
||||
int ch = offset >> 3;
|
||||
|
||||
// channel regs:
|
||||
// 0,1: start address
|
||||
// 2,3: end? address
|
||||
// 4: rate
|
||||
// 5: volume
|
||||
// 6: control
|
||||
// 7: voice status (read-only)
|
||||
|
||||
switch (offset & 0x7)
|
||||
{
|
||||
case 4:
|
||||
m_channel[ch].rate = data;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
m_channel[ch].volume = (data * 256) / (data + 10);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
// d1: key on/off
|
||||
if (data & 2)
|
||||
{
|
||||
m_channel[ch].play = true;
|
||||
m_channel[ch].pos = (m_regs[ch << 3 | 0] | m_regs[ch << 3 | 1] << 8) << 4;
|
||||
m_channel[ch].end = (m_regs[ch << 3 | 2] | m_regs[ch << 3 | 3] << 8) << 4;
|
||||
m_channel[ch].counter = 0x100;
|
||||
}
|
||||
else
|
||||
m_channel[ch].play = false;
|
||||
|
||||
// other: unknown/unused
|
||||
// possibilities are: loop flag, left/right speaker(stereo)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u8 iremga20_device::read(u32 offset)
|
||||
{
|
||||
offset &= 0x1f;
|
||||
int ch = offset >> 3;
|
||||
|
||||
switch (offset & 0x7)
|
||||
{
|
||||
case 7: // voice status. bit 0 is 1 if active. (routine around 0xccc in rtypeleo)
|
||||
return m_channel[ch].play ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
74
src/engine/platform/sound/ga20/iremga20.h
Normal file
74
src/engine/platform/sound/ga20/iremga20.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// license:BSD-3-Clause
|
||||
// copyright-holders:Acho A. Tang,R. Belmont
|
||||
/*********************************************************
|
||||
|
||||
Irem GA20 PCM Sound Chip
|
||||
|
||||
DISCLAIMER
|
||||
- This file is modified for suitable in furnace.
|
||||
- modified by cam900
|
||||
|
||||
*********************************************************/
|
||||
#ifndef MAME_SOUND_IREMGA20_H
|
||||
#define MAME_SOUND_IREMGA20_H
|
||||
|
||||
#pragma once
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
using u8 = unsigned char;
|
||||
using u32 = unsigned int;
|
||||
using s32 = signed int;
|
||||
|
||||
class iremga20_intf
|
||||
{
|
||||
public:
|
||||
virtual u8 read_byte(u32 address) { return 0; };
|
||||
};
|
||||
|
||||
// ======================> iremga20_device
|
||||
|
||||
class iremga20_device
|
||||
{
|
||||
public:
|
||||
iremga20_device(iremga20_intf &intf);
|
||||
|
||||
void write(u32 offset, u8 data);
|
||||
u8 read(u32 offset);
|
||||
|
||||
// device-level overrides
|
||||
void device_reset();
|
||||
|
||||
// sound stream update overrides
|
||||
void sound_stream_update(short** outputs, int len);
|
||||
|
||||
private:
|
||||
struct channel_def
|
||||
{
|
||||
channel_def() :
|
||||
rate(0),
|
||||
pos(0),
|
||||
counter(0),
|
||||
end(0),
|
||||
volume(0),
|
||||
play(0)
|
||||
{
|
||||
}
|
||||
|
||||
u32 rate;
|
||||
u32 pos;
|
||||
u32 counter;
|
||||
u32 end;
|
||||
u32 volume;
|
||||
bool play;
|
||||
};
|
||||
|
||||
u8 m_regs[0x20];
|
||||
channel_def m_channel[4];
|
||||
|
||||
iremga20_intf &m_intf;
|
||||
};
|
||||
|
||||
#endif // MAME_SOUND_IREMGA20_H
|
||||
Loading…
Add table
Add a link
Reference in a new issue