OXYGENHUB
◆ main openmsx / src / sound / YM2413Okazaki.hh
5.8 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef YM2413OKAZAKI_HH
2
#define YM2413OKAZAKI_HH
3
4
#include "YM2413Core.hh"
5
6
#include "serialize_meta.hh"
7
8
#include "FixedPoint.hh"
9
10
#include <array>
11
#include <cstdint>
12
#include <span>
13
14
namespace openmsx {
15
namespace YM2413Okazaki {
16
17
class YM2413;
18
19
inline constexpr int EP_FP_BITS = 15;
20
using EnvPhaseIndex = FixedPoint<EP_FP_BITS>;
21
22
// Size of sin table
23
inline constexpr int PG_BITS = 9;
24
inline constexpr int PG_WIDTH = 1 << PG_BITS;
25
inline constexpr int PG_MASK = PG_WIDTH - 1;
26
27
class Patch {
28
public:
29
	/** Creates an uninitialized Patch object; call initXXX() before use.
30
	  * This approach makes it possible to create an array of Patches.
31
	  */
32
	Patch();
33
34
	void initModulator(std::span<const uint8_t, 8> data);
35
	void initCarrier  (std::span<const uint8_t, 8> data);
36
37
	/** Sets the Key Scale of Rate (0 or 1). */
38
	void setKR(uint8_t value);
39
	/** Sets the frequency multiplier factor [0..15]. */
40
	void setML(uint8_t value);
41
	/** Sets Key scale level [0..3]. */
42
	void setKL(uint8_t value);
43
	/** Set volume (total level) [0..63]. */
44
	void setTL(uint8_t value);
45
	/** Set waveform [0..1]. */
46
	void setWF(uint8_t value);
47
	/** Sets the amount of feedback [0..7]. */
48
	void setFB(uint8_t value);
49
	/** Sets sustain level [0..15]. */
50
	void setSL(uint8_t value);
51
52
	std::span<const unsigned, PG_WIDTH> WF; // 0-1    transformed to waveform[0-1]
53
	std::span<const uint8_t, 16 * 8> KL;    // 0-3    transformed to tllTab[0-3]
54
	unsigned SL;        // 0-15   transformed to slTable[0-15]
55
	uint8_t AMPM = 0;   // 0-3    2 packed booleans
56
	bool EG = false;    // 0-1
57
	uint8_t KR;         // 0-1    transformed to 10,8
58
	uint8_t ML;         // 0-15   transformed to mlTable[0-15]
59
	uint8_t TL;         // 0-63   transformed to TL2EG(0..63) == [0..252]
60
	uint8_t FB;         // 0,1-7  transformed to 0,7-1
61
	uint8_t AR = 0;     // 0-15
62
	uint8_t DR = 0;     // 0-15
63
	uint8_t RR = 0;     // 0-15
64
};
65
66
class Slot {
67
public:
68
	enum class EnvelopeState : uint8_t {
69
		ATTACK, DECAY, SUSHOLD, SUSTAIN, RELEASE, SETTLE, FINISH
70
	};
71
72
	Slot();
73
	void reset();
74
75
	void setEnvelopeState(EnvelopeState state);
76
	[[nodiscard]] bool isActive() const;
77
78
	void slotOn();
79
	void slotOn2();
80
	void slotOff();
81
	void setPatch(const Patch& patch);
82
	void setVolume(unsigned value);
83
84
	[[nodiscard]] unsigned calc_phase(unsigned lfo_pm);
85
	template<bool HAS_AM, bool FIXED_ENV>
86
	[[nodiscard]] unsigned calc_envelope(int lfo_am, unsigned fixed_env);
87
	template<bool HAS_AM> [[nodiscard]] unsigned calc_fixed_env() const;
88
	void calc_envelope_outline(unsigned& out);
89
	template<bool HAS_AM, bool FIXED_ENV>
90
	[[nodiscard]] int calc_slot_car(unsigned lfo_pm, int lfo_am, int fm, unsigned fixed_env);
91
	template<bool HAS_AM, bool HAS_FB, bool FIXED_ENV>
92
	[[nodiscard]] int calc_slot_mod(unsigned lfo_pm, int lfo_am, unsigned fixed_env);
93
94
	[[nodiscard]] int calc_slot_tom();
95
	[[nodiscard]] int calc_slot_snare(bool noise);
96
	[[nodiscard]] int calc_slot_cym(unsigned phase7, unsigned phase8);
97
	[[nodiscard]] int calc_slot_hat(unsigned phase7, unsigned phase8, bool noise);
98
	void updatePG(unsigned freq);
99
	void updateTLL(unsigned freq, bool actAsCarrier);
100
	void updateRKS(unsigned freq);
101
	void updateEG();
102
	void updateAll(unsigned freq, bool actAsCarrier);
103
104
	template<typename Archive>
105
	void serialize(Archive& ar, unsigned version);
106
107
	// OUTPUT
108
	int feedback;
109
	int output;		// Output value of slot
110
111
	// for Phase Generator (PG)
112
	unsigned cPhase;		// Phase counter
113
	std::array<unsigned, 8> dPhase;	// Phase increment
114
115
	// for Envelope Generator (EG)
116
	unsigned volume;             // Current volume
117
	unsigned tll;                // Total Level + Key scale level
118
	std::span<const int, 16> dPhaseDRTableRks; // (converted to EnvPhaseIndex)
119
	EnvelopeState state;         // Current state
120
	EnvPhaseIndex eg_phase;      // Phase
121
	EnvPhaseIndex eg_dPhase;     // Phase increment amount
122
	EnvPhaseIndex eg_phase_max;
123
	uint8_t slot_on_flag;
124
	bool sustain;                // Sustain
125
126
	Patch patch;
127
	Slot* sibling; // pointer to sibling slot (only valid for car -> mod)
128
};
129
130
class Channel {
131
public:
132
	Channel();
133
	void reset(YM2413& ym2413);
134
	void setPatch(unsigned num, YM2413& ym2413);
135
	void setSustain(bool sustain, bool modActAsCarrier);
136
	void keyOn();
137
	void keyOff();
138
139
	Slot mod, car;
140
141
	template<typename Archive>
142
	void serialize(Archive& ar, unsigned version);
143
};
144
145
class YM2413 final : public YM2413Core
146
{
147
public:
148
	YM2413();
149
150
	// YM2413Core
151
	void reset() override;
152
	void writePort(bool port, uint8_t value, int offset) override;
153
	void pokeReg(uint8_t reg, uint8_t data) override;
154
	[[nodiscard]] std::span<const uint8_t, 64>peekRegs() const override;
155
	void generateChannels(std::span<float*, 9 + 5> bufs, unsigned num) override;
156
	[[nodiscard]] float getAmplificationFactor() const override;
157
158
	[[nodiscard]] Patch& getPatch(unsigned instrument, bool carrier);
159
160
	template<typename Archive>
161
	void serialize(Archive& ar, unsigned version);
162
163
private:
164
	void writeReg(uint8_t r, uint8_t data);
165
166
	void keyOn_BD();
167
	void keyOn_SD();
168
	void keyOn_TOM();
169
	void keyOn_HH();
170
	void keyOn_CYM();
171
	void keyOff_BD();
172
	void keyOff_SD();
173
	void keyOff_TOM();
174
	void keyOff_HH();
175
	void keyOff_CYM();
176
	void setRhythmFlags(uint8_t old);
177
	void update_key_status();
178
	[[nodiscard]] bool isRhythm() const;
179
	[[nodiscard]] unsigned getFreq(unsigned channel) const;
180
181
	template<unsigned FLAGS>
182
	void calcChannel(Channel& ch, std::span<float> buf);
183
184
private:
185
	/** Channel & Slot */
186
	std::array<Channel, 9> channels;
187
188
	/** Pitch Modulator */
189
	unsigned pm_phase;
190
191
	/** Amp Modulator */
192
	unsigned am_phase;
193
194
	/** Noise Generator */
195
	unsigned noise_seed;
196
197
	/** Voice Data */
198
	std::array<std::array<Patch, 2>, 19> patches;
199
200
	/** Registers */
201
	std::array<uint8_t, 0x40> reg;
202
	uint8_t registerLatch;
203
};
204
205
} // namespace YM2413Okazaki
206
207
SERIALIZE_CLASS_VERSION(YM2413Okazaki::Slot, 4);
208
SERIALIZE_CLASS_VERSION(YM2413Okazaki::Channel, 2);
209
SERIALIZE_CLASS_VERSION(YM2413Okazaki::YM2413, 4);
210
211
} // namespace openmsx
212
213
#endif