mmc5: fix bug in pcm audio that i didn't even know about because nothing ever uses it at all. sunsoft 5b: implement audio. affects Gimmick(J). note that the audio emulation is rather incomplete.

This commit is contained in:
goyuken 2012-12-14 21:06:58 +00:00
parent c90d2dcd56
commit bab873fa13
4 changed files with 179 additions and 5 deletions

View File

@ -442,6 +442,7 @@
<Compile Include="QuickCollections.cs" />
<Compile Include="Sound\CDAudio.cs" />
<Compile Include="Sound\MMC5Audio.cs" />
<Compile Include="Sound\Sunsoft5BAudio.cs" />
<Compile Include="Sound\Utilities\BlipBuffer.cs" />
<Compile Include="Sound\Utilities\DCFilter.cs" />
<Compile Include="Sound\Utilities\Equalizer.cs" />

View File

@ -315,9 +315,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public override byte ReadPRG(int addr)
{
bool ram;
addr = MapPRG(addr, out ram);
if (ram) return WRAM[addr];
else return ROM[addr];
byte ret;
int mapaddr = MapPRG(addr, out ram);
if (ram)
ret = WRAM[mapaddr];
else
ret = ROM[mapaddr];
if (addr < 0x4000)
audio.ReadROMTrigger(ret);
return ret;
}
public override void WritePRG(int addr, byte value)

View File

@ -9,6 +9,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
class Sunsoft_5 : Sunsoft_FME7
{
Sound.Sunsoft5BAudio audio;
public override bool Configure(NES.EDetectionOrigin origin)
{
//configure
@ -22,14 +24,33 @@ namespace BizHawk.Emulation.Consoles.Nintendo
}
BaseConfigure();
if (NES.apu != null)
audio = new Sound.Sunsoft5BAudio(NES.apu.ExternalQueue);
return true;
}
public override void WritePRG(int addr, byte value)
{
//TODO - sound
base.WritePRG(addr, value);
int a = addr & 0xe000;
if (a == 0x4000)
audio.RegSelect(value);
else if (a == 0x6000)
audio.RegWrite(value);
else
base.WritePRG(addr, value);
}
public override void SyncState(Serializer ser)
{
base.SyncState(ser);
audio.SyncState(ser);
}
public override void ClockCPU()
{
audio.Clock();
base.ClockCPU();
}
}

View File

@ -0,0 +1,146 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Emulation.Sound
{
// YM2149F variant
// this implementation is quite incomplete
// http://wiki.nesdev.com/w/index.php/Sunsoft_5B_audio
public class Sunsoft5BAudio
{
class Pulse
{
Action<int> SendDiff;
// regs
int Period;
bool Disable;
int Volume;
// state
int clock;
int sequence;
int output;
public void SyncState(Serializer ser)
{
ser.Sync("Period", ref Period);
ser.Sync("Disable", ref Disable);
ser.Sync("Volume", ref Volume);
ser.Sync("clock", ref clock);
ser.Sync("sequence", ref sequence);
ser.Sync("output", ref output);
}
public Pulse(Action<int> SendDiff)
{
this.SendDiff = SendDiff;
}
void CalcOut()
{
int newout = 1;
if (!Disable)
newout = sequence;
newout *= Volume;
if (newout != output)
{
SendDiff(newout - output);
output = newout;
}
}
public void Clock()
{
clock--;
if (clock < 0)
{
clock = Period * 16;
sequence ^= 1;
CalcOut();
}
}
public void WritePeriodLow(byte val)
{
Period &= 0xf00;
Period |= val;
}
public void WritePeriodHigh(byte val)
{
Period &= 0x0ff;
Period |= val << 8 & 0xf00;
}
public void SetToneDisable(bool disable)
{
Disable = disable;
CalcOut();
}
public void SetVolume(byte val)
{
Volume = val & 15;
CalcOut();
}
}
int RegNum;
Pulse[] pulse = new Pulse[3];
public void RegSelect(byte val)
{
RegNum = val & 15;
}
public void RegWrite(byte val)
{
switch (RegNum)
{
case 0: pulse[0].WritePeriodLow(val); break;
case 1: pulse[0].WritePeriodHigh(val); break;
case 2: pulse[1].WritePeriodLow(val); break;
case 3: pulse[1].WritePeriodHigh(val); break;
case 4: pulse[2].WritePeriodLow(val); break;
case 5: pulse[2].WritePeriodHigh(val); break;
case 6: break; // noise period
case 7: // also noise disable
pulse[0].SetToneDisable(val.Bit(0));
pulse[1].SetToneDisable(val.Bit(1));
pulse[2].SetToneDisable(val.Bit(2));
break;
case 8: pulse[0].SetVolume(val); break; // also envelope enable
case 9: pulse[1].SetVolume(val); break; // also envelope enable
case 10: pulse[2].SetVolume(val); break; // also envelope enable
case 11: break; // envelope low
case 12: break; // envelope high
case 13: break; // envelope params
// ports 14 and 15 are not hooked up on Sunsoft 5B
}
}
public void SyncState(Serializer ser)
{
ser.BeginSection("Sunsoft5BAudio");
ser.Sync("RegNum", ref RegNum);
for (int i = 0; i < pulse.Length; i++)
pulse[i].SyncState(ser);
ser.EndSection();
}
Action<int> enqueuer;
void PulseAddDiff(int val)
{
enqueuer(val * 250);
}
public Sunsoft5BAudio(Action<int> enqueuer)
{
this.enqueuer = enqueuer;
for (int i = 0; i < pulse.Length; i++)
pulse[i] = new Pulse(PulseAddDiff);
}
public void Clock()
{
for (int i = 0; i < pulse.Length; i++)
pulse[i].Clock();
}
}
}