58[[nodiscard]]
static constexpr YMF262::FreqIndex fnumToIncrement(
unsigned block_fnum)
62 int block = narrow<int>((block_fnum & 0x1C00) >> 10);
67static constexpr int ENV_BITS = 10;
68static constexpr int ENV_LEN = 1 << ENV_BITS;
69static constexpr double ENV_STEP = 128.0 / ENV_LEN;
71static constexpr int MAX_ATT_INDEX = (1 << (ENV_BITS - 1)) - 1;
72static constexpr int MIN_ATT_INDEX = 0;
74static constexpr int TL_RES_LEN = 256;
77static constexpr uint8_t MOD = 0;
78static constexpr uint8_t CAR = 1;
82static constexpr std::array<int, 32> slot_array = {
83 0, 2, 4, 1, 3, 5, -1, -1,
84 6, 8, 10, 7, 9, 11, -1, -1,
85 12, 14, 16, 13, 15, 17, -1, -1,
86 -1, -1, -1, -1, -1, -1, -1, -1
94[[nodiscard]]
static constexpr int DV(
double x) {
return int(x / (0.1875 / 2.0)); }
95static constexpr std::array<unsigned, 8 * 16> ksl_tab = {
97 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
98 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
99 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
100 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
102 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
103 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
104 DV( 0.000), DV( 0.750), DV( 1.125), DV( 1.500),
105 DV( 1.875), DV( 2.250), DV( 2.625), DV( 3.000),
107 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
108 DV( 0.000), DV( 1.125), DV( 1.875), DV( 2.625),
109 DV( 3.000), DV( 3.750), DV( 4.125), DV( 4.500),
110 DV( 4.875), DV( 5.250), DV( 5.625), DV( 6.000),
112 DV( 0.000), DV( 0.000), DV( 0.000), DV( 1.875),
113 DV( 3.000), DV( 4.125), DV( 4.875), DV( 5.625),
114 DV( 6.000), DV( 6.750), DV( 7.125), DV( 7.500),
115 DV( 7.875), DV( 8.250), DV( 8.625), DV( 9.000),
117 DV( 0.000), DV( 0.000), DV( 3.000), DV( 4.875),
118 DV( 6.000), DV( 7.125), DV( 7.875), DV( 8.625),
119 DV( 9.000), DV( 9.750), DV(10.125), DV(10.500),
120 DV(10.875), DV(11.250), DV(11.625), DV(12.000),
122 DV( 0.000), DV( 3.000), DV( 6.000), DV( 7.875),
123 DV( 9.000), DV(10.125), DV(10.875), DV(11.625),
124 DV(12.000), DV(12.750), DV(13.125), DV(13.500),
125 DV(13.875), DV(14.250), DV(14.625), DV(15.000),
127 DV( 0.000), DV( 6.000), DV( 9.000), DV(10.875),
128 DV(12.000), DV(13.125), DV(13.875), DV(14.625),
129 DV(15.000), DV(15.750), DV(16.125), DV(16.500),
130 DV(16.875), DV(17.250), DV(17.625), DV(18.000),
132 DV( 0.000), DV( 9.000), DV(12.000), DV(13.875),
133 DV(15.000), DV(16.125), DV(16.875), DV(17.625),
134 DV(18.000), DV(18.750), DV(19.125), DV(19.500),
135 DV(19.875), DV(20.250), DV(20.625), DV(21.000)
140[[nodiscard]]
static constexpr int SC(
int db) {
return int(db * (2.0 / ENV_STEP)); }
141static constexpr std::array<int, 16> sl_tab = {
142 SC( 0), SC( 1), SC( 2), SC(3 ), SC(4 ), SC(5 ), SC(6 ), SC( 7),
143 SC( 8), SC( 9), SC(10), SC(11), SC(12), SC(13), SC(14), SC(31)
147static constexpr uint8_t RATE_STEPS = 8;
148static constexpr std::array<uint8_t, 15 * RATE_STEPS> eg_inc = {
172[[nodiscard]]
static constexpr uint8_t O(
int a) {
return narrow<uint8_t>(a * RATE_STEPS); }
173static constexpr std::array<uint8_t, 16 + 64 + 16> eg_rate_select = {
176 O(14), O(14), O(14), O(14), O(14), O(14), O(14), O(14),
177 O(14), O(14), O(14), O(14), O(14), O(14), O(14), O(14),
180 O( 0), O( 1), O( 2), O( 3),
181 O( 0), O( 1), O( 2), O( 3),
182 O( 0), O( 1), O( 2), O( 3),
183 O( 0), O( 1), O( 2), O( 3),
184 O( 0), O( 1), O( 2), O( 3),
185 O( 0), O( 1), O( 2), O( 3),
186 O( 0), O( 1), O( 2), O( 3),
187 O( 0), O( 1), O( 2), O( 3),
188 O( 0), O( 1), O( 2), O( 3),
189 O( 0), O( 1), O( 2), O( 3),
190 O( 0), O( 1), O( 2), O( 3),
191 O( 0), O( 1), O( 2), O( 3),
192 O( 0), O( 1), O( 2), O( 3),
195 O( 4), O( 5), O( 6), O( 7),
198 O( 8), O( 9), O(10), O(11),
201 O(12), O(12), O(12), O(12),
204 O(12), O(12), O(12), O(12), O(12), O(12), O(12), O(12),
205 O(12), O(12), O(12), O(12), O(12), O(12), O(12), O(12),
211static constexpr std::array<uint8_t, 16 + 64 + 16> eg_rate_shift =
215 0, 0, 0, 0, 0, 0, 0, 0,
216 0, 0, 0, 0, 0, 0, 0, 0,
237 0, 0, 0, 0, 0, 0, 0, 0,
238 0, 0, 0, 0, 0, 0, 0, 0,
243[[nodiscard]]
static constexpr uint8_t ML(
double x) {
return uint8_t(2 * x); }
244static constexpr std::array<uint8_t, 16> mul_tab = {
246 ML( 0.5), ML( 1.0), ML( 2.0), ML( 3.0),
247 ML( 4.0), ML( 5.0), ML( 6.0), ML( 7.0),
248 ML( 8.0), ML( 9.0), ML(10.0), ML(10.0),
249 ML(12.0), ML(12.0), ML(15.0), ML(15.0)
264static constexpr unsigned LFO_AM_TAB_ELEMENTS = 210;
265static constexpr std::array<uint8_t, LFO_AM_TAB_ELEMENTS> lfo_am_table = {
322static constexpr std::array<int8_t, 8 * 8 * 2> lfo_pm_table = {
324 0, 0, 0, 0, 0, 0, 0, 0,
325 0, 0, 0, 0, 0, 0, 0, 0,
328 0, 0, 0, 0, 0, 0, 0, 0,
329 1, 0, 0, 0,-1, 0, 0, 0,
332 1, 0, 0, 0,-1, 0, 0, 0,
333 2, 1, 0,-1,-2,-1, 0, 1,
336 1, 0, 0, 0,-1, 0, 0, 0,
337 3, 1, 0,-1,-3,-1, 0, 1,
340 2, 1, 0,-1,-2,-1, 0, 1,
341 4, 2, 0,-2,-4,-2, 0, 2,
344 2, 1, 0,-1,-2,-1, 0, 1,
345 5, 2, 0,-2,-5,-2, 0, 2,
348 3, 1, 0,-1,-3,-1, 0, 1,
349 6, 3, 0,-3,-6,-3, 0, 3,
352 3, 1, 0,-1,-3,-1, 0, 1,
353 7, 3, 0,-3,-7,-3, 0, 3
363static constexpr int TL_TAB_LEN = 13 * 2 * TL_RES_LEN;
364static constexpr int ENV_QUIET = TL_TAB_LEN >> 4;
366static constexpr auto tlTab = [] {
367 std::array<int, TL_TAB_LEN> result = {};
369 for (
auto x :
xrange(TL_RES_LEN)) {
370 double m = (1 << 16) / cstd::exp2<6>((x + 1) * (ENV_STEP / 4.0) / 8.0);
376 n = (n >> 1) + (n & 1);
379 result[x * 2 + 0] = n;
380 result[x * 2 + 1] = ~result[x * 2 + 0];
382 for (
int i :
xrange(1, 13)) {
383 result[x * 2 + 0 + i * 2 * TL_RES_LEN] =
384 result[x * 2 + 0] >> i;
385 result[x * 2 + 1 + i * 2 * TL_RES_LEN] =
386 ~result[x * 2 + 0 + i * 2 * TL_RES_LEN];
396 std::array<std::array<unsigned, YMF262::SIN_LEN>, 8>
tab;
399static constexpr SinTab getSinTab()
406 for (
auto i :
xrange(SIN_LEN / 4)) {
408 double m = cstd::sin<2>(((i * 2) + 1) *
Math::pi / SIN_LEN);
410 double o = -8.0 * cstd::log2<11, 3>(m);
411 o = o / (double(ENV_STEP) / 4);
414 n = (n >> 1) + (n & 1);
415 sin.
tab[0][i] = 2 * n;
417 for (
auto i :
xrange(SIN_LEN / 4)) {
418 sin.
tab[0][SIN_LEN / 2 - 1 - i] = sin.
tab[0][i];
420 for (
auto i :
xrange(SIN_LEN / 2)) {
421 sin.
tab[0][SIN_LEN / 2 + i] = sin.
tab[0][i] + 1;
424 for (
auto i :
xrange(SIN_LEN)) {
429 sin.
tab[1][i] = (i & (1 << (SIN_BITS - 1)))
436 sin.
tab[2][i] = sin.
tab[0][i & (SIN_MASK >> 1)];
441 sin.
tab[3][i] = (i & (1 << (SIN_BITS - 2)))
443 : sin.tab[0][i & (SIN_MASK>>2)];
449 sin.
tab[4][i] = (i & (1 << (SIN_BITS - 1)))
457 sin.
tab[5][i] = (i & (1 << (SIN_BITS - 1)))
459 : sin.tab[0][(i * 2) & (SIN_MASK >> 1)];
465 sin.
tab[6][i] = (i & (1 << (SIN_BITS - 1)))
472 int x = (i & (1 << (SIN_BITS - 1)))
473 ? ((SIN_LEN - 1) - i) * 16 + 1
475 x = std::min(x, TL_TAB_LEN);
482static constexpr SinTab sin = getSinTab();
486static int phase_modulation;
487static int phase_modulation2;
492 : waveTable(sin.tab[0])
497void YMF262::callback(uint8_t flag)
503void YMF262::setStatus(uint8_t flag)
507 if (status & statusMask) {
514void YMF262::resetStatus(uint8_t flag)
518 if (!(status & statusMask)) {
525void YMF262::changeStatusMask(uint8_t flag)
528 status &= statusMask;
538void YMF262::Slot::advanceEnvelopeGenerator(
unsigned egCnt)
542 if (!(egCnt & eg_m_ar)) {
543 volume += (~volume * eg_inc[eg_sel_ar + ((egCnt >> eg_sh_ar) & 7)]) >> 3;
544 if (volume <= MIN_ATT_INDEX) {
545 volume = MIN_ATT_INDEX;
552 if (!(egCnt & eg_m_dr)) {
553 volume += eg_inc[eg_sel_dr + ((egCnt >> eg_sh_dr) & 7)];
571 if (!(egCnt & eg_m_rr)) {
572 volume += eg_inc[eg_sel_rr + ((egCnt >> eg_sh_rr) & 7)];
573 if (volume >= MAX_ATT_INDEX) {
574 volume = MAX_ATT_INDEX;
583 if (!(egCnt & eg_m_rr)) {
584 volume += eg_inc[eg_sel_rr + ((egCnt >> eg_sh_rr) & 7)];
585 if (volume >= MAX_ATT_INDEX) {
586 volume = MAX_ATT_INDEX;
597void YMF262::Slot::advancePhaseGenerator(
const Channel& ch,
unsigned lfo_pm)
601 unsigned block_fnum = ch.block_fnum;
602 unsigned fnum_lfo = (block_fnum & 0x0380) >> 7;
603 auto lfo_fn_table_index_offset = narrow_cast<int>(lfo_pm_table[lfo_pm + 16 * fnum_lfo]);
604 Cnt += fnumToIncrement(block_fnum + lfo_fn_table_index_offset) * mul;
612void YMF262::advance()
617 unsigned lfo_pm = (lfo_pm_cnt.
toInt() & 7) | lfo_pm_depth_range;
620 for (
auto& ch : channel) {
621 for (
auto& op : ch.slot) {
622 op.advanceEnvelopeGenerator(eg_cnt);
623 op.advancePhaseGenerator(ch, lfo_pm);
647 noise_rng ^= 0x800302;
652inline int YMF262::Slot::op_calc(
unsigned phase,
unsigned lfo_am)
const
654 unsigned env = (TLL + volume + (lfo_am & AMmask)) << 4;
655 auto p = env + waveTable[phase & SIN_MASK];
656 return (p < TL_TAB_LEN) ? tlTab[p] : 0;
661void YMF262::Channel::chan_calc(
unsigned lfo_am)
684 phase_modulation = 0;
685 phase_modulation2 = 0;
687 auto& mod = slot[MOD];
688 int out = mod.fb_shift
689 ? mod.op1_out[0] + mod.op1_out[1]
691 mod.op1_out[0] = mod.op1_out[1];
692 mod.op1_out[1] = mod.op_calc(mod.Cnt.toInt() + (out >> mod.fb_shift), lfo_am);
693 *mod.connect += mod.op1_out[1];
695 auto& car = slot[CAR];
696 *car.connect += car.op_calc(car.Cnt.toInt() + phase_modulation, lfo_am);
700void YMF262::Channel::chan_calc_ext(
unsigned lfo_am)
712 phase_modulation = 0;
714 auto& mod = slot[MOD];
715 *mod.connect += mod.op_calc(mod.Cnt.toInt() + phase_modulation2, lfo_am);
717 auto& car = slot[CAR];
718 *car.connect += car.op_calc(car.Cnt.toInt() + phase_modulation, lfo_am);
756inline unsigned YMF262::genPhaseHighHat()
763 int op71phase = channel[7].slot[MOD].Cnt.toInt();
764 bool bit7 = (op71phase & 0x80) != 0;
765 bool bit3 = (op71phase & 0x08) != 0;
766 bool bit2 = (op71phase & 0x04) != 0;
767 bool res1 = (bit2 ^ bit7) | bit3;
770 unsigned phase = res1 ? (0x200 | (0xd0 >> 2)) : 0xd0;
773 int op82phase = channel[8].slot[CAR].Cnt.toInt();
774 bool bit5e= (op82phase & 0x20) != 0;
775 bool bit3e= (op82phase & 0x08) != 0;
776 bool res2 = (bit3e ^ bit5e);
780 phase = (0x200 | (0xd0 >> 2));
787 phase = 0x200 | 0xd0;
799inline unsigned YMF262::genPhaseSnare()
804 return ((channel[7].slot[MOD].Cnt.toInt() & 0x100) + 0x100)
805 ^ ((noise_rng & 1) << 8);
808inline unsigned YMF262::genPhaseCymbal()
814 int op82phase = channel[8].slot[CAR].Cnt.toInt();
815 if ((op82phase ^ (op82phase << 2)) & 0x20) {
819 int op71phase = channel[7].slot[MOD].Cnt.toInt();
820 bool bit7 = (op71phase & 0x80) != 0;
821 bool bit3 = (op71phase & 0x08) != 0;
822 bool bit2 = (op71phase & 0x04) != 0;
823 return ((bit2 != bit7) || bit3) ? 0x300 : 0x100;
828void YMF262::chan_calc_rhythm(
unsigned lfo_am)
837 auto& mod6 = channel[6].slot[MOD];
838 int out = mod6.fb_shift ? mod6.op1_out[0] + mod6.op1_out[1] : 0;
839 mod6.op1_out[0] = mod6.op1_out[1];
840 int pm = mod6.CON ? 0 : mod6.op1_out[0];
841 mod6.op1_out[1] = mod6.op_calc(mod6.Cnt.toInt() + (out >> mod6.fb_shift), lfo_am);
842 auto& car6 = channel[6].slot[CAR];
843 chanOut[6] += 2 * car6.op_calc(car6.Cnt.toInt() + pm, lfo_am);
858 auto& mod7 = channel[7].slot[MOD];
859 chanOut[7] += 2 * mod7.op_calc(genPhaseHighHat(), lfo_am);
860 auto& car7 = channel[7].slot[CAR];
861 chanOut[7] += 2 * car7.op_calc(genPhaseSnare(), lfo_am);
862 auto& mod8 = channel[8].slot[MOD];
863 chanOut[8] += 2 * mod8.op_calc(mod8.Cnt.toInt(), lfo_am);
864 auto& car8 = channel[8].slot[CAR];
865 chanOut[8] += 2 * car8.op_calc(genPhaseCymbal(), lfo_am);
868void YMF262::Slot::FM_KEYON(uint8_t key_set)
879void YMF262::Slot::FM_KEYOFF(uint8_t key_clr)
885 if (state != EG_OFF) {
892void YMF262::Slot::update_ar_dr()
894 if ((ar + ksr) < 16 + 60) {
896 eg_sh_ar = eg_rate_shift [ar + ksr];
897 eg_sel_ar = eg_rate_select[ar + ksr];
900 eg_sel_ar = 13 * RATE_STEPS;
902 eg_m_ar = (1 << eg_sh_ar) - 1;
903 eg_sh_dr = eg_rate_shift [dr + ksr];
904 eg_sel_dr = eg_rate_select[dr + ksr];
905 eg_m_dr = (1 << eg_sh_dr) - 1;
907void YMF262::Slot::update_rr()
909 eg_sh_rr = eg_rate_shift [rr + ksr];
910 eg_sel_rr = eg_rate_select[rr + ksr];
911 eg_m_rr = (1 << eg_sh_rr) - 1;
915void YMF262::Slot::calc_fc(
const Channel& ch)
920 auto newKsr = narrow<uint8_t>(ch.kcode >> KSR);
921 if (ksr == newKsr)
return;
929static constexpr std::array<unsigned, 18> channelPairTab = {
930 0, 1, 2, 0, 1, 2, unsigned(~0), unsigned(~0), unsigned(~0),
931 9, 10, 11, 9, 10, 11, unsigned(~0), unsigned(~0), unsigned(~0),
933inline bool YMF262::isExtended(
unsigned ch)
const
936 if (!OPL3_mode)
return false;
937 if (channelPairTab[ch] ==
unsigned(~0))
return false;
938 return channel[channelPairTab[ch]].extended;
940static constexpr unsigned getFirstOfPairNum(
unsigned ch)
942 assert((ch < 18) && (channelPairTab[ch] !=
unsigned(~0)));
943 return channelPairTab[ch];
945inline YMF262::Channel& YMF262::getFirstOfPair(
unsigned ch)
947 return channel[getFirstOfPairNum(ch) + 0];
949inline YMF262::Channel& YMF262::getSecondOfPair(
unsigned ch)
951 return channel[getFirstOfPairNum(ch) + 3];
955void YMF262::set_mul(
unsigned sl, uint8_t v)
957 unsigned chan_no = sl / 2;
958 auto& ch = channel[chan_no];
959 auto& slot = ch.slot[sl & 1];
961 slot.mul = mul_tab[v & 0x0f];
962 slot.KSR = (v & 0x10) ? 0 : 2;
963 slot.eg_type = (v & 0x20) != 0;
964 slot.vib = (v & 0x40) != 0;
965 slot.AMmask = (v & 0x80) ? ~0 : 0;
967 if (isExtended(chan_no)) {
970 slot.calc_fc(getFirstOfPair(chan_no));
978void YMF262::set_ksl_tl(
unsigned sl, uint8_t v)
980 unsigned chan_no = sl / 2;
981 auto& ch = channel[chan_no];
982 auto& slot = ch.slot[sl & 1];
986 static constexpr std::array<uint8_t, 4> ksl_shift = {31, 1, 2, 0};
987 slot.ksl = ksl_shift[v >> 6];
989 slot.TL = (v & 0x3F) << (ENV_BITS - 1 - 7);
991 if (isExtended(chan_no)) {
993 auto& ch0 = getFirstOfPair(chan_no);
994 slot.TLL = slot.TL + (ch0.ksl_base >> slot.ksl);
997 slot.TLL = slot.TL + (ch.ksl_base >> slot.ksl);
1002void YMF262::set_ar_dr(
unsigned sl, uint8_t v)
1004 auto& ch = channel[sl / 2];
1005 auto& slot = ch.slot[sl & 1];
1007 slot.ar = (v >> 4) ? narrow<uint8_t>(16 + ((v >> 4) << 2)) : 0;
1008 slot.dr = (v & 0x0F) ? narrow<uint8_t>(16 + ((v & 0x0F) << 2)) : 0;
1009 slot.update_ar_dr();
1013void YMF262::set_sl_rr(
unsigned sl, uint8_t v)
1015 auto& ch = channel[sl / 2];
1016 auto& slot = ch.slot[sl & 1];
1018 slot.sl = sl_tab[v >> 4];
1019 slot.rr = (v & 0x0F) ? uint8_t(16 + ((v & 0x0F) << 2)) : 0;
1036 if (!OPL3_mode && (r != 0x105)) {
1045 writeRegDirect(r, v, time);
1047void YMF262::writeRegDirect(
unsigned r, uint8_t v, EmuTime::param time)
1051 unsigned ch_offset = (r & 0x100) ? 9 : 0;
1060 timer1->setValue(v);
1064 timer2->setValue(v);
1072 changeStatusMask((~v) & 0x60);
1073 timer1->setStart((v & R04_ST1) != 0, time);
1074 timer2->setStart((v & R04_ST2) != 0, time);
1079 nts = (v & 0x40) != 0;
1088 channel[ 0].extended = (v & 0x01) != 0;
1089 channel[ 1].extended = (v & 0x02) != 0;
1090 channel[ 2].extended = (v & 0x04) != 0;
1091 channel[ 9].extended = (v & 0x08) != 0;
1092 channel[10].extended = (v & 0x10) != 0;
1093 channel[11].extended = (v & 0x20) != 0;
1098 OPL3_mode = v & 0x01;
1105 if ((v & 0x02) && !alreadySignaledNEW2 && isYMF278) {
1107 alreadySignaledNEW2 =
true;
1127 int slot = slot_array[r & 0x1F];
1128 if (slot < 0)
return;
1129 set_mul(slot + ch_offset * 2, v);
1133 int slot = slot_array[r & 0x1F];
1134 if (slot < 0)
return;
1135 set_ksl_tl(slot + ch_offset * 2, v);
1139 int slot = slot_array[r & 0x1F];
1140 if (slot < 0)
return;
1141 set_ar_dr(slot + ch_offset * 2, v);
1145 int slot = slot_array[r & 0x1F];
1146 if (slot < 0)
return;
1147 set_sl_rr(slot + ch_offset * 2, v);
1154 lfo_am_depth = (v & 0x80) != 0;
1155 lfo_pm_depth_range = (v & 0x40) ? 8 : 0;
1158 if (rhythm & 0x20) {
1161 channel[6].slot[MOD].FM_KEYON (2);
1162 channel[6].slot[CAR].FM_KEYON (2);
1164 channel[6].slot[MOD].FM_KEYOFF(2);
1165 channel[6].slot[CAR].FM_KEYOFF(2);
1169 channel[7].slot[MOD].FM_KEYON (2);
1171 channel[7].slot[MOD].FM_KEYOFF(2);
1175 channel[7].slot[CAR].FM_KEYON (2);
1177 channel[7].slot[CAR].FM_KEYOFF(2);
1181 channel[8].slot[MOD].FM_KEYON (2);
1183 channel[8].slot[MOD].FM_KEYOFF(2);
1187 channel[8].slot[CAR].FM_KEYON (2);
1189 channel[8].slot[CAR].FM_KEYOFF(2);
1193 channel[6].slot[MOD].FM_KEYOFF(2);
1194 channel[6].slot[CAR].FM_KEYOFF(2);
1196 channel[7].slot[MOD].FM_KEYOFF(2);
1198 channel[7].slot[CAR].FM_KEYOFF(2);
1200 channel[8].slot[MOD].FM_KEYOFF(2);
1202 channel[8].slot[CAR].FM_KEYOFF(2);
1208 if ((r & 0x0F) > 8) {
1211 unsigned chan_no = (r & 0x0F) + ch_offset;
1212 auto& ch = channel[chan_no];
1216 block_fnum = (ch.block_fnum & 0x1F00) | v;
1219 block_fnum = ((v & 0x1F) << 8) | (ch.block_fnum & 0xFF);
1220 if (isExtended(chan_no)) {
1221 if (getFirstOfPairNum(chan_no) == chan_no) {
1224 auto& ch0 = getFirstOfPair(chan_no);
1225 auto& ch3 = getSecondOfPair(chan_no);
1227 ch0.slot[MOD].FM_KEYON(1);
1228 ch0.slot[CAR].FM_KEYON(1);
1229 ch3.slot[MOD].FM_KEYON(1);
1230 ch3.slot[CAR].FM_KEYON(1);
1232 ch0.slot[MOD].FM_KEYOFF(1);
1233 ch0.slot[CAR].FM_KEYOFF(1);
1234 ch3.slot[MOD].FM_KEYOFF(1);
1235 ch3.slot[CAR].FM_KEYOFF(1);
1243 ch.slot[MOD].FM_KEYON (1);
1244 ch.slot[CAR].FM_KEYON (1);
1246 ch.slot[MOD].FM_KEYOFF(1);
1247 ch.slot[CAR].FM_KEYOFF(1);
1252 if (ch.block_fnum != block_fnum) {
1253 ch.block_fnum = block_fnum;
1254 ch.ksl_base = ksl_tab[block_fnum >> 6];
1255 ch.fc = fnumToIncrement(block_fnum);
1258 ch.kcode = (ch.block_fnum & 0x1C00) >> 9;
1265 ch.kcode |= (ch.block_fnum & 0x100) >> 8;
1267 ch.kcode |= (ch.block_fnum & 0x200) >> 9;
1269 if (isExtended(chan_no)) {
1270 if (getFirstOfPairNum(chan_no) == chan_no) {
1274 auto& ch0 = getFirstOfPair(chan_no);
1275 auto& ch3 = getSecondOfPair(chan_no);
1276 ch0.slot[MOD].TLL = ch0.slot[MOD].TL + (ch.ksl_base >> ch0.slot[MOD].ksl);
1277 ch0.slot[CAR].TLL = ch0.slot[CAR].TL + (ch.ksl_base >> ch0.slot[CAR].ksl);
1278 ch3.slot[MOD].TLL = ch3.slot[MOD].TL + (ch.ksl_base >> ch3.slot[MOD].ksl);
1279 ch3.slot[CAR].TLL = ch3.slot[CAR].TL + (ch.ksl_base >> ch3.slot[CAR].ksl);
1282 ch0.slot[MOD].calc_fc(ch);
1283 ch0.slot[CAR].calc_fc(ch);
1284 ch3.slot[MOD].calc_fc(ch);
1285 ch3.slot[CAR].calc_fc(ch);
1291 ch.slot[MOD].TLL = ch.slot[MOD].TL + (ch.ksl_base >> ch.slot[MOD].ksl);
1292 ch.slot[CAR].TLL = ch.slot[CAR].TL + (ch.ksl_base >> ch.slot[CAR].ksl);
1295 ch.slot[MOD].calc_fc(ch);
1296 ch.slot[CAR].calc_fc(ch);
1303 if ((r & 0xF) > 8) {
1306 unsigned chan_no = (r & 0x0F) + ch_offset;
1307 auto& ch = channel[chan_no];
1309 unsigned base = chan_no * 4;
1312 pan[base + 0] = (v & 0x10) ? ~0 : 0;
1313 pan[base + 1] = (v & 0x20) ? ~0 : 0;
1314 pan[base + 2] = (v & 0x40) ? ~0 : 0;
1315 pan[base + 3] = (v & 0x80) ? ~0 : 0;
1324 ch.slot[MOD].setFeedbackShift((v >> 1) & 7);
1325 ch.slot[MOD].CON = v & 1;
1327 if (isExtended(chan_no)) {
1328 unsigned chan_no0 = getFirstOfPairNum(chan_no);
1329 unsigned chan_no3 = chan_no0 + 3;
1330 auto& ch0 = getFirstOfPair(chan_no);
1331 auto& ch3 = getSecondOfPair(chan_no);
1332 switch ((ch0.slot[MOD].CON ? 2:0) | (ch3.slot[MOD].CON ? 1:0)) {
1335 ch0.slot[MOD].connect = &phase_modulation;
1336 ch0.slot[CAR].connect = &phase_modulation2;
1337 ch3.slot[MOD].connect = &phase_modulation;
1338 ch3.slot[CAR].connect = &chanOut[chan_no3];
1343 ch0.slot[MOD].connect = &phase_modulation;
1344 ch0.slot[CAR].connect = &chanOut[chan_no0];
1345 ch3.slot[MOD].connect = &phase_modulation;
1346 ch3.slot[CAR].connect = &chanOut[chan_no3];
1351 ch0.slot[MOD].connect = &chanOut[chan_no0];
1352 ch0.slot[CAR].connect = &phase_modulation2;
1353 ch3.slot[MOD].connect = &phase_modulation;
1354 ch3.slot[CAR].connect = &chanOut[chan_no3];
1360 ch0.slot[MOD].connect = &chanOut[chan_no0];
1361 ch0.slot[CAR].connect = &phase_modulation2;
1362 ch3.slot[MOD].connect = &chanOut[chan_no3];
1363 ch3.slot[CAR].connect = &chanOut[chan_no3];
1368 ch.slot[MOD].connect = ch.slot[MOD].CON
1370 : &phase_modulation;
1371 ch.slot[CAR].connect = &chanOut[chan_no];
1377 int slot = slot_array[r & 0x1f];
1378 if (slot < 0)
return;
1379 slot += narrow<int>(ch_offset * 2);
1380 auto& ch = channel[slot / 2];
1389 ch.slot[slot & 1].waveTable = sin.
tab[v];
1402 alreadySignaledNEW2 =
false;
1406 writeRegDirect(0x01, 0, time);
1407 writeRegDirect(0x02, 0, time);
1408 writeRegDirect(0x03, 0, time);
1409 writeRegDirect(0x04, 0, time);
1413 for (
int c = 0xFF; c >= 0x20; c--) {
1414 writeRegDirect(c, 0, time);
1417 for (
int c = 0x1FF; c >= 0x120; c--) {
1418 writeRegDirect(c, 0, time);
1422 for (
auto& ch : channel) {
1423 for (
auto& sl : ch.slot) {
1425 sl.volume = MAX_ATT_INDEX;
1432static unsigned calcInputRate(
bool isYMF278)
1434 return unsigned(lrintf(isYMF278 ? 33868800.0f / (19 * 36)
1435 : 4 * 3579545.0f / ( 8 * 36)));
1440 18, calcInputRate(isYMF278_), true)
1441 , debuggable(config.getMotherBoard(), getName())
1443 ?
EmuTimer::createOPL4_1(config.getScheduler(), *this)
1444 :
EmuTimer::createOPL3_1(config.getScheduler(), *this))
1446 ?
EmuTimer::createOPL4_2(config.getScheduler(), *this)
1447 :
EmuTimer::createOPL3_2(config.getScheduler(), *this))
1448 , irq(config.getMotherBoard(), getName() +
".IRQ")
1449 , isYMF278(isYMF278_)
1454 for (
const auto& e : tlTab) std::cout << e <<
'\n';
1456 for (
const auto&
t : sin.
tab) {
1457 for (
const auto& e :
t) {
1458 std::cout << e <<
'\n';
1475 uint8_t result = status | status2;
1482 return status | status2;
1485bool YMF262::checkMuteHelper()
const
1488 for (
auto& ch : channel) {
1489 for (
auto& sl : ch.slot) {
1490 if (!((sl.state ==
EG_OFF) ||
1492 ((narrow<int>(sl.TLL) + sl.volume) >= ENV_QUIET)))) {
1504 static constexpr std::array<float, 8> level = {
1517float YMF262::getAmplificationFactorImpl()
const
1519 return 1.0f / 4096.0f;
1522void YMF262::generateChannels(std::span<float*> bufs,
unsigned num)
1526 if (checkMuteHelper()) {
1532 bool rhythmEnabled = (rhythm & 0x20) != 0;
1534 for (
auto j :
xrange(num)) {
1539 if (lfo_am_cnt == LFOAMIndex(LFO_AM_TAB_ELEMENTS)) {
1541 lfo_am_cnt = LFOAMIndex(0);
1543 unsigned tmp = lfo_am_table[lfo_am_cnt.
toInt()];
1544 unsigned lfo_am = lfo_am_depth ? tmp : tmp / 4;
1551 for (
int k = 0; k <= 9; k += 9) {
1552 for (
auto i :
xrange(3)) {
1553 auto& ch0 = channel[k + i + 0];
1554 auto& ch3 = channel[k + i + 3];
1556 ch0.chan_calc(lfo_am);
1559 ch3.chan_calc_ext(lfo_am);
1562 ch3.chan_calc(lfo_am);
1568 if (!rhythmEnabled) {
1569 channel[6].chan_calc(lfo_am);
1570 channel[7].chan_calc(lfo_am);
1571 channel[8].chan_calc(lfo_am);
1574 chan_calc_rhythm(lfo_am);
1578 channel[15].chan_calc(lfo_am);
1579 channel[16].chan_calc(lfo_am);
1580 channel[17].chan_calc(lfo_am);
1582 for (
auto i :
xrange(18)) {
1583 bufs[i][2 * j + 0] += narrow_cast<float>(chanOut[i] & pan[4 * i + 0]);
1584 bufs[i][2 * j + 1] += narrow_cast<float>(chanOut[i] & pan[4 * i + 1]);
1594static constexpr std::initializer_list<enum_string<YMF262::EnvelopeState>> envelopeStateInfo = {
1603template<
typename Archive>
1604void YMF262::Slot::serialize(Archive& a,
unsigned )
1607 auto waveform = unsigned((waveTable.data() - sin.
tab[0].data()) / SIN_LEN);
1608 a.serialize(
"waveform", waveform);
1609 if constexpr (Archive::IS_LOADER) {
1610 waveTable = sin.
tab[waveform];
1617 a.serialize(
"Cnt", Cnt,
1628 "eg_sh_ar", eg_sh_ar,
1629 "eg_sel_ar", eg_sel_ar,
1630 "eg_sh_dr", eg_sh_dr,
1631 "eg_sel_dr", eg_sel_dr,
1632 "eg_sh_rr", eg_sh_rr,
1633 "eg_sel_rr", eg_sel_rr,
1647template<
typename Archive>
1648void YMF262::Channel::serialize(Archive& a,
unsigned )
1650 a.serialize(
"slots", slot,
1651 "block_fnum", block_fnum,
1653 "ksl_base", ksl_base,
1655 "extended", extended);
1660template<
typename Archive>
1663 a.serialize(
"timer1", *timer1,
1666 "chanout", chanOut);
1667 a.serialize_blob(
"registers", reg);
1668 a.serialize(
"channels", channel,
1670 "noise_rng", noise_rng,
1671 "lfo_am_cnt", lfo_am_cnt,
1672 "lfo_pm_cnt", lfo_pm_cnt,
1673 "lfo_am_depth", lfo_am_depth,
1674 "lfo_pm_depth_range", lfo_pm_depth_range,
1677 "OPL3_mode", OPL3_mode,
1680 "statusMask", statusMask);
1681 if (a.versionAtLeast(version, 2)) {
1682 a.serialize(
"alreadySignaledNEW2", alreadySignaledNEW2);
1684 assert(Archive::IS_LOADER);
1685 alreadySignaledNEW2 =
true;
1691 EmuTime::param time = timer1->getCurrentTime();
1692 for (
auto i :
xrange(0xC0, 0xC9)) {
1693 writeRegDirect(i + 0x000, reg[i + 0x000], time);
1694 writeRegDirect(i + 0x100, reg[i + 0x100], time);
1704 const std::string& name_)
1706 "MoonSound FM-part registers", 0x200)
1710uint8_t YMF262::Debuggable::read(
unsigned address)
1712 auto& ymf262 =
OUTER(YMF262, debuggable);
1713 return ymf262.peekReg(address);
1716void YMF262::Debuggable::write(
unsigned address, uint8_t value, EmuTime::param time)
1718 auto& ymf262 =
OUTER(YMF262, debuggable);
1719 ymf262.writeReg512(address, value, time);
MSXMotherBoard & getMotherBoard() const
constexpr int toInt() const
Returns the integer part (rounded down) of this fixed point number.
constexpr void addQuantum()
Increase this value with the smallest possible amount.
void set()
Set the interrupt request on the bus.
void reset()
Reset the interrupt request on the bus.
EmuTime::param getCurrentTime() const
Convenience method: This is the same as getScheduler().getCurrentTime().
void updateStream(EmuTime::param time)
void setSoftwareVolume(float volume, EmuTime::param time)
Change the 'software volume' of this sound device.
void unregisterSound()
Unregisters this sound device with the Mixer.
void registerSound(const DeviceConfig &config)
Registers this sound device with the Mixer.
static constexpr int SIN_LEN
uint8_t readReg(unsigned reg) const
void reset(EmuTime::param time)
uint8_t peekStatus() const
void setMixLevel(uint8_t x, EmuTime::param time)
YMF262(const std::string &name, const DeviceConfig &config, bool isYMF278)
static constexpr int SIN_BITS
static constexpr int SIN_MASK
FixedPoint< 16 > FreqIndex
16.16 fixed point type for frequency calculations
void serialize(Archive &ar, unsigned version)
void writeReg(unsigned r, uint8_t v, EmuTime::param time)
uint8_t peekReg(unsigned reg) const
void writeReg512(unsigned r, uint8_t v, EmuTime::param time)
FixedPoint< 16 > FreqIndex
16.16 fixed point type for frequency calculations.
This file implemented 3 utility functions:
constexpr void fill(ForwardRange &&range, const T &value)
#define OUTER(type, member)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
#define SERIALIZE_ENUM(TYPE, INFO)
std::array< std::array< unsigned, YMF262::SIN_LEN >, 8 > tab
constexpr auto xrange(T e)