summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/k054539.cpp
diff options
context:
space:
mode:
author Tony Konzel <saxxonpike@gmail.com>2022-06-09 07:05:08 -0500
committer GitHub <noreply@github.com>2022-06-09 22:05:08 +1000
commit21cf4d3cd4fee5c83b52ea50afaf4f178edd301a (patch)
treeb6deca6e40d461c2930047389519c9008ca3b66a /src/devices/sound/k054539.cpp
parenta0f069a766ef59576dc8f8655a680db2cfc2f1fd (diff)
sound/k054539.cpp: Fixed DPCM table, and added cubic interpolation. (#9778)
Using powers of 2 rather than squares for the DPCM table fixes DC offsets for 4-bit sample playback.
Diffstat (limited to 'src/devices/sound/k054539.cpp')
-rw-r--r--src/devices/sound/k054539.cpp59
1 files changed, 52 insertions, 7 deletions
diff --git a/src/devices/sound/k054539.cpp b/src/devices/sound/k054539.cpp
index ae0ac92e310..639303cefac 100644
--- a/src/devices/sound/k054539.cpp
+++ b/src/devices/sound/k054539.cpp
@@ -104,13 +104,34 @@ void k054539_device::keyoff(int channel)
regs[0x22c] &= ~(1 << channel);
}
+void k054539_device::advance_filter(int channel, int val)
+{
+ auto &hist = filter_hist[channel];
+ hist[0] = hist[1];
+ hist[1] = hist[2];
+ hist[2] = hist[3];
+ hist[3] = ((float) val) / 32768.0f;
+}
+
+float k054539_device::calculate_filter(int channel, float t)
+{
+ // Cubic hermite interpolation
+ // t is domain [0,1]
+
+ auto &hist = filter_hist[channel];
+ const float a = (-hist[0] / 2.0f) + (3.0f * hist[1] / 2.0f) - (3.0f * hist[2] / 2.0f) + (hist[3] / 2.0f);
+ const float b = hist[0] - (5.0f * hist[1] / 2.0f) + (2.0f * hist[2]) - (hist[3] / 2.0f);
+ const float c = (-hist[0] / 2.0f) + (hist[2] / 2.0f);
+ return (t * t * t * a) + (t * t * b) + (t * c) + hist[1];
+}
+
void k054539_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
#define VOL_CAP 1.80
static const int16_t dpcm[16] = {
- 0 * 0x100, 1 * 0x100, 4 * 0x100, 9 * 0x100, 16 * 0x100, 25 * 0x100, 36 * 0x100, 49 * 0x100,
- -64 * 0x100, -49 * 0x100, -36 * 0x100, -25 * 0x100, -16 * 0x100, -9 * 0x100, -4 * 0x100, -1 * 0x100
+ 0 * 0x100, 1 * 0x100, 2 * 0x100, 4 * 0x100, 8 * 0x100, 16 * 0x100, 32 * 0x100, 64 * 0x100,
+ 0 * 0x100, -64 * 0x100, -32 * 0x100, -16 * 0x100, -8 * 0x100, -4 * 0x100, -2 * 0x100, -1 * 0x100
};
@@ -195,6 +216,8 @@ void k054539_device::sound_stream_update(sound_stream &stream, std::vector<read_
cur_pval = chan->pval;
}
+ float filter_frac = 0;
+
switch(base2[0] & 0xc) {
case 0x0: { // 8bit pcm
cur_pfrac += delta;
@@ -208,12 +231,17 @@ void k054539_device::sound_stream_update(sound_stream &stream, std::vector<read_
cur_pos = (base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16));
cur_val = (int16_t)(read_byte(cur_pos) << 8);
}
+
if(cur_val == (int16_t)0x8000) {
keyoff(ch);
cur_val = 0;
break;
}
+
+ advance_filter(ch, cur_val);
}
+
+ filter_frac = (float)(cur_pfrac & 0xffff) / 65536.0f;
break;
}
@@ -231,12 +259,17 @@ void k054539_device::sound_stream_update(sound_stream &stream, std::vector<read_
cur_pos = (base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16));
cur_val = (int16_t)(read_byte(cur_pos) | read_byte(cur_pos+1)<<8);
}
+
if(cur_val == (int16_t)0x8000) {
keyoff(ch);
cur_val = 0;
break;
}
+
+ advance_filter(ch, cur_val);
}
+
+ filter_frac = (float)(cur_pfrac & 0xffff) / 65536.0f;
break;
}
@@ -273,8 +306,12 @@ void k054539_device::sound_stream_update(sound_stream &stream, std::vector<read_
cur_val = -32768;
else if(cur_val > 32767)
cur_val = 32767;
+
+ advance_filter(ch, cur_val);
}
+ filter_frac = (float)(cur_pfrac & 0xffff) / 65536.0f;
+
cur_pfrac >>= 1;
if(cur_pos & 1)
cur_pfrac |= 0x8000;
@@ -285,9 +322,12 @@ void k054539_device::sound_stream_update(sound_stream &stream, std::vector<read_
LOG("Unknown sample type %x for channel %d\n", base2[0] & 0xc, ch);
break;
}
- lval += cur_val * lvol;
- rval += cur_val * rvol;
- rbase[(rdelta + reverb_pos) & 0x1fff] += int16_t(cur_val*rbvol);
+
+ const float filter_val = calculate_filter(ch, filter_frac);
+
+ lval += filter_val * lvol;
+ rval += filter_val * rvol;
+ rbase[(rdelta + reverb_pos) & 0x1fff] += int16_t(filter_val*rbvol);
chan->pos = cur_pos;
chan->pfrac = cur_pfrac;
@@ -299,10 +339,13 @@ void k054539_device::sound_stream_update(sound_stream &stream, std::vector<read_
base1[0x0d] = cur_pos>> 8 & 0xff;
base1[0x0e] = cur_pos>>16 & 0xff;
}
+ } else {
+ // Fill the interpolation vectors with silence when channel is disabled
+ advance_filter(ch, 0);
}
reverb_pos = (reverb_pos + 1) & 0x1fff;
- outputs[0].put_int(sample, lval, 32768);
- outputs[1].put_int(sample, rval, 32768);
+ outputs[0].put(sample, lval);
+ outputs[1].put(sample, rval);
}
}
@@ -317,6 +360,7 @@ void k054539_device::init_chip()
{
memset(regs, 0, sizeof(regs));
memset(posreg_latch, 0, sizeof(posreg_latch)); //*
+ memset(filter_hist, 0, sizeof(filter_hist));
flags |= UPDATE_AT_KEYON; //* make it default until proven otherwise
ram = std::make_unique<uint8_t []>(0x4000);
@@ -339,6 +383,7 @@ void k054539_device::init_chip()
save_item(NAME(cur_ptr));
save_item(NAME(cur_limit));
save_item(NAME(rom_addr));
+ save_item(NAME(filter_hist));
save_item(NAME(m_timer_state));
}