summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/okiadpcm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/okiadpcm.cpp')
-rw-r--r--src/devices/sound/okiadpcm.cpp192
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);
+ }
+ }
+}