55[[nodiscard]]
static constexpr YMF262::FreqIndex fnumToIncrement(
unsigned block_fnum)
59 int block = narrow<int>((block_fnum & 0x1C00) >> 10);
64static constexpr int ENV_BITS = 10;
65static constexpr int ENV_LEN = 1 << ENV_BITS;
66static constexpr double ENV_STEP = 128.0 / ENV_LEN;
68static constexpr int MAX_ATT_INDEX = (1 << (ENV_BITS - 1)) - 1;
69static constexpr int MIN_ATT_INDEX = 0;
71static constexpr int TL_RES_LEN = 256;
74static constexpr uint8_t MOD = 0;
75static constexpr uint8_t CAR = 1;
79static constexpr std::array<int, 32> slot_array = {
80 0, 2, 4, 1, 3, 5, -1, -1,
81 6, 8, 10, 7, 9, 11, -1, -1,
82 12, 14, 16, 13, 15, 17, -1, -1,
83 -1, -1, -1, -1, -1, -1, -1, -1
91[[nodiscard]]
static constexpr int DV(
double x) {
return int(x / (0.1875 / 2.0)); }
92static constexpr std::array<unsigned, 8 * 16> ksl_tab = {
94 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
95 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
96 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
97 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),
101 DV( 0.000), DV( 0.750), DV( 1.125), DV( 1.500),
102 DV( 1.875), DV( 2.250), DV( 2.625), DV( 3.000),
104 DV( 0.000), DV( 0.000), DV( 0.000), DV( 0.000),
105 DV( 0.000), DV( 1.125), DV( 1.875), DV( 2.625),
106 DV( 3.000), DV( 3.750), DV( 4.125), DV( 4.500),
107 DV( 4.875), DV( 5.250), DV( 5.625), DV( 6.000),
109 DV( 0.000), DV( 0.000), DV( 0.000), DV( 1.875),
110 DV( 3.000), DV( 4.125), DV( 4.875), DV( 5.625),
111 DV( 6.000), DV( 6.750), DV( 7.125), DV( 7.500),
112 DV( 7.875), DV( 8.250), DV( 8.625), DV( 9.000),
114 DV( 0.000), DV( 0.000), DV( 3.000), DV( 4.875),
115 DV( 6.000), DV( 7.125), DV( 7.875), DV( 8.625),
116 DV( 9.000), DV( 9.750), DV(10.125), DV(10.500),
117 DV(10.875), DV(11.250), DV(11.625), DV(12.000),
119 DV( 0.000), DV( 3.000), DV( 6.000), DV( 7.875),
120 DV( 9.000), DV(10.125), DV(10.875), DV(11.625),
121 DV(12.000), DV(12.750), DV(13.125), DV(13.500),
122 DV(13.875), DV(14.250), DV(14.625), DV(15.000),
124 DV( 0.000), DV( 6.000), DV( 9.000), DV(10.875),
125 DV(12.000), DV(13.125), DV(13.875), DV(14.625),
126 DV(15.000), DV(15.750), DV(16.125), DV(16.500),
127 DV(16.875), DV(17.250), DV(17.625), DV(18.000),
129 DV( 0.000), DV( 9.000), DV(12.000), DV(13.875),
130 DV(15.000), DV(16.125), DV(16.875), DV(17.625),
131 DV(18.000), DV(18.750), DV(19.125), DV(19.500),
132 DV(19.875), DV(20.250), DV(20.625), DV(21.000)
137[[nodiscard]]
static constexpr int SC(
int db) {
return int(db * (2.0 / ENV_STEP)); }
138static constexpr std::array<int, 16> sl_tab = {
139 SC( 0), SC( 1), SC( 2), SC(3 ), SC(4 ), SC(5 ), SC(6 ), SC( 7),
140 SC( 8), SC( 9), SC(10), SC(11), SC(12), SC(13), SC(14), SC(31)
144static constexpr uint8_t RATE_STEPS = 8;
145static constexpr std::array<uint8_t, 15 * RATE_STEPS> eg_inc = {
169[[nodiscard]]
static constexpr uint8_t O(
int a) {
return narrow<uint8_t>(a * RATE_STEPS); }
170static constexpr std::array<uint8_t, 16 + 64 + 16> eg_rate_select = {
173 O(14), O(14), O(14), O(14), O(14), O(14), O(14), O(14),
174 O(14), O(14), O(14), O(14), O(14), O(14), O(14), O(14),
177 O( 0), O( 1), O( 2), O( 3),
178 O( 0), O( 1), O( 2), O( 3),
179 O( 0), O( 1), O( 2), O( 3),
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),
192 O( 4), O( 5), O( 6), O( 7),
195 O( 8), O( 9), O(10), O(11),
198 O(12), O(12), O(12), O(12),
201 O(12), O(12), O(12), O(12), O(12), O(12), O(12), O(12),
202 O(12), O(12), O(12), O(12), O(12), O(12), O(12), O(12),
208static constexpr std::array<uint8_t, 16 + 64 + 16> eg_rate_shift =
212 0, 0, 0, 0, 0, 0, 0, 0,
213 0, 0, 0, 0, 0, 0, 0, 0,
234 0, 0, 0, 0, 0, 0, 0, 0,
235 0, 0, 0, 0, 0, 0, 0, 0,
240[[nodiscard]]
static constexpr uint8_t ML(
double x) {
return uint8_t(2 * x); }
241static constexpr std::array<uint8_t, 16> mul_tab = {
243 ML( 0.5), ML( 1.0), ML( 2.0), ML( 3.0),
244 ML( 4.0), ML( 5.0), ML( 6.0), ML( 7.0),
245 ML( 8.0), ML( 9.0), ML(10.0), ML(10.0),
246 ML(12.0), ML(12.0), ML(15.0), ML(15.0)
261static constexpr unsigned LFO_AM_TAB_ELEMENTS = 210;
262static constexpr std::array<uint8_t, LFO_AM_TAB_ELEMENTS> lfo_am_table = {
319static constexpr std::array<int8_t, 8 * 8 * 2> lfo_pm_table = {
321 0, 0, 0, 0, 0, 0, 0, 0,
322 0, 0, 0, 0, 0, 0, 0, 0,
325 0, 0, 0, 0, 0, 0, 0, 0,
326 1, 0, 0, 0,-1, 0, 0, 0,
329 1, 0, 0, 0,-1, 0, 0, 0,
330 2, 1, 0,-1,-2,-1, 0, 1,
333 1, 0, 0, 0,-1, 0, 0, 0,
334 3, 1, 0,-1,-3,-1, 0, 1,
337 2, 1, 0,-1,-2,-1, 0, 1,
338 4, 2, 0,-2,-4,-2, 0, 2,
341 2, 1, 0,-1,-2,-1, 0, 1,
342 5, 2, 0,-2,-5,-2, 0, 2,
345 3, 1, 0,-1,-3,-1, 0, 1,
346 6, 3, 0,-3,-6,-3, 0, 3,
349 3, 1, 0,-1,-3,-1, 0, 1,
350 7, 3, 0,-3,-7,-3, 0, 3
360static constexpr int TL_TAB_LEN = 13 * 2 * TL_RES_LEN;
361static constexpr int ENV_QUIET = TL_TAB_LEN >> 4;
363static constexpr auto tlTab = [] {
364 std::array<int, TL_TAB_LEN> result = {};
366 for (
auto x :
xrange(TL_RES_LEN)) {
367 double m = (1 << 16) / cstd::exp2<6>((x + 1) * (ENV_STEP / 4.0) / 8.0);
373 n = (n >> 1) + (n & 1);
376 result[x * 2 + 0] = n;
377 result[x * 2 + 1] = ~result[x * 2 + 0];
379 for (
int i :
xrange(1, 13)) {
380 result[x * 2 + 0 + i * 2 * TL_RES_LEN] =
381 result[x * 2 + 0] >> i;
382 result[x * 2 + 1 + i * 2 * TL_RES_LEN] =
383 ~result[x * 2 + 0 + i * 2 * TL_RES_LEN];
393 std::array<std::array<unsigned, YMF262::SIN_LEN>, 8>
tab;
396static constexpr SinTab getSinTab()
403 for (
auto i :
xrange(SIN_LEN / 4)) {
405 double m = cstd::sin<2>(((i * 2) + 1) *
Math::pi / SIN_LEN);
407 double o = -8.0 * cstd::log2<11, 3>(m);
408 o = o / (double(ENV_STEP) / 4);
411 n = (n >> 1) + (n & 1);
412 sin.
tab[0][i] = 2 * n;
414 for (
auto i :
xrange(SIN_LEN / 4)) {
415 sin.
tab[0][SIN_LEN / 2 - 1 - i] = sin.
tab[0][i];
417 for (
auto i :
xrange(SIN_LEN / 2)) {
418 sin.
tab[0][SIN_LEN / 2 + i] = sin.
tab[0][i] + 1;
421 for (
auto i :
xrange(SIN_LEN)) {
426 sin.
tab[1][i] = (i & (1 << (SIN_BITS - 1)))
433 sin.
tab[2][i] = sin.
tab[0][i & (SIN_MASK >> 1)];
438 sin.
tab[3][i] = (i & (1 << (SIN_BITS - 2)))
440 : sin.
tab[0][i & (SIN_MASK>>2)];
446 sin.
tab[4][i] = (i & (1 << (SIN_BITS - 1)))
454 sin.
tab[5][i] = (i & (1 << (SIN_BITS - 1)))
456 : sin.
tab[0][(i * 2) & (SIN_MASK >> 1)];
462 sin.
tab[6][i] = (i & (1 << (SIN_BITS - 1)))
469 int x = (i & (1 << (SIN_BITS - 1)))
470 ? ((SIN_LEN - 1) - i) * 16 + 1
479static constexpr SinTab sin = getSinTab();
483static int phase_modulation;
484static int phase_modulation2;
489 : waveTable(sin.tab[0])
494void YMF262::callback(uint8_t flag)
500void YMF262::setStatus(uint8_t flag)
504 if (status & statusMask) {
511void YMF262::resetStatus(uint8_t flag)
515 if (!(status & statusMask)) {
522void YMF262::changeStatusMask(uint8_t flag)
525 status &= statusMask;
535void YMF262::Slot::advanceEnvelopeGenerator(
unsigned egCnt)
539 if (!(egCnt & eg_m_ar)) {
540 volume += (~volume * eg_inc[eg_sel_ar + ((egCnt >> eg_sh_ar) & 7)]) >> 3;
541 if (volume <= MIN_ATT_INDEX) {
542 volume = MIN_ATT_INDEX;
549 if (!(egCnt & eg_m_dr)) {
550 volume += eg_inc[eg_sel_dr + ((egCnt >> eg_sh_dr) & 7)];
568 if (!(egCnt & eg_m_rr)) {
569 volume += eg_inc[eg_sel_rr + ((egCnt >> eg_sh_rr) & 7)];
570 if (volume >= MAX_ATT_INDEX) {
571 volume = MAX_ATT_INDEX;
580 if (!(egCnt & eg_m_rr)) {
581 volume += eg_inc[eg_sel_rr + ((egCnt >> eg_sh_rr) & 7)];
582 if (volume >= MAX_ATT_INDEX) {
583 volume = MAX_ATT_INDEX;
594void YMF262::Slot::advancePhaseGenerator(Channel& ch,
unsigned lfo_pm)
598 unsigned block_fnum = ch.block_fnum;
599 unsigned fnum_lfo = (block_fnum & 0x0380) >> 7;
600 auto lfo_fn_table_index_offset = narrow_cast<int>(lfo_pm_table[lfo_pm + 16 * fnum_lfo]);
601 Cnt += fnumToIncrement(block_fnum + lfo_fn_table_index_offset) * mul;
609void YMF262::advance()
614 unsigned lfo_pm = (lfo_pm_cnt.
toInt() & 7) | lfo_pm_depth_range;
617 for (
auto& ch : channel) {
618 for (
auto& op : ch.slot) {
619 op.advanceEnvelopeGenerator(eg_cnt);
620 op.advancePhaseGenerator(ch, lfo_pm);
644 noise_rng ^= 0x800302;
649inline int YMF262::Slot::op_calc(
unsigned phase,
unsigned lfo_am)
const
651 unsigned env = (TLL + volume + (lfo_am & AMmask)) << 4;
652 auto p = env + waveTable[phase & SIN_MASK];
653 return (p < TL_TAB_LEN) ? tlTab[p] : 0;
658void YMF262::Channel::chan_calc(
unsigned lfo_am)
681 phase_modulation = 0;
682 phase_modulation2 = 0;
684 auto& mod = slot[MOD];
685 int out = mod.fb_shift
686 ? mod.op1_out[0] + mod.op1_out[1]
688 mod.op1_out[0] = mod.op1_out[1];
689 mod.op1_out[1] = mod.op_calc(mod.Cnt.toInt() + (out >> mod.fb_shift), lfo_am);
690 *mod.connect += mod.op1_out[1];
692 auto& car = slot[CAR];
693 *car.connect += car.op_calc(car.Cnt.toInt() + phase_modulation, lfo_am);
697void YMF262::Channel::chan_calc_ext(
unsigned lfo_am)
709 phase_modulation = 0;
711 auto& mod = slot[MOD];
712 *mod.connect += mod.op_calc(mod.Cnt.toInt() + phase_modulation2, lfo_am);
714 auto& car = slot[CAR];
715 *car.connect += car.op_calc(car.Cnt.toInt() + phase_modulation, lfo_am);
753inline unsigned YMF262::genPhaseHighHat()
760 int op71phase = channel[7].slot[MOD].Cnt.toInt();
761 bool bit7 = (op71phase & 0x80) != 0;
762 bool bit3 = (op71phase & 0x08) != 0;
763 bool bit2 = (op71phase & 0x04) != 0;
764 bool res1 = (bit2 ^ bit7) | bit3;
767 unsigned phase = res1 ? (0x200 | (0xd0 >> 2)) : 0xd0;
770 int op82phase = channel[8].slot[CAR].Cnt.toInt();
771 bool bit5e= (op82phase & 0x20) != 0;
772 bool bit3e= (op82phase & 0x08) != 0;
773 bool res2 = (bit3e ^ bit5e);
777 phase = (0x200 | (0xd0 >> 2));
784 phase = 0x200 | 0xd0;
796inline unsigned YMF262::genPhaseSnare()
801 return ((channel[7].slot[MOD].Cnt.toInt() & 0x100) + 0x100)
802 ^ ((noise_rng & 1) << 8);
805inline unsigned YMF262::genPhaseCymbal()
811 int op82phase = channel[8].slot[CAR].Cnt.toInt();
812 if ((op82phase ^ (op82phase << 2)) & 0x20) {
816 int op71phase = channel[7].slot[MOD].Cnt.toInt();
817 bool bit7 = (op71phase & 0x80) != 0;
818 bool bit3 = (op71phase & 0x08) != 0;
819 bool bit2 = (op71phase & 0x04) != 0;
820 return ((bit2 != bit7) || bit3) ? 0x300 : 0x100;
825void YMF262::chan_calc_rhythm(
unsigned lfo_am)
834 auto& mod6 = channel[6].slot[MOD];
835 int out = mod6.fb_shift ? mod6.op1_out[0] + mod6.op1_out[1] : 0;
836 mod6.op1_out[0] = mod6.op1_out[1];
837 int pm = mod6.CON ? 0 : mod6.op1_out[0];
838 mod6.op1_out[1] = mod6.op_calc(mod6.Cnt.toInt() + (out >> mod6.fb_shift), lfo_am);
839 auto& car6 = channel[6].slot[CAR];
840 chanOut[6] += 2 * car6.op_calc(car6.Cnt.toInt() + pm, lfo_am);
855 auto& mod7 = channel[7].slot[MOD];
856 chanOut[7] += 2 * mod7.op_calc(genPhaseHighHat(), lfo_am);
857 auto& car7 = channel[7].slot[CAR];
858 chanOut[7] += 2 * car7.op_calc(genPhaseSnare(), lfo_am);
859 auto& mod8 = channel[8].slot[MOD];
860 chanOut[8] += 2 * mod8.op_calc(mod8.Cnt.toInt(), lfo_am);
861 auto& car8 = channel[8].slot[CAR];
862 chanOut[8] += 2 * car8.op_calc(genPhaseCymbal(), lfo_am);
865void YMF262::Slot::FM_KEYON(uint8_t key_set)
876void YMF262::Slot::FM_KEYOFF(uint8_t key_clr)
882 if (state != EG_OFF) {
889void YMF262::Slot::update_ar_dr()
891 if ((ar + ksr) < 16 + 60) {
893 eg_sh_ar = eg_rate_shift [ar + ksr];
894 eg_sel_ar = eg_rate_select[ar + ksr];
897 eg_sel_ar = 13 * RATE_STEPS;
899 eg_m_ar = (1 << eg_sh_ar) - 1;
900 eg_sh_dr = eg_rate_shift [dr + ksr];
901 eg_sel_dr = eg_rate_select[dr + ksr];
902 eg_m_dr = (1 << eg_sh_dr) - 1;
904void YMF262::Slot::update_rr()
906 eg_sh_rr = eg_rate_shift [rr + ksr];
907 eg_sel_rr = eg_rate_select[rr + ksr];
908 eg_m_rr = (1 << eg_sh_rr) - 1;
912void YMF262::Slot::calc_fc(
const Channel& ch)
917 auto newKsr = narrow<uint8_t>(ch.kcode >> KSR);
918 if (ksr == newKsr)
return;
926static constexpr std::array<unsigned, 18> channelPairTab = {
927 0, 1, 2, 0, 1, 2, unsigned(~0), unsigned(~0), unsigned(~0),
928 9, 10, 11, 9, 10, 11, unsigned(~0), unsigned(~0), unsigned(~0),
930inline bool YMF262::isExtended(
unsigned ch)
const
933 if (!OPL3_mode)
return false;
934 if (channelPairTab[ch] ==
unsigned(~0))
return false;
935 return channel[channelPairTab[ch]].extended;
937static constexpr unsigned getFirstOfPairNum(
unsigned ch)
939 assert((ch < 18) && (channelPairTab[ch] !=
unsigned(~0)));
940 return channelPairTab[ch];
942inline YMF262::Channel& YMF262::getFirstOfPair(
unsigned ch)
944 return channel[getFirstOfPairNum(ch) + 0];
946inline YMF262::Channel& YMF262::getSecondOfPair(
unsigned ch)
948 return channel[getFirstOfPairNum(ch) + 3];
952void YMF262::set_mul(
unsigned sl, uint8_t v)
954 unsigned chan_no = sl / 2;
955 auto& ch = channel[chan_no];
956 auto& slot = ch.slot[sl & 1];
958 slot.mul = mul_tab[v & 0x0f];
959 slot.KSR = (v & 0x10) ? 0 : 2;
960 slot.eg_type = (v & 0x20) != 0;
961 slot.vib = (v & 0x40) != 0;
962 slot.AMmask = (v & 0x80) ? ~0 : 0;
964 if (isExtended(chan_no)) {
967 slot.calc_fc(getFirstOfPair(chan_no));
975void YMF262::set_ksl_tl(
unsigned sl, uint8_t v)
977 unsigned chan_no = sl / 2;
978 auto& ch = channel[chan_no];
979 auto& slot = ch.slot[sl & 1];
983 static constexpr std::array<uint8_t, 4> ksl_shift = {31, 1, 2, 0};
984 slot.ksl = ksl_shift[v >> 6];
986 slot.TL = (v & 0x3F) << (ENV_BITS - 1 - 7);
988 if (isExtended(chan_no)) {
990 auto& ch0 = getFirstOfPair(chan_no);
991 slot.TLL = slot.TL + (ch0.ksl_base >> slot.ksl);
994 slot.TLL = slot.TL + (ch.ksl_base >> slot.ksl);
999void YMF262::set_ar_dr(
unsigned sl, uint8_t v)
1001 auto& ch = channel[sl / 2];
1002 auto& slot = ch.slot[sl & 1];
1004 slot.ar = (v >> 4) ? narrow<uint8_t>(16 + ((v >> 4) << 2)) : 0;
1005 slot.dr = (v & 0x0F) ? narrow<uint8_t>(16 + ((v & 0x0F) << 2)) : 0;
1006 slot.update_ar_dr();
1010void YMF262::set_sl_rr(
unsigned sl, uint8_t v)
1012 auto& ch = channel[sl / 2];
1013 auto& slot = ch.slot[sl & 1];
1015 slot.sl = sl_tab[v >> 4];
1016 slot.rr = (v & 0x0F) ? uint8_t(16 + ((v & 0x0F) << 2)) : 0;
1033 if (!OPL3_mode && (r != 0x105)) {
1042 writeRegDirect(r, v, time);
1044void YMF262::writeRegDirect(
unsigned r, uint8_t v, EmuTime::param time)
1051 channel[ 0].extended = (v & 0x01) != 0;
1052 channel[ 1].extended = (v & 0x02) != 0;
1053 channel[ 2].extended = (v & 0x04) != 0;
1054 channel[ 9].extended = (v & 0x08) != 0;
1055 channel[10].extended = (v & 0x10) != 0;
1056 channel[11].extended = (v & 0x20) != 0;
1061 OPL3_mode = v & 0x01;
1068 if ((v & 0x02) && !alreadySignaledNEW2 && isYMF278) {
1070 alreadySignaledNEW2 =
true;
1085 unsigned ch_offset = (r & 0x100) ? 9 : 0;
1093 timer1->setValue(v);
1097 timer2->setValue(v);
1105 changeStatusMask((~v) & 0x60);
1106 timer1->setStart((v & R04_ST1) != 0, time);
1107 timer2->setStart((v & R04_ST2) != 0, time);
1112 nts = (v & 0x40) != 0;
1121 int slot = slot_array[r & 0x1F];
1122 if (slot < 0)
return;
1123 set_mul(slot + ch_offset * 2, v);
1127 int slot = slot_array[r & 0x1F];
1128 if (slot < 0)
return;
1129 set_ksl_tl(slot + ch_offset * 2, v);
1133 int slot = slot_array[r & 0x1F];
1134 if (slot < 0)
return;
1135 set_ar_dr(slot + ch_offset * 2, v);
1139 int slot = slot_array[r & 0x1F];
1140 if (slot < 0)
return;
1141 set_sl_rr(slot + ch_offset * 2, v);
1148 lfo_am_depth = (v & 0x80) != 0;
1149 lfo_pm_depth_range = (v & 0x40) ? 8 : 0;
1152 if (rhythm & 0x20) {
1155 channel[6].slot[MOD].FM_KEYON (2);
1156 channel[6].slot[CAR].FM_KEYON (2);
1158 channel[6].slot[MOD].FM_KEYOFF(2);
1159 channel[6].slot[CAR].FM_KEYOFF(2);
1163 channel[7].slot[MOD].FM_KEYON (2);
1165 channel[7].slot[MOD].FM_KEYOFF(2);
1169 channel[7].slot[CAR].FM_KEYON (2);
1171 channel[7].slot[CAR].FM_KEYOFF(2);
1175 channel[8].slot[MOD].FM_KEYON (2);
1177 channel[8].slot[MOD].FM_KEYOFF(2);
1181 channel[8].slot[CAR].FM_KEYON (2);
1183 channel[8].slot[CAR].FM_KEYOFF(2);
1187 channel[6].slot[MOD].FM_KEYOFF(2);
1188 channel[6].slot[CAR].FM_KEYOFF(2);
1190 channel[7].slot[MOD].FM_KEYOFF(2);
1192 channel[7].slot[CAR].FM_KEYOFF(2);
1194 channel[8].slot[MOD].FM_KEYOFF(2);
1196 channel[8].slot[CAR].FM_KEYOFF(2);
1202 if ((r & 0x0F) > 8) {
1205 unsigned chan_no = (r & 0x0F) + ch_offset;
1206 auto& ch = channel[chan_no];
1210 block_fnum = (ch.block_fnum & 0x1F00) | v;
1213 block_fnum = ((v & 0x1F) << 8) | (ch.block_fnum & 0xFF);
1214 if (isExtended(chan_no)) {
1215 if (getFirstOfPairNum(chan_no) == chan_no) {
1218 auto& ch0 = getFirstOfPair(chan_no);
1219 auto& ch3 = getSecondOfPair(chan_no);
1221 ch0.slot[MOD].FM_KEYON(1);
1222 ch0.slot[CAR].FM_KEYON(1);
1223 ch3.slot[MOD].FM_KEYON(1);
1224 ch3.slot[CAR].FM_KEYON(1);
1226 ch0.slot[MOD].FM_KEYOFF(1);
1227 ch0.slot[CAR].FM_KEYOFF(1);
1228 ch3.slot[MOD].FM_KEYOFF(1);
1229 ch3.slot[CAR].FM_KEYOFF(1);
1237 ch.slot[MOD].FM_KEYON (1);
1238 ch.slot[CAR].FM_KEYON (1);
1240 ch.slot[MOD].FM_KEYOFF(1);
1241 ch.slot[CAR].FM_KEYOFF(1);
1246 if (ch.block_fnum != block_fnum) {
1247 ch.block_fnum = block_fnum;
1248 ch.ksl_base = ksl_tab[block_fnum >> 6];
1249 ch.fc = fnumToIncrement(block_fnum);
1252 ch.kcode = (ch.block_fnum & 0x1C00) >> 9;
1259 ch.kcode |= (ch.block_fnum & 0x100) >> 8;
1261 ch.kcode |= (ch.block_fnum & 0x200) >> 9;
1263 if (isExtended(chan_no)) {
1264 if (getFirstOfPairNum(chan_no) == chan_no) {
1268 auto& ch0 = getFirstOfPair(chan_no);
1269 auto& ch3 = getSecondOfPair(chan_no);
1270 ch0.slot[MOD].TLL = ch0.slot[MOD].TL + (ch.ksl_base >> ch0.slot[MOD].ksl);
1271 ch0.slot[CAR].TLL = ch0.slot[CAR].TL + (ch.ksl_base >> ch0.slot[CAR].ksl);
1272 ch3.slot[MOD].TLL = ch3.slot[MOD].TL + (ch.ksl_base >> ch3.slot[MOD].ksl);
1273 ch3.slot[CAR].TLL = ch3.slot[CAR].TL + (ch.ksl_base >> ch3.slot[CAR].ksl);
1276 ch0.slot[MOD].calc_fc(ch);
1277 ch0.slot[CAR].calc_fc(ch);
1278 ch3.slot[MOD].calc_fc(ch);
1279 ch3.slot[CAR].calc_fc(ch);
1285 ch.slot[MOD].TLL = ch.slot[MOD].TL + (ch.ksl_base >> ch.slot[MOD].ksl);
1286 ch.slot[CAR].TLL = ch.slot[CAR].TL + (ch.ksl_base >> ch.slot[CAR].ksl);
1289 ch.slot[MOD].calc_fc(ch);
1290 ch.slot[CAR].calc_fc(ch);
1297 if ((r & 0xF) > 8) {
1300 unsigned chan_no = (r & 0x0F) + ch_offset;
1301 auto& ch = channel[chan_no];
1303 unsigned base = chan_no * 4;
1306 pan[base + 0] = (v & 0x10) ? ~0 : 0;
1307 pan[base + 1] = (v & 0x20) ? ~0 : 0;
1308 pan[base + 2] = (v & 0x40) ? ~0 : 0;
1309 pan[base + 3] = (v & 0x80) ? ~0 : 0;
1318 ch.slot[MOD].setFeedbackShift((v >> 1) & 7);
1319 ch.slot[MOD].CON = v & 1;
1321 if (isExtended(chan_no)) {
1322 unsigned chan_no0 = getFirstOfPairNum(chan_no);
1323 unsigned chan_no3 = chan_no0 + 3;
1324 auto& ch0 = getFirstOfPair(chan_no);
1325 auto& ch3 = getSecondOfPair(chan_no);
1326 switch ((ch0.slot[MOD].CON ? 2:0) | (ch3.slot[MOD].CON ? 1:0)) {
1329 ch0.slot[MOD].connect = &phase_modulation;
1330 ch0.slot[CAR].connect = &phase_modulation2;
1331 ch3.slot[MOD].connect = &phase_modulation;
1332 ch3.slot[CAR].connect = &chanOut[chan_no3];
1337 ch0.slot[MOD].connect = &phase_modulation;
1338 ch0.slot[CAR].connect = &chanOut[chan_no0];
1339 ch3.slot[MOD].connect = &phase_modulation;
1340 ch3.slot[CAR].connect = &chanOut[chan_no3];
1345 ch0.slot[MOD].connect = &chanOut[chan_no0];
1346 ch0.slot[CAR].connect = &phase_modulation2;
1347 ch3.slot[MOD].connect = &phase_modulation;
1348 ch3.slot[CAR].connect = &chanOut[chan_no3];
1354 ch0.slot[MOD].connect = &chanOut[chan_no0];
1355 ch0.slot[CAR].connect = &phase_modulation2;
1356 ch3.slot[MOD].connect = &chanOut[chan_no3];
1357 ch3.slot[CAR].connect = &chanOut[chan_no3];
1362 ch.slot[MOD].connect = ch.slot[MOD].CON
1364 : &phase_modulation;
1365 ch.slot[CAR].connect = &chanOut[chan_no];
1371 int slot = slot_array[r & 0x1f];
1372 if (slot < 0)
return;
1373 slot += narrow<int>(ch_offset * 2);
1374 auto& ch = channel[slot / 2];
1383 ch.slot[slot & 1].waveTable = sin.
tab[v];
1396 alreadySignaledNEW2 =
false;
1400 writeRegDirect(0x01, 0, time);
1401 writeRegDirect(0x02, 0, time);
1402 writeRegDirect(0x03, 0, time);
1403 writeRegDirect(0x04, 0, time);
1407 for (
int c = 0xFF; c >= 0x20; c--) {
1408 writeRegDirect(c, 0, time);
1411 for (
int c = 0x1FF; c >= 0x120; c--) {
1412 writeRegDirect(c, 0, time);
1416 for (
auto& ch : channel) {
1417 for (
auto& sl : ch.slot) {
1419 sl.volume = MAX_ATT_INDEX;
1426static unsigned calcInputRate(
bool isYMF278)
1428 return unsigned(lrintf(isYMF278 ? 33868800.0f / (19 * 36)
1429 : 4 * 3579545.0f / ( 8 * 36)));
1434 18, calcInputRate(isYMF278_), true)
1435 , debuggable(config.getMotherBoard(), getName())
1437 ?
EmuTimer::createOPL4_1(config.getScheduler(), *this)
1438 :
EmuTimer::createOPL3_1(config.getScheduler(), *this))
1440 ?
EmuTimer::createOPL4_2(config.getScheduler(), *this)
1441 :
EmuTimer::createOPL3_2(config.getScheduler(), *this))
1442 , irq(config.getMotherBoard(), getName() +
".IRQ")
1443 , isYMF278(isYMF278_)
1448 for (
const auto&
e : tlTab) std::cout <<
e <<
'\n';
1450 for (
const auto&
t : sin.
tab) {
1451 for (
const auto&
e :
t) {
1452 std::cout <<
e <<
'\n';
1469 uint8_t result = status | status2;
1476 return status | status2;
1479bool YMF262::checkMuteHelper()
1482 for (
auto& ch : channel) {
1483 for (
auto& sl : ch.slot) {
1484 if (!((sl.state ==
EG_OFF) ||
1486 ((narrow<int>(sl.TLL) + sl.volume) >= ENV_QUIET)))) {
1498 static constexpr std::array<float, 8> level = {
1511float YMF262::getAmplificationFactorImpl()
const
1513 return 1.0f / 4096.0f;
1516void YMF262::generateChannels(std::span<float*> bufs,
unsigned num)
1520 if (checkMuteHelper()) {
1526 bool rhythmEnabled = (rhythm & 0x20) != 0;
1528 for (
auto j :
xrange(num)) {
1533 if (lfo_am_cnt == LFOAMIndex(LFO_AM_TAB_ELEMENTS)) {
1535 lfo_am_cnt = LFOAMIndex(0);
1537 unsigned tmp = lfo_am_table[lfo_am_cnt.
toInt()];
1538 unsigned lfo_am = lfo_am_depth ? tmp : tmp / 4;
1545 for (
int k = 0; k <= 9; k += 9) {
1546 for (
auto i :
xrange(3)) {
1547 auto& ch0 = channel[k + i + 0];
1548 auto& ch3 = channel[k + i + 3];
1550 ch0.chan_calc(lfo_am);
1553 ch3.chan_calc_ext(lfo_am);
1556 ch3.chan_calc(lfo_am);
1562 if (!rhythmEnabled) {
1563 channel[6].chan_calc(lfo_am);
1564 channel[7].chan_calc(lfo_am);
1565 channel[8].chan_calc(lfo_am);
1568 chan_calc_rhythm(lfo_am);
1572 channel[15].chan_calc(lfo_am);
1573 channel[16].chan_calc(lfo_am);
1574 channel[17].chan_calc(lfo_am);
1576 for (
auto i :
xrange(18)) {
1577 bufs[i][2 * j + 0] += narrow_cast<float>(chanOut[i] & pan[4 * i + 0]);
1578 bufs[i][2 * j + 1] += narrow_cast<float>(chanOut[i] & pan[4 * i + 1]);
1588static constexpr std::initializer_list<enum_string<YMF262::EnvelopeState>> envelopeStateInfo = {
1597template<
typename Archive>
1601 auto waveform = unsigned((waveTable.data() - sin.
tab[0].data()) / SIN_LEN);
1602 a.serialize(
"waveform", waveform);
1603 if constexpr (Archive::IS_LOADER) {
1604 waveTable = sin.
tab[waveform];
1611 a.serialize(
"Cnt", Cnt,
1622 "eg_sh_ar", eg_sh_ar,
1623 "eg_sel_ar", eg_sel_ar,
1624 "eg_sh_dr", eg_sh_dr,
1625 "eg_sel_dr", eg_sel_dr,
1626 "eg_sh_rr", eg_sh_rr,
1627 "eg_sel_rr", eg_sel_rr,
1641template<
typename Archive>
1644 a.serialize(
"slots", slot,
1645 "block_fnum", block_fnum,
1647 "ksl_base", ksl_base,
1649 "extended", extended);
1654template<
typename Archive>
1657 a.serialize(
"timer1", *timer1,
1660 "chanout", chanOut);
1661 a.serialize_blob(
"registers", reg);
1662 a.serialize(
"channels", channel,
1664 "noise_rng", noise_rng,
1665 "lfo_am_cnt", lfo_am_cnt,
1666 "lfo_pm_cnt", lfo_pm_cnt,
1667 "lfo_am_depth", lfo_am_depth,
1668 "lfo_pm_depth_range", lfo_pm_depth_range,
1671 "OPL3_mode", OPL3_mode,
1674 "statusMask", statusMask);
1675 if (a.versionAtLeast(version, 2)) {
1676 a.serialize(
"alreadySignaledNEW2", alreadySignaledNEW2);
1678 assert(Archive::IS_LOADER);
1679 alreadySignaledNEW2 =
true;
1685 EmuTime::param time = timer1->getCurrentTime();
1686 for (
auto i :
xrange(0xC0, 0xC9)) {
1687 writeRegDirect(i + 0x000, reg[i + 0x000], time);
1688 writeRegDirect(i + 0x100, reg[i + 0x100], time);
1698 const std::string& name_)
1700 "MoonSound FM-part registers", 0x200)
1704uint8_t YMF262::Debuggable::read(
unsigned address)
1707 return ymf262.peekReg(address);
1710void YMF262::Debuggable::write(
unsigned address, uint8_t value, EmuTime::param time)
1713 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()
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
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
uint8_t readReg(unsigned reg)
void writeReg512(unsigned r, uint8_t v, EmuTime::param time)
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
FixedPoint< 16 > FreqIndex
16.16 fixed point type for frequency calculations.
This file implemented 3 utility functions:
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
void serialize(Archive &ar, T &t, unsigned version)
constexpr void fill(ForwardRange &&range, const T &value)
#define OUTER(type, member)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
std::array< std::array< unsigned, YMF262::SIN_LEN >, 8 > tab
constexpr auto xrange(T e)