📄 nes_mmc5.cpp
字号:
/*
** Nintendo MMC3 ExSound by TAKEDA, toshiya
**
** original: s_apu.c in nezp0922
*/
#define V(x) (x*64/60)
static uint32 mmc5_vbl_length[32] =
{
V(0x05), V(0x7F), V(0x0A), V(0x01), V(0x14), V(0x02), V(0x28), V(0x03),
V(0x50), V(0x04), V(0x1E), V(0x05), V(0x07), V(0x06), V(0x0E), V(0x07),
V(0x06), V(0x08), V(0x0C), V(0x09), V(0x18), V(0x0A), V(0x30), V(0x0B),
V(0x60), V(0x0C), V(0x24), V(0x0D), V(0x08), V(0x0E), V(0x10), V(0x0F),
};
#undef V
#define V(x) ((x) << 19)
static const uint32 mmc5_spd_limit[8] =
{
V(0x3FF), V(0x555), V(0x666), V(0x71C),
V(0x787), V(0x7C1), V(0x7E0), V(0x7F0),
};
#undef V
static int32 MMC5SoundSquareRender(MMC5_SQUARE *ch)
{
uint32 output;
if (ch->update)
{
if (ch->update & 1)
{
ch->duty = (ch->regs[0] >> 4) & 0x0C;
if (ch->duty == 0) ch->duty = 2;
ch->envspd = ((ch->regs[0] & 0x0F) + 1) << (19 + 7);
}
if (ch->update & 2)
{
ch->sweepspd = (((ch->regs[1] >> 4) & 0x07) + 1) << (19 + 8);
}
if (ch->update & (4 | 8))
{
ch->spd = (((ch->regs[3] & 7) << 8) + ch->regs[2] + 1) << 19;
}
if ((ch->update & 8) && (ch->key & 1))
{
ch->key &= ~2;
ch->length = (mmc5_vbl_length[ch->regs[3] >> 3] * ch->freq) >> 6;
ch->envadr = 0;
}
ch->update = 0;
}
if (ch->key == 0) return 0;
ch->envphase -= ch->cps >> (13 - 7);
if (ch->regs[0] & 0x20)
{
while (ch->envphase < 0)
{
ch->envphase += ch->envspd;
ch->envadr++;
}
ch->envadr &= 0x0F;
}
else
{
while (ch->envphase < 0)
{
ch->envphase += ch->envspd;
ch->envadr += (ch->envadr < 15);
}
}
if (ch->length)
{
if (!(ch->regs[0] & 0x20)) ch->length--;
}
else
{
ch->key |= 2;
}
if ((ch->regs[1] & 0x80))
{
if (ch->regs[1] & 7)
{
ch->sweepphase -= ch->cps >> (14 - 8);
if (ch->regs[1] & 8)
while (ch->sweepphase < 0)
{
ch->sweepphase += ch->sweepspd;
ch->spd -= ch->spd >> (ch->regs[1] & 7);
}
else
while (ch->sweepphase < 0)
{
ch->sweepphase += ch->sweepspd;
ch->spd += ch->spd >> (ch->regs[1] & 7);
}
}
}
if (ch->spd < (4 << 19)) return 0;
if (!(ch->regs[1] & 8))
{
if (ch->spd > mmc5_spd_limit[ch->regs[1] & 7]) return 0;
}
ch->cycles -= ch->cps;
while (ch->cycles < 0)
{
ch->cycles += ch->spd;
ch->adr++;
}
ch->adr &= 0x0F;
if (ch->key & 2)
{
if (ch->release < (31 << (LOG_BITS + 1)))
ch->release += 3 << (LOG_BITS - 8 + 1);
}
else
{
ch->release = 0;
}
if (ch->mute) return 0;
if (ch->regs[0] & 0x10) /* fixed volume */
output = ch->regs[0] & 0x0F;
else
output = 15 - ch->envadr;
output = LinearToLog(output) + ch->mastervolume + ch->release;
output += (ch->adr < ch->duty);
return LogToLinear(output, LOG_LIN_BITS - LIN_BITS - 16);
}
static void MMC5SoundSquareReset(MMC5_SQUARE *ch)
{
memset(ch, 0, sizeof(MMC5_SQUARE));
ch->freq = SAMPLE_RATE;
ch->cps = DivFix(NES_BASECYCLES, 12 * ch->freq, 19);
}
static int32 MMC5SoundRender(void)
{
int32 accum = 0;
accum += MMC5SoundSquareRender(&apu->mmc5.square[0]);
accum += MMC5SoundSquareRender(&apu->mmc5.square[1]);
return accum;
}
static void MMC5SoundVolume(uint32 volume)
{
volume = (volume << (LOG_BITS - 8)) << 1;
apu->mmc5.square[0].mastervolume = volume;
apu->mmc5.square[1].mastervolume = volume;
}
static void MMC5SoundWrite(uint32 address, uint8 value)
{
if (0x5000 <= address && address <= 0x5015)
{
switch (address)
{
case 0x5000: case 0x5002: case 0x5003:
case 0x5004: case 0x5006: case 0x5007:
{
int ch = address >= 0x5004;
int port = address & 3;
apu->mmc5.square[ch].regs[port] = value;
apu->mmc5.square[ch].update |= 1 << port;
}
break;
case 0x5011:
apu->mmc5.da.output = ((int32)value) - 0x80;
break;
case 0x5010:
apu->mmc5.da.key = (value & 0x01);
break;
case 0x5015:
if (value & 1)
apu->mmc5.square[0].key = 1;
else
{
apu->mmc5.square[0].key = 0;
apu->mmc5.square[0].length = 0;
}
if (value & 2)
apu->mmc5.square[1].key = 1;
else
{
apu->mmc5.square[1].key = 0;
apu->mmc5.square[1].length = 0;
}
break;
}
}
}
static void MMC5SoundDaReset(MMC5_DA *ch)
{
memset(ch, 0, sizeof(MMC5_DA));
}
static void MMC5SoundReset(void)
{
MMC5SoundSquareReset(&apu->mmc5.square[0]);
MMC5SoundSquareReset(&apu->mmc5.square[1]);
MMC5SoundDaReset(&apu->mmc5.da);
MMC5SoundWrite(0x5000, 0x00);
MMC5SoundWrite(0x5002, 0x00);
MMC5SoundWrite(0x5003, 0x00);
MMC5SoundWrite(0x5004, 0x00);
MMC5SoundWrite(0x5006, 0x00);
MMC5SoundWrite(0x5007, 0x00);
MMC5SoundWrite(0x5010, 0x00);
MMC5SoundWrite(0x5011, 0x00);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -