| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
|
| 21 |
|
| 22 |
|
| 23 |
|
| 24 |
|
| 25 |
|
| 26 |
|
| 27 |
|
| 28 |
|
| 29 |
|
| 30 |
|
| 31 |
|
| 32 |
|
| 33 |
|
| 34 |
|
| 35 |
|
| 36 |
|
| 37 |
|
| 38 |
|
| 39 |
|
| 40 |
|
| 41 |
|
| 42 |
|
| 43 |
|
| 44 |
|
| 45 |
|
| 46 |
|
| 47 |
|
| 48 |
|
| 49 |
|
| 50 |
|
| 51 |
|
| 52 |
|
| 53 |
|
| 54 |
|
| 55 |
|
| 56 |
|
| 57 |
|
| 58 |
#ifndef YM2413NUKEYKT_HH |
| 59 |
#define YM2413NUKEYKT_HH |
| 60 |
|
| 61 |
#include "YM2413Core.hh" |
| 62 |
|
| 63 |
#include "inline.hh" |
| 64 |
#include "stl.hh" |
| 65 |
|
| 66 |
#include <array> |
| 67 |
#include <span> |
| 68 |
|
| 69 |
namespace openmsx::YM2413NukeYKT { |
| 70 |
|
| 71 |
class YM2413 final : public YM2413Core |
| 72 |
{ |
| 73 |
public: |
| 74 |
YM2413(); |
| 75 |
void reset() override; |
| 76 |
void writePort(bool port, uint8_t value, int cycle_offset) override; |
| 77 |
void pokeReg(uint8_t reg, uint8_t value) override; |
| 78 |
[[nodiscard]] std::span<const uint8_t, 64> peekRegs() const override; |
| 79 |
void generateChannels(std::span<float*, 9 + 5> out, uint32_t n) override; |
| 80 |
[[nodiscard]] float getAmplificationFactor() const override; |
| 81 |
void setSpeed(double speed) override; |
| 82 |
|
| 83 |
template<typename Archive> |
| 84 |
void serialize(Archive& ar, unsigned version); |
| 85 |
|
| 86 |
enum class EgState : uint8_t { |
| 87 |
attack, |
| 88 |
decay, |
| 89 |
sustain, |
| 90 |
release, |
| 91 |
}; |
| 92 |
enum class RmNum : uint8_t { |
| 93 |
bd0, |
| 94 |
hh, |
| 95 |
tom, |
| 96 |
bd1, |
| 97 |
sd, |
| 98 |
tc, |
| 99 |
NUM |
| 100 |
}; |
| 101 |
|
| 102 |
private: |
| 103 |
using bool_2 = std::array<bool, 2>; |
| 104 |
using int8_t_2 = std::array<int8_t, 2>; |
| 105 |
using uint8_t_2 = std::array<uint8_t, 2>; |
| 106 |
struct Patch { |
| 107 |
constexpr Patch() = default; |
| 108 |
constexpr Patch(uint8_t tl_, uint8_t dcm_, uint8_t fb_, |
| 109 |
bool_2 am_, bool_2 vib_, bool_2 et_, bool_2 ksr_, uint8_t_2 multi_, |
| 110 |
uint8_t_2 ksl_, uint8_t_2 ar_, uint8_t_2 dr_, uint8_t_2 sl_, uint8_t_2 rr_) |
| 111 |
: dcm(dcm_), vib(vib_), et(et_), sl(sl_) { |
| 112 |
setTL(tl_); |
| 113 |
setFB(fb_); |
| 114 |
setAM(0, am_[0]); |
| 115 |
setAM(1, am_[1]); |
| 116 |
setKSR(0, ksr_[0]); |
| 117 |
setKSR(1, ksr_[1]); |
| 118 |
setMulti(0, multi_[0]); |
| 119 |
setMulti(1, multi_[1]); |
| 120 |
setKSL(0, ksl_[0]); |
| 121 |
setKSL(1, ksl_[1]); |
| 122 |
setAR(0, ar_[0]); |
| 123 |
setAR(1, ar_[1]); |
| 124 |
setDR(0, dr_[0]); |
| 125 |
setDR(1, dr_[1]); |
| 126 |
setRR(0, rr_[0]); |
| 127 |
setRR(1, rr_[1]); |
| 128 |
} |
| 129 |
|
| 130 |
constexpr void setTL(uint8_t tl) { tl2 = 2 * tl; } |
| 131 |
constexpr void setFB(uint8_t fb) { fb_t = fb ? (8 - fb) : 31; } |
| 132 |
constexpr void setAM(int i, bool am) { am_t[i] = am ? -1 : 0; } |
| 133 |
constexpr void setKSR(int i, bool ksr) { ksr_t[i] = ksr ? 0 : 2; } |
| 134 |
constexpr void setMulti(int i, uint8_t multi) { |
| 135 |
constexpr std::array<uint8_t, 16> PG_MULTI = { |
| 136 |
1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 |
| 137 |
}; |
| 138 |
multi_t[i] = PG_MULTI[multi]; |
| 139 |
} |
| 140 |
constexpr void setKSL(int i, uint8_t ksl) { ksl_t[i] = ksl ? (3 - ksl) : 31; } |
| 141 |
constexpr void setAR (int i, uint8_t ar) { ar4[i] = 4 * ar; } |
| 142 |
constexpr void setDR (int i, uint8_t dr) { dr4[i] = 4 * dr; } |
| 143 |
constexpr void setRR (int i, uint8_t rr) { rr4[i] = 4 * rr; } |
| 144 |
|
| 145 |
uint8_t tl2 = 0; |
| 146 |
uint8_t dcm = 0; |
| 147 |
uint8_t fb_t = 31; |
| 148 |
int8_t_2 am_t = {0, 0}; |
| 149 |
bool_2 vib = {false, false}; |
| 150 |
bool_2 et = {false, false}; |
| 151 |
uint8_t_2 ksr_t = {2, 2}; |
| 152 |
uint8_t_2 multi_t = {1, 1}; |
| 153 |
uint8_t_2 ksl_t = {31, 31}; |
| 154 |
uint8_t_2 ar4 = {0, 0}; |
| 155 |
uint8_t_2 dr4 = {0, 0}; |
| 156 |
uint8_t_2 sl = {0, 0}; |
| 157 |
uint8_t_2 rr4 = {0, 0}; |
| 158 |
}; |
| 159 |
struct Locals { |
| 160 |
explicit Locals(std::span<float*, 9 + 5> out_) : out(out_) {} |
| 161 |
|
| 162 |
std::span<float*, 9 + 5> out; |
| 163 |
uint8_t rm_hh_bits = 0; |
| 164 |
bool use_rm_patches = false; |
| 165 |
bool lfo_am_car = false; |
| 166 |
bool eg_timer_carry = false; |
| 167 |
}; |
| 168 |
struct Write { |
| 169 |
uint8_t port = 0; |
| 170 |
uint8_t value = 0; |
| 171 |
|
| 172 |
template<typename Archive> |
| 173 |
void serialize(Archive& ar, unsigned version); |
| 174 |
}; |
| 175 |
|
| 176 |
private: |
| 177 |
template<bool TEST_MODE> NEVER_INLINE void step18(std::span<float*, 9 + 5> out); |
| 178 |
template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void step(Locals& l); |
| 179 |
|
| 180 |
template<uint32_t CYCLES> [[nodiscard]] ALWAYS_INLINE uint32_t phaseCalcIncrement(const Patch& patch1) const; |
| 181 |
template<uint32_t CYCLES> ALWAYS_INLINE void channelOutput(std::span<float*, 9 + 5> out, int32_t ch_out); |
| 182 |
template<uint32_t CYCLES> [[nodiscard]] ALWAYS_INLINE const Patch& preparePatch1(bool use_rm_patches) const; |
| 183 |
template<uint32_t CYCLES, bool TEST_MODE> [[nodiscard]] ALWAYS_INLINE uint32_t getPhase(uint8_t& rm_hh_bits); |
| 184 |
template<uint32_t CYCLES> [[nodiscard]] ALWAYS_INLINE bool keyOnEvent() const; |
| 185 |
template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void incrementPhase(uint32_t phase_incr, bool prev_rhythm); |
| 186 |
template<uint32_t CYCLES> [[nodiscard]] ALWAYS_INLINE uint32_t getPhaseMod(uint8_t fb_t); |
| 187 |
template<uint32_t CYCLES> ALWAYS_INLINE void doOperator(std::span<float*, 9 + 5> out, bool eg_silent); |
| 188 |
template<uint32_t CYCLES, bool TEST_MODE> [[nodiscard]] ALWAYS_INLINE uint8_t envelopeOutput(uint32_t ksltl, int8_t am_t) const; |
| 189 |
template<uint32_t CYCLES> [[nodiscard]] ALWAYS_INLINE uint32_t envelopeKSLTL(const Patch& patch1, bool use_rm_patches) const; |
| 190 |
template<uint32_t CYCLES> ALWAYS_INLINE void envelopeTimer1(); |
| 191 |
template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void envelopeTimer2(bool& eg_timer_carry); |
| 192 |
template<uint32_t CYCLES> [[nodiscard]] ALWAYS_INLINE bool envelopeGenerate1(); |
| 193 |
template<uint32_t CYCLES> ALWAYS_INLINE void envelopeGenerate2(const Patch& patch1, bool use_rm_patches); |
| 194 |
template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void doLFO(bool& lfo_am_car); |
| 195 |
template<uint32_t CYCLES, bool TEST_MODE> ALWAYS_INLINE void doRhythm(); |
| 196 |
template<uint32_t CYCLES> ALWAYS_INLINE void doRegWrite(); |
| 197 |
template<uint32_t CYCLES> ALWAYS_INLINE void doIO(); |
| 198 |
|
| 199 |
NEVER_INLINE void doRegWrite(uint8_t channel); |
| 200 |
void doRegWrite(uint8_t block, uint8_t channel, uint8_t data); |
| 201 |
NEVER_INLINE void doIO(uint32_t cycles_plus_1, Write& write); |
| 202 |
|
| 203 |
void doModeWrite(uint8_t address, uint8_t value); |
| 204 |
void changeFnumBlock(uint32_t ch); |
| 205 |
|
| 206 |
private: |
| 207 |
static const std::array<Patch, 15> m_patches; |
| 208 |
static const array_with_enum_index<RmNum, Patch> r_patches; |
| 209 |
|
| 210 |
|
| 211 |
std::array<Write, 18> writes; |
| 212 |
uint8_t write_data; |
| 213 |
uint8_t fm_data; |
| 214 |
uint8_t write_address; |
| 215 |
uint8_t write_fm_cycle; |
| 216 |
bool fast_fm_rewrite; |
| 217 |
bool test_mode_active; |
| 218 |
|
| 219 |
|
| 220 |
std::span<const uint8_t, 64> attackPtr; |
| 221 |
std::span<const uint8_t, 64> releasePtr; |
| 222 |
uint32_t eg_timer; |
| 223 |
std::array<uint8_t, 2> eg_sl; |
| 224 |
std::array<uint8_t, 2> eg_out; |
| 225 |
uint8_t eg_counter_state; |
| 226 |
uint8_t eg_timer_shift; |
| 227 |
uint8_t eg_timer_shift_lock; |
| 228 |
uint8_t eg_timer_lock; |
| 229 |
std::array<EgState, 18> eg_state; |
| 230 |
std::array<uint8_t, 18> eg_level; |
| 231 |
std::array<uint8_t, 2> eg_rate; |
| 232 |
std::array<bool, 18> eg_dokon; |
| 233 |
std::array<bool, 2> eg_kon; |
| 234 |
std::array<bool, 2> eg_off; |
| 235 |
bool eg_timer_shift_stop; |
| 236 |
|
| 237 |
|
| 238 |
std::array<uint32_t, 18> pg_phase; |
| 239 |
|
| 240 |
|
| 241 |
std::array<int16_t, 9> op_fb1; |
| 242 |
std::array<int16_t, 9> op_fb2; |
| 243 |
int16_t op_mod; |
| 244 |
std::array<uint16_t, 2> op_phase; |
| 245 |
|
| 246 |
|
| 247 |
uint16_t lfo_counter; |
| 248 |
uint16_t lfo_am_counter; |
| 249 |
uint8_t lfo_vib_counter; |
| 250 |
int8_t lfo_vib; |
| 251 |
uint8_t lfo_am_out; |
| 252 |
bool lfo_am_step; |
| 253 |
bool lfo_am_dir; |
| 254 |
|
| 255 |
|
| 256 |
std::array<uint16_t, 9> fnum; |
| 257 |
std::array<uint8_t, 9> block; |
| 258 |
std::array<uint8_t, 9> p_ksl; |
| 259 |
std::array<uint16_t, 9> p_incr; |
| 260 |
std::array<uint8_t, 9> p_ksr_freq; |
| 261 |
std::array<uint8_t, 9> sk_on; |
| 262 |
std::array<uint8_t, 9> vol8; |
| 263 |
std::array<uint8_t, 9> inst; |
| 264 |
std::array<const Patch*, 9> p_inst; |
| 265 |
uint8_t rhythm; |
| 266 |
uint8_t testMode; |
| 267 |
std::array<Patch, 1 + 15> patches; |
| 268 |
std::array<uint8_t, 3> c_dcm; |
| 269 |
|
| 270 |
|
| 271 |
uint32_t rm_noise; |
| 272 |
uint8_t rm_tc_bits; |
| 273 |
|
| 274 |
int delay6; |
| 275 |
int delay7; |
| 276 |
int delay10; |
| 277 |
int delay11; |
| 278 |
int delay12; |
| 279 |
|
| 280 |
|
| 281 |
std::array<uint8_t, 64> regs; |
| 282 |
uint8_t latch; |
| 283 |
|
| 284 |
int allowed_offset = 0; |
| 285 |
bool speedUpHack = false; |
| 286 |
}; |
| 287 |
|
| 288 |
} |
| 289 |
|
| 290 |
#endif |