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 int 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()
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()
394 eg_dPhase = dPhaseARTableRks[patch.AR];
397 eg_dPhase = dPhaseDRTableRks[patch.DR];
401 eg_dPhase = dPhaseDRTableRks[patch.RR];
409void Y8950::Slot::updateAll(
unsigned freq)
417bool Y8950::Slot::isActive()
const
423void Y8950::Slot::slotOn(KeyPart part)
434void Y8950::Slot::slotOff(KeyPart part)
450Y8950::Channel::Channel()
455void Y8950::Channel::reset()
464void Y8950::Channel::setFreq(
unsigned freq_)
469void Y8950::Channel::keyOn(KeyPart part)
471 slot[MOD].slotOn(part);
472 slot[CAR].slotOn(part);
475void Y8950::Channel::keyOff(KeyPart part)
477 slot[MOD].slotOff(part);
478 slot[CAR].slotOff(part);
481static constexpr auto INPUT_RATE = unsigned(
cstd::round(Y8950::CLOCK_FREQ /
double(Y8950::CLOCK_FREQ_DIV)));
484 unsigned sampleRam, EmuTime::param time,
MSXAudio& audio)
485 :
ResampledSoundDevice(config.getMotherBoard(), name_,
"MSX-AUDIO", 9 + 5 + 1, INPUT_RATE, false)
486 , motherBoard(config.getMotherBoard())
487 , periphery(audio.createPeriphery(
getName()))
488 , adpcm(*this, config, name_, sampleRam)
489 , connector(motherBoard.getPluggingController())
490 , dac13(name_ +
" DAC",
"MSX-AUDIO 13-bit DAC", config)
491 , debuggable(motherBoard,
getName())
492 , timer1(
EmuTimer::createOPL3_1(motherBoard.getScheduler(), *this))
493 , timer2(
EmuTimer::createOPL3_2(motherBoard.getScheduler(), *this))
494 , irq(motherBoard,
getName() +
".IRQ")
499 for (
auto i :
xrange(PM_PG_WIDTH)) {
500 std::cout << pmTable[0][i] <<
' '
501 << pmTable[1][i] <<
'\n';
505 for (
auto i :
xrange(EG_MUTE)) {
506 std::cout << adjustRA[i] <<
' '
507 << adjustAR[i] <<
'\n';
509 std::cout << adjustRA[EG_MUTE] <<
"\n\n";
511 for (
const auto&
e : dB2LinTab) std::cout <<
e <<
'\n';
514 for (
auto i :
xrange(16 * 8)) {
515 for (
auto j :
xrange(4)) {
516 std::cout << tllTable[i][j] <<
' ';
522 for (
const auto&
e : sinTable) std::cout <<
e <<
'\n';
525 for (
auto i :
xrange(16)) {
526 for (
auto j :
xrange(16)) {
527 std::cout << dPhaseArTable[i][j].getRawValue() <<
' ';
533 for (
auto i :
xrange(16)) {
534 for (
auto j :
xrange(16)) {
535 std::cout << dPhaseDrTable[i][j].getRawValue() <<
' ';
559 for (
auto& c : ch) c.reset();
587void Y8950::keyOn_BD() { ch[6].keyOn(KEY_RHYTHM); }
588void Y8950::keyOn_HH() { ch[7].slot[MOD].slotOn(KEY_RHYTHM); }
589void Y8950::keyOn_SD() { ch[7].slot[CAR].slotOn(KEY_RHYTHM); }
590void Y8950::keyOn_TOM() { ch[8].slot[MOD].slotOn(KEY_RHYTHM); }
591void Y8950::keyOn_CYM() { ch[8].slot[CAR].slotOn(KEY_RHYTHM); }
594void Y8950::keyOff_BD() { ch[6].keyOff(KEY_RHYTHM); }
595void Y8950::keyOff_HH() { ch[7].slot[MOD].slotOff(KEY_RHYTHM); }
596void Y8950::keyOff_SD() { ch[7].slot[CAR].slotOff(KEY_RHYTHM); }
597void Y8950::keyOff_TOM(){ ch[8].slot[MOD].slotOff(KEY_RHYTHM); }
598void Y8950::keyOff_CYM(){ ch[8].slot[CAR].slotOff(KEY_RHYTHM); }
601void Y8950::setRythmMode(
int data)
603 bool newMode = (data & 32) != 0;
604 if (rythm_mode != newMode) {
605 rythm_mode = newMode;
618void Y8950::update_key_status()
621 uint8_t
main = (reg[0xb0 + i] & 0x20) ? KEY_MAIN : 0;
622 c.slot[MOD].key =
main;
623 c.slot[CAR].key =
main;
626 ch[6].slot[MOD].key |= uint8_t((reg[0xbd] & 0x10) ? KEY_RHYTHM : 0);
627 ch[6].slot[CAR].key |= uint8_t((reg[0xbd] & 0x10) ? KEY_RHYTHM : 0);
628 ch[7].slot[MOD].key |= uint8_t((reg[0xbd] & 0x01) ? KEY_RHYTHM : 0);
629 ch[7].slot[CAR].key |= uint8_t((reg[0xbd] & 0x08) ? KEY_RHYTHM : 0);
630 ch[8].slot[MOD].key |= uint8_t((reg[0xbd] & 0x04) ? KEY_RHYTHM : 0);
631 ch[8].slot[CAR].key |= uint8_t((reg[0xbd] & 0x02) ? KEY_RHYTHM : 0);
641static constexpr int wave2_8pi(
int e)
643 int shift = SLOT_AMP_BITS - PG_BITS - 2;
644 return (shift > 0) ? (
e >> shift) : (
e << -shift);
647unsigned Y8950::Slot::calc_phase(
int lfo_pm)
650 phase += (dPhase * lfo_pm) >> PM_AMP_BITS;
654 return phase >> DP_BASE_BITS;
657static constexpr auto S2E(
int x) {
660static constexpr std::array<Y8950::EnvPhaseIndex, 16> SL = {
661 S2E( 0), S2E( 3), S2E( 6), S2E( 9), S2E(12), S2E(15), S2E(18), S2E(21),
662 S2E(24), S2E(27), S2E(30), S2E(33), S2E(36), S2E(39), S2E(42), S2E(93)
664unsigned Y8950::Slot::calc_envelope(
int lfo_am)
669 eg_phase += eg_dPhase;
670 if (eg_phase >= EG_DP_MAX) {
676 egOut = adjustAR[eg_phase.toInt()];
681 eg_phase += eg_dPhase;
682 if (eg_phase >= SL[patch.SL]) {
683 eg_phase = SL[patch.SL];
687 egOut = eg_phase.toInt();
692 eg_phase += eg_dPhase;
694 egOut = eg_phase.toInt();
695 if (egOut >= EG_MUTE) {
696 eg_phase = EG_DP_MAX;
703 eg_phase += eg_dPhase;
704 egOut = eg_phase.toInt();
705 if (egOut >= EG_MUTE) {
706 eg_phase = EG_DP_MAX;
717 egOut = ((egOut + tll) * EG_PER_DB);
721 return std::min<unsigned>(egOut, DB_MUTE - 1);
724int Y8950::Slot::calc_slot_car(
int lfo_pm,
int lfo_am,
int fm)
726 unsigned egOut = calc_envelope(lfo_am);
727 int pgout = narrow<int>(calc_phase(lfo_pm)) + wave2_8pi(fm);
728 return dB2LinTab[sinTable[pgout & PG_MASK] + egOut];
731int Y8950::Slot::calc_slot_mod(
int lfo_pm,
int lfo_am)
733 unsigned egOut = calc_envelope(lfo_am);
734 unsigned pgout = calc_phase(lfo_pm);
737 pgout += wave2_8pi(feedback) >> patch.FB;
739 int newOutput = dB2LinTab[sinTable[pgout & PG_MASK] + egOut];
740 feedback = (output + newOutput) >> 1;
745int Y8950::Slot::calc_slot_tom(
int lfo_pm,
int lfo_am)
747 unsigned egOut = calc_envelope(lfo_am);
748 unsigned pgout = calc_phase(lfo_pm);
749 return dB2LinTab[sinTable[pgout & PG_MASK] + egOut];
752int Y8950::Slot::calc_slot_snare(
int lfo_pm,
int lfo_am,
int whiteNoise)
754 unsigned egOut = calc_envelope(lfo_am);
755 unsigned pgout = calc_phase(lfo_pm);
756 unsigned tmp = (pgout & (1 << (PG_BITS - 1))) ? 0 : 2 * DB_MUTE;
757 return (dB2LinTab[tmp + egOut] + dB2LinTab[egOut + whiteNoise]) >> 1;
760int Y8950::Slot::calc_slot_cym(
int lfo_am,
int a,
int b)
762 unsigned egOut = calc_envelope(lfo_am);
763 return (dB2LinTab[egOut + a] + dB2LinTab[egOut + b]) >> 1;
767int Y8950::Slot::calc_slot_hat(
int lfo_am,
int a,
int b,
int whiteNoise)
769 unsigned egOut = calc_envelope(lfo_am);
770 return (dB2LinTab[egOut + whiteNoise] +
771 dB2LinTab[egOut + a] +
772 dB2LinTab[egOut + b]) >> 2;
775float Y8950::getAmplificationFactorImpl()
const
777 return 1.0f / (1 << DB2LIN_AMP_BITS);
786bool Y8950::checkMuteHelper()
791 for (
auto i :
xrange(6)) {
792 if (ch[i].slot[CAR].isActive())
return false;
795 for (
auto i :
xrange(6, 9)) {
796 if (ch[i].slot[CAR].isActive())
return false;
799 if (ch[6].slot[CAR].isActive())
return false;
800 if (ch[7].slot[MOD].isActive())
return false;
801 if (ch[7].slot[CAR].isActive())
return false;
802 if (ch[8].slot[MOD].isActive())
return false;
803 if (ch[8].slot[CAR].isActive())
return false;
809void Y8950::generateChannels(std::span<float*> bufs,
unsigned num)
812 if (checkMuteHelper()) {
820 for (
auto sample :
xrange(num)) {
826 if (am_phase == (LFO_AM_TAB_ELEMENTS * 64)) am_phase = 0;
827 int tmp = narrow_cast<int>(lfo_am_table[am_phase / 64]);
828 int lfo_am = am_mode ? tmp : tmp / 4;
830 pm_phase = (pm_phase + PM_DPHASE) & (PM_DP_WIDTH - 1);
831 int lfo_pm = pmTable[pm_mode][pm_phase >> (PM_DP_BITS - PM_PG_BITS)];
833 if (noise_seed & 1) {
834 noise_seed ^= 0x24000;
837 int whiteNoise = noise_seed & 1 ? DB_POS(6) : DB_NEG(6);
839 noiseA_phase += noiseA_dPhase;
840 noiseA_phase &= (0x40 << 11) - 1;
841 if ((noiseA_phase >> 11) == 0x3f) {
844 int noiseA = noiseA_phase & (0x03 << 11) ? DB_POS(6) : DB_NEG(6);
846 noiseB_phase += noiseB_dPhase;
847 noiseB_phase &= (0x10 << 11) - 1;
848 int noiseB = noiseB_phase & (0x0A << 11) ? DB_POS(6) : DB_NEG(6);
850 for (
auto i :
xrange(rythm_mode ? 6 : 9)) {
851 if (ch[i].slot[CAR].isActive()) {
852 bufs[i][sample] += narrow_cast<float>(ch[i].alg
853 ? ch[i].slot[CAR].calc_slot_car(lfo_pm, lfo_am, 0) +
854 ch[i].slot[MOD].calc_slot_mod(lfo_pm, lfo_am)
855 : ch[i].slot[CAR].calc_slot_car(lfo_pm, lfo_am,
856 ch[i].slot[MOD].calc_slot_mod(lfo_pm, lfo_am)));
867 (void)ch[7].slot[MOD].calc_phase(lfo_pm);
868 (void)ch[8].slot[CAR].calc_phase(lfo_pm);
870 bufs[ 9][sample] += (ch[6].slot[CAR].isActive())
871 ? narrow_cast<float>(
872 2 * ch[6].slot[CAR].calc_slot_car(lfo_pm, lfo_am,
873 ch[6].slot[MOD].calc_slot_mod(lfo_pm, lfo_am)))
875 bufs[10][sample] += (ch[7].slot[CAR].isActive())
876 ? narrow_cast<float>(2 * ch[7].slot[CAR].calc_slot_snare(lfo_pm, lfo_am, whiteNoise))
878 bufs[11][sample] += (ch[8].slot[CAR].isActive())
879 ? narrow_cast<float>(2 * ch[8].slot[CAR].calc_slot_cym(lfo_am, noiseA, noiseB))
881 bufs[12][sample] += (ch[7].slot[MOD].isActive())
882 ? narrow_cast<float>(2 * ch[7].slot[MOD].calc_slot_hat(lfo_am, noiseA, noiseB, whiteNoise))
884 bufs[13][sample] += (ch[8].slot[MOD].isActive())
885 ? narrow_cast<float>(2 * ch[8].slot[MOD].calc_slot_tom(lfo_pm, lfo_am))
895 bufs[14][sample] += narrow_cast<float>(adpcm.
calcSample());
905 static constexpr std::array<int, 32> sTbl = {
906 0, 2, 4, 1, 3, 5, -1, -1,
907 6, 8, 10, 7, 9, 11, -1, -1,
908 12, 14, 16, 13, 15, 17, -1, -1,
909 -1, -1, -1, -1, -1, -1, -1, -1
954 timer1->setValue(data);
959 timer2->setValue(data);
967 changeStatusMask((~data) & 0x78);
976 connector.
write(data, time);
981 periphery.
setSPOFF((data & 8) != 0, time);
1002 if (reg[0x08] & 0x04) {
1003 int tmp =
static_cast<signed char>(reg[0x15]) * 256
1005 tmp = (tmp * 4) >> (7 - reg[0x17]);
1010 reg[rg] = data & 0xC0;
1013 reg[rg] = data & 0x07;
1020 periphery.
write(reg[0x18], reg[0x19], time);
1025 periphery.
write(reg[0x18], reg[0x19], time);
1031 int s = sTbl[rg & 0x1f];
1033 auto& chan = ch[s / 2];
1034 auto& slot = chan.slot[s & 1];
1035 slot.patch.AM = (data >> 7) & 1;
1036 slot.patch.PM = (data >> 6) & 1;
1037 slot.patch.EG = (data >> 5) & 1;
1038 slot.patch.setKeyScaleRate((data & 0x10) != 0);
1039 slot.patch.ML = (data >> 0) & 15;
1040 slot.updateAll(chan.freq);
1046 int s = sTbl[rg & 0x1f];
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 int s = sTbl[rg & 0x1f];
1060 auto& slot = ch[s / 2].slot[s & 1];
1061 slot.patch.AR = (data >> 4) & 15;
1062 slot.patch.DR = (data >> 0) & 15;
1069 int s = sTbl[rg & 0x1f];
1071 auto& slot = ch[s / 2].slot[s & 1];
1072 slot.patch.SL = (data >> 4) & 15;
1073 slot.patch.RR = (data >> 0) & 15;
1081 am_mode = (data & 0x80) != 0;
1082 pm_mode = (data & 0x40) != 0;
1086 if (data & 0x10) keyOn_BD();
else keyOff_BD();
1087 if (data & 0x08) keyOn_SD();
else keyOff_SD();
1088 if (data & 0x04) keyOn_TOM();
else keyOff_TOM();
1089 if (data & 0x02) keyOn_CYM();
else keyOff_CYM();
1090 if (data & 0x01) keyOn_HH();
else keyOff_HH();
1092 ch[6].slot[MOD].updateAll(ch[6].freq);
1093 ch[6].slot[CAR].updateAll(ch[6].freq);
1094 ch[7].slot[MOD].updateAll(ch[7].freq);
1095 ch[7].slot[CAR].updateAll(ch[7].freq);
1096 ch[8].slot[MOD].updateAll(ch[8].freq);
1097 ch[8].slot[CAR].updateAll(ch[8].freq);
1102 unsigned c = rg & 0x0f;
1107 unsigned freq = [&] {
1110 return data | ((reg[rg + 0x10] & 0x1F) << 8);
1114 ch[c].keyOn (KEY_MAIN);
1116 ch[c].keyOff(KEY_MAIN);
1118 return reg[rg - 0x10] | ((data & 0x1F) << 8);
1121 ch[c].setFreq(freq);
1122 unsigned fNum = freq % 1024;
1123 unsigned block = freq / 1024;
1125 case 7: noiseA_dPhase = fNum << block;
1127 case 8: noiseB_dPhase = fNum << block;
1130 ch[c].slot[CAR].updateAll(freq);
1131 ch[c].slot[MOD].updateAll(freq);
1139 ch[c].slot[MOD].patch.setFeedbackShift((data >> 1) & 7);
1140 ch[c].alg = data & 1;
1155 return adpcm.
readReg(rg, time);
1165 return connector.
peek(time);
1171 return adpcm.
peekReg(rg, time);
1174 uint8_t input = periphery.
read(time);
1175 uint8_t output = reg[0x19];
1176 uint8_t enable = reg[0x18];
1177 return (output & enable) | (input & ~enable) | 0xF0;
1194 return (status & (0x87 | statusMask)) | 0x06;
1197void Y8950::callback(uint8_t flag)
1205 if (status & statusMask) {
1213 if (!(status & statusMask)) {
1222void Y8950::changeStatusMask(uint8_t newMask)
1224 statusMask = newMask;
1225 status &= 0x87 | statusMask;
1226 if (status & statusMask) {
1236template<
typename Archive>
1239 ar.serialize(
"AM", AM,
1253static constexpr std::initializer_list<enum_string<Y8950::EnvelopeState>> envelopeStateInfo = {
1267template<
typename Archive>
1270 ar.serialize(
"feedback", feedback,
1273 "eg_phase", eg_phase,
1275 if (ar.versionAtLeast(version, 3)) {
1276 ar.serialize(
"eg_mode", eg_mode);
1278 assert(Archive::IS_LOADER);
1280 ar.serialize(
"eg_mode", tmp);
1282 case 0: eg_mode =
ATTACK;
break;
1283 case 1: eg_mode =
DECAY;
break;
1284 case 2: eg_mode =
SUSTAIN;
break;
1285 case 3: eg_mode =
SUSTAIN;
break;
1286 case 4: eg_mode =
RELEASE;
break;
1287 default: eg_mode =
FINISH;
break;
1297template<
typename Archive>
1300 ar.serialize(
"mod", slot[MOD],
1305 if constexpr (Archive::IS_LOADER) {
1306 slot[MOD].updateAll(freq);
1307 slot[CAR].updateAll(freq);
1311template<
typename Archive>
1314 ar.serialize(
"keyboardConnector", connector,
1319 ar.serialize_blob(
"registers", reg);
1320 ar.serialize(
"pm_phase", pm_phase,
1321 "am_phase", am_phase,
1322 "noise_seed", noise_seed,
1323 "noiseA_phase", noiseA_phase,
1324 "noiseB_phase", noiseB_phase,
1325 "noiseA_dphase", noiseA_dPhase,
1326 "noiseB_dphase", noiseB_dPhase,
1329 "statusMask", statusMask,
1330 "rythm_mode", rythm_mode,
1333 "enabled", enabled);
1335 if constexpr (Archive::IS_LOADER) {
1337 static constexpr std::array<uint8_t, 2> rewriteRegs = {
1342 update_key_status();
1344 for (
auto r : rewriteRegs) {
1354 const std::string& name_)
1359uint8_t Y8950::Debuggable::read(
unsigned address, EmuTime::param time)
1362 return y8950.peekReg(narrow<uint8_t>(address), time);
1365void Y8950::Debuggable::write(
unsigned address, uint8_t value, EmuTime::param time)
1368 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()
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)
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
std::string getName(KeyCode keyCode)
Translate key code to key name.
FixedPoint< EP_FP_BITS > EnvPhaseIndex
This file implemented 3 utility functions:
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
SERIALIZE_CLASS_VERSION(CassettePlayer, 2)
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)
constexpr auto xrange(T e)