summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/sound.lua14
-rw-r--r--src/devices/machine/spg2xx_audio.cpp2
-rw-r--r--src/devices/machine/spg2xx_audio.h4
-rw-r--r--src/devices/sound/imaadpcm.cpp133
-rw-r--r--src/devices/sound/imaadpcm.h45
5 files changed, 195 insertions, 3 deletions
diff --git a/scripts/src/sound.lua b/scripts/src/sound.lua
index ccbab43419c..ab5c7e5ebfb 100644
--- a/scripts/src/sound.lua
+++ b/scripts/src/sound.lua
@@ -700,6 +700,20 @@ end
---------------------------------------------------
+-- IMA ADPCM sample player
+--@src/devices/sound/imaadpcm.h,SOUNDS["IMAADPCM"] = true
+---------------------------------------------------
+
+if (SOUNDS["IMAADPCM"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/sound/imaadpcm.cpp",
+ MAME_DIR .. "src/devices/sound/imaadpcm.h",
+ }
+end
+
+
+
+---------------------------------------------------
-- OKI ADPCM sample players
--@src/devices/sound/okim6258.h,SOUNDS["OKIM6258"] = true
--@src/devices/sound/msm5205.h,SOUNDS["MSM5205"] = true
diff --git a/src/devices/machine/spg2xx_audio.cpp b/src/devices/machine/spg2xx_audio.cpp
index 2cf0fd822d8..e77c2af33ae 100644
--- a/src/devices/machine/spg2xx_audio.cpp
+++ b/src/devices/machine/spg2xx_audio.cpp
@@ -1159,7 +1159,7 @@ bool spg2xx_audio_device::fetch_sample(const uint32_t channel)
if (get_adpcm36_bit(channel))
m_audio_regs[wave_data_reg] = decode_adpcm36_nybble(channel, adpcm_sample);
else
- m_audio_regs[wave_data_reg] = (uint16_t)(m_adpcm[channel].clock(adpcm_sample) << 4) ^ 0x8000;
+ m_audio_regs[wave_data_reg] = (uint16_t)(m_adpcm[channel].clock(adpcm_sample)) ^ 0x8000;
}
m_sample_count[channel]++;
}
diff --git a/src/devices/machine/spg2xx_audio.h b/src/devices/machine/spg2xx_audio.h
index d0712139134..1d3b964b039 100644
--- a/src/devices/machine/spg2xx_audio.h
+++ b/src/devices/machine/spg2xx_audio.h
@@ -11,7 +11,7 @@
#pragma once
-#include "sound/okiadpcm.h"
+#include "sound/imaadpcm.h"
#include "cpu/unsp/unsp.h"
class spg2xx_audio_device : public device_t, public device_sound_interface
@@ -366,7 +366,7 @@ protected:
emu_timer *m_channel_irq[16];
sound_stream *m_stream;
- oki_adpcm_state m_adpcm[16];
+ ima_adpcm_state m_adpcm[16];
adpcm36_state m_adpcm36_state[16];
static const uint32_t s_rampdown_frame_counts[8];
diff --git a/src/devices/sound/imaadpcm.cpp b/src/devices/sound/imaadpcm.cpp
new file mode 100644
index 00000000000..0b1e2255e63
--- /dev/null
+++ b/src/devices/sound/imaadpcm.cpp
@@ -0,0 +1,133 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrew Gardner,Aaron Giles
+/***************************************************************************
+
+ imaadpcm.cpp
+
+ IMA ADPCM emulation.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "imaadpcm.h"
+
+
+//**************************************************************************
+// ADPCM STATE HELPER
+//**************************************************************************
+
+// ADPCM state and tables
+bool ima_adpcm_state::s_tables_computed = false;
+const int8_t ima_adpcm_state::s_index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
+int ima_adpcm_state::s_diff_lookup[89*16];
+
+//-------------------------------------------------
+// reset - reset the ADPCM state
+//-------------------------------------------------
+
+void ima_adpcm_state::reset()
+{
+ // reset the signal/step
+ m_signal = m_loop_signal = 0;
+ m_step = m_loop_step = 0;
+ m_saved = false;
+}
+
+
+//-------------------------------------------------
+// clock - decode single nibble and update
+// ADPCM output
+//-------------------------------------------------
+
+int16_t ima_adpcm_state::clock(uint8_t nibble)
+{
+ // update the signal
+ m_signal += s_diff_lookup[m_step * 16 + (nibble & 15)];
+
+ // clamp to the maximumf
+ if (m_signal > 32767)
+ m_signal = 32767;
+ else if (m_signal < -32768)
+ m_signal = -32768;
+
+ // adjust the step size and clamp
+ m_step += s_index_shift[nibble & 7];
+ if (m_step > 88)
+ m_step = 88;
+ else if (m_step < 0)
+ m_step = 0;
+
+ // return the signal
+ return m_signal;
+}
+
+
+//-------------------------------------------------
+// save - save current ADPCM state to buffer
+//-------------------------------------------------
+
+void ima_adpcm_state::save()
+{
+ if (!m_saved)
+ {
+ m_loop_signal = m_signal;
+ m_loop_step = m_step;
+ m_saved = true;
+ }
+}
+
+
+//-------------------------------------------------
+// restore - restore previous ADPCM state
+// from buffer
+//-------------------------------------------------
+
+void ima_adpcm_state::restore()
+{
+ m_signal = m_loop_signal;
+ m_step = m_loop_step;
+}
+
+
+//-------------------------------------------------
+// compute_tables - precompute tables for faster
+// sound generation
+//-------------------------------------------------
+
+void ima_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_t 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 = -8; step <= 80; step++)
+ {
+ // compute the step value
+ int stepval = std::min(floor(16.0 * pow(11.0 / 10.0, (double)step)), 32767.);
+
+ // manual correction of some early values
+ if (step == -5 || step == -4)
+ stepval++;
+
+ // loop over all nibbles and compute the difference
+ for (int nib = 0; nib < 16; nib++)
+ {
+ s_diff_lookup[(step + 8)*16 + nib] = nbl2bit[nib][0] *
+ (stepval * nbl2bit[nib][1] +
+ stepval/2 * nbl2bit[nib][2] +
+ stepval/4 * nbl2bit[nib][3] +
+ stepval/8);
+ }
+ }
+}
diff --git a/src/devices/sound/imaadpcm.h b/src/devices/sound/imaadpcm.h
new file mode 100644
index 00000000000..eb03fce6af2
--- /dev/null
+++ b/src/devices/sound/imaadpcm.h
@@ -0,0 +1,45 @@
+// license:BSD-3-Clause
+// copyright-holders:Andrew Gardner,Aaron Giles
+/***************************************************************************
+
+ imaadpcm.h
+
+ IMA ADCPM emulation.
+
+***************************************************************************/
+
+#ifndef MAME_SOUND_IMAADPCM_H
+#define MAME_SOUND_IMAADPCM_H
+
+#pragma once
+
+
+// ======================> ima_adpcm_state
+
+// Internal ADPCM state
+class ima_adpcm_state
+{
+public:
+ ima_adpcm_state() { compute_tables(); reset(); }
+
+ void reset();
+ int16_t clock(uint8_t nibble);
+ int16_t output() { return m_signal; }
+ void save();
+ void restore();
+
+ int32_t m_signal;
+ int32_t m_step;
+ int32_t m_loop_signal;
+ int32_t m_loop_step;
+ bool m_saved;
+
+private:
+ static const int8_t s_index_shift[8];
+ static int s_diff_lookup[89*16];
+
+ static void compute_tables();
+ static bool s_tables_computed;
+};
+
+#endif // MAME_SOUND_IMAADPCM_H