diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Core.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Core.cs
index 5e4318dc54..2af80d8ffe 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/Core.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Core.cs
@@ -34,6 +34,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
bool vs_io = false;
bool vs_coin1;
bool vs_coin2;
+ /// clock speed of the main cpu in hz
+ 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
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDS.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDS.cs
index 489eff95f9..7cca1eaec5 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDS.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDS.cs
@@ -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;
+ }
+ }
}
}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDSAudio.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDSAudio.cs
index abf18d80e1..65cab075f2 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDSAudio.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/FDS/FDSAudio.cs
@@ -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;
- ///
- /// enough room to hold roughly one frame of final output, 0-2047
- ///
- 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;
+ }
}
///
@@ -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 dlist = new List();
+
+ 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];
+ }
}
}
}