nes: FDS: use blargg's blip_buf. there are still problems with the audio channel though...

This commit is contained in:
goyuken 2012-12-09 17:07:34 +00:00
parent cb4288ada4
commit 34a6248606
3 changed files with 92 additions and 42 deletions

View File

@ -34,6 +34,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
bool vs_io = false;
bool vs_coin1;
bool vs_coin2;
/// <summary>clock speed of the main cpu in hz</summary>
public int cpuclockrate { get; private set; }
//irq state management
public bool irq_apu { get { return _irq_apu; } set { _irq_apu = value; } }
@ -84,7 +86,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public void GetSamples(short[] samples)
{
Console.WriteLine("Sync: {0}", nes.apu.dlist.Count);
//Console.WriteLine("Sync: {0}", nes.apu.dlist.Count);
int nsamp = samples.Length / 2;
if (nsamp > blipbuffsize) // oh well.
nsamp = blipbuffsize;
@ -107,7 +109,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public void GetSamples(out short[] samples, out int nsamp)
{
Console.WriteLine("ASync: {0}", nes.apu.dlist.Count);
//Console.WriteLine("ASync: {0}", nes.apu.dlist.Count);
foreach (var d in nes.apu.dlist)
blip.AddDelta(d.time, d.value);
nes.apu.dlist.Clear();
@ -165,12 +167,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ports[0] = new JoypadPortDevice(this, 0);
ports[1] = new JoypadPortDevice(this, 1);
BoardSystemHardReset();
// don't replace the magicSoundProvider on reset, as it's not needed
// if (magicSoundProvider != null) magicSoundProvider.Dispose();
// set up region
switch (cart.system)
{
@ -181,26 +180,23 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ppu.region = PPU.Region.PAL;
CoreOutputComm.VsyncNum = 50;
CoreOutputComm.VsyncDen = 1;
cpuclockrate = 1662607;
cpu_sequence = cpu_sequence_PAL;
if (magicSoundProvider == null)
magicSoundProvider = new MagicSoundProvider(this, 1662607);
break;
case "NES-NTSC":
case "Famicom":
apu = new APU(this, apu, false);
ppu.region = PPU.Region.NTSC;
cpuclockrate = 1789773;
cpu_sequence = cpu_sequence_NTSC;
if (magicSoundProvider == null)
magicSoundProvider = new MagicSoundProvider(this, 1789773);
break;
// there's no official name for these in bootgod, not sure what we should use
//case "PC10"://TODO
case "VS":
apu = new APU(this, apu, false);
ppu.region = PPU.Region.RGB;
cpuclockrate = 1789773;
cpu_sequence = cpu_sequence_NTSC;
if (magicSoundProvider == null)
magicSoundProvider = new MagicSoundProvider(this, 1789773);
vs_io = true;
break;
// this is in bootgod, but not used at all
@ -209,9 +205,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ppu.region = PPU.Region.Dendy;
CoreOutputComm.VsyncNum = 50;
CoreOutputComm.VsyncDen = 1;
cpuclockrate = 1773448;
cpu_sequence = cpu_sequence_NTSC;
if (magicSoundProvider == null)
magicSoundProvider = new MagicSoundProvider(this, 1773448);
break;
case null:
Console.WriteLine("Unknown NES system! Defaulting to NTSC.");
@ -220,6 +215,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
Console.WriteLine("Unrecognized NES system \"{0}\"! Defaulting to NTSC.", cart.system);
goto case "NES-NTSC";
}
if (magicSoundProvider == null)
magicSoundProvider = new MagicSoundProvider(this, (uint)cpuclockrate);
BoardSystemHardReset();
//check fceux's PowerNES function for more information:
//relevant games: Cybernoid; Minna no Taabou no Nakayoshi Daisakusen; Huang Di; and maybe mechanized attack

View File

@ -116,7 +116,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
Cart.board_type = "FAMICOM_DISK_SYSTEM";
diskdrive = new RamAdapter();
audio = new FDSAudio();
audio = new FDSAudio(NES.cpuclockrate);
InsertSide(0);
// set mirroring??
@ -386,5 +386,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
audio.ApplyCustomAudio(samples);
}
public override void Dispose()
{
base.Dispose();
if (audio != null)
{
audio.Dispose();
audio = null;
}
}
}
}

View File

@ -6,7 +6,7 @@ using System.Text;
namespace BizHawk.Emulation.Consoles.Nintendo
{
// http://wiki.nesdev.com/w/index.php/FDS_audio
public class FDSAudio
public class FDSAudio : IDisposable
{
public void SyncState(Serializer ser)
{
@ -99,11 +99,25 @@ namespace BizHawk.Emulation.Consoles.Nintendo
int latchedoutput;
/// <summary>
/// enough room to hold roughly one frame of final output, 0-2047
/// </summary>
short[] samplebuff = new short[32768];
int samplebuffpos = 0;
public FDSAudio(int m2rate)
{
// minor hack: due to the way the initialization sequence goes, this might get called
// with m2rate = 0. such an instance will never be asked for samples, though
if (m2rate > 0)
{
blip = new Sound.Utilities.BlipBuffer(blipsize);
blip.SetRates(m2rate, 44100);
}
}
public void Dispose()
{
if (blip != null)
{
blip.Dispose();
blip = null;
}
}
void CalcMod()
{
@ -134,7 +148,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo
tmp *= waveramoutput;
tmp *= mastervol_num;
tmp /= mastervol_den;
latchedoutput = tmp;
if (latchedoutput != tmp)
{
dlist.Add(new Delta(sampleclock, tmp - latchedoutput));
latchedoutput = tmp;
}
}
/// <summary>
@ -206,9 +225,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
CalcOut();
}
}
samplebuff[samplebuffpos++] = (short)latchedoutput;
// if for some reason ApplyCustomAudio() is not called, glitch up but don't crash
samplebuffpos &= 32767;
sampleclock++;
}
public void WriteReg(int addr, byte value)
@ -309,30 +326,54 @@ namespace BizHawk.Emulation.Consoles.Nintendo
return ret;
}
Sound.Utilities.DCFilter dc = Sound.Utilities.DCFilter.DetatchedMode(4096);
Sound.Utilities.BlipBuffer blip;
struct Delta
{
public uint time;
public int value;
public Delta(uint time, int value)
{
this.time = time;
this.value = value;
}
}
List<Delta> dlist = new List<Delta>();
uint sampleclock = 0;
const int blipsize = 4096;
short[] mixout = new short[blipsize];
public void ApplyCustomAudio(short[] samples)
{
for (int i = 0; i < samples.Length; i += 2)
int nsamp = samples.Length / 2;
if (nsamp > blipsize) // oh well.
nsamp = blipsize;
uint targetclock = (uint)blip.ClocksNeeded(nsamp);
foreach (var d in dlist)
{
// worst imaginable resampling
int pos = i * samplebuffpos / samples.Length;
int samp = samplebuff[pos] * 6 - 12096;
samp += samples[i];
if (samp > 32767)
samples[i] = 32767;
else if (samp < -32768)
samples[i] = -32768;
else
samples[i] = (short)samp;
// NES audio is mono, so this should be identical anyway
samples[i + 1] = samples[i];
// original deltas are in -2016..2016
blip.AddDelta(d.time * targetclock / sampleclock, d.value * 6);
}
//Console.WriteLine("##{0}##", samplebuffpos);
samplebuffpos = 0;
//Console.WriteLine("sclock {0} tclock {1} ndelta {2}", sampleclock, targetclock, dlist.Count);
dlist.Clear();
blip.EndFrame(targetclock);
sampleclock = 0;
blip.ReadSamples(mixout, nsamp, false);
dc.PushThroughSamples(samples, samples.Length);
for (int i = 0, j = 0; i < nsamp; i++, j += 2)
{
int s = mixout[i] + samples[j];
if (s > 32767)
samples[j] = 32767;
else if (s <= -32768)
samples[j] = -32768;
else
samples[j] = (short)s;
// nes audio is mono, so we can ignore the original value of samples[j+1]
samples[j + 1] = samples[j];
}
}
}
}