openMSX
YM2151.hh
Go to the documentation of this file.
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 (s0246@poczta.onet.pl, bujar@mame.net)
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
38#include "EmuTimer.hh"
39#include "EmuTime.hh"
40#include "IRQHelper.hh"
41#include <array>
42#include <cstdint>
43#include <string>
44#include <memory>
45
46namespace openmsx {
47
48class DeviceConfig;
49
50class YM2151 final : public ResampledSoundDevice, private EmuTimerCallback
51{
52public:
53 enum class Variant : char {
54 YM2151, // aka OPM
55 YM2164, // aka OPP
56 };
57
58 YM2151(const std::string& name, static_string_view desc,
59 const DeviceConfig& config, EmuTime::param time, Variant variant);
60 ~YM2151();
61
62 void reset(EmuTime::param time);
63 void writeReg(uint8_t r, uint8_t v, EmuTime::param time);
64 [[nodiscard]] uint8_t readStatus() const;
65
66 template<typename Archive>
67 void serialize(Archive& ar, unsigned version);
68
69private:
70 // a single operator
71 struct YM2151Operator {
72 template<typename Archive>
73 void serialize(Archive& ar, unsigned version);
74
75 int* connect; // operator output 'direction'
76 int* mem_connect; // where to put the delayed sample (MEM)
77
78 unsigned phase; // accumulated operator phase
79 unsigned freq; // operator frequency count
80 int dt1; // current DT1 (detune 1 phase inc/decrement) value
81 unsigned mul; // frequency count multiply
82 unsigned dt1_i; // DT1 index * 32
83 unsigned dt2; // current DT2 (detune 2) value
84
85 int mem_value; // delayed sample (MEM) value
86
87 // channel specific data
88 // note: each operator number 0 contains channel specific data
89 unsigned fb_shift; // feedback shift value for operators 0 in each channel
90 int fb_out_curr; // operator feedback value (used only by operators 0)
91 int fb_out_prev; // previous feedback value (used only by operators 0)
92 unsigned kc; // channel KC (copied to all operators)
93 unsigned kc_i; // just for speedup
94 int8_t pms; // channel PMS 0..7
95 unsigned ams; // channel AMS
96
97 unsigned AMmask; // LFO Amplitude Modulation enable mask
98 unsigned state; // Envelope state: 4-attack(AR)
99 // 3-decay(D1R)
100 // 2-sustain(D2R)
101 // 1-release(RR)
102 // 0-off
103 unsigned tl; // Total attenuation Level
104 int volume; // current envelope attenuation level
105 unsigned d1l; // envelope switches to sustain state after
106
107 unsigned key; // 0=last key was KEY OFF, 1=last key was KEY ON
108
109 unsigned ks; // key scale
110 unsigned ar; // attack rate
111 unsigned d1r; // decay rate
112 unsigned d2r; // sustain rate
113 unsigned rr; // release rate
114
115 uint8_t eg_sh_ar; // (attack state)
116 uint8_t eg_sel_ar; // (attack state)
117 uint8_t eg_sh_d1r; // (decay state)
118 uint8_t eg_sel_d1r; // (decay state)
119 // reaching this level
120 uint8_t eg_sh_d2r; // (sustain state)
121 uint8_t eg_sel_d2r; // (sustain state)
122 uint8_t eg_sh_rr; // (release state)
123 uint8_t eg_sel_rr; // (release state)
124 };
125
126 void setConnect(std::span<YM2151Operator, 4> o, int cha, int v);
127
128 // SoundDevice
129 void generateChannels(std::span<float*> bufs, unsigned num) override;
130
131 void callback(uint8_t flag) override;
132 void setStatus(uint8_t flags);
133 void resetStatus(uint8_t flags);
134
135 // operator methods
136 void envelopeKONKOFF(std::span<YM2151Operator, 4> op, int v);
137 static void refreshEG(std::span<YM2151Operator, 4> op);
138 [[nodiscard]] int opCalc(YM2151Operator& op, unsigned env, int pm);
139 [[nodiscard]] int opCalc1(YM2151Operator& op, unsigned env, int pm);
140 [[nodiscard]] inline unsigned volumeCalc(YM2151Operator& op, unsigned AM);
141 inline void keyOn(YM2151Operator& op, unsigned keySet);
142 inline void keyOff(YM2151Operator& op, unsigned keyClear);
143
144 // general chip methods
145 void chanCalc(unsigned chan);
146 void chan7Calc();
147
148 void advanceEG();
149 void advance();
150
151 [[nodiscard]] bool checkMuteHelper();
152
153 IRQHelper irq;
154
155 // Timers (see EmuTimer class for details about timing)
156 const std::unique_ptr<EmuTimer> timer1;
157 const std::unique_ptr<EmuTimer> timer2;
158
159 std::array<YM2151Operator, 32> oper; // the 32 operators
160
161 std::array<unsigned, 16> pan; // channels output masks (0xffffffff = enable)
162
163 unsigned eg_cnt; // global envelope generator counter
164 unsigned eg_timer; // global envelope generator counter
165 // works at frequency = chip-clock / (64 * 3)
166 unsigned lfo_phase; // accumulated LFO phase (0 to 255)
167 unsigned lfo_timer; // LFO timer
168 unsigned lfo_overflow; // LFO generates new output when lfo_timer
169 // reaches this value
170 unsigned lfo_counter; // LFO phase increment counter
171 unsigned lfo_counter_add;// step of lfo_counter
172 unsigned lfa; // LFO current AM output
173 int lfp; // LFO current PM output
174
175 unsigned noise; // noise enable/period register
176 // bit 7 - noise enable, bits 4-0 - noise period
177 unsigned noise_rng; // 17 bit noise shift register
178 int noise_p; // current noise 'phase'
179 int noise_f; // current noise period
180
181 unsigned csm_req; // CSM KEY ON / KEY OFF sequence request
182
183 unsigned irq_enable; // IRQ enable for timer B (bit 3) and timer A
184 // (bit 2); bit 7 - CSM mode (keyon to all
185 // slots, every time timer A overflows)
186 uint8_t status; // chip status (BUSY, IRQ Flags)
187
188 std::array<int, 8> chanOut;
189 int m2, c1, c2; // Phase Modulation input for operators 2,3,4
190 int mem; // one sample delay memory
191
192 uint16_t timer_A_val{0};
193
194 uint8_t lfo_wsel; // LFO waveform (0-saw, 1-square, 2-triangle,
195 // 3-random noise)
196 uint8_t amd; // LFO Amplitude Modulation Depth
197 int8_t pmd; // LFO Phase Modulation Depth
198
199 uint8_t test; // TEST register
200 uint8_t ct; // output control pins (bit1-CT2, bit0-CT1)
201
202 std::array<uint8_t, 256> regs = {}; // only used for serialization ATM
203 const Variant variant; // Whether we're emulating YM2151 or YM2164
204};
205
206} // namespace openmsx
207
208#endif
uint8_t readStatus() const
Definition YM2151.cc:1532
void reset(EmuTime::param time)
Definition YM2151.cc:924
void serialize(Archive &ar, unsigned version)
Definition YM2151.cc:1597
void writeReg(uint8_t r, uint8_t v, EmuTime::param time)
Definition YM2151.cc:648
static_string_view
This file implemented 3 utility functions:
Definition Autofire.cc:9
void serialize(Archive &ar, T &t, unsigned version)
IntHelper< IRQSource > IRQHelper
Definition IRQHelper.hh:122