OXYGENHUB
◆ main openmsx / src / sound / YMF262.hh
7.1 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef YMF262_HH
2
#define YMF262_HH
3
4
#include "ResampledSoundDevice.hh"
5
6
#include "EmuTimer.hh"
7
8
#include "EmuTime.hh"
9
#include "FixedPoint.hh"
10
#include "IRQHelper.hh"
11
#include "SimpleDebuggable.hh"
12
#include "serialize_meta.hh"
13
14
#include <array>
15
#include <cstdint>
16
#include <memory>
17
#include <span>
18
#include <string>
19
20
namespace openmsx {
21
22
class DeviceConfig;
23
24
class YMF262 final : private ResampledSoundDevice, private EmuTimerCallback
25
{
26
public:
27
	// sin-wave entries
28
	static constexpr int SIN_BITS = 10;
29
	static constexpr int SIN_LEN  = 1 << SIN_BITS;
30
	static constexpr int SIN_MASK = SIN_LEN - 1;
31
32
public:
33
	YMF262(const std::string& name, const DeviceConfig& config,
34
	       bool isYMF278);
35
	~YMF262();
36
37
	void reset(EmuTime time);
38
	void writeReg   (unsigned r, uint8_t v, EmuTime time);
39
	void writeReg512(unsigned r, uint8_t v, EmuTime time);
40
	[[nodiscard]] uint8_t readReg(unsigned reg) const;
41
	[[nodiscard]] uint8_t peekReg(unsigned reg) const;
42
	[[nodiscard]] uint8_t readStatus();
43
	[[nodiscard]] uint8_t peekStatus() const;
44
45
	void setMixLevel(uint8_t x, EmuTime time);
46
47
	template<typename Archive>
48
	void serialize(Archive& ar, unsigned version);
49
50
public:
51
	/** 16.16 fixed point type for frequency calculations */
52
	using FreqIndex = FixedPoint<16>;
53
54
	enum class EnvelopeState : uint8_t {
55
		ATTACK, DECAY, SUSTAIN, RELEASE, OFF
56
	};
57
58
private:
59
	class Channel;
60
61
	class Slot {
62
	public:
63
		Slot();
64
		[[nodiscard]] int op_calc(unsigned phase, unsigned lfo_am) const;
65
		void FM_KEYON(uint8_t key_set);
66
		void FM_KEYOFF(uint8_t key_clr);
67
		void advanceEnvelopeGenerator(unsigned egCnt);
68
		void advancePhaseGenerator(const Channel& ch, unsigned lfo_pm);
69
		void update_ar_dr();
70
		void update_rr();
71
		void calc_fc(const Channel& ch);
72
73
		/** Sets the amount of feedback [0..7]
74
		 */
75
		void setFeedbackShift(uint8_t value) {
76
			fb_shift = value ? 9 - value : 0;
77
		}
78
79
		template<typename Archive>
80
		void serialize(Archive& ar, unsigned version);
81
82
		// Phase Generator
83
		FreqIndex Cnt{0};  // frequency counter
84
		FreqIndex Incr{0}; // frequency counter step
85
		int* connect{nullptr}; // slot output pointer
86
		std::array<int, 2> op1_out{0, 0}; // slot1 output for feedback
87
88
		// Envelope Generator
89
		unsigned TL{0};  // total level: TL << 2
90
		unsigned TLL{0}; // adjusted now TL
91
		int volume{0};   // envelope counter
92
		int sl{0};       // sustain level: sl_tab[SL]
93
94
		std::span<const unsigned, SIN_LEN> waveTable; // waveform select
95
96
		EnvelopeState state{EnvelopeState::OFF}; // EG: phase type
97
		unsigned eg_m_ar{0};  // (attack state)
98
		unsigned eg_m_dr{0};  // (decay state)
99
		unsigned eg_m_rr{0};  // (release state)
100
		uint8_t eg_sh_ar{0};  // (attack state)
101
		uint8_t eg_sel_ar{0}; // (attack state)
102
		uint8_t eg_sh_dr{0};  // (decay state)
103
		uint8_t eg_sel_dr{0}; // (decay state)
104
		uint8_t eg_sh_rr{0};  // (release state)
105
		uint8_t eg_sel_rr{0}; // (release state)
106
107
		uint8_t key{0}; // 0 = KEY OFF, >0 = KEY ON
108
109
		uint8_t fb_shift{0}; // PG: feedback shift value
110
		bool CON{false};     // PG: connection (algorithm) type
111
		bool eg_type{false}; // EG: percussive/non-percussive mode
112
113
		// LFO
114
		uint8_t AMmask{0}; // LFO Amplitude Modulation enable mask
115
		bool vib{false};   // LFO Phase Modulation enable flag (active high)
116
117
		uint8_t ar{0};	// attack rate: AR<<2
118
		uint8_t dr{0};	// decay rate:  DR<<2
119
		uint8_t rr{0};	// release rate:RR<<2
120
		uint8_t KSR{0};	// key scale rate
121
		uint8_t ksl{0};	// key scale level
122
		uint8_t ksr{0};	// key scale rate: kcode>>KSR
123
		uint8_t mul{0};	// multiple: mul_tab[ML]
124
	};
125
126
	class Channel {
127
	public:
128
		void chan_calc(unsigned lfo_am);
129
		void chan_calc_ext(unsigned lfo_am);
130
131
		template<typename Archive>
132
		void serialize(Archive& ar, unsigned version);
133
134
		std::array<Slot, 2> slot;
135
136
		int block_fnum{0};    // block+fnum
137
		FreqIndex fc{0};      // Freq. Increment base
138
		unsigned ksl_base{0}; // KeyScaleLevel Base step
139
		uint8_t kcode{0};     // key code (for key scaling)
140
141
		// there are 12 2-operator channels which can be combined in pairs
142
		// to form six 4-operator channel, they are:
143
		//  0 and 3,
144
		//  1 and 4,
145
		//  2 and 5,
146
		//  9 and 12,
147
		//  10 and 13,
148
		//  11 and 14
149
		bool extended{false}; // set if this channel forms up a 4op channel with
150
		                      // another channel (only used by first of pair of
151
		                      // channels, ie 0,1,2 and 9,10,11)
152
	};
153
154
	// SoundDevice
155
	[[nodiscard]] float getAmplificationFactorImpl() const override;
156
	void generateChannels(std::span<float*> bufs, unsigned num) override;
157
158
	void callback(uint8_t flag) override;
159
160
	void writeRegDirect(unsigned r, uint8_t v, EmuTime time);
161
	void init_tables();
162
	void setStatus(uint8_t flag);
163
	void resetStatus(uint8_t flag);
164
	void changeStatusMask(uint8_t flag);
165
	void advance();
166
167
	[[nodiscard]] unsigned genPhaseHighHat();
168
	[[nodiscard]] unsigned genPhaseSnare();
169
	[[nodiscard]] unsigned genPhaseCymbal();
170
171
	void chan_calc_rhythm(unsigned lfo_am);
172
	void set_mul(unsigned sl, uint8_t v);
173
	void set_ksl_tl(unsigned sl, uint8_t v);
174
	void set_ar_dr(unsigned sl, uint8_t v);
175
	void set_sl_rr(unsigned sl, uint8_t v);
176
	[[nodiscard]] bool checkMuteHelper() const;
177
178
	[[nodiscard]] bool isExtended(unsigned ch) const;
179
	[[nodiscard]] Channel& getFirstOfPair(unsigned ch);
180
	[[nodiscard]] Channel& getSecondOfPair(unsigned ch);
181
182
	struct Debuggable final : SimpleDebuggable {
183
		Debuggable(MSXMotherBoard& motherBoard, const std::string& name);
184
		[[nodiscard]] uint8_t read(unsigned address) override;
185
		void write(unsigned address, uint8_t value, EmuTime time) override;
186
	} debuggable;
187
188
	// Bitmask for register 0x04
189
	static constexpr int R04_ST1       = 0x01; // Timer1 Start
190
	static constexpr int R04_ST2       = 0x02; // Timer2 Start
191
	static constexpr int R04_MASK_T2   = 0x20; // Mask Timer2 flag
192
	static constexpr int R04_MASK_T1   = 0x40; // Mask Timer1 flag
193
	static constexpr int R04_IRQ_RESET = 0x80; // IRQ RESET
194
195
	// Bitmask for status register
196
	static constexpr int STATUS_T2      = R04_MASK_T2;
197
	static constexpr int STATUS_T1      = R04_MASK_T1;
198
	// Timers (see EmuTimer class for details about timing)
199
	const std::unique_ptr<EmuTimer> timer1; //  80.8us OPL4  ( 80.5us OPL3)
200
	const std::unique_ptr<EmuTimer> timer2; // 323.1us OPL4  (321.8us OPL3)
201
202
	IRQHelper irq;
203
204
	std::array<int, 18> chanOut = {};      // 18 channels
205
206
	std::array<uint8_t, 512> reg = {};
207
	std::array<Channel, 18> channel;  // OPL3 chips have 18 channels
208
209
	std::array<int, 18 * 4> pan; // channels output masks 4 per channel
210
	                             //    0xffffffff = enable
211
	unsigned eg_cnt{0};          // global envelope generator counter
212
	unsigned noise_rng{1};       // 23 bit noise shift register
213
214
	// LFO
215
	using LFOAMIndex = FixedPoint< 6>;
216
	using LFOPMIndex = FixedPoint<10>;
217
	LFOAMIndex lfo_am_cnt{0};
218
	LFOPMIndex lfo_pm_cnt{0};
219
	bool lfo_am_depth{false};
220
	uint8_t lfo_pm_depth_range{0};
221
222
	uint8_t rhythm{0};		// Rhythm mode
223
	bool nts{false};			// NTS (note select)
224
	bool OPL3_mode{false};		// OPL3 extension enable flag
225
226
	uint8_t status{0};		// status flag
227
	uint8_t status2{0};
228
	uint8_t statusMask{0};		// status mask
229
230
	bool alreadySignaledNEW2{false};
231
	const bool isYMF278;		// true iff this is actually a YMF278
232
					// ATM only used for NEW2 bit
233
};
234
SERIALIZE_CLASS_VERSION(YMF262, 2);
235
236
} // namespace openmsx
237
238
#endif