sound/swp00.cpp: Improved DPCM sample decompression (#12300)

This commit is contained in:
Theo Niessink 2024-04-24 08:35:25 +02:00 committed by GitHub
parent cf0f8bc748
commit 48161ce9ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 16 deletions

View File

@ -91,6 +91,8 @@ const std::array<s32, 16> swp00_device::panmap = {
0x300, 0x340, 0x380, 0xfff
};
const std::array<u8, 4> swp00_device::dpcm_offset = { 7, 6, 4, 0 };
bool swp00_device::istep(s32 &value, s32 limit, s32 step)
{
// fprintf(stderr, "istep(%x, %x, %x)\n", value, limit, step);
@ -314,7 +316,7 @@ void swp00_device::device_start()
save_item(NAME(m_pitch));
save_item(NAME(m_sample_start));
save_item(NAME(m_sample_end));
save_item(NAME(m_sample_dec_and_format));
save_item(NAME(m_sample_dpcm_and_format));
save_item(NAME(m_sample_address));
save_item(NAME(m_lfo_step));
save_item(NAME(m_lfo_pmod_depth));
@ -342,6 +344,7 @@ void swp00_device::device_start()
save_item(NAME(m_dpcm_current));
save_item(NAME(m_dpcm_next));
save_item(NAME(m_dpcm_address));
save_item(NAME(m_dpcm_sum));
for(int i=0; i<128; i++) {
u32 v = 0;
@ -359,7 +362,7 @@ void swp00_device::device_start()
// Delta-packed samples decompression.
for(int i=0; i<128; i++) {
s16 base = ((i & 0x1f) << (5+(i >> 5))) + (((1 << (i >> 5))-1) << 10);
s16 base = ((i & 0x1f) << (3+(i >> 5))) + (((1 << (i >> 5))-1) << 8);
m_dpcm[i | 0x80] = - base;
m_dpcm[i] = + base;
}
@ -449,7 +452,7 @@ void swp00_device::device_reset()
std::fill(m_pitch.begin(), m_pitch.end(), 0);
std::fill(m_sample_start.begin(), m_sample_start.end(), 0);
std::fill(m_sample_end.begin(), m_sample_end.end(), 0);
std::fill(m_sample_dec_and_format.begin(), m_sample_dec_and_format.end(), 0);
std::fill(m_sample_dpcm_and_format.begin(), m_sample_dpcm_and_format.end(), 0);
std::fill(m_sample_address.begin(), m_sample_address.end(), 0);
std::fill(m_lfo_step.begin(), m_lfo_step.end(), 0);
std::fill(m_lfo_pmod_depth.begin(), m_lfo_pmod_depth.end(), 0);
@ -477,6 +480,7 @@ void swp00_device::device_reset()
std::fill(m_dpcm_current.begin(), m_dpcm_current.end(), false);
std::fill(m_dpcm_next.begin(), m_dpcm_next.end(), false);
std::fill(m_dpcm_address.begin(), m_dpcm_address.end(), false);
std::fill(m_dpcm_sum.begin(), m_dpcm_sum.end(), 0);
}
void swp00_device::rom_bank_pre_change()
@ -514,7 +518,7 @@ void swp00_device::map(address_map &map)
rchan(map, 0x2d).rw(FUNC(swp00_device::var_level_r), FUNC(swp00_device::var_level_w));
rchan(map, 0x2e).rw(FUNC(swp00_device::glo_level_r), FUNC(swp00_device::glo_level_w));
rchan(map, 0x2f).rw(FUNC(swp00_device::panning_r), FUNC(swp00_device::panning_w));
rchan(map, 0x30).rw(FUNC(swp00_device::sample_dec_and_format_r), FUNC(swp00_device::sample_dec_and_format_w));
rchan(map, 0x30).rw(FUNC(swp00_device::sample_dpcm_and_format_r), FUNC(swp00_device::sample_dpcm_and_format_w));
rchan(map, 0x31).rw(FUNC(swp00_device::sample_address_r<2>), FUNC(swp00_device::sample_address_w<2>));
rchan(map, 0x32).rw(FUNC(swp00_device::sample_address_r<1>), FUNC(swp00_device::sample_address_w<1>));
rchan(map, 0x33).rw(FUNC(swp00_device::sample_address_r<0>), FUNC(swp00_device::sample_address_w<0>));
@ -832,19 +836,19 @@ template<int sel> u8 swp00_device::sample_end_r(offs_t offset)
return m_sample_end[chan] >> (8*sel);
}
void swp00_device::sample_dec_and_format_w(offs_t offset, u8 data)
void swp00_device::sample_dpcm_and_format_w(offs_t offset, u8 data)
{
int chan = offset >> 1;
m_stream->update();
m_sample_dec_and_format[chan] = data;
// logerror("sample_dec_and_format[%02x] = %02x\n", chan, m_sample_dec_and_format[chan]);
m_sample_dpcm_and_format[chan] = data;
// logerror("sample_dpcm_and_format[%02x] = %02x\n", chan, m_sample_dpcm_and_format[chan]);
}
u8 swp00_device::sample_dec_and_format_r(offs_t offset)
u8 swp00_device::sample_dpcm_and_format_r(offs_t offset)
{
int chan = offset >> 1;
return m_sample_dec_and_format[chan];
return m_sample_dpcm_and_format[chan];
}
template<int sel> void swp00_device::sample_address_w(offs_t offset, u8 data)
@ -900,7 +904,7 @@ u8 swp00_device::lfo_pmod_depth_r(offs_t offset)
void swp00_device::keyon(int chan)
{
m_stream->update();
logerror("keyon %02x a=%02x/%02x d=%02x/%02x glo=%02x pan=%02x [%x %x %x %x]\n", chan, m_attack_speed[chan], m_attack_level[chan], m_decay_speed[chan], m_decay_level[chan], m_glo_level[chan], m_panning[chan], m_sample_start[chan], m_sample_end[chan], m_sample_address[chan], m_sample_dec_and_format[chan]);
logerror("keyon %02x a=%02x/%02x d=%02x/%02x glo=%02x pan=%02x [%x %x %x %x]\n", chan, m_attack_speed[chan], m_attack_level[chan], m_decay_speed[chan], m_decay_level[chan], m_glo_level[chan], m_panning[chan], m_sample_start[chan], m_sample_end[chan], m_sample_address[chan], m_sample_dpcm_and_format[chan]);
m_lfo_phase[chan] = 0;
m_sample_pos[chan] = -m_sample_start[chan] << 15;
@ -913,6 +917,7 @@ void swp00_device::keyon(int chan)
m_dpcm_current[chan] = 0;
m_dpcm_next[chan] = 0;
m_dpcm_address[chan] = m_sample_address[chan] - m_sample_start[chan];
m_dpcm_sum[chan] = 0;
m_lpf_value[chan] = m_lpf_target_value[chan];
m_lpf_timer[chan] = 0x4000000;
@ -1279,7 +1284,7 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
s16 val0, val1;
u32 base_address = m_sample_address[chan];
s32 spos = m_sample_pos[chan] >> 15;
switch(m_sample_dec_and_format[chan] >> 6) {
switch(m_sample_dpcm_and_format[chan] >> 6) {
case 0: { // 16-bits linear
offs_t adr = base_address + (spos << 1);
val0 = read_word(adr);
@ -1329,10 +1334,13 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
break;
case 3: { // 8-bits delta-pcm
u8 offset = dpcm_offset[m_sample_dpcm_and_format[chan] & 3];
u8 scale = (m_sample_dpcm_and_format[chan] >> 2) & 7;
u32 target_address = base_address + spos + 1;
while(m_dpcm_address[chan] <= target_address) {
m_dpcm_current[chan] = m_dpcm_next[chan];
s32 sample = m_dpcm_next[chan] + m_dpcm[read_byte(m_dpcm_address[chan])];
m_dpcm_sum[chan] += m_dpcm[read_byte(m_dpcm_address[chan])] - offset;
s32 sample = (m_dpcm_sum[chan] << scale) >> 3;
m_dpcm_address[chan] ++;
if(sample < -0x8000)
sample = -0x8000;
@ -1383,9 +1391,10 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
else {
s32 prev = m_sample_pos[chan];
do
m_sample_pos[chan] -= (m_sample_end[chan] << 15) | ((m_sample_dec_and_format[chan] & 0x3f) << 9);
m_sample_pos[chan] -= m_sample_end[chan] << 15;
while((m_sample_pos[chan] >> 15) >= m_sample_end[chan]);
m_dpcm_address[chan] += (m_sample_pos[chan] >> 15) - (prev >> 15);
m_dpcm_sum[chan] = 0;
}
}

View File

@ -42,6 +42,7 @@ private:
static const std::array<s32, 0x80> attack_linear_step;
static const std::array<s32, 0x20> decay_linear_step;
static const std::array<s32, 16> panmap;
static const std::array<u8, 4> dpcm_offset;
std::array<s32, 0x80> m_global_step;
std::array<s16, 0x100> m_dpcm;
@ -76,7 +77,7 @@ private:
std::array<u16, 0x20> m_pitch;
std::array<u16, 0x20> m_sample_start;
std::array<u16, 0x20> m_sample_end;
std::array<u8, 0x20> m_sample_dec_and_format;
std::array<u8, 0x20> m_sample_dpcm_and_format;
std::array<u32, 0x20> m_sample_address;
std::array<u8, 0x20> m_lfo_step;
std::array<u8, 0x20> m_lfo_pmod_depth;
@ -97,6 +98,7 @@ private:
std::array<s16, 0x20> m_dpcm_current;
std::array<s16, 0x20> m_dpcm_next;
std::array<u32, 0x20> m_dpcm_address;
std::array<s32, 0x20> m_dpcm_sum;
u16 m_waverom_val;
u8 m_waverom_access;
@ -167,8 +169,8 @@ private:
template<int sel> u8 sample_start_r(offs_t offset);
template<int sel> void sample_end_w(offs_t offset, u8 data);
template<int sel> u8 sample_end_r(offs_t offset);
void sample_dec_and_format_w(offs_t offset, u8 data);
u8 sample_dec_and_format_r(offs_t offset);
void sample_dpcm_and_format_w(offs_t offset, u8 data);
u8 sample_dpcm_and_format_r(offs_t offset);
template<int sel> void sample_address_w(offs_t offset, u8 data);
template<int sel> u8 sample_address_r(offs_t offset);
void lfo_step_w(offs_t offset, u8 data);