📄 nes_fds.cpp
字号:
/*
** Nintendo FDS ExSound by TAKEDA, toshiya
**
** original: s_fds.c in nezp0922
*/
/* modifyed by stun 2000.10.24 */
/* bug fix by stun 2000.11.27 */
static int32 FDSSoundRender(void)
{
FDS_FMOP *pop;
uint32 vol;
pop = &apu->fdssound.op[0];
if(pop->timer>=0) pop->timer--;
if(pop->timer==0)
{
apu->fdssound.op[1].sweep=pop->last_spd;
pop->envmode=1;
}
if(pop->envmode==1)
{
apu->fdssound.op[1].spd = apu->fdssound.op[1].sweep;
}
else if(pop->envmode & 0x80)
{
uint32 sweeps=(uint32)apu->fdssound.op[1].sweep;
pop->envphase++;
if (!(pop->envmode & 0x40))
{
if((uint32)pop->envphase==pop->envspd)
{
pop->envphase=0;
if(apu->fdssound.op[1].spd <sweeps)
{
apu->fdssound.op[1].spd += pop->volume;
if(apu->fdssound.op[1].spd >sweeps)
apu->fdssound.op[1].spd=sweeps;
}
}
}
else
{
if((uint32)pop->envphase==pop->envspd)
{
pop->envphase=0;
if(apu->fdssound.op[1].spd > sweeps/2)
{
apu->fdssound.op[1].spd -= pop->volume;
if(apu->fdssound.op[1].spd < sweeps)
apu->fdssound.op[1].spd=sweeps;
}
}
}
}
vol = pop->volume;
if (pop->sweep)
{
vol += pop->sweep;
if (vol < 0)
vol = 0;
else if (vol > 0x3f)
vol = 0x3f;
}
//pop->envout = LinearToLog(vol);
pop->envout = LinearToLog(0);
pop = &apu->fdssound.op[1];
{
uint32 vol;
if (pop->envmode && apu->fdssound.fade)
{
pop->envphase -= apu->fdssound.cps >> (11 - 1);
if (pop->envmode & 0x40)
while (pop->envphase < 0)
{
pop->envphase += pop->envspd;
pop->volume += (pop->volume < 0x1f);
}
else
while (pop->envphase < 0)
{
pop->envphase += pop->envspd;
pop->volume -= (pop->volume > 0x00);
}
}
vol = pop->volume;
pop->envout = LinearToLog(vol);
}
apu->fdssound.op[1].envout += apu->fdssound.mastervolume;
apu->fdssound.cycles -= apu->fdssound.cps;
while (apu->fdssound.cycles < 0)
{
apu->fdssound.cycles += 1 << 23;
apu->fdssound.output = 0;
for (pop = &apu->fdssound.op[0]; pop < &apu->fdssound.op[2]; pop++)
{
if (!pop->spd || !pop->enable)
{
apu->fdssound.output = 0;
continue;
}
pop->phase += pop->spd + apu->fdssound.output;
apu->fdssound.output = LogToLinear(pop->envout + pop->wave[(pop->phase >> (23 - 1)) & 0x3f], pop->outlvl);
}
}
if (apu->fdssound.mute) return 0;
return apu->fdssound.output;
}
static void FDSSoundVolume(uint32 volume)
{
apu->fdssound.mastervolume = (volume << (LOG_BITS - 8)) << 1;
}
static void FDSSoundWrite(uint32 address, uint8 value)
{
if (0x4040 <= address && address <= 0x407F)
{
apu->fdssound.op[1].wave[address - 0x4040] = LinearToLog(((int32)value & 0x3f) - 0x20);
}
else if (0x4080 <= address && address <= 0x408F)
{
int ch = (address < 0x4084);
FDS_FMOP *pop = &apu->fdssound.op[ch];
apu->fdssound.reg[address - 0x4080] = value;
switch (address & 15)
{
case 0:
if (value & 0x80)
{
pop->volume = (value & 0x3f);
pop->envmode = 0;
}
else
{
pop->envspd = ((value & 0x3f) + 1) << 23;
pop->envmode = 0x80 | value;
}
break;
case 4:
if(value & 0x80)
{
int32 a=apu->fdssound.op[1].spd;
int32 b=apu->fdssound.op[1].sweep;
pop->timer=(0x3f-(value & 0x3f)) << 10;
if(pop->timer==0) pop->timer=1;
pop->last_spd=a*(0x3f-(value & 0x3f))/0x3f+
b*(value & 0x3f)/0x3f;
}
else if(apu->fdssound.op[1].sweep)
{
pop->envspd = (value & 0x3f) << 5;
if((value & 0x3f)==0) pop->envspd=1;
pop->envphase = 0;
pop->envmode = 0x80 | (value & 0x40) ;
pop->volume=abs(apu->fdssound.op[1].sweep - apu->fdssound.op[1].spd);
pop->volume/=pop->envspd;
if((value & 0x3f)==0) pop->envmode=1;
}
apu->fdssound.waveaddr = 0;
break;
case 1:
if ((value & 0x7f) < 0x60)
apu->fdssound.op[0].sweep = value & 0x7f;
else
apu->fdssound.op[0].sweep = ((int32)value & 0x7f) - 0x80;
break;
case 5:
if (!value) break;
if ((value & 0x7f) < 0x60)
{
apu->fdssound.op[1].sweep = (int32)apu->fdssound.op[1].spd+
((apu->fdssound.op[1].spd * (value & 0x7f))>>5);
}
else
{
apu->fdssound.op[1].sweep = (int32)apu->fdssound.op[1].spd-
(((apu->fdssound.op[1].spd) * (((int32)value & 0x7f) - 0x80)) >> 5);
}
break;
case 2:
pop->spd &= 0x00000F00 << 7;
pop->spd |= (value & 0xFF) << 7;
apu->fdssound.op[0].envmode = 0;
apu->fdssound.op[0].timer=0;
break;
case 6:
pop->spd &= 0x00000F00 << 7;
pop->spd |= (value & 0xFF) << 7;
pop->envmode = 0;
break;
case 3:
pop->spd &= 0x000000FF << 7;
pop->spd |= (value & 0x0F) << (7 + 8);
pop->enable = !(value & 0x80);
apu->fdssound.op[0].envmode = 0;
apu->fdssound.op[0].timer=0;
break;
case 7:
pop->spd &= 0x000000FF << 7;
pop->spd |= (value & 0x0F) << (7 + 8);
pop->enable = !(value & 0x80);
apu->fdssound.waveaddr = 0;
break;
case 8:
{
static int8 lfotbl[8] = { 0,1,2,3,-4,-3,-2,-1 };
uint32 v = LinearToLog(lfotbl[value & 7]);
apu->fdssound.op[0].wave[apu->fdssound.waveaddr++] = v;
apu->fdssound.op[0].wave[apu->fdssound.waveaddr++] = v;
if (apu->fdssound.waveaddr == 0x40)
{
apu->fdssound.waveaddr = 0;
}
}
break;
case 9:
apu->fdssound.op[0].outlvl = LOG_LIN_BITS - LIN_BITS - LIN_BITS - 10 - (value & 3);
if(value & 0x80) apu->fdssound.mute=1;
else apu->fdssound.mute=0;
break;
case 10:
apu->fdssound.op[1].outlvl = LOG_LIN_BITS - LIN_BITS - LIN_BITS - 10 - (value & 3);
if(value & 0x80) apu->fdssound.fade=1;
else apu->fdssound.fade=0;
break;
}
}
}
static void FDSSoundWriteCurrent(uint32 address, uint8 value)
{
if (0x4080 <= address && address <= 0x408F)
{
apu->fdssound.reg_cur[address - 0x4080] = value;
}
}
static uint8 FDSSoundRead(uint32 address)
{
if (0x4090 <= address && address <= 0x409F)
{
return apu->fdssound.reg_cur[address - 0x4090];
}
return 0;
}
static void FDSSoundReset(void)
{
int8 i;
FDS_FMOP *pop;
memset(&apu->fdssound, 0, sizeof(FDSSOUND));
apu->fdssound.cps = DivFix(NES_BASECYCLES, 12 * (1 << 1) * SAMPLE_RATE, 23);
for (pop = &apu->fdssound.op[0]; pop < &apu->fdssound.op[2]; pop++)
{
pop->enable = 1;
}
apu->fdssound.op[0].outlvl = LOG_LIN_BITS - LIN_BITS - LIN_BITS - 10;
apu->fdssound.op[1].outlvl = LOG_LIN_BITS - LIN_BITS - LIN_BITS - 10;
for (i = 0; i < 0x40; i++)
{
apu->fdssound.op[1].wave[i] = LinearToLog((i < 0x20)?0x1f:-0x20);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -