OXYGENHUB
◆ main openmsx / src / sound / Y8950.hh
6.2 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#ifndef Y8950_HH
2
#define Y8950_HH
3
4
#include "DACSound16S.hh"
5
#include "ResampledSoundDevice.hh"
6
#include "Y8950Adpcm.hh"
7
#include "Y8950KeyboardConnector.hh"
8
9
#include "EmuTime.hh"
10
#include "EmuTimer.hh"
11
#include "FixedPoint.hh"
12
#include "IRQHelper.hh"
13
#include "SimpleDebuggable.hh"
14
15
#include <array>
16
#include <cstdint>
17
#include <memory>
18
#include <span>
19
#include <string>
20
21
namespace openmsx {
22
23
class MSXAudio;
24
class DeviceConfig;
25
class Y8950Periphery;
26
27
class Y8950 final : private ResampledSoundDevice, private EmuTimerCallback
28
{
29
public:
30
	static constexpr int CLOCK_FREQ     = 3579545;
31
	static constexpr int CLOCK_FREQ_DIV = 72;
32
33
	// Bitmask for register 0x04
34
	// Timer1 Start.
35
	static constexpr int R04_ST1          = 0x01;
36
	// Timer2 Start.
37
	static constexpr int R04_ST2          = 0x02;
38
	// not used
39
	//static constexpr int R04            = 0x04;
40
	// Mask 'Buffer Ready'.
41
	static constexpr int R04_MASK_BUF_RDY = 0x08;
42
	// Mask 'End of sequence'.
43
	static constexpr int R04_MASK_EOS     = 0x10;
44
	// Mask Timer2 flag.
45
	static constexpr int R04_MASK_T2      = 0x20;
46
	// Mask Timer1 flag.
47
	static constexpr int R04_MASK_T1      = 0x40;
48
	// IRQ RESET.
49
	static constexpr int R04_IRQ_RESET    = 0x80;
50
51
	// Bitmask for status register
52
	static constexpr int STATUS_PCM_BSY = 0x01;
53
	static constexpr int STATUS_EOS     = R04_MASK_EOS;
54
	static constexpr int STATUS_BUF_RDY = R04_MASK_BUF_RDY;
55
	static constexpr int STATUS_T2      = R04_MASK_T2;
56
	static constexpr int STATUS_T1      = R04_MASK_T1;
57
58
	Y8950(const std::string& name, const DeviceConfig& config,
59
	      unsigned sampleRam, EmuTime time, MSXAudio& audio);
60
	~Y8950();
61
62
	void setEnabled(bool enabled, EmuTime time);
63
	void clearRam();
64
	void reset(EmuTime time);
65
	void writeReg(uint8_t rg, uint8_t data, EmuTime time);
66
	[[nodiscard]] uint8_t readReg(uint8_t rg, EmuTime time);
67
	[[nodiscard]] uint8_t peekReg(uint8_t rg, EmuTime time) const;
68
	[[nodiscard]] uint8_t readStatus(EmuTime time) const;
69
	[[nodiscard]] uint8_t peekStatus(EmuTime time) const;
70
71
	// for ADPCM
72
	void setStatus(uint8_t flags);
73
	void resetStatus(uint8_t flags);
74
	[[nodiscard]] uint8_t peekRawStatus() const;
75
76
	template<typename Archive>
77
	void serialize(Archive& ar, unsigned version);
78
79
private:
80
	// SoundDevice
81
	[[nodiscard]] float getAmplificationFactorImpl() const override;
82
	void generateChannels(std::span<float*> bufs, unsigned num) override;
83
84
	void keyOn_BD();
85
	void keyOn_SD();
86
	void keyOn_TOM();
87
	void keyOn_HH();
88
	void keyOn_CYM();
89
	void keyOff_BD();
90
	void keyOff_SD();
91
	void keyOff_TOM();
92
	void keyOff_HH();
93
	void keyOff_CYM();
94
	void setRythmMode(int data);
95
	void update_key_status();
96
97
	[[nodiscard]] bool checkMuteHelper();
98
99
	void changeStatusMask(uint8_t newMask);
100
101
	void callback(uint8_t flag) override;
102
103
public:
104
	// Dynamic range of envelope
105
	static constexpr int EG_BITS = 9;
106
107
	// Bits for envelope phase incremental counter
108
	static constexpr int EG_DP_BITS = 23;
109
	using EnvPhaseIndex = FixedPoint<EG_DP_BITS - EG_BITS>;
110
111
	enum class EnvelopeState : uint8_t { ATTACK, DECAY, SUSTAIN, RELEASE, FINISH };
112
113
private:
114
	enum KeyPart : uint8_t { KEY_MAIN = 1, KEY_RHYTHM = 2 };
115
116
	class Patch {
117
	public:
118
		Patch();
119
		void reset();
120
121
		void setKeyScaleRate(bool value) {
122
			KR = value ? 9 : 11;
123
		}
124
		void setFeedbackShift(uint8_t value) {
125
			FB = value ? 8 - value : 0;
126
		}
127
128
		template<typename Archive>
129
		void serialize(Archive& ar, unsigned version);
130
131
		bool AM, PM, EG;
132
		uint8_t KR; // 0,1   transformed to 9,11
133
		uint8_t ML; // 0-15
134
		uint8_t KL; // 0-3
135
		uint8_t TL; // 0-63
136
		uint8_t FB; // 0,1-7  transformed to 0,7-1
137
		uint8_t AR; // 0-15
138
		uint8_t DR; // 0-15
139
		uint8_t SL; // 0-15
140
		uint8_t RR; // 0-15
141
	};
142
143
	class Slot {
144
	public:
145
		Slot();
146
		void reset();
147
148
		[[nodiscard]] bool isActive() const;
149
		void slotOn (KeyPart part);
150
		void slotOff(KeyPart part);
151
152
		[[nodiscard]] unsigned calc_phase(int lfo_pm);
153
		[[nodiscard]] unsigned calc_envelope(int lfo_am);
154
		[[nodiscard]] int calc_slot_car(int lfo_pm, int lfo_am, int fm);
155
		[[nodiscard]] int calc_slot_mod(int lfo_pm, int lfo_am);
156
		[[nodiscard]] int calc_slot_tom(int lfo_pm, int lfo_am);
157
		[[nodiscard]] int calc_slot_snare(int lfo_pm, int lfo_am, int whiteNoise);
158
		[[nodiscard]] int calc_slot_cym(int lfo_am, int a, int b);
159
		[[nodiscard]] int calc_slot_hat(int lfo_am, int a, int b, int whiteNoise);
160
161
		void updateAll(unsigned freq);
162
		void updatePG(unsigned freq);
163
		void updateTLL(unsigned freq);
164
		void updateRKS(unsigned freq);
165
		void updateEG();
166
167
		template<typename Archive>
168
		void serialize(Archive& ar, unsigned version);
169
170
		// OUTPUT
171
		int feedback;
172
		int output;		// Output value of slot
173
174
		// for Phase Generator (PG)
175
		unsigned phase;		// Phase
176
		unsigned dPhase;	// Phase increment amount
177
178
		// for Envelope Generator (EG)
179
		std::span<const EnvPhaseIndex, 16> dPhaseARTableRks;
180
		std::span<const EnvPhaseIndex, 16> dPhaseDRTableRks;
181
		int tll;		// Total Level + Key scale level
182
		EnvelopeState eg_mode;  // Current state
183
		EnvPhaseIndex eg_phase;	// Phase
184
		EnvPhaseIndex eg_dPhase;// Phase increment amount
185
186
		Patch patch;
187
		uint8_t key;
188
	};
189
190
	class Channel {
191
	public:
192
		Channel();
193
		void reset();
194
		void setFreq(unsigned freq);
195
		void keyOn (KeyPart part);
196
		void keyOff(KeyPart part);
197
198
		template<typename Archive>
199
		void serialize(Archive& ar, unsigned version);
200
201
		std::array<Slot, 2> slot;
202
		unsigned freq; // combined F-Number and Block
203
		bool alg;
204
	};
205
206
	MSXMotherBoard& motherBoard;
207
	Y8950Periphery& periphery;
208
	Y8950Adpcm adpcm;
209
	Y8950KeyboardConnector connector;
210
	DACSound16S dac13; // 13-bit (exponential) DAC
211
212
	struct Debuggable final : SimpleDebuggable {
213
		Debuggable(MSXMotherBoard& motherBoard, const std::string& name);
214
		[[nodiscard]] uint8_t read(unsigned address, EmuTime time) override;
215
		void write(unsigned address, uint8_t value, EmuTime time) override;
216
	} debuggable;
217
218
	const std::unique_ptr<EmuTimer> timer1; //  80us timer
219
	const std::unique_ptr<EmuTimer> timer2; // 320us timer
220
	IRQHelper irq;
221
222
	std::array<uint8_t, 0x100> reg;
223
224
	std::array<Channel, 9> ch;
225
226
	unsigned pm_phase; // Pitch Modulator
227
	unsigned am_phase; // Amp Modulator
228
229
	// Noise Generator
230
	int noise_seed;
231
	unsigned noiseA_phase;
232
	unsigned noiseB_phase;
233
	unsigned noiseA_dPhase;
234
	unsigned noiseB_dPhase;
235
236
	uint8_t status;     // STATUS Register
237
	uint8_t statusMask; // bit=0 -> masked
238
	bool rythm_mode;
239
	bool am_mode;
240
	bool pm_mode;
241
	bool enabled = true;
242
};
243
244
} // namespace openmsx
245
246
#endif