swp00: Correct the sample decompression

This commit is contained in:
Olivier Galibert 2023-10-29 09:26:41 +01:00
parent 21c537bd51
commit 2efa642e2d
2 changed files with 42 additions and 28 deletions

View File

@ -321,7 +321,6 @@ void swp00_device::device_start()
save_item(NAME(m_lfo_phase));
save_item(NAME(m_sample_pos));
save_item(NAME(m_sample_increment));
save_item(NAME(m_envelope_level));
save_item(NAME(m_glo_level_cur));
@ -340,6 +339,10 @@ void swp00_device::device_start()
save_item(NAME(m_decay_done));
save_item(NAME(m_lpf_done));
save_item(NAME(m_dpcm_current));
save_item(NAME(m_dpcm_next));
save_item(NAME(m_dpcm_address));
for(int i=0; i != 128; i++) {
u32 v = 0;
switch(i >> 3) {
@ -353,24 +356,12 @@ void swp00_device::device_start()
m_global_step[i] = v;
}
// Log to linear 8-bits sample decompression. Statistics say
// that's what it should look like. Note that 0 can be encoded
// both as 0x00 and 0x80, and as it happens 0x80 is never used in
// these samples. Ends up with a 55dB dynamic range, to compare
// with 8bits 48dB, 12bits 72dB and 16bits 96dB.
// Delta-packed samples decompression.
// Rescale so that it's roughly 16 bits. Range ends up being +/- 78c0.
for(int i=0; i<32; i++) {
m_sample_log8[ i] = i << 0;
m_sample_log8[0x20|i] = (i << 1) + 0x21;
m_sample_log8[0x40|i] = (i << 2) + 0x62;
m_sample_log8[0x60|i] = (i << 3) + 0xe3;
}
for(int i=0; i<128; i++) {
s16 base = m_sample_log8[i] << 6;
m_sample_log8[i | 0x80] = - base;
m_sample_log8[i] = + base;
s16 base = ((i & 0x1f) << (7+(i >> 5))) + (((1 << (i >> 5))-1) << 12);
m_dpcm[i | 0x80] = - base;
m_dpcm[i] = + base;
}
}
@ -465,7 +456,6 @@ void swp00_device::device_reset()
std::fill(m_lfo_phase.begin(), m_lfo_phase.end(), 0);
std::fill(m_sample_pos.begin(), m_sample_pos.end(), 0);
std::fill(m_sample_increment.begin(), m_sample_increment.end(), 0);
std::fill(m_envelope_level.begin(), m_envelope_level.end(), 0);
std::fill(m_glo_level_cur.begin(), m_glo_level_cur.end(), 0);
@ -483,6 +473,10 @@ void swp00_device::device_reset()
std::fill(m_decay.begin(), m_decay.end(), false);
std::fill(m_decay_done.begin(), m_decay_done.end(), false);
std::fill(m_lpf_done.begin(), m_lpf_done.end(), false);
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);
}
void swp00_device::rom_bank_pre_change()
@ -914,6 +908,10 @@ void swp00_device::keyon(int chan)
m_decay[chan] = false;
m_decay_done[chan] = false;
m_dpcm_current[chan] = 0;
m_dpcm_next[chan] = 0;
m_dpcm_address[chan] = m_sample_address[chan] - m_sample_start[chan];
m_lpf_value[chan] = m_lpf_target_value[chan];
m_lpf_timer[chan] = 0x4000000;
m_lpf_ha[chan] = 0;
@ -1278,21 +1276,21 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
case 0: { // 16-bits linear
offs_t adr = base_address + (spos << 1);
val0 = read_word(adr);
val1 = read_word(adr+1);
val1 = read_word(adr+2);
break;
}
case 1: { // 12-bits linear
offs_t adr = base_address + (spos >> 2)*6;
switch(spos & 3) {
case 0: { // .abc .... ....
case 0: { // Cabc ..AB .... ....
u16 w0 = read_word(adr);
u16 w1 = read_word(adr+2);
val0 = (w0 & 0x0fff) << 4;
val1 = ((w0 & 0xf000) >> 8) | ((w1 & 0x00ff) << 8);
break;
}
case 1: { // C... ..AB ....
case 1: { // c... BCab ...A ....
u16 w0 = read_word(adr);
u16 w1 = read_word(adr+2);
u16 w2 = read_word(adr+4);
@ -1300,14 +1298,14 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
val1 = ((w1 & 0xff00) >> 4) | ((w2 & 0x000f) << 12);
break;
}
case 2: { // .... bc.. ...a
case 2: { // .... bc.. ABCa ....
u16 w1 = read_word(adr+2);
u16 w2 = read_word(adr+4);
val0 = ((w1 & 0xff00) >> 4) | ((w2 & 0x000f) << 12);
val1 = w2 & 0xfff0;
break;
}
case 3: { // .... .... ABC.
case 3: { // .... .... abc. .ABC
u16 w2 = read_word(adr+4);
u16 w3 = read_word(adr+6);
val0 = w2 & 0xfff0;
@ -1323,11 +1321,23 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
val1 = (read_byte(base_address + spos + 1) << 8);
break;
case 3: // 8-bits logarithmic
val0 = m_sample_log8[read_byte(base_address + spos)];
val1 = m_sample_log8[read_byte(base_address + spos + 1)];
case 3: { // 8-bits logarithmic
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_address[chan] ++;
if(sample < -0x8000)
sample = -0x8000;
else if(sample > 0x7fff)
sample = 0x7fff;
m_dpcm_next[chan] = sample;
}
val0 = m_dpcm_current[chan];
val1 = m_dpcm_next[chan];
break;
}
}
s32 mul = m_sample_pos[chan] & 0x7fff;
s32 sample = (val1 * mul + val0 * (0x8000 - mul)) >> 7;
@ -1363,9 +1373,11 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
if(!m_sample_end[chan])
m_active[chan] = false;
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);
while((m_sample_pos[chan] >> 15) >= m_sample_end[chan]);
m_dpcm_address[chan] += (m_sample_pos[chan] >> 15) - (prev >> 15);
}
}

View File

@ -43,7 +43,7 @@ private:
static const std::array<s32, 0x20> decay_linear_step;
static const std::array<s32, 16> panmap;
std::array<s32, 0x80> m_global_step;
std::array<s16, 0x100> m_sample_log8;
std::array<s16, 0x100> m_dpcm;
static const std::array<u32, 4> lfo_shape_centered_saw;
static const std::array<u32, 4> lfo_shape_centered_tri;
@ -83,7 +83,6 @@ private:
std::array<u32, 0x20> m_lfo_phase;
std::array<s32, 0x20> m_sample_pos;
std::array<u32, 0x20> m_sample_increment;
std::array<s32, 0x20> m_envelope_level;
std::array<s32, 0x20> m_glo_level_cur;
std::array<s32, 0x20> m_pan_l;
@ -95,6 +94,9 @@ private:
std::array<s32, 0x20> m_lpf_ha;
std::array<s32, 0x20> m_lpf_hb;
std::array<bool, 0x20> m_active, m_decay, m_decay_done, m_lpf_done;
std::array<s16, 0x20> m_dpcm_current;
std::array<s16, 0x20> m_dpcm_next;
std::array<u32, 0x20> m_dpcm_address;
u16 m_waverom_val;
u8 m_waverom_access;