diff options
author | 2022-06-09 07:05:08 -0500 | |
---|---|---|
committer | 2022-06-09 22:05:08 +1000 | |
commit | 21cf4d3cd4fee5c83b52ea50afaf4f178edd301a (patch) | |
tree | b6deca6e40d461c2930047389519c9008ca3b66a /src/devices/sound/k054539.cpp | |
parent | a0f069a766ef59576dc8f8655a680db2cfc2f1fd (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.cpp | 59 |
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)); } |