diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 6f8f40ce3a..26ef44b106 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -295,6 +295,7 @@
+
diff --git a/BizHawk.Emulation/Sound/Utilities/DualSound.cs b/BizHawk.Emulation/Sound/Utilities/DualSound.cs
new file mode 100644
index 0000000000..a84c5bccc4
--- /dev/null
+++ b/BizHawk.Emulation/Sound/Utilities/DualSound.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Sound.Utilities
+{
+ ///
+ /// provides pass-through sound for the dumping tool to use, while making a "best effort"
+ /// to have something available for audio output
+ ///
+ public class DualSound : ISoundProvider
+ {
+ ///
+ /// implementation of a "slave" ISoundProvider that recieves best effort audio
+ ///
+ class SecondPin : ISoundProvider
+ {
+ ///
+ /// the source to draw from
+ ///
+ DualSound master;
+
+ public SecondPin(DualSound master)
+ {
+ this.master = master;
+ }
+
+ public void GetSamples(short[] samples)
+ {
+ int i;
+ for (i = 0; i < Math.Min(samples.Length, master.ringbuffer.Count); i++)
+ samples[i] = master.ringbuffer.Dequeue();
+ for (; i < samples.Length; i++)
+ // underflow
+ samples[i] = 0;
+ }
+
+ public void DiscardSamples()
+ {
+ master.ringbuffer.Clear();
+ }
+
+ public int MaxVolume
+ {
+ // ignored
+ get;
+ set;
+ }
+ }
+
+ ///
+ /// original input source
+ ///
+ ISoundProvider input;
+
+ ///
+ /// threshold at which to discard samples
+ ///
+ int killsize;
+
+ ///
+ /// storage of samples waiting to go to second pin
+ ///
+ Queue ringbuffer;
+
+ ///
+ /// get the slave pin
+ ///
+ public ISoundProvider secondpin
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// default constructor
+ ///
+ /// the ISoundProvider to use as input
+ /// how many sample pairs to save for the second pin
+ public DualSound(ISoundProvider input, int buffsize)
+ {
+ this.input = input;
+ killsize = buffsize * 2;
+ ringbuffer = new Queue(killsize);
+ secondpin = new SecondPin(this);
+ }
+
+ public void GetSamples(short[] samples)
+ {
+ input.GetSamples(samples);
+ if (ringbuffer.Count >= killsize)
+ ringbuffer.Clear();
+ foreach (var sample in samples)
+ ringbuffer.Enqueue(sample);
+ }
+
+ public void DiscardSamples()
+ {
+ throw new Exception("Dumpers should never discard samples!");
+ }
+
+ public int MaxVolume
+ {
+ get { return input.MaxVolume; }
+ set { input.MaxVolume = value; }
+ }
+ }
+}
diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs
index 3f6a49c586..0e46b545d2 100644
--- a/BizHawk.MultiClient/MainForm.cs
+++ b/BizHawk.MultiClient/MainForm.cs
@@ -33,6 +33,11 @@ namespace BizHawk.MultiClient
//avi/wav state
IVideoWriter CurrAviWriter = null;
+ ///
+ /// an audio proxy used for dumping
+ ///
+ Emulation.Sound.Utilities.DualSound DumpProxy = null;
+
//runloop control
bool exit;
@@ -1874,8 +1879,9 @@ namespace BizHawk.MultiClient
//TODO - this will stray over time! have AviWriter keep an accumulation!
int samples = (int)(44100 / Global.Emulator.CoreOutputComm.VsyncRate);
short[] temp = new short[samples * 2];
- Global.Emulator.SoundProvider.GetSamples(temp);
- genSound = false;
+ //Global.Emulator.SoundProvider.GetSamples(temp);
+ DumpProxy.GetSamples(temp);
+ //genSound = false;
CurrAviWriter.AddFrame(Global.Emulator.VideoProvider);
CurrAviWriter.AddSamples(temp);
@@ -1891,10 +1897,16 @@ namespace BizHawk.MultiClient
PressFrameAdvance = false;
}
- if (genSound)
- Global.Sound.UpdateSound(Global.Emulator.SoundProvider);
- else
- Global.Sound.UpdateSound(NullSound.SilenceProvider);
+ if (genSound)
+ {
+ // change audio path if dumping is occuring
+ if (DumpProxy != null)
+ Global.Sound.UpdateSound(DumpProxy.secondpin);
+ else
+ Global.Sound.UpdateSound(Global.Emulator.SoundProvider);
+ }
+ else
+ Global.Sound.UpdateSound(NullSound.SilenceProvider);
}
///
@@ -2704,16 +2716,23 @@ namespace BizHawk.MultiClient
aw.Dispose();
throw;
}
+ // buffersize here is entirely guess
+ DumpProxy = new Emulation.Sound.Utilities.DualSound(Global.Emulator.SoundProvider, 8192);
}
public void StopAVI()
{
- if (CurrAviWriter == null) return;
+ if (CurrAviWriter == null)
+ {
+ DumpProxy = null;
+ return;
+ }
CurrAviWriter.CloseFile();
CurrAviWriter = null;
Global.OSD.AddMessage("AVI capture stopped");
AVIStatusLabel.Image = BizHawk.MultiClient.Properties.Resources.Blank;
AVIStatusLabel.ToolTipText = "";
+ DumpProxy = null; // return to normal sound output
}
private void SwapBackupSavestate(string path)