diff options
-rw-r--r-- | scripts/src/sound.lua | 14 | ||||
-rw-r--r-- | src/devices/machine/spg2xx_audio.cpp | 2 | ||||
-rw-r--r-- | src/devices/machine/spg2xx_audio.h | 4 | ||||
-rw-r--r-- | src/devices/sound/imaadpcm.cpp | 133 | ||||
-rw-r--r-- | src/devices/sound/imaadpcm.h | 45 |
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 |