bring up MSM6295 core
vgsound_emu by cam900
This commit is contained in:
parent
98e9a4b28d
commit
43981eb59f
|
@ -324,6 +324,7 @@ src/engine/platform/sound/ymz280b.cpp
|
||||||
src/engine/platform/sound/rf5c68.cpp
|
src/engine/platform/sound/rf5c68.cpp
|
||||||
|
|
||||||
src/engine/platform/sound/oki/okim6258.cpp
|
src/engine/platform/sound/oki/okim6258.cpp
|
||||||
|
src/engine/platform/sound/oki/msm6295.cpp
|
||||||
|
|
||||||
src/engine/platform/oplAInterface.cpp
|
src/engine/platform/oplAInterface.cpp
|
||||||
src/engine/platform/ym2608Interface.cpp
|
src/engine/platform/ym2608Interface.cpp
|
||||||
|
|
209
src/engine/platform/sound/oki/msm6295.cpp
Normal file
209
src/engine/platform/sound/oki/msm6295.cpp
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
/*
|
||||||
|
License: BSD-3-Clause
|
||||||
|
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
|
||||||
|
|
||||||
|
Copyright holder(s): cam900
|
||||||
|
OKI MSM6295 emulation core
|
||||||
|
|
||||||
|
It is 4 channel ADPCM playback chip from OKI semiconductor.
|
||||||
|
It was becomes de facto standard for ADPCM playback in arcade machine, due to cost performance.
|
||||||
|
|
||||||
|
The chip itself is pretty barebone: there is no "register" in chip.
|
||||||
|
It can't control volume and pitch in currently playing channels, only stopable them.
|
||||||
|
And volume is must be determined at playback start command.
|
||||||
|
|
||||||
|
Command format:
|
||||||
|
|
||||||
|
Playback command (2 byte):
|
||||||
|
|
||||||
|
Byte Bit Description
|
||||||
|
76543210
|
||||||
|
0 1xxxxxxx Phrase select (Header stored in ROM)
|
||||||
|
1 x000---- Play channel 4
|
||||||
|
0x00---- Play channel 3
|
||||||
|
00x0---- Play channel 2
|
||||||
|
000x---- Play channel 1
|
||||||
|
----xxxx Volume
|
||||||
|
----0000 0.0dB
|
||||||
|
----0001 -3.2dB
|
||||||
|
----0010 -6.0dB
|
||||||
|
----0011 -9.2dB
|
||||||
|
----0100 -12.0dB
|
||||||
|
----0101 -14.5dB
|
||||||
|
----0110 -18.0dB
|
||||||
|
----0111 -20.5dB
|
||||||
|
----1000 -24.0dB
|
||||||
|
|
||||||
|
Suspend command (1 byte):
|
||||||
|
|
||||||
|
Byte Bit Description
|
||||||
|
76543210
|
||||||
|
0 0x------ Suspend channel 4
|
||||||
|
0-x----- Suspend channel 3
|
||||||
|
0--x---- Suspend channel 2
|
||||||
|
0---x--- Suspend channel 1
|
||||||
|
|
||||||
|
Frequency calculation:
|
||||||
|
if (SS) then
|
||||||
|
Frequency = Input clock / 165
|
||||||
|
else then
|
||||||
|
Frequency = Input clock / 132
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "msm6295.hpp"
|
||||||
|
|
||||||
|
void msm6295_core::tick()
|
||||||
|
{
|
||||||
|
// command handler
|
||||||
|
if (m_command_pending)
|
||||||
|
{
|
||||||
|
if (bitfield(m_command, 7)) // play voice
|
||||||
|
{
|
||||||
|
if ((++m_clock) >= ((15 * (m_ss ? 5 : 4))))
|
||||||
|
{
|
||||||
|
m_clock = 0;
|
||||||
|
if (bitfield(m_next_command, 4, 4) != 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (bitfield(m_next_command, 4 + i))
|
||||||
|
{
|
||||||
|
if (!m_voice[i].m_busy)
|
||||||
|
{
|
||||||
|
m_voice[i].m_command = m_command;
|
||||||
|
m_voice[i].m_volume = (bitfield(m_next_command, 0, 4) < 9) ? m_volume_table[std::min<u8>(8, bitfield(m_next_command, 0, 4))] : 0;
|
||||||
|
}
|
||||||
|
break; // voices aren't be playable simultaneously at once
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_command = 0;
|
||||||
|
m_command_pending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (bitfield(m_next_command, 7)) // select phrase
|
||||||
|
{
|
||||||
|
if ((++m_clock) >= ((15 * (m_ss ? 5 : 4))))
|
||||||
|
{
|
||||||
|
m_clock = 0;
|
||||||
|
m_command = m_next_command;
|
||||||
|
m_command_pending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (bitfield(m_next_command, 3, 4) != 0) // suspend voices
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (bitfield(m_next_command, 3 + i))
|
||||||
|
{
|
||||||
|
if (m_voice[i].m_busy)
|
||||||
|
m_voice[i].m_command = m_next_command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_next_command &= ~0x78;
|
||||||
|
}
|
||||||
|
m_command_pending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_out = 0;
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
m_voice[i].tick();
|
||||||
|
m_out += m_voice[i].m_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void msm6295_core::reset()
|
||||||
|
{
|
||||||
|
for (auto & elem : m_voice)
|
||||||
|
elem.reset();
|
||||||
|
|
||||||
|
m_command = 0;
|
||||||
|
m_next_command = 0;
|
||||||
|
m_command_pending = false;
|
||||||
|
m_clock = 0;
|
||||||
|
m_out = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void msm6295_core::voice_t::tick()
|
||||||
|
{
|
||||||
|
if (!m_busy)
|
||||||
|
{
|
||||||
|
if (bitfield(m_command, 7))
|
||||||
|
{
|
||||||
|
// get phrase header (stored in data memory)
|
||||||
|
const u32 phrase = bitfield(m_command, 0, 7) << 3;
|
||||||
|
// Start address
|
||||||
|
m_addr = (bitfield(m_host.m_intf.read_byte(phrase | 0), 0, 2) << 16)
|
||||||
|
| (m_host.m_intf.read_byte(phrase | 1) << 8)
|
||||||
|
| (m_host.m_intf.read_byte(phrase | 2) << 0);
|
||||||
|
// End address
|
||||||
|
m_end = (bitfield(m_host.m_intf.read_byte(phrase | 3), 0, 2) << 16)
|
||||||
|
| (m_host.m_intf.read_byte(phrase | 4) << 8)
|
||||||
|
| (m_host.m_intf.read_byte(phrase | 5) << 0);
|
||||||
|
m_nibble = 4; // MSB first, LSB second
|
||||||
|
m_command = 0;
|
||||||
|
m_busy = true;
|
||||||
|
vox_decoder_t::reset();
|
||||||
|
}
|
||||||
|
m_out = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// playback
|
||||||
|
if ((++m_clock) >= ((33 * (m_host.m_ss ? 5 : 4))))
|
||||||
|
{
|
||||||
|
m_clock = 0;
|
||||||
|
bool is_end = (m_command != 0);
|
||||||
|
m_curr.decode(bitfield(m_host.m_intf.read_byte(m_addr), m_nibble, 4));
|
||||||
|
if (m_nibble <= 0)
|
||||||
|
{
|
||||||
|
m_nibble = 4;
|
||||||
|
if (++m_addr > m_end)
|
||||||
|
is_end = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_nibble -= 4;
|
||||||
|
if (is_end)
|
||||||
|
{
|
||||||
|
m_command = 0;
|
||||||
|
m_busy = false;
|
||||||
|
}
|
||||||
|
m_out = (out() * m_volume) >> 7; // scale out to 12 bit output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void msm6295_core::voice_t::reset()
|
||||||
|
{
|
||||||
|
vox_decoder_t::reset();
|
||||||
|
m_clock = 0;
|
||||||
|
m_busy = false;
|
||||||
|
m_command = 0;
|
||||||
|
m_addr = 0;
|
||||||
|
m_nibble = 0;
|
||||||
|
m_end = 0;
|
||||||
|
m_volume = 0;
|
||||||
|
m_out = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// accessors
|
||||||
|
u8 msm6295_core::busy_r()
|
||||||
|
{
|
||||||
|
return (m_voice[0].m_busy ? 0x01 : 0x00)
|
||||||
|
| (m_voice[1].m_busy ? 0x02 : 0x00)
|
||||||
|
| (m_voice[2].m_busy ? 0x04 : 0x00)
|
||||||
|
| (m_voice[3].m_busy ? 0x08 : 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
void msm6295_core::command_w(u8 data)
|
||||||
|
{
|
||||||
|
if (!m_command_pending)
|
||||||
|
{
|
||||||
|
m_next_command = data;
|
||||||
|
m_command_pending = true;
|
||||||
|
}
|
||||||
|
}
|
91
src/engine/platform/sound/oki/msm6295.hpp
Normal file
91
src/engine/platform/sound/oki/msm6295.hpp
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
License: BSD-3-Clause
|
||||||
|
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
|
||||||
|
|
||||||
|
Copyright holder(s): cam900
|
||||||
|
OKI MSM6295 emulation core
|
||||||
|
|
||||||
|
See msm6295.cpp for more info.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "util.hpp"
|
||||||
|
#include "vox.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#ifndef _VGSOUND_EMU_MSM6295_HPP
|
||||||
|
#define _VGSOUND_EMU_MSM6295_HPP
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class msm6295_core : public vox_core
|
||||||
|
{
|
||||||
|
friend class vgsound_emu_mem_intf; // common memory interface
|
||||||
|
public:
|
||||||
|
// constructor
|
||||||
|
msm6295_core(vgsound_emu_mem_intf &intf)
|
||||||
|
: m_voice{{*this,*this},{*this,*this},{*this,*this},{*this,*this}}
|
||||||
|
, m_intf(intf)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
// accessors, getters, setters
|
||||||
|
u8 busy_r();
|
||||||
|
void command_w(u8 data);
|
||||||
|
void ss_w(bool ss) { m_ss = ss; } // SS pin
|
||||||
|
|
||||||
|
// internal state
|
||||||
|
void reset();
|
||||||
|
void tick();
|
||||||
|
|
||||||
|
s32 out() { return m_out; } // built in 12 bit DAC
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Internal volume table, 9 step
|
||||||
|
const s32 m_volume_table[9] = {
|
||||||
|
32/* 0.0dB */,
|
||||||
|
22/* -3.2dB */,
|
||||||
|
16/* -6.0dB */,
|
||||||
|
11/* -9.2dB */,
|
||||||
|
8/* -12.0dB */,
|
||||||
|
6/* -14.5dB */,
|
||||||
|
4/* -18.0dB */,
|
||||||
|
3/* -20.5dB */,
|
||||||
|
2/* -24.0dB */ }; // scale out to 5 bit for optimization
|
||||||
|
|
||||||
|
// msm6295 voice structs
|
||||||
|
struct voice_t : vox_decoder_t
|
||||||
|
{
|
||||||
|
// constructor
|
||||||
|
voice_t(vox_core &vox, msm6295_core &host)
|
||||||
|
: vox_decoder_t(vox)
|
||||||
|
, m_host(host)
|
||||||
|
{};
|
||||||
|
|
||||||
|
// internal state
|
||||||
|
virtual void reset() override;
|
||||||
|
void tick();
|
||||||
|
|
||||||
|
// accessors, getters, setters
|
||||||
|
// registers
|
||||||
|
msm6295_core &m_host;
|
||||||
|
u16 m_clock = 0; // clock counter
|
||||||
|
bool m_busy = false; // busy status
|
||||||
|
u8 m_command = 0; // current command
|
||||||
|
u32 m_addr = 0; // current address
|
||||||
|
s8 m_nibble = 0; // current nibble
|
||||||
|
u32 m_end = 0; // end address
|
||||||
|
s32 m_volume = 0; // volume
|
||||||
|
s32 m_out = 0; // output
|
||||||
|
};
|
||||||
|
voice_t m_voice[4];
|
||||||
|
vgsound_emu_mem_intf &m_intf; // common memory interface
|
||||||
|
|
||||||
|
bool m_ss = false; // SS pin controls divider, input clock / 33 * (SS ? 5 : 4)
|
||||||
|
u8 m_command = 0; // Command byte
|
||||||
|
u8 m_next_command = 0; // Next command
|
||||||
|
bool m_command_pending = false; // command pending flag
|
||||||
|
u16 m_clock = 0; // clock counter
|
||||||
|
s32 m_out = 0; // 12 bit output
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
158
src/engine/platform/sound/oki/util.hpp
Normal file
158
src/engine/platform/sound/oki/util.hpp
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
License: BSD-3-Clause
|
||||||
|
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
|
||||||
|
|
||||||
|
Copyright holders: cam900
|
||||||
|
Various core utilities for vgsound_emu
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#ifndef _VGSOUND_EMU_CORE_UTIL_HPP
|
||||||
|
#define _VGSOUND_EMU_CORE_UTIL_HPP
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
typedef unsigned long long u64;
|
||||||
|
typedef signed char s8;
|
||||||
|
typedef signed short s16;
|
||||||
|
typedef signed int s32;
|
||||||
|
typedef signed long long s64;
|
||||||
|
typedef float f32;
|
||||||
|
typedef double f64;
|
||||||
|
|
||||||
|
const f64 PI = 3.1415926535897932384626433832795;
|
||||||
|
|
||||||
|
// get bitfield, bitfield(input, position, len)
|
||||||
|
template<typename T> T bitfield(T in, u8 pos, u8 len = 1)
|
||||||
|
{
|
||||||
|
return (in >> pos) & (len ? (T(1 << len) - 1) : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get sign extended value, sign_ext<type>(input, len)
|
||||||
|
template<typename T> T sign_ext(T in, u8 len)
|
||||||
|
{
|
||||||
|
len = std::max<u8>(0, (8 * sizeof(T)) - len);
|
||||||
|
return T(T(in) << len) >> len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert attenuation decibel value to gain
|
||||||
|
f32 dB_to_gain(f32 attenuation)
|
||||||
|
{
|
||||||
|
return powf(10.0f, attenuation / 20.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
class vgsound_emu_mem_intf
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual u8 read_byte(u32 address) { return 0; }
|
||||||
|
virtual u16 read_word(u32 address) { return 0; }
|
||||||
|
virtual u32 read_dword(u32 address) { return 0; }
|
||||||
|
virtual u64 read_qword(u32 address) { return 0; }
|
||||||
|
virtual void write_byte(u32 address, u8 data) { }
|
||||||
|
virtual void write_word(u32 address, u16 data) { }
|
||||||
|
virtual void write_dword(u32 address, u32 data) { }
|
||||||
|
virtual void write_qword(u32 address, u64 data) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, T InitWidth, u8 InitEdge = 0>
|
||||||
|
struct clock_pulse_t
|
||||||
|
{
|
||||||
|
void reset(T init = InitWidth)
|
||||||
|
{
|
||||||
|
m_edge.reset();
|
||||||
|
m_width = m_width_latch = m_counter = init;
|
||||||
|
m_cycle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tick(T width = 0)
|
||||||
|
{
|
||||||
|
bool carry = ((--m_counter) <= 0);
|
||||||
|
if (carry)
|
||||||
|
{
|
||||||
|
if (!width)
|
||||||
|
m_width = m_width_latch;
|
||||||
|
else
|
||||||
|
m_width = width; // reset width
|
||||||
|
m_counter = m_width;
|
||||||
|
m_cycle = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_cycle++;
|
||||||
|
|
||||||
|
m_edge.tick(carry);
|
||||||
|
return carry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_width(T width) { m_width = width; }
|
||||||
|
void set_width_latch(T width) { m_width_latch = width; }
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
bool current_edge() { return m_edge.m_current; }
|
||||||
|
bool rising_edge() { return m_edge.m_rising; }
|
||||||
|
bool falling_edge() { return m_edge.m_rising; }
|
||||||
|
T cycle() { return m_cycle; }
|
||||||
|
|
||||||
|
struct edge_t
|
||||||
|
{
|
||||||
|
edge_t()
|
||||||
|
: m_current(InitEdge ^ 1)
|
||||||
|
, m_previous(InitEdge)
|
||||||
|
, m_rising(0)
|
||||||
|
, m_falling(0)
|
||||||
|
, m_changed(0)
|
||||||
|
{
|
||||||
|
set(InitEdge);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tick(bool toggle)
|
||||||
|
{
|
||||||
|
u8 current = m_current;
|
||||||
|
if (toggle)
|
||||||
|
current ^= 1;
|
||||||
|
set(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(u8 edge)
|
||||||
|
{
|
||||||
|
edge &= 1;
|
||||||
|
m_rising = m_falling = m_changed = 0;
|
||||||
|
if (m_current != edge)
|
||||||
|
{
|
||||||
|
m_changed = 1;
|
||||||
|
if (m_current && (!edge))
|
||||||
|
m_falling = 1;
|
||||||
|
else if ((!m_current) && edge)
|
||||||
|
m_rising = 1;
|
||||||
|
m_current = edge;
|
||||||
|
}
|
||||||
|
m_previous = m_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
m_previous = InitEdge;
|
||||||
|
m_current = InitEdge ^ 1;
|
||||||
|
set(InitEdge);
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 m_current : 1; // current edge
|
||||||
|
u8 m_previous : 1; // previous edge
|
||||||
|
u8 m_rising : 1; // rising edge
|
||||||
|
u8 m_falling : 1; // falling edge
|
||||||
|
u8 m_changed : 1; // changed flag
|
||||||
|
};
|
||||||
|
|
||||||
|
edge_t m_edge;
|
||||||
|
T m_width = InitWidth; // clock pulse width
|
||||||
|
T m_width_latch = InitWidth; // clock pulse width latch
|
||||||
|
T m_counter = InitWidth; // clock counter
|
||||||
|
T m_cycle = 0; // clock cycle
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
115
src/engine/platform/sound/oki/vox.hpp
Normal file
115
src/engine/platform/sound/oki/vox.hpp
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
License: BSD-3-Clause
|
||||||
|
see https://github.com/cam900/vgsound_emu/blob/main/LICENSE for more details
|
||||||
|
|
||||||
|
Copyright holder(s): cam900
|
||||||
|
Dialogic ADPCM core
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "util.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#ifndef _VGSOUND_EMU_CORE_VOX_HPP
|
||||||
|
#define _VGSOUND_EMU_CORE_VOX_HPP
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define MODIFIED_CLAMP(x,xMin,xMax) (std::min(std::max((x),(xMin)),(xMax)))
|
||||||
|
|
||||||
|
class vox_core
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
struct vox_decoder_t
|
||||||
|
{
|
||||||
|
vox_decoder_t(vox_core &vox)
|
||||||
|
: m_curr(vox)
|
||||||
|
, m_loop(vox)
|
||||||
|
{ };
|
||||||
|
|
||||||
|
virtual void reset()
|
||||||
|
{
|
||||||
|
m_curr.reset();
|
||||||
|
m_loop.reset();
|
||||||
|
m_loop_saved = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void save()
|
||||||
|
{
|
||||||
|
if (!m_loop_saved)
|
||||||
|
{
|
||||||
|
m_loop.copy(m_curr);
|
||||||
|
m_loop_saved = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore()
|
||||||
|
{
|
||||||
|
if (m_loop_saved)
|
||||||
|
m_curr.copy(m_loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 out() { return m_curr.m_step; }
|
||||||
|
|
||||||
|
struct decoder_state_t
|
||||||
|
{
|
||||||
|
decoder_state_t(vox_core &vox)
|
||||||
|
: m_vox(vox)
|
||||||
|
{ };
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
m_index = 0;
|
||||||
|
m_step = 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy(decoder_state_t src)
|
||||||
|
{
|
||||||
|
m_index = src.m_index;
|
||||||
|
m_step = src.m_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decode(u8 nibble)
|
||||||
|
{
|
||||||
|
const u8 delta = bitfield(nibble, 0, 3);
|
||||||
|
s16 ss = m_vox.m_step_table[m_index]; // ss(n)
|
||||||
|
|
||||||
|
// d(n) = (ss(n) * B2) + ((ss(n) / 2) * B1) + ((ss(n) / 4) * B0) + (ss(n) / 8)
|
||||||
|
s16 d = ss >> 3;
|
||||||
|
if (bitfield(delta, 2))
|
||||||
|
d += ss;
|
||||||
|
if (bitfield(delta, 1))
|
||||||
|
d += (ss >> 1);
|
||||||
|
if (bitfield(delta, 0))
|
||||||
|
d += (ss >> 2);
|
||||||
|
|
||||||
|
// if (B3 = 1) then d(n) = d(n) * (-1) X(n) = X(n-1) * d(n)
|
||||||
|
if (bitfield(nibble, 3))
|
||||||
|
m_step = std::max(m_step - d, -2048);
|
||||||
|
else
|
||||||
|
m_step = std::min(m_step + d, 2047);
|
||||||
|
|
||||||
|
// adjust step index
|
||||||
|
m_index = MODIFIED_CLAMP(m_index + m_vox.m_index_table[delta], 0, 48);
|
||||||
|
}
|
||||||
|
|
||||||
|
vox_core &m_vox;
|
||||||
|
s8 m_index = 0;
|
||||||
|
s32 m_step = 16;
|
||||||
|
};
|
||||||
|
|
||||||
|
decoder_state_t m_curr;
|
||||||
|
decoder_state_t m_loop;
|
||||||
|
bool m_loop_saved = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
s8 m_index_table[8] = {-1, -1, -1, -1, 2, 4, 6, 8};
|
||||||
|
s32 m_step_table[49] = {
|
||||||
|
16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||||
|
50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143,
|
||||||
|
157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449,
|
||||||
|
494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue