OXYGENHUB
◆ main openmsx / src / sound / YM2151.hh
7.3 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
/*
2
 **
3
 ** File: ym2151.h - header file for software implementation of YM2151
4
 **                                            FM Operator Type-M(OPM)
5
 **
6
 ** (c) 1997-2002 Jarek Burczynski ([email protected], [email protected])
7
 ** Some of the optimizing ideas by Tatsuyuki Satoh
8
 **
9
 ** Version 2.150 final beta May, 11th 2002
10
 **
11
 **
12
 ** I would like to thank following people for making this project possible:
13
 **
14
 ** Beauty Planets - for making a lot of real YM2151 samples and providing
15
 ** additional informations about the chip. Also for the time spent making
16
 ** the samples and the speed of replying to my endless requests.
17
 **
18
 ** Shigeharu Isoda - for general help, for taking time to scan his YM2151
19
 ** Japanese Manual first of all, and answering MANY of my questions.
20
 **
21
 ** Nao - for giving me some info about YM2151 and pointing me to Shigeharu.
22
 ** Also for creating fmemu (which I still use to test the emulator).
23
 **
24
 ** Aaron Giles and Chris Hardy - they made some samples of one of my favorite
25
 ** arcade games so I could compare it to my emulator.
26
 **
27
 ** Bryan McPhail and Tim (powerjaw) - for making some samples.
28
 **
29
 ** Ishmair - for the datasheet and motivation.
30
 */
31
32
// YM2164/OPP specifics info from http://map.grauw.nl/resources/sound/yamaha_ym2164.php
33
34
#ifndef YM2151_HH
35
#define YM2151_HH
36
37
#include "EmuTimer.hh"
38
#include "ResampledSoundDevice.hh"
39
40
#include "EmuTime.hh"
41
#include "IRQHelper.hh"
42
43
#include <array>
44
#include <cstdint>
45
#include <memory>
46
#include <string>
47
48
namespace openmsx {
49
50
class DeviceConfig;
51
52
class YM2151 final : public ResampledSoundDevice, private EmuTimerCallback
53
{
54
public:
55
	enum class Variant : char {
56
	    YM2151,   // aka OPM
57
	    YM2164,   // aka OPP
58
	};
59
60
	YM2151(const std::string& name, static_string_view desc,
61
	       const DeviceConfig& config, EmuTime time, Variant variant);
62
	~YM2151();
63
64
	void reset(EmuTime time);
65
	void writeReg(uint8_t r, uint8_t v, EmuTime time);
66
	[[nodiscard]] uint8_t readStatus() const;
67
68
	template<typename Archive>
69
	void serialize(Archive& ar, unsigned version);
70
71
private:
72
	// a single operator
73
	struct YM2151Operator {
74
		template<typename Archive>
75
		void serialize(Archive& ar, unsigned version);
76
77
		int* connect;      // operator output 'direction'
78
		int* mem_connect;  // where to put the delayed sample (MEM)
79
80
		unsigned phase;    // accumulated operator phase
81
		unsigned freq;     // operator frequency count
82
		int dt1;           // current DT1 (detune 1 phase inc/decrement) value
83
		unsigned mul;      // frequency count multiply
84
		unsigned dt1_i;    // DT1 index * 32
85
		unsigned dt2;      // current DT2 (detune 2) value
86
87
		int mem_value;     // delayed sample (MEM) value
88
89
		// channel specific data
90
		// note: each operator number 0 contains channel specific data
91
		unsigned fb_shift; // feedback shift value for operators 0 in each channel
92
		int fb_out_curr;   // operator feedback value (used only by operators 0)
93
		int fb_out_prev;   // previous feedback value (used only by operators 0)
94
		unsigned kc;       // channel KC (copied to all operators)
95
		unsigned kc_i;     // just for speedup
96
		int8_t pms;        // channel PMS  0..7
97
		unsigned ams;      // channel AMS
98
99
		unsigned AMmask;   // LFO Amplitude Modulation enable mask
100
		unsigned state;    // Envelope state: 4-attack(AR)
101
		                   //                 3-decay(D1R)
102
		                   //                 2-sustain(D2R)
103
		                   //                 1-release(RR)
104
		                   //                 0-off
105
		unsigned tl;       // Total attenuation Level
106
		int volume;        // current envelope attenuation level
107
		unsigned d1l;      // envelope switches to sustain state after
108
109
		unsigned key;      // 0=last key was KEY OFF, 1=last key was KEY ON
110
111
		unsigned ks;       // key scale
112
		unsigned ar;       // attack rate
113
		unsigned d1r;      // decay rate
114
		unsigned d2r;      // sustain rate
115
		unsigned rr;       // release rate
116
117
		uint8_t eg_sh_ar;     //  (attack state)
118
		uint8_t eg_sel_ar;    //  (attack state)
119
		uint8_t eg_sh_d1r;    //  (decay state)
120
		uint8_t eg_sel_d1r;   //  (decay state)
121
		                   // reaching this level
122
		uint8_t eg_sh_d2r;    //  (sustain state)
123
		uint8_t eg_sel_d2r;   //  (sustain state)
124
		uint8_t eg_sh_rr;     //  (release state)
125
		uint8_t eg_sel_rr;    //  (release state)
126
	};
127
128
	void setConnect(std::span<YM2151Operator, 4> o, int cha, int v);
129
130
	// SoundDevice
131
	void generateChannels(std::span<float*> bufs, unsigned num) override;
132
133
	void callback(uint8_t flag) override;
134
	void setStatus(uint8_t flags);
135
	void resetStatus(uint8_t flags);
136
137
	// operator methods
138
	void envelopeKONKOFF(std::span<YM2151Operator, 4> op, int v) const;
139
	static void refreshEG(std::span<YM2151Operator, 4> op);
140
	[[nodiscard]] int opCalc(const YM2151Operator& op, unsigned env, int pm) const;
141
	[[nodiscard]] int opCalc1(const YM2151Operator& op, unsigned env, int pm) const;
142
	[[nodiscard]] inline unsigned volumeCalc(const YM2151Operator& op, unsigned AM) const;
143
	inline void keyOn(YM2151Operator& op, unsigned keySet) const;
144
	inline void keyOff(YM2151Operator& op, unsigned keyClear) const;
145
146
	// general chip methods
147
	void chanCalc(unsigned chan);
148
	void chan7Calc();
149
150
	void advanceEG();
151
	void advance();
152
153
	[[nodiscard]] bool checkMuteHelper();
154
155
	IRQHelper irq;
156
157
	// Timers (see EmuTimer class for details about timing)
158
	const std::unique_ptr<EmuTimer> timer1;
159
	const std::unique_ptr<EmuTimer> timer2;
160
161
	std::array<YM2151Operator, 32> oper; // the 32 operators
162
163
	std::array<unsigned, 16> pan; // channels output masks (0xffffffff = enable)
164
165
	unsigned eg_cnt;         // global envelope generator counter
166
	unsigned eg_timer;       // global envelope generator counter
167
	                         //   works at frequency = chip-clock / (64 * 3)
168
	unsigned lfo_phase;      // accumulated LFO phase (0 to 255)
169
	unsigned lfo_timer;      // LFO timer
170
	unsigned lfo_overflow;   // LFO generates new output when lfo_timer
171
	                         // reaches this value
172
	unsigned lfo_counter;    // LFO phase increment counter
173
	unsigned lfo_counter_add;// step of lfo_counter
174
	unsigned lfa;            // LFO current AM output
175
	int lfp;                 // LFO current PM output
176
177
	unsigned noise;          // noise enable/period register
178
	                         // bit 7 - noise enable, bits 4-0 - noise period
179
	unsigned noise_rng;      // 17 bit noise shift register
180
	int noise_p;             // current noise 'phase'
181
	int noise_f;             // current noise period
182
183
	unsigned csm_req;        // CSM  KEY ON / KEY OFF sequence request
184
185
	unsigned irq_enable;     // IRQ enable for timer B (bit 3) and timer A
186
	                         // (bit 2); bit 7 - CSM mode (keyon to all
187
	                         // slots, every time timer A overflows)
188
	uint8_t status;          // chip status (BUSY, IRQ Flags)
189
190
	std::array<int, 8> chanOut;
191
	int m2, c1, c2;          // Phase Modulation input for operators 2,3,4
192
	int mem;                 // one sample delay memory
193
194
	uint16_t timer_A_val{0};
195
196
	uint8_t lfo_wsel;        // LFO waveform (0-saw, 1-square, 2-triangle,
197
	                         //               3-random noise)
198
	uint8_t amd;             // LFO Amplitude Modulation Depth
199
	int8_t pmd;              // LFO Phase Modulation Depth
200
201
	uint8_t test;            // TEST register
202
	uint8_t ct;              // output control pins (bit1-CT2, bit0-CT1)
203
204
	std::array<uint8_t, 256> regs = {}; // only used for serialization ATM
205
	const Variant variant;   // Whether we're emulating YM2151 or YM2164
206
};
207
208
} // namespace openmsx
209
210
#endif