67 0, 8, 16, 24, 32, 40, 48, 255, 255, 0, 0, 0, 0, 0, 0, 0
70 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 48, 40, 32, 24, 16, 8
75 static constexpr int16_t SC(
int dB) {
return int16_t(dB / 3 * 0x20); }
77 SC( 0), SC( 3), SC( 6), SC( 9), SC(12), SC(15), SC(18), SC(21),
78 SC(24), SC(27), SC(30), SC(33), SC(36), SC(39), SC(42), SC(93)
84 0, 1, 0, 1, 0, 1, 0, 1,
85 0, 1, 0, 1, 1, 1, 0, 1,
86 0, 1, 1, 1, 0, 1, 1, 1,
87 0, 1, 1, 1, 1, 1, 1, 1,
89 1, 1, 1, 1, 1, 1, 1, 1,
90 1, 1, 1, 2, 1, 1, 1, 2,
91 1, 2, 1, 2, 1, 2, 1, 2,
92 1, 2, 2, 2, 1, 2, 2, 2,
94 2, 2, 2, 2, 2, 2, 2, 2,
95 2, 2, 2, 4, 2, 2, 2, 4,
96 2, 4, 2, 4, 2, 4, 2, 4,
97 2, 4, 4, 4, 2, 4, 4, 4,
99 4, 4, 4, 4, 4, 4, 4, 4,
100 8, 8, 8, 8, 8, 8, 8, 8,
101 0, 0, 0, 0, 0, 0, 0, 0,
104 [[nodiscard]]
static constexpr
byte O(
int a) {
return a *
RATE_STEPS; }
106 O(14),O(14),O(14),O(14),
107 O( 0),O( 1),O( 2),O( 3),
108 O( 0),O( 1),O( 2),O( 3),
109 O( 0),O( 1),O( 2),O( 3),
110 O( 0),O( 1),O( 2),O( 3),
111 O( 0),O( 1),O( 2),O( 3),
112 O( 0),O( 1),O( 2),O( 3),
113 O( 0),O( 1),O( 2),O( 3),
114 O( 0),O( 1),O( 2),O( 3),
115 O( 0),O( 1),O( 2),O( 3),
116 O( 0),O( 1),O( 2),O( 3),
117 O( 0),O( 1),O( 2),O( 3),
118 O( 0),O( 1),O( 2),O( 3),
119 O( 4),O( 5),O( 6),O( 7),
120 O( 8),O( 9),O(10),O(11),
121 O(12),O(12),O(12),O(12),
149 [[nodiscard]]
static constexpr
int L(
double a) {
return int((
LFO_PERIOD * a) / 44100.0 + 0.5); }
201 [[nodiscard]]
static constexpr
int sign_extend_4(
int x)
212 [[nodiscard]]
static constexpr
unsigned calcStep(int8_t oct, uint16_t fn, int16_t vib = 0)
214 if (oct == -8)
return 0;
215 unsigned t = (fn + 1024 + vib) << (8 + oct);
219 void YMF278::Slot::reset()
221 wave = FN = OCT = TLdest = TL = pan = vib = AM = 0;
222 DL = AR = D1R = D2R = RC = RR = 0;
223 PRVB = keyon = DAMP =
false;
225 step = calcStep(OCT, FN);
226 bits = startaddr = loopaddr = endaddr = 0;
239 int YMF278::Slot::compute_rate(
int val)
const
243 }
else if (val == 15) {
250 res += (FN & 0x200) ? 1 : 0;
255 int YMF278::Slot::compute_decay_rate(
int val)
const
270 if (env_vol <
dl_tab[4]) {
286 if (env_vol >=
dl_tab[6]) {
290 return compute_rate(val);
293 int16_t YMF278::Slot::compute_vib()
const
302 int16_t lfo_fm = lfo_cnt / (
LFO_PERIOD / 0x40);
304 if (lfo_fm & 0x10) lfo_fm ^= 0x1F;
305 if (lfo_fm & 0x20) lfo_fm = -(lfo_fm & 0x0F);
310 uint16_t YMF278::Slot::compute_am()
const
316 uint16_t lfo_am = lfo_cnt / (
LFO_PERIOD / 0x100);
318 if (lfo_am >= 0x80) lfo_am ^= 0xFF;
320 return (lfo_am *
am_depth[AM]) >> 7;
324 void YMF278::advance()
329 int tl_int_cnt = eg_cnt % 9;
330 int tl_int_step = (eg_cnt / 9) % 3;
332 for (
auto& op : slots) {
334 if (tl_int_cnt == 0) {
335 if (tl_int_step == 0) {
337 if (op.TL < op.TLdest) ++op.TL;
340 if (op.TL > op.TLdest) --op.TL;
351 uint8_t rate = op.compute_rate(op.AR);
359 if (!(eg_cnt & ((1 << shift) - 1))) {
362 op.env_vol += (~op.env_vol *
eg_inc[select + ((eg_cnt >> shift) & 7)]) >> 4;
373 uint8_t rate = op.compute_decay_rate(op.D1R);
375 if (!(eg_cnt & ((1 << shift) - 1))) {
377 op.env_vol +=
eg_inc[select + ((eg_cnt >> shift) & 7)];
378 if (op.env_vol >= op.DL) {
385 uint8_t rate = op.compute_decay_rate(op.D2R);
387 if (!(eg_cnt & ((1 << shift) - 1))) {
389 op.env_vol +=
eg_inc[select + ((eg_cnt >> shift) & 7)];
398 uint8_t rate = op.compute_decay_rate(op.RR);
400 if (!(eg_cnt & ((1 << shift) - 1))) {
402 op.env_vol +=
eg_inc[select + ((eg_cnt >> shift) & 7)];
420 int16_t YMF278::getSample(Slot& slot, uint16_t pos)
const
428 return readMem(slot.startaddr + pos) << 8;
432 unsigned addr = slot.startaddr + ((pos / 2) * 3);
434 return (
readMem(addr + 2) << 8) |
437 return (
readMem(addr + 0) << 8) |
438 ((
readMem(addr + 1) << 4) & 0xF0);
443 unsigned addr = slot.startaddr + (pos * 2);
444 return (
readMem(addr + 0) << 8) |
453 uint16_t YMF278::nextPos(Slot& slot, uint16_t pos, uint16_t increment)
459 if ((uint32_t(pos) + slot.endaddr) >= 0x10000)
460 pos += slot.endaddr + slot.loopaddr;
464 bool YMF278::anyActive()
473 static constexpr
int vol_factor(
int x,
unsigned envVol)
476 int vol_mul = 0x80 - (envVol & 0x3F);
477 int vol_shift = 7 + (envVol >> 6);
478 return (
x * ((0x8000 * vol_mul) >> vol_shift)) >> 15;
483 static constexpr
float level[8] = {
496 void YMF278::generateChannels(
float** bufs,
unsigned num)
501 std::fill_n(bufs, 24,
nullptr);
505 for (
auto j :
xrange(num)) {
506 for (
auto i :
xrange(24)) {
514 int16_t sample = (getSample(sl, sl.pos) * (0x10000 - sl.stepptr) +
515 getSample(sl, nextPos(sl, sl.pos, 1)) * sl.stepptr) >> 16;
522 uint16_t envVol =
std::min(sl.env_vol + ((sl.lfo_active && sl.AM) ? sl.compute_am() : 0),
524 int smplOut = vol_factor(vol_factor(sample, envVol), sl.TL <<
TL_SHIFT);
529 int32_t volLeft =
pan_left [sl.pan];
532 volLeft = (0x20 - (volLeft & 0x0f)) >> (volLeft >> 4);
533 volRight = (0x20 - (volRight & 0x0f)) >> (volRight >> 4);
535 bufs[i][2 * j + 0] += (smplOut * volLeft ) >> 5;
536 bufs[i][2 * j + 1] += (smplOut * volRight) >> 5;
538 unsigned step = (sl.lfo_active && sl.vib)
539 ? calcStep(sl.OCT, sl.FN, sl.compute_vib())
543 if (sl.stepptr >= 0x10000) {
544 sl.pos = nextPos(sl, sl.pos, sl.stepptr >> 16);
545 sl.stepptr &= 0xffff;
552 void YMF278::keyOnHelper(YMF278::Slot& slot)
556 if (slot.compute_rate(slot.AR) < 63) {
572 writeRegDirect(reg, data, time);
575 void YMF278::writeRegDirect(
byte reg,
byte data, EmuTime::param time)
578 if (reg >= 0x08 && reg <= 0xF7) {
579 int sNum = (reg - 8) % 24;
580 auto& slot = slots[sNum];
581 switch ((reg - 8) / 24) {
583 slot.wave = (slot.wave & 0x100) | data;
584 int waveTblHdr = (regs[2] >> 2) & 0x7;
585 int base = (slot.wave < 384 || !waveTblHdr) ?
587 (waveTblHdr * 0x80000 + ((slot.wave - 384) * 12));
589 for (
auto i :
xrange(12)) {
594 slot.bits = (buf[0] & 0xC0) >> 6;
595 slot.startaddr = buf[2] | (buf[1] << 8) | ((buf[0] & 0x3F) << 16);
596 slot.loopaddr = buf[4] | (buf[3] << 8);
597 slot.endaddr = buf[6] | (buf[5] << 8);
598 for (
auto i :
xrange(7, 12)) {
602 writeRegDirect(8 + sNum + (i - 2) * 24, buf[i], time);
613 slot.wave = (slot.wave & 0xFF) | ((data & 0x1) << 8);
614 slot.FN = (slot.FN & 0x380) | (data >> 1);
615 slot.step = calcStep(slot.OCT, slot.FN);
619 slot.FN = (slot.FN & 0x07F) | ((data & 0x07) << 7);
620 slot.PRVB = (data & 0x08) != 0;
621 slot.OCT = sign_extend_4((data & 0xF0) >> 4);
622 slot.step = calcStep(slot.OCT, slot.FN);
626 uint8_t
t = data >> 1;
627 slot.TLdest = (
t != 0x7f) ?
t : 0xff;
630 slot.TL = slot.TLdest;
643 slot.pan = data & 0x0F;
648 slot.lfo_active =
false;
652 slot.lfo_active =
true;
655 slot.DAMP = (data & 0x40) != 0;
670 slot.lfo = (data >> 3) & 0x7;
671 slot.vib = data & 0x7;
675 slot.D1R = data & 0xF;
678 slot.DL =
dl_tab[data >> 4];
679 slot.D2R = data & 0xF;
683 slot.RR = data & 0xF;
686 slot.AM = data & 0x7;
721 memAdr = (regs[3] << 16) | (regs[4] << 8) | data;
763 return (regs[2] & 0x1F) | 0x20;
778 constexpr
unsigned INPUT_RATE = 44100;
783 24, INPUT_RATE, true)
784 , motherBoard(config.getMotherBoard())
785 , debugRegisters(motherBoard,
getName())
786 , debugMemory (motherBoard,
getName())
787 , rom(
getName() +
" ROM",
"rom", config)
788 , ram(config,
getName() +
" RAM",
"YMF278 sample RAM",
791 if (rom.
getSize() != 0x200000) {
793 "Wrong ROM for MoonSound (YMF278). The ROM (usually "
794 "called yrw801.rom) should have a size of exactly 2MB.");
796 if ((ramSize_ != 0) &&
801 (ramSize_ != 1024) &&
802 (ramSize_ != 2048)) {
804 "Wrong sampleram size for MoonSound (YMF278). "
805 "Got ", ramSize_,
", but must be one of "
806 "0, 128, 256, 512, 640, 1024 or 2048.");
832 for (
auto& op : slots) {
836 for (
int i = 0xf7; i >= 0; --i) {
837 writeRegDirect(i, 0, time);
889 unsigned YMF278::getRamAddress(
unsigned addr)
const
892 if (regs[2] & 2) [[unlikely]] {
895 if ((0x180000 <= addr) && (addr <= 0x1FFFFF)) {
897 switch (addr & 0x060000) {
902 if (ram.
getSize() == 256 * 1024) {
923 if (ram.
getSize() == 640 * 1024) {
928 if (addr > 0x080000) {
939 if (address < 0x200000) {
943 unsigned ramAddr = getRamAddress(address);
956 if (address < 0x200000) {
959 unsigned ramAddr = getRamAddress(address);
961 ram.
write(ramAddr, value);
986 template<
typename Archive>
990 ar.serialize(
"startaddr", startaddr,
991 "loopaddr", loopaddr,
999 if (ar.versionAtLeast(version, 4)) {
1000 ar.serialize(
"endaddr", endaddr,
1003 unsigned e = 0; ar.serialize(
"endaddr",
e); endaddr = (
e ^ 0xffff) + 1;
1006 if (ar.versionAtLeast(version, 2)) {
1007 ar.serialize(
"OCT", O);
1009 ar.serializeChar(
"OCT", O);
1011 OCT = sign_extend_4(O);
1014 if (ar.versionAtLeast(version, 2)) {
1015 ar.serialize(
"PRVB", PRVB,
1027 char PRVB_ = 0; ar.serializeChar(
"PRVB", PRVB_); PRVB = PRVB_;
1028 char TL_ = 0; ar.serializeChar(
"TL", TL_ ); TL = TL_;
1029 char pan_ = 0; ar.serializeChar(
"pan", pan_); pan = pan_;
1030 char vib_ = 0; ar.serializeChar(
"vib", vib_); vib = vib_;
1031 char AM_ = 0; ar.serializeChar(
"AM", AM_ ); AM = AM_;
1032 char AR_ = 0; ar.serializeChar(
"AR", AR_ ); AR = AR_;
1033 char D1R_ = 0; ar.serializeChar(
"D1R", D1R_); D1R = D1R_;
1034 char D2R_ = 0; ar.serializeChar(
"D2R", D2R_); D2R = D2R_;
1035 char RC_ = 0; ar.serializeChar(
"RC", RC_ ); RC = RC_;
1036 char RR_ = 0; ar.serializeChar(
"RR", RR_ ); RR = RR_;
1038 ar.serialize(
"bits", bits,
1039 "lfo_active", lfo_active);
1041 ar.serialize(
"state", state);
1042 if (ar.versionBelow(version, 4)) {
1043 assert(Archive::IS_LOADER);
1050 if constexpr (Archive::IS_LOADER) {
1051 step = calcStep(OCT, FN);
1070 template<
typename Archive>
1073 ar.serialize(
"slots", slots,
1075 if (ar.versionAtLeast(version, 4)) {
1076 ar.serialize(
"ram", ram);
1080 ar.serialize_blob(
"registers", regs,
sizeof(regs));
1081 if (ar.versionAtLeast(version, 3)) {
1082 ar.serialize(
"memadr", memAdr);
1084 assert(Archive::IS_LOADER);
1089 memAdr = (regs[3] << 16) | (regs[4] << 8) | regs[5];
1093 if constexpr (Archive::IS_LOADER) {
1095 auto t = regs[0x50 + i] >> 1;
1096 sl.TLdest = (
t != 0x7f) ?
t : 0xff;
1098 sl.keyon = (regs[0x68 + i] & 0x80) != 0;
1099 sl.DAMP = (regs[0x68 + i] & 0x40) != 0;
1100 sl.lfo = (regs[0x80 + i] >> 3) & 7;
1109 YMF278::DebugRegisters::DebugRegisters(
MSXMotherBoard& motherBoard_,
1110 const std::string& name_)
1112 "OPL4 registers", 0x100)
1116 byte YMF278::DebugRegisters::read(
unsigned address)
1119 return ymf278.peekReg(address);
1122 void YMF278::DebugRegisters::write(
unsigned address,
byte value, EmuTime::param time)
1125 ymf278.writeReg(address, value, time);
1131 YMF278::DebugMemory::DebugMemory(MSXMotherBoard& motherBoard_,
1132 const std::string& name_)
1133 : SimpleDebuggable(motherBoard_, name_ +
" mem",
1134 "OPL4 memory (includes both ROM and RAM)", 0x400000)
1138 byte YMF278::DebugMemory::read(
unsigned address)
1141 return ymf278.readMem(address);
1144 void YMF278::DebugMemory::write(
unsigned address,
byte value)
1147 ymf278.writeMem(address, value);
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.
void write(unsigned addr, byte value)
byte * getWriteBackdoor()
byte readMem(unsigned address) const
void writeReg(byte reg, byte data, EmuTime::param time)
void setMixLevel(uint8_t x, EmuTime::param time)
YMF278(const std::string &name, int ramSize, const DeviceConfig &config)
void writeMem(unsigned address, byte value)
void reset(EmuTime::param time)
byte peekReg(byte reg) const
void serialize(Archive &ar, unsigned version)
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
constexpr vecN< N, T > clamp(const vecN< N, T > &x, const vecN< N, T > &minVal, const vecN< N, T > &maxVal)
std::string getName(KeyCode keyCode)
Translate key code to key name.
This file implemented 3 utility functions:
constexpr byte eg_rate_shift[32+64+32]
constexpr int16_t dl_tab[16]
constexpr uint8_t pan_right[16]
constexpr unsigned EG_SUS
constexpr int16_t vib_depth[8]
constexpr unsigned RATE_STEPS
constexpr byte eg_inc[19 *RATE_STEPS]
constexpr unsigned LFO_SHIFT
constexpr uint8_t pan_left[16]
constexpr KeyMatrixPosition x
Keyboard bindings.
void serialize(Archive &ar, T &t, unsigned version)
constexpr unsigned EG_REL
constexpr byte eg_rate_select[32+64+32]
constexpr int MIN_ATT_INDEX
constexpr unsigned LFO_PERIOD
constexpr int MAX_ATT_INDEX
constexpr unsigned EG_DEC
constexpr uint8_t am_depth[8]
constexpr int lfo_period[8]
constexpr unsigned EG_OFF
constexpr unsigned EG_ATT
bool any_of(InputRange &&range, UnaryPredicate pred)
constexpr void fill(ForwardRange &&range, const T &value)
#define OUTER(type, member)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)