OXYGENHUB
◆ main openmsx / src / sound / YM2413Burczynski.hh
8.2 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef YM2413BURCZYNSKI_HH
2
#define YM2413BURCZYNSKI_HH
3
4
#include "YM2413Core.hh"
5
6
#include "FixedPoint.hh"
7
#include "serialize_meta.hh"
8
9
#include <array>
10
#include <cstdint>
11
#include <span>
12
13
namespace openmsx {
14
namespace YM2413Burczynski {
15
16
// sin wave entries
17
inline constexpr int SIN_BITS = 10;
18
inline constexpr size_t SIN_LEN  = 1 << SIN_BITS;
19
inline constexpr size_t SIN_MASK = SIN_LEN - 1;
20
21
class Channel;
22
23
/** 16.16 fixed point type for frequency calculations.
24
  */
25
using FreqIndex = FixedPoint<16>;
26
27
class Slot
28
{
29
public:
30
	Slot();
31
32
	void resetOperators();
33
34
	/** Update phase increment counter of operator.
35
	 * Also updates the EG rates if necessary.
36
	 */
37
	void updateGenerators(const Channel& channel);
38
39
	[[nodiscard]] int calcOutput(const Channel& channel, unsigned eg_cnt, bool carrier,
40
	                             unsigned lfo_am, int phase);
41
	[[nodiscard]] int calc_slot_mod(const Channel& channel, unsigned eg_cnt, bool carrier,
42
	                                unsigned lfo_pm, unsigned lfo_am);
43
	[[nodiscard]] int calc_envelope(const Channel& channel, unsigned eg_cnt, bool carrier);
44
	[[nodiscard]] int calc_phase(const Channel& channel, unsigned lfo_pm);
45
46
	enum class KeyPart : uint8_t { MAIN = 1, RHYTHM = 2 };
47
	void setKeyOn(KeyPart part);
48
	void setKeyOff(KeyPart part);
49
	void setKeyOnOff(KeyPart part, bool enabled);
50
51
	/** Does this slot currently produce an output signal?
52
	 */
53
	[[nodiscard]] bool isActive() const;
54
55
	/** Sets the frequency multiplier [0..15].
56
	 */
57
	void setFrequencyMultiplier(uint8_t value);
58
59
	/** Sets the key scale rate: true->0, false->2.
60
	 */
61
	void setKeyScaleRate(bool value);
62
63
	/** Sets the envelope type of the current instrument.
64
	  * @param value true->sustained, false->percussive.
65
	  */
66
	void setEnvelopeSustained(bool value);
67
68
	/** Enables (true) or disables (false) vibrato.
69
	 */
70
	void setVibrato(bool value);
71
72
	/** Enables (true) or disables (false) amplitude modulation.
73
	 */
74
	void setAmplitudeModulation(bool value);
75
76
	/** Sets the total level: [0..63].
77
	 */
78
	void setTotalLevel(const Channel& channel, uint8_t value);
79
80
	/** Sets the key scale level: 0->0 / 1->1.5 / 2->3.0 / 3->6.0 dB/OCT.
81
	 */
82
	void setKeyScaleLevel(const Channel& channel, uint8_t value);
83
84
	/** Sets the waveform: 0 = sinus, 1 = half sinus, half silence.
85
	 */
86
	void setWaveform(uint8_t value);
87
88
	/** Sets the amount of feedback [0..7].
89
	 */
90
	void setFeedbackShift(uint8_t value);
91
92
	/** Sets the attack rate [0..15].
93
	 */
94
	void setAttackRate(const Channel& channel, uint8_t value);
95
96
	/** Sets the decay rate [0..15].
97
	 */
98
	void setDecayRate(const Channel& channel, uint8_t value);
99
100
	/** Sets the release rate [0..15].
101
	 */
102
	void setReleaseRate(const Channel& channel, uint8_t value);
103
104
	/** Sets the sustain level [0..15].
105
	 */
106
	void setSustainLevel(uint8_t value);
107
108
	/** Called by Channel when block_fnum changes.
109
	 */
110
	void updateFrequency(const Channel& channel);
111
112
	template<typename Archive>
113
	void serialize(Archive& ar, unsigned version);
114
115
public: // public for serialization, otherwise could be private
116
	enum class EnvelopeState : uint8_t {
117
		DUMP, ATTACK, DECAY, SUSTAIN, RELEASE, OFF
118
	};
119
120
private:
121
	/** Change envelope state
122
	 */
123
	void setEnvelopeState(EnvelopeState state);
124
125
	void updateTotalLevel(const Channel& channel);
126
	void updateAttackRate(int kcodeScaled);
127
	void updateDecayRate(int kcodeScaled);
128
	void updateReleaseRate(int kcodeScaled);
129
130
	std::span<const unsigned, SIN_LEN> waveTable;	// waveform select
131
132
	// Phase Generator
133
	FreqIndex phase{0}; // frequency counter
134
	FreqIndex freq{0};  // frequency counter step
135
136
	// Envelope Generator
137
	int TL{0};	// total level: TL << 2
138
	int TLL{0};	// adjusted now TL
139
	int egOut{0};	// envelope counter
140
	int sl{0};	// sustain level: sl_tab[SL]
141
	EnvelopeState state;
142
143
	std::array<int, 2> op1_out = {0, 0}; // MOD output for feedback
144
	bool eg_sustain{false};  // percussive/non-percussive mode
145
	uint8_t fb_shift{0}; // feedback shift value
146
147
	uint8_t key{0};	// 0 = KEY OFF, >0 = KEY ON
148
149
	std::span<const uint8_t, 8> eg_sel_dp;
150
	std::span<const uint8_t, 8> eg_sel_ar;
151
	std::span<const uint8_t, 8> eg_sel_dr;
152
	std::span<const uint8_t, 8> eg_sel_rr;
153
	std::span<const uint8_t, 8> eg_sel_rs;
154
	unsigned eg_mask_dp{0}; // == (1 << eg_sh_dp) - 1
155
	unsigned eg_mask_ar{0}; // == (1 << eg_sh_ar) - 1
156
	unsigned eg_mask_dr{0}; // == (1 << eg_sh_dr) - 1
157
	unsigned eg_mask_rr{0}; // == (1 << eg_sh_rr) - 1
158
	unsigned eg_mask_rs{0}; // == (1 << eg_sh_rs) - 1
159
	uint8_t eg_sh_dp{0};    // (dump state)
160
	uint8_t eg_sh_ar{0};    // (attack state)
161
	uint8_t eg_sh_dr{0};    // (decay state)
162
	uint8_t eg_sh_rr{0};    // (release state for non-perc.)
163
	uint8_t eg_sh_rs{0};    // (release state for perc.mode)
164
165
	uint8_t ar{0};	// attack rate: AR<<2
166
	uint8_t dr{0};	// decay rate:  DR<<2
167
	uint8_t rr{0};	// release rate:RR<<2
168
	uint8_t KSR{0};	// key scale rate
169
	uint8_t ksl{0};	// key scale level
170
	uint8_t mul{0};	// multiple: mul_tab[ML]
171
172
	// LFO
173
	uint8_t AMmask{0}; // LFO Amplitude Modulation enable mask
174
	uint8_t vib{0};    // LFO Phase Modulation enable flag (active high)
175
};
176
177
class Channel
178
{
179
public:
180
	/** Calculate the value of the current sample produced by this channel.
181
	 */
182
	[[nodiscard]] int calcOutput(unsigned eg_cnt, unsigned lfo_pm, unsigned lfo_am, int fm);
183
184
	/** Sets the frequency for this channel.
185
	 */
186
	void setFrequency(int block_fnum);
187
188
	/** Changes the lower 8 bits of the frequency for this channel.
189
	 */
190
	void setFrequencyLow(uint8_t value);
191
192
	/** Changes the higher 4 bits of the frequency for this channel.
193
	 */
194
	void setFrequencyHigh(uint8_t value);
195
196
	/** Sets some synthesis parameters as specified by the instrument.
197
	 * @param part Part [0..7] of the instrument.
198
	 * @param value New value for this part.
199
	 */
200
	void updateInstrumentPart(int part, uint8_t value);
201
202
	/** Sets all synthesis parameters as specified by the instrument.
203
	 * @param inst Instrument data.
204
	 */
205
	void updateInstrument(std::span<const uint8_t, 8> inst);
206
207
	[[nodiscard]] int getBlockFNum() const;
208
	[[nodiscard]] FreqIndex getFrequencyIncrement() const;
209
	[[nodiscard]] int getKeyScaleLevelBase() const;
210
	[[nodiscard]] uint8_t getKeyCode() const;
211
	[[nodiscard]] bool isSustained() const;
212
	void setSustain(bool sustained);
213
214
	template<typename Archive>
215
	void serialize(Archive& ar, unsigned version);
216
217
	Slot mod;
218
	Slot car;
219
220
private:
221
	// phase generator state
222
	int block_fnum{0}; // block+fnum
223
	FreqIndex fc{0};   // Freq. increment base
224
	int ksl_base{0};   // KeyScaleLevel Base step
225
	bool sus{false};   // sus on/off (release speed in percussive mode)
226
};
227
228
class YM2413 final : public YM2413Core
229
{
230
public:
231
	YM2413();
232
233
	// YM2413Core
234
	void reset() override;
235
	void writePort(bool port, uint8_t value, int offset) override;
236
	void pokeReg(uint8_t reg, uint8_t value) override;
237
	[[nodiscard]] std::span<const uint8_t, 64> peekRegs() const override;
238
	void generateChannels(std::span<float*, 9 + 5> bufs, unsigned num) override;
239
	[[nodiscard]] float getAmplificationFactor() const override;
240
241
	template<typename Archive>
242
	void serialize(Archive& ar, unsigned version);
243
244
private:
245
	void writeReg(uint8_t reg, uint8_t value);
246
247
	/** Reset operator parameters.
248
	 */
249
	void resetOperators();
250
251
	[[nodiscard]] bool isRhythm() const;
252
253
	[[nodiscard]] Channel& getChannelForReg(uint8_t reg);
254
255
	/** Called when the custom instrument (instrument 0) has changed.
256
	 * @param part Part [0..7] of the instrument.
257
	 * @param value The new value.
258
	 */
259
	void updateCustomInstrument(int part, uint8_t value);
260
261
	void setRhythmFlags(uint8_t old);
262
263
private:
264
	/** OPLL chips have 9 channels. */
265
	std::array<Channel, 9> channels;
266
267
	/** Global envelope generator counter. */
268
	unsigned eg_cnt;
269
270
	/** Random generator for noise: 23 bit shift register. */
271
	int noise_rng;
272
273
	/** Number of samples the output was completely silent. */
274
	unsigned idleSamples;
275
276
	using LFOAMIndex = FixedPoint< 6>;
277
	using LFOPMIndex = FixedPoint<10>;
278
	LFOAMIndex lfo_am_cnt{0};
279
	LFOPMIndex lfo_pm_cnt{0};
280
281
	/** Instrument settings:
282
	 *  0     - user instrument
283
	 *  1-15  - fixed instruments
284
	 *  16    - bass drum settings
285
	 *  17-18 - other percussion instruments
286
	 */
287
	std::array<std::array<uint8_t, 8>, 19> inst_tab;
288
289
	/** Registers */
290
	std::array<uint8_t, 0x40> reg;
291
	uint8_t registerLatch;
292
};
293
294
} // namespace YM2413Burczynski
295
296
SERIALIZE_CLASS_VERSION(YM2413Burczynski::YM2413, 4);
297
SERIALIZE_CLASS_VERSION(YM2413Burczynski::Channel, 3);
298
SERIALIZE_CLASS_VERSION(YM2413Burczynski::Slot, 2);
299
300
} // namespace openmsx
301
302
#endif