diff options
Diffstat (limited to 'src/devices/sound/okiadpcm.cpp')
-rw-r--r-- | src/devices/sound/okiadpcm.cpp | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/devices/sound/okiadpcm.cpp b/src/devices/sound/okiadpcm.cpp new file mode 100644 index 00000000000..611f7e2f13f --- /dev/null +++ b/src/devices/sound/okiadpcm.cpp @@ -0,0 +1,192 @@ +// license:BSD-3-Clause +// copyright-holders:Andrew Gardner,Aaron Giles +/*************************************************************************** + + okiadpcm.h + + OKI ADCPM emulation. + +***************************************************************************/ + +#include "emu.h" +#include "okiadpcm.h" + + +//************************************************************************** +// ADPCM STATE HELPER +//************************************************************************** + +// ADPCM state and tables +bool oki_adpcm_state::s_tables_computed = false; +const INT8 oki_adpcm_state::s_index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; +int oki_adpcm_state::s_diff_lookup[49*16]; + +//------------------------------------------------- +// reset - reset the ADPCM state +//------------------------------------------------- + +void oki_adpcm_state::reset() +{ + // reset the signal/step + m_signal = -2; + m_step = 0; +} + + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +INT16 oki_adpcm_state::clock(UINT8 nibble) +{ + // update the signal + m_signal += s_diff_lookup[m_step * 16 + (nibble & 15)]; + + // clamp to the maximum + if (m_signal > 2047) + m_signal = 2047; + else if (m_signal < -2048) + m_signal = -2048; + + // adjust the step size and clamp + m_step += s_index_shift[nibble & 7]; + if (m_step > 48) + m_step = 48; + else if (m_step < 0) + m_step = 0; + + // return the signal + return m_signal; +} + + +//------------------------------------------------- +// compute_tables - precompute tables for faster +// sound generation +//------------------------------------------------- + +void oki_adpcm_state::compute_tables() +{ + // skip if we already did it + if (s_tables_computed) + return; + s_tables_computed = true; + + // nibble to bit map + static const INT8 nbl2bit[16][4] = + { + { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1}, + { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1}, + {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1}, + {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1} + }; + + // loop over all possible steps + for (int step = 0; step <= 48; step++) + { + // compute the step value + int stepval = floor(16.0 * pow(11.0 / 10.0, (double)step)); + + // loop over all nibbles and compute the difference + for (int nib = 0; nib < 16; nib++) + { + s_diff_lookup[step*16 + nib] = nbl2bit[nib][0] * + (stepval * nbl2bit[nib][1] + + stepval/2 * nbl2bit[nib][2] + + stepval/4 * nbl2bit[nib][3] + + stepval/8); + } + } +} + + +//************************************************************************** +// ADPCM2 STATE HELPER +//************************************************************************** + +// ADPCM state and tables +bool oki_adpcm2_state::s_tables_computed = false; +const INT8 oki_adpcm2_state::s_index_shift[8] = { -2, -2, -2, -2, 2, 6, 9, 11 }; +int oki_adpcm2_state::s_diff_lookup[49*16]; + +//------------------------------------------------- +// reset - reset the ADPCM state +//------------------------------------------------- + +void oki_adpcm2_state::reset() +{ + // reset the signal/step + m_signal = -2; + m_step = 0; +} + + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +INT16 oki_adpcm2_state::clock(UINT8 nibble) +{ + // update the signal + m_signal += s_diff_lookup[m_step * 16 + (nibble & 15)]; + + // clamp to the maximum + if (m_signal > 2047) + m_signal = 2047; + else if (m_signal < -2048) + m_signal = -2048; + + // adjust the step size and clamp + m_step += s_index_shift[nibble & 7]; + if (m_step > 48) + m_step = 48; + else if (m_step < 0) + m_step = 0; + + // return the signal + return m_signal; +} + + +//------------------------------------------------- +// compute_tables - precompute tables for faster +// sound generation +//------------------------------------------------- + +void oki_adpcm2_state::compute_tables() +{ + // skip if we already did it + if (s_tables_computed) + return; + s_tables_computed = true; + + // nibble to bit map + static const INT8 nbl2bit[16][4] = + { + { 1, 0, 0, 0}, { 1, 0, 0, 1}, { 1, 0, 1, 0}, { 1, 0, 1, 1}, + { 1, 1, 0, 0}, { 1, 1, 0, 1}, { 1, 1, 1, 0}, { 1, 1, 1, 1}, + {-1, 0, 0, 0}, {-1, 0, 0, 1}, {-1, 0, 1, 0}, {-1, 0, 1, 1}, + {-1, 1, 0, 0}, {-1, 1, 0, 1}, {-1, 1, 1, 0}, {-1, 1, 1, 1} + }; + + // loop over all possible steps + float floatstep = 64; + for (int step = 0; step <= 48; step++) + { + // compute the step value + int stepval = floor(floatstep * 1.08f); + floatstep = floatstep * 1.08f; + + // loop over all nibbles and compute the difference + for (int nib = 0; nib < 16; nib++) + { + s_diff_lookup[step*16 + nib] = nbl2bit[nib][0] * + (stepval * nbl2bit[nib][1] + + stepval/2 * nbl2bit[nib][2] + + stepval/4 * nbl2bit[nib][3] + + stepval/8); + } + } +} |