30static constexpr unsigned MOD = 0;
31static constexpr unsigned CAR = 1;
33static constexpr double EG_STEP = 0.1875;
34static constexpr double SL_STEP = 3.0;
35static constexpr double TL_STEP = 0.75;
36static constexpr double DB_STEP = 0.1875;
38static constexpr unsigned SL_PER_EG = 16;
39static constexpr unsigned TL_PER_EG = 4;
40static constexpr unsigned EG_PER_DB = 1;
43static constexpr double PM_SPEED = 6.4;
44static constexpr double PM_DEPTH = 13.75 / 2;
45static constexpr double PM_DEPTH2 = 13.75;
48static constexpr int SL_BITS = 4;
49static constexpr int SL_MUTE = 1 << SL_BITS;
51static constexpr int PG_BITS = 10;
52static constexpr int PG_WIDTH = 1 << PG_BITS;
53static constexpr int PG_MASK = PG_WIDTH - 1;
55static constexpr int DP_BITS = 19;
56static constexpr int DP_BASE_BITS = DP_BITS - PG_BITS;
59static constexpr int DB_BITS = 9;
60static constexpr int DB_MUTE = 1 << DB_BITS;
62static constexpr int PM_AMP_BITS = 8;
63static constexpr int PM_AMP = 1 << PM_AMP_BITS;
66static constexpr int DB2LIN_AMP_BITS = 11;
67static constexpr int SLOT_AMP_BITS = DB2LIN_AMP_BITS;
70static constexpr int PM_PG_BITS = 8;
71static constexpr int PM_PG_WIDTH = 1 << PM_PG_BITS;
72static constexpr int PM_DP_BITS = 16;
73static constexpr int PM_DP_WIDTH = 1 << PM_DP_BITS;
74static constexpr int AM_PG_BITS = 8;
75static constexpr int AM_PG_WIDTH = 1 << AM_PG_BITS;
76static constexpr int AM_DP_BITS = 16;
77static constexpr int AM_DP_WIDTH = 1 << AM_DP_BITS;
98static constexpr unsigned LFO_AM_TAB_ELEMENTS = 210;
99static constexpr std::array<int8_t, LFO_AM_TAB_ELEMENTS> lfo_am_table =
161static constexpr unsigned DB_POS(
int x)
163 auto result = int(x / DB_STEP);
164 assert(result < DB_MUTE);
168static constexpr unsigned DB_NEG(
int x)
170 return 2 * DB_MUTE + DB_POS(x);
184static constexpr auto adjustAR = [] {
185 std::array<unsigned, EG_MUTE> result = {};
187 auto log_eg_mute = cstd::log<6, 5>(EG_MUTE);
188 for (
int i :
xrange(1, int(EG_MUTE))) {
189 result[i] = narrow_cast<unsigned>((EG_MUTE - 1 - EG_MUTE * cstd::log<6, 5>(i) / log_eg_mute) / 2);
190 assert(0 <=
int(result[i]));
191 assert(result[i] <= EG_MUTE);
195static constexpr auto adjustRA = [] {
196 std::array<unsigned, EG_MUTE + 1> result = {};
198 for (
int i :
xrange(1, int(EG_MUTE))) {
199 result[i] = narrow_cast<unsigned>(cstd::pow<6, 5>(EG_MUTE, (
double(EG_MUTE) - 1 - 2 * i) / EG_MUTE));
200 assert(0 <=
int(result[i]));
201 assert(result[i] <= EG_MUTE);
208static constexpr auto dB2LinTab = [] {
209 std::array<int, (2 * DB_MUTE) * 2> result = {};
210 for (
int i :
xrange(DB_MUTE)) {
211 result[i] = int(
double((1 << DB2LIN_AMP_BITS) - 1) *
212 cstd::pow<7, 3>(10, -
double(i) * DB_STEP / 20.0));
214 assert(result[DB_MUTE - 1] == 0);
215 for (
auto i :
xrange(DB_MUTE, 2 * DB_MUTE)) {
218 for (
auto i :
xrange(2 * DB_MUTE)) {
219 result[i + 2 * DB_MUTE] = -result[i];
227static constexpr auto sinTable = [] {
229 auto lin2db = [](
double d) {
233 int tmp = -int(20.0 * cstd::log10<6, 2>(d) / DB_STEP);
234 int result = std::min(tmp, DB_MUTE - 1);
236 assert(result <= DB_MUTE - 1);
240 std::array<unsigned, PG_WIDTH> result = {};
241 for (
int i :
xrange(PG_WIDTH / 4)) {
242 result[i] = lin2db(cstd::sin<2>(2.0 *
Math::pi * i / PG_WIDTH));
244 for (
auto i :
xrange(PG_WIDTH / 4)) {
245 result[PG_WIDTH / 2 - 1 - i] = result[i];
247 for (
auto i :
xrange(PG_WIDTH / 2)) {
248 result[PG_WIDTH / 2 + i] = 2 * DB_MUTE + result[i];
254static constexpr auto pmTable = [] {
255 std::array<std::array<int, PM_PG_WIDTH>, 2> result = {};
256 for (
int i :
xrange(PM_PG_WIDTH)) {
257 auto s = cstd::sin<5>(2.0 *
Math::pi * i / PM_PG_WIDTH) / 1200;
258 result[0][i] = int(PM_AMP * cstd::exp2<2>(PM_DEPTH * s));
259 result[1][i] = int(PM_AMP * cstd::exp2<2>(PM_DEPTH2 * s));
265static constexpr auto tllTable = [] {
267 constexpr std::array<int, 16> klTable = {
268 0, 24, 32, 37, 40, 43, 45, 47, 48, 50, 51, 52, 53, 54, 55, 56
272 constexpr std::array<int, 4> shift = { 31, 1, 2, 0 };
274 std::array<std::array<int, 4>, 16 * 8> result = {};
275 for (
auto freq :
xrange(16 * 8)) {
276 int fnum = freq % 16;
277 int block = freq / 16;
278 int tmp = 4 * klTable[fnum] - 32 * (7 - block);
279 for (
auto KL :
xrange(4)) {
280 result[freq][KL] = (tmp <= 0) ? 0 : (tmp >> shift[KL]);
287static constexpr auto dPhaseArTable = [] {
288 std::array<std::array<Y8950::EnvPhaseIndex, 16>, 16> result = {};
289 for (
auto Rks :
xrange(16)) {
291 for (
auto AR :
xrange(1, 15)) {
292 int RM = std::min(AR + (Rks >> 2), 15);
297 result[Rks][15] = EG_DP_MAX;
303static constexpr auto dPhaseDrTable = [] {
304 std::array<std::array<Y8950::EnvPhaseIndex, 16>, 16> result = {};
305 for (
auto Rks :
xrange(16)) {
307 for (
auto DR :
xrange(1, 16)) {
308 int RM = std::min(DR + (Rks >> 2), 15);
325void Y8950::Patch::reset()
337 setKeyScaleRate(
false);
345 : dPhaseARTableRks(dPhaseArTable[0])
346 , dPhaseDRTableRks(dPhaseDrTable[0])
350void Y8950::Slot::reset()
355 eg_mode = EnvelopeState::FINISH;
356 eg_phase = EG_DP_MAX;
365void Y8950::Slot::updatePG(
unsigned freq)
367 static constexpr std::array<int, 16> mlTable = {
368 1, 1*2, 2*2, 3*2, 4*2, 5*2, 6*2 , 7*2,
369 8*2, 9*2, 10*2, 10*2, 12*2, 12*2, 15*2, 15*2
372 unsigned fnum = freq % 1024;
373 unsigned block = freq / 1024;
374 dPhase = ((fnum * mlTable[patch.ML]) << block) >> (21 - DP_BITS);
377void Y8950::Slot::updateTLL(
unsigned freq)
379 tll = tllTable[freq >> 6][patch.KL] + narrow<int>(patch.TL * TL_PER_EG);
382void Y8950::Slot::updateRKS(
unsigned freq)
384 unsigned rks = freq >> patch.KR;
386 dPhaseARTableRks = dPhaseArTable[rks];
387 dPhaseDRTableRks = dPhaseDrTable[rks];
390void Y8950::Slot::updateEG()
393 using enum EnvelopeState;
395 eg_dPhase = dPhaseARTableRks[patch.AR];
398 eg_dPhase = dPhaseDRTableRks[patch.DR];
402 eg_dPhase = dPhaseDRTableRks[patch.RR];
405 eg_dPhase = Y8950::EnvPhaseIndex(0);
410void Y8950::Slot::updateAll(
unsigned freq)
418bool Y8950::Slot::isActive()
const
420 return eg_mode != EnvelopeState::FINISH;
424void Y8950::Slot::slotOn(KeyPart part)
427 eg_mode = EnvelopeState::ATTACK;
429 eg_phase = Y8950::EnvPhaseIndex(adjustRA[eg_phase.toInt()]);
435void Y8950::Slot::slotOff(KeyPart part)
440 if (eg_mode == EnvelopeState::ATTACK) {
441 eg_phase = Y8950::EnvPhaseIndex(adjustAR[eg_phase.toInt()]);
443 eg_mode = EnvelopeState::RELEASE;
451Y8950::Channel::Channel()
456void Y8950::Channel::reset()
465void Y8950::Channel::setFreq(
unsigned freq_)
470void Y8950::Channel::keyOn(KeyPart part)
472 slot[MOD].slotOn(part);
473 slot[CAR].slotOn(part);
476void Y8950::Channel::keyOff(KeyPart part)
478 slot[MOD].slotOff(part);
479 slot[CAR].slotOff(part);
482static constexpr auto INPUT_RATE = unsigned(
cstd::round(Y8950::CLOCK_FREQ /
double(Y8950::CLOCK_FREQ_DIV)));
485 unsigned sampleRam, EmuTime::param time,
MSXAudio& audio)
486 :
ResampledSoundDevice(config.getMotherBoard(), name_,
"MSX-AUDIO", 9 + 5 + 1, INPUT_RATE, false)
487 , motherBoard(config.getMotherBoard())
488 , periphery(audio.createPeriphery(getName()))
489 , adpcm(*this, config, name_, sampleRam)
490 , connector(motherBoard.getPluggingController())
491 , dac13(name_ +
" DAC",
"MSX-AUDIO 13-bit DAC", config)
492 , debuggable(motherBoard, getName())
493 , timer1(
EmuTimer::createOPL3_1(motherBoard.getScheduler(), *this))
494 , timer2(
EmuTimer::createOPL3_2(motherBoard.getScheduler(), *this))
495 , irq(motherBoard, getName() +
".IRQ")
500 for (
auto i :
xrange(PM_PG_WIDTH)) {
501 std::cout << pmTable[0][i] <<
' '
502 << pmTable[1][i] <<
'\n';
506 for (
auto i :
xrange(EG_MUTE)) {
507 std::cout << adjustRA[i] <<
' '
508 << adjustAR[i] <<
'\n';
510 std::cout << adjustRA[EG_MUTE] <<
"\n\n";
512 for (
const auto& e : dB2LinTab) std::cout << e <<
'\n';
515 for (
auto i :
xrange(16 * 8)) {
516 for (
auto j :
xrange(4)) {
517 std::cout << tllTable[i][j] <<
' ';
523 for (
const auto& e : sinTable) std::cout << e <<
'\n';
526 for (
auto i :
xrange(16)) {
527 for (
auto j :
xrange(16)) {
528 std::cout << dPhaseArTable[i][j].getRawValue() <<
' ';
534 for (
auto i :
xrange(16)) {
535 for (
auto j :
xrange(16)) {
536 std::cout << dPhaseDrTable[i][j].getRawValue() <<
' ';
560 for (
auto& c : ch) c.reset();
588void Y8950::keyOn_BD() { ch[6].keyOn(KEY_RHYTHM); }
589void Y8950::keyOn_HH() { ch[7].slot[MOD].slotOn(KEY_RHYTHM); }
590void Y8950::keyOn_SD() { ch[7].slot[CAR].slotOn(KEY_RHYTHM); }
591void Y8950::keyOn_TOM() { ch[8].slot[MOD].slotOn(KEY_RHYTHM); }
592void Y8950::keyOn_CYM() { ch[8].slot[CAR].slotOn(KEY_RHYTHM); }
595void Y8950::keyOff_BD() { ch[6].keyOff(KEY_RHYTHM); }
596void Y8950::keyOff_HH() { ch[7].slot[MOD].slotOff(KEY_RHYTHM); }
597void Y8950::keyOff_SD() { ch[7].slot[CAR].slotOff(KEY_RHYTHM); }
598void Y8950::keyOff_TOM(){ ch[8].slot[MOD].slotOff(KEY_RHYTHM); }
599void Y8950::keyOff_CYM(){ ch[8].slot[CAR].slotOff(KEY_RHYTHM); }
602void Y8950::setRythmMode(
int data)
604 bool newMode = (data & 32) != 0;
605 if (rythm_mode != newMode) {
606 rythm_mode = newMode;
619void Y8950::update_key_status()
622 uint8_t
main = (reg[0xb0 + i] & 0x20) ? KEY_MAIN : 0;
623 c.slot[MOD].key =
main;
624 c.slot[CAR].key =
main;
627 ch[6].slot[MOD].key |= uint8_t((reg[0xbd] & 0x10) ? KEY_RHYTHM : 0);
628 ch[6].slot[CAR].key |= uint8_t((reg[0xbd] & 0x10) ? KEY_RHYTHM : 0);
629 ch[7].slot[MOD].key |= uint8_t((reg[0xbd] & 0x01) ? KEY_RHYTHM : 0);
630 ch[7].slot[CAR].key |= uint8_t((reg[0xbd] & 0x08) ? KEY_RHYTHM : 0);
631 ch[8].slot[MOD].key |= uint8_t((reg[0xbd] & 0x04) ? KEY_RHYTHM : 0);
632 ch[8].slot[CAR].key |= uint8_t((reg[0xbd] & 0x02) ? KEY_RHYTHM : 0);
642static constexpr int wave2_8pi(
int e)
644 int shift = SLOT_AMP_BITS - PG_BITS - 2;
645 return (shift > 0) ? (
e >> shift) : (
e << -shift);
648unsigned Y8950::Slot::calc_phase(
int lfo_pm)
651 phase += (dPhase * lfo_pm) >> PM_AMP_BITS;
655 return phase >> DP_BASE_BITS;
658static constexpr auto S2E(
int x) {
661static constexpr std::array<Y8950::EnvPhaseIndex, 16> SL = {
662 S2E( 0), S2E( 3), S2E( 6), S2E( 9), S2E(12), S2E(15), S2E(18), S2E(21),
663 S2E(24), S2E(27), S2E(30), S2E(33), S2E(36), S2E(39), S2E(42), S2E(93)
665unsigned Y8950::Slot::calc_envelope(
int lfo_am)
669 using enum EnvelopeState;
671 eg_phase += eg_dPhase;
672 if (eg_phase >= EG_DP_MAX) {
678 egOut = adjustAR[eg_phase.toInt()];
683 eg_phase += eg_dPhase;
684 if (eg_phase >= SL[patch.SL]) {
685 eg_phase = SL[patch.SL];
689 egOut = eg_phase.toInt();
694 eg_phase += eg_dPhase;
696 egOut = eg_phase.toInt();
697 if (egOut >= EG_MUTE) {
698 eg_phase = EG_DP_MAX;
705 eg_phase += eg_dPhase;
706 egOut = eg_phase.toInt();
707 if (egOut >= EG_MUTE) {
708 eg_phase = EG_DP_MAX;
719 egOut = ((egOut + tll) * EG_PER_DB);
723 return std::min<unsigned>(egOut, DB_MUTE - 1);
726int Y8950::Slot::calc_slot_car(
int lfo_pm,
int lfo_am,
int fm)
728 unsigned egOut = calc_envelope(lfo_am);
729 int pgout = narrow<int>(calc_phase(lfo_pm)) + wave2_8pi(fm);
730 return dB2LinTab[sinTable[pgout & PG_MASK] + egOut];
733int Y8950::Slot::calc_slot_mod(
int lfo_pm,
int lfo_am)
735 unsigned egOut = calc_envelope(lfo_am);
736 unsigned pgout = calc_phase(lfo_pm);
739 pgout += wave2_8pi(feedback) >> patch.FB;
741 int newOutput = dB2LinTab[sinTable[pgout & PG_MASK] + egOut];
742 feedback = (output + newOutput) >> 1;
747int Y8950::Slot::calc_slot_tom(
int lfo_pm,
int lfo_am)
749 unsigned egOut = calc_envelope(lfo_am);
750 unsigned pgout = calc_phase(lfo_pm);
751 return dB2LinTab[sinTable[pgout & PG_MASK] + egOut];
754int Y8950::Slot::calc_slot_snare(
int lfo_pm,
int lfo_am,
int whiteNoise)
756 unsigned egOut = calc_envelope(lfo_am);
757 unsigned pgout = calc_phase(lfo_pm);
758 unsigned tmp = (pgout & (1 << (PG_BITS - 1))) ? 0 : 2 * DB_MUTE;
759 return (dB2LinTab[tmp + egOut] + dB2LinTab[egOut + whiteNoise]) >> 1;
762int Y8950::Slot::calc_slot_cym(
int lfo_am,
int a,
int b)
764 unsigned egOut = calc_envelope(lfo_am);
765 return (dB2LinTab[egOut + a] + dB2LinTab[egOut + b]) >> 1;
769int Y8950::Slot::calc_slot_hat(
int lfo_am,
int a,
int b,
int whiteNoise)
771 unsigned egOut = calc_envelope(lfo_am);
772 return (dB2LinTab[egOut + whiteNoise] +
773 dB2LinTab[egOut + a] +
774 dB2LinTab[egOut + b]) >> 2;
777float Y8950::getAmplificationFactorImpl()
const
779 return 1.0f / (1 << DB2LIN_AMP_BITS);
788bool Y8950::checkMuteHelper()
793 for (
auto i :
xrange(6)) {
794 if (ch[i].slot[CAR].isActive())
return false;
797 for (
auto i :
xrange(6, 9)) {
798 if (ch[i].slot[CAR].isActive())
return false;
801 if (ch[6].slot[CAR].isActive())
return false;
802 if (ch[7].slot[MOD].isActive())
return false;
803 if (ch[7].slot[CAR].isActive())
return false;
804 if (ch[8].slot[MOD].isActive())
return false;
805 if (ch[8].slot[CAR].isActive())
return false;
811void Y8950::generateChannels(std::span<float*> bufs,
unsigned num)
814 if (checkMuteHelper()) {
822 for (
auto sample :
xrange(num)) {
828 if (am_phase == (LFO_AM_TAB_ELEMENTS * 64)) am_phase = 0;
829 int tmp = narrow_cast<int>(lfo_am_table[am_phase / 64]);
830 int lfo_am = am_mode ? tmp : tmp / 4;
832 pm_phase = (pm_phase + PM_DPHASE) & (PM_DP_WIDTH - 1);
833 int lfo_pm = pmTable[pm_mode][pm_phase >> (PM_DP_BITS - PM_PG_BITS)];
835 if (noise_seed & 1) {
836 noise_seed ^= 0x24000;
839 int whiteNoise = noise_seed & 1 ? DB_POS(6) : DB_NEG(6);
841 noiseA_phase += noiseA_dPhase;
842 noiseA_phase &= (0x40 << 11) - 1;
843 if ((noiseA_phase >> 11) == 0x3f) {
846 int noiseA = noiseA_phase & (0x03 << 11) ? DB_POS(6) : DB_NEG(6);
848 noiseB_phase += noiseB_dPhase;
849 noiseB_phase &= (0x10 << 11) - 1;
850 int noiseB = noiseB_phase & (0x0A << 11) ? DB_POS(6) : DB_NEG(6);
852 for (
auto i :
xrange(rythm_mode ? 6 : 9)) {
853 if (ch[i].slot[CAR].isActive()) {
854 bufs[i][sample] += narrow_cast<float>(ch[i].alg
855 ? ch[i].slot[CAR].calc_slot_car(lfo_pm, lfo_am, 0) +
856 ch[i].slot[MOD].calc_slot_mod(lfo_pm, lfo_am)
857 : ch[i].slot[CAR].calc_slot_car(lfo_pm, lfo_am,
858 ch[i].slot[MOD].calc_slot_mod(lfo_pm, lfo_am)));
869 (void)ch[7].slot[MOD].calc_phase(lfo_pm);
870 (void)ch[8].slot[CAR].calc_phase(lfo_pm);
872 bufs[ 9][sample] += (ch[6].slot[CAR].isActive())
873 ? narrow_cast<float>(
874 2 * ch[6].slot[CAR].calc_slot_car(lfo_pm, lfo_am,
875 ch[6].slot[MOD].calc_slot_mod(lfo_pm, lfo_am)))
877 bufs[10][sample] += (ch[7].slot[CAR].isActive())
878 ? narrow_cast<float>(2 * ch[7].slot[CAR].calc_slot_snare(lfo_pm, lfo_am, whiteNoise))
880 bufs[11][sample] += (ch[8].slot[CAR].isActive())
881 ? narrow_cast<float>(2 * ch[8].slot[CAR].calc_slot_cym(lfo_am, noiseA, noiseB))
883 bufs[12][sample] += (ch[7].slot[MOD].isActive())
884 ? narrow_cast<float>(2 * ch[7].slot[MOD].calc_slot_hat(lfo_am, noiseA, noiseB, whiteNoise))
886 bufs[13][sample] += (ch[8].slot[MOD].isActive())
887 ? narrow_cast<float>(2 * ch[8].slot[MOD].calc_slot_tom(lfo_pm, lfo_am))
897 bufs[14][sample] += narrow_cast<float>(adpcm.
calcSample());
907 static constexpr std::array<int, 32> sTbl = {
908 0, 2, 4, 1, 3, 5, -1, -1,
909 6, 8, 10, 7, 9, 11, -1, -1,
910 12, 14, 16, 13, 15, 17, -1, -1,
911 -1, -1, -1, -1, -1, -1, -1, -1
956 timer1->setValue(data);
961 timer2->setValue(data);
969 changeStatusMask((~data) & 0x78);
978 connector.
write(data, time);
983 periphery.
setSPOFF((data & 8) != 0, time);
1004 if (reg[0x08] & 0x04) {
1005 int tmp =
static_cast<signed char>(reg[0x15]) * 256
1007 tmp = (tmp * 4) >> (7 - reg[0x17]);
1012 reg[rg] = data & 0xC0;
1015 reg[rg] = data & 0x07;
1022 periphery.
write(reg[0x18], reg[0x19], time);
1027 periphery.
write(reg[0x18], reg[0x19], time);
1033 if (
int s = sTbl[rg & 0x1f]; s >= 0) {
1034 auto& chan = ch[s / 2];
1035 auto& slot = chan.slot[s & 1];
1036 slot.patch.AM = (data >> 7) & 1;
1037 slot.patch.PM = (data >> 6) & 1;
1038 slot.patch.EG = (data >> 5) & 1;
1039 slot.patch.setKeyScaleRate((data & 0x10) != 0);
1040 slot.patch.ML = (data >> 0) & 15;
1041 slot.updateAll(chan.freq);
1047 if (
int s = sTbl[rg & 0x1f]; s >= 0) {
1048 auto& chan = ch[s / 2];
1049 auto& slot = chan.slot[s & 1];
1050 slot.patch.KL = (data >> 6) & 3;
1051 slot.patch.TL = (data >> 0) & 63;
1052 slot.updateAll(chan.freq);
1058 if (
int s = sTbl[rg & 0x1f]; s >= 0) {
1059 auto& slot = ch[s / 2].slot[s & 1];
1060 slot.patch.AR = (data >> 4) & 15;
1061 slot.patch.DR = (data >> 0) & 15;
1068 if (
int s = sTbl[rg & 0x1f]; s >= 0) {
1069 auto& slot = ch[s / 2].slot[s & 1];
1070 slot.patch.SL = (data >> 4) & 15;
1071 slot.patch.RR = (data >> 0) & 15;
1079 am_mode = (data & 0x80) != 0;
1080 pm_mode = (data & 0x40) != 0;
1084 if (data & 0x10) keyOn_BD();
else keyOff_BD();
1085 if (data & 0x08) keyOn_SD();
else keyOff_SD();
1086 if (data & 0x04) keyOn_TOM();
else keyOff_TOM();
1087 if (data & 0x02) keyOn_CYM();
else keyOff_CYM();
1088 if (data & 0x01) keyOn_HH();
else keyOff_HH();
1090 ch[6].slot[MOD].updateAll(ch[6].freq);
1091 ch[6].slot[CAR].updateAll(ch[6].freq);
1092 ch[7].slot[MOD].updateAll(ch[7].freq);
1093 ch[7].slot[CAR].updateAll(ch[7].freq);
1094 ch[8].slot[MOD].updateAll(ch[8].freq);
1095 ch[8].slot[CAR].updateAll(ch[8].freq);
1100 unsigned c = rg & 0x0f;
1105 unsigned freq = [&] {
1108 return data | ((reg[rg + 0x10] & 0x1F) << 8);
1112 ch[c].keyOn (KEY_MAIN);
1114 ch[c].keyOff(KEY_MAIN);
1116 return reg[rg - 0x10] | ((data & 0x1F) << 8);
1119 ch[c].setFreq(freq);
1120 unsigned fNum = freq % 1024;
1121 unsigned block = freq / 1024;
1123 case 7: noiseA_dPhase = fNum << block;
1125 case 8: noiseB_dPhase = fNum << block;
1128 ch[c].slot[CAR].updateAll(freq);
1129 ch[c].slot[MOD].updateAll(freq);
1137 ch[c].slot[MOD].patch.setFeedbackShift((data >> 1) & 7);
1138 ch[c].alg = data & 1;
1153 return adpcm.
readReg(rg, time);
1163 return connector.
peek(time);
1169 return adpcm.
peekReg(rg, time);
1172 uint8_t input = periphery.
read(time);
1173 uint8_t output = reg[0x19];
1174 uint8_t enable = reg[0x18];
1175 return (output & enable) | (input & ~enable) | 0xF0;
1190 return (status & (0x87 | statusMask)) | 0x06;
1193void Y8950::callback(uint8_t flag)
1201 if (status & statusMask) {
1209 if (!(status & statusMask)) {
1218void Y8950::changeStatusMask(uint8_t newMask)
1220 statusMask = newMask;
1221 status &= 0x87 | statusMask;
1222 if (status & statusMask) {
1232template<
typename Archive>
1233void Y8950::Patch::serialize(Archive& ar,
unsigned )
1235 ar.serialize(
"AM", AM,
1249static constexpr std::initializer_list<enum_string<Y8950::EnvelopeState>> envelopeStateInfo = {
1263template<
typename Archive>
1264void Y8950::Slot::serialize(Archive& ar,
unsigned version)
1266 ar.serialize(
"feedback", feedback,
1269 "eg_phase", eg_phase,
1271 if (ar.versionAtLeast(version, 3)) {
1272 ar.serialize(
"eg_mode", eg_mode);
1274 assert(Archive::IS_LOADER);
1276 ar.serialize(
"eg_mode", tmp);
1278 using enum EnvelopeState;
1279 case 0: eg_mode = ATTACK;
break;
1280 case 1: eg_mode = DECAY;
break;
1281 case 2: eg_mode = SUSTAIN;
break;
1282 case 3: eg_mode = SUSTAIN;
break;
1283 case 4: eg_mode = RELEASE;
break;
1284 default: eg_mode = FINISH;
break;
1294template<
typename Archive>
1295void Y8950::Channel::serialize(Archive& ar,
unsigned )
1297 ar.serialize(
"mod", slot[MOD],
1302 if constexpr (Archive::IS_LOADER) {
1303 slot[MOD].updateAll(freq);
1304 slot[CAR].updateAll(freq);
1308template<
typename Archive>
1311 ar.serialize(
"keyboardConnector", connector,
1316 ar.serialize_blob(
"registers", reg);
1317 ar.serialize(
"pm_phase", pm_phase,
1318 "am_phase", am_phase,
1319 "noise_seed", noise_seed,
1320 "noiseA_phase", noiseA_phase,
1321 "noiseB_phase", noiseB_phase,
1322 "noiseA_dphase", noiseA_dPhase,
1323 "noiseB_dphase", noiseB_dPhase,
1326 "statusMask", statusMask,
1327 "rythm_mode", rythm_mode,
1330 "enabled", enabled);
1332 if constexpr (Archive::IS_LOADER) {
1334 static constexpr std::array<uint8_t, 2> rewriteRegs = {
1339 update_key_status();
1341 for (
auto r : rewriteRegs) {
1351 const std::string& name_)
1356uint8_t Y8950::Debuggable::read(
unsigned address, EmuTime::param time)
1358 const auto& y8950 =
OUTER(Y8950, debuggable);
1359 return y8950.peekReg(narrow<uint8_t>(address), time);
1362void Y8950::Debuggable::write(
unsigned address, uint8_t value, EmuTime::param time)
1364 auto& y8950 =
OUTER(Y8950, debuggable);
1365 y8950.writeReg(narrow<uint8_t>(address), value, time);
void writeDAC(int16_t value, EmuTime::param time)
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 unregisterSound()
Unregisters this sound device with the Mixer.
void registerSound(const DeviceConfig &config)
Registers this sound device with the Mixer.
byte readReg(byte rg, EmuTime::param time)
byte peekReg(byte rg, EmuTime::param time) const
void writeReg(byte rg, byte data, EmuTime::param time)
void reset(EmuTime::param time)
void write(byte data, EmuTime::param time)
byte peek(EmuTime::param time) const
virtual void write(nibble outputs, nibble values, EmuTime::param time)=0
Write to (some of) the pins.
virtual void setSPOFF(bool value, EmuTime::param time)
SP-OFF bit (bit 3 in Y8950 register 7)
virtual nibble read(EmuTime::param time)=0
Read from (some of) the pins Some of the pins might be programmed as output, but this method doesn't ...
void reset(EmuTime::param time)
void setStatus(uint8_t flags)
uint8_t peekReg(uint8_t rg, EmuTime::param time) const
void setEnabled(bool enabled, EmuTime::param time)
static constexpr int CLOCK_FREQ_DIV
static constexpr int R04_IRQ_RESET
uint8_t peekStatus(EmuTime::param time) const
uint8_t readStatus(EmuTime::param time) const
FixedPoint< EG_DP_BITS - EG_BITS > EnvPhaseIndex
static constexpr int R04_ST2
void serialize(Archive &ar, unsigned version)
static constexpr int R04_ST1
void writeReg(uint8_t rg, uint8_t data, EmuTime::param time)
static constexpr int CLOCK_FREQ
static constexpr int EG_BITS
void resetStatus(uint8_t flags)
uint8_t readReg(uint8_t rg, EmuTime::param time)
uint8_t peekRawStatus() const
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
int main(int argc, char **argv)
int16_t clipToInt16(T x)
Clip x to range [-32768,32767].
constexpr double round(double x)
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)
constexpr auto xrange(T e)