diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 78c6dcb950..f2e8380d3e 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -355,9 +355,12 @@
+
+
+
diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs
index 8ab5ebb941..c6db050764 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs
@@ -173,6 +173,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
_gc_snes_audio_sample = GCHandle.Alloc(soundcb);
BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_audio_sample(soundcb);
+ // start up audio resampler
+ resampler.StartSession(resamplingfactor);
+
//strip header
if ((romData.Length & 0x7FFF) == 512)
{
@@ -437,38 +440,44 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
/// total number of samples (left and right combined) in the InBuffer before we ask for resampling
const int resamplechunk = 1000;
/// actual sampling factor used
- const double sfactor = 44100.0 / 32040.5;
+ const double resamplingfactor = 44100.0 / 32040.5;
- Sound.Utilities.BizhawkResampler resampler = new Sound.Utilities.BizhawkResampler(false, sfactor, sfactor);
+ Sound.Utilities.IStereoResampler resampler = new Sound.Utilities.BizhawkResampler(false);
+ //Sound.Utilities.IStereoResampler resampler = new Sound.Utilities.CubicResampler();
+ //Sound.Utilities.IStereoResampler resampler = new Sound.Utilities.LinearResampler();
Sound.MetaspuSoundProvider metaspu = new Sound.MetaspuSoundProvider(Sound.ESynchMethod.ESynchMethod_Z);
void snes_audio_sample(ushort left, ushort right)
{
+
AudioInBuffer.Enqueue((short)left);
AudioInBuffer.Enqueue((short)right);
+ /*
try
{
// fixme: i get all sorts of crashes if i do the resampling in here. what?
- /*
+
if (AudioInBuffer.Count >= resamplechunk)
{
- resampler.process(sfactor, false, AudioInBuffer, AudioOutBuffer);
+ resampler.ResampleChunk(AudioInBuffer, AudioOutBuffer, false);
// drain into the metaspu immediately
// we could skip this step and drain directly by changing SampleBuffers
while (AudioOutBuffer.Count > 0)
metaspu.buffer.enqueue_sample(AudioOutBuffer.Dequeue(), AudioOutBuffer.Dequeue());
}
- */
+
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.ToString());
AudioOutBuffer.Clear();
}
-
+ */
+
+
}
@@ -480,7 +489,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES
if (true)
{
- resampler.process(sfactor, false, AudioInBuffer, AudioOutBuffer);
+ resampler.ResampleChunk(AudioInBuffer, AudioOutBuffer, false);
// drain into the metaspu immediately
// we could skip this step and drain directly by changing SampleBuffers implementation
diff --git a/BizHawk.Emulation/Sound/Utilities/CubicResampler.cs b/BizHawk.Emulation/Sound/Utilities/CubicResampler.cs
new file mode 100644
index 0000000000..0e99066b9e
--- /dev/null
+++ b/BizHawk.Emulation/Sound/Utilities/CubicResampler.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Sound.Utilities
+{
+ ///
+ /// a simple cubic interpolation resampler. no lowpass. original code
+ ///
+ public class CubicResampler : IStereoResampler
+ {
+ int[] data = new int[8];
+
+ double mu;
+ /// input rate / output rate
+ double ratio;
+
+ public CubicResampler()
+ {
+ }
+
+ public void StartSession(double ratio)
+ {
+ this.ratio = 1.0 / ratio;
+ mu = 0.0;
+ for (int i = 0; i < data.Length; i++)
+ data[i] = 0;
+ }
+
+ public void ResampleChunk(Queue input, Queue output, bool finish)
+ {
+ while (true)
+ {
+ while (mu >= 1.0 && input.Count >= 2)
+ {
+ mu -= 1.0;
+ for (int i = 0; i < 6; i++)
+ data[i] = data[i + 2];
+ data[6] = input.Dequeue();
+ data[7] = input.Dequeue();
+ }
+ if (mu >= 1.0)
+ return;
+
+ double mu2 = mu * mu;
+ double mu3 = mu2 * mu2;
+
+ int l0 = data[6] - data[4] - data[0] + data[2];
+ int l1 = data[0] - data[2] - l0;
+ int l2 = data[4] - data[0];
+ int l3 = data[2];
+
+ int r0 = data[7] - data[5] - data[1] + data[3];
+ int r1 = data[1] - data[3] - r0;
+ int r2 = data[5] - data[1];
+ int r3 = data[3];
+
+ double ls = l0 * mu3 + l1 * mu2 + l2 * mu + l3;
+ double rs = r0 * mu3 + r1 * mu2 + r2 * mu + r3;
+
+ short l, r;
+
+ if (ls > 32767.0)
+ l = 32767;
+ else if (ls < -32768.0)
+ l = -32768;
+ else
+ l = (short)ls;
+
+ if (rs > 32767.0)
+ r = 32767;
+ else if (ls < -32768.0)
+ r = -32768;
+ else
+ r = (short)ls;
+
+ output.Enqueue(l);
+ output.Enqueue(r);
+
+ mu += ratio;
+
+ }
+
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Sound/Utilities/IStereoResampler.cs b/BizHawk.Emulation/Sound/Utilities/IStereoResampler.cs
new file mode 100644
index 0000000000..31f6971bd5
--- /dev/null
+++ b/BizHawk.Emulation/Sound/Utilities/IStereoResampler.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Sound.Utilities
+{
+ ///
+ /// describes an audio resampler that works with stereo streams of shorts (interleaved)
+ ///
+ public interface IStereoResampler
+ {
+ ///
+ /// start a resampling session, with the given conversion rate
+ ///
+ /// outrate / inrate
+ void StartSession(double ratio);
+
+ ///
+ /// process any available input
+ ///
+ /// input samples. all might not be consumed unless finish == true
+ /// where to put output samples.
+ /// if true, consume all input and end session
+ void ResampleChunk(Queue input, Queue output, bool finish);
+ }
+}
diff --git a/BizHawk.Emulation/Sound/Utilities/LinearResampler.cs b/BizHawk.Emulation/Sound/Utilities/LinearResampler.cs
new file mode 100644
index 0000000000..a0f2c6bf63
--- /dev/null
+++ b/BizHawk.Emulation/Sound/Utilities/LinearResampler.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Sound.Utilities
+{
+ // a simple linear resampler
+ public class LinearResampler : IStereoResampler
+ {
+ short[] data = new short[4];
+
+ double mu;
+ /// input rate / output rate
+ double ratio;
+
+ public LinearResampler()
+ {
+ }
+
+ public void StartSession(double ratio)
+ {
+ this.ratio = 1.0 / ratio;
+ mu = 0.0;
+ for (int i = 0; i < data.Length; i++)
+ data[i] = 0;
+ }
+
+ public void ResampleChunk(Queue input, Queue output, bool finish)
+ {
+ while (true)
+ {
+ while (mu >= 1.0 && input.Count >= 2)
+ {
+ mu -= 1.0;
+ data[0] = data[2];
+ data[1] = data[3];
+ data[2] = input.Dequeue();
+ data[3] = input.Dequeue();
+ }
+ if (mu >= 1.0)
+ return;
+
+ double ls = data[0] * (1.0 - mu) + data[1] * mu;
+ double rs = data[1] * (1.0 - mu) + data[3] * mu;
+
+ short l, r;
+
+ if (ls > 32767.0)
+ l = 32767;
+ else if (ls < -32768.0)
+ l = -32768;
+ else
+ l = (short)ls;
+
+ if (rs > 32767.0)
+ r = 32767;
+ else if (ls < -32768.0)
+ r = -32768;
+ else
+ r = (short)ls;
+
+ output.Enqueue(l);
+ output.Enqueue(r);
+
+ mu += ratio;
+ }
+ }
+ }
+}
diff --git a/BizHawk.Emulation/Sound/Utilities/Resampler.cs b/BizHawk.Emulation/Sound/Utilities/Resampler.cs
index f1709f7a56..346eaa6a62 100644
--- a/BizHawk.Emulation/Sound/Utilities/Resampler.cs
+++ b/BizHawk.Emulation/Sound/Utilities/Resampler.cs
@@ -507,37 +507,44 @@ namespace BizHawk.Emulation.Sound.Utilities
/// implements a pair of Resamplers that work off of interleaved stereo buffers of shorts
/// this is what's used inside most of bizhawk
///
- public class BizhawkResampler
+ public class BizhawkResampler : IStereoResampler
{
- private Resampler left;
- private Resampler right;
+ bool highQuality;
+ double ratio;
- public BizhawkResampler(bool highQuality, double minFactor, double maxFactor)
+ public void StartSession(double ratio)
{
- left = new Resampler(highQuality, minFactor, maxFactor);
- right = new Resampler(highQuality, minFactor, maxFactor);
+ this.ratio = ratio;
+ left = new Resampler(highQuality, ratio, ratio);
+ right = new Resampler(highQuality, ratio, ratio);
}
-
-
- ///
- /// resample some audio.
- ///
- /// outrate / inrate
- /// true to finalize (empty buffers and finish)
- /// input samples, as interleaved stereo shorts. in general, all won't be used unless lastbatch = true
- /// recieves output samples, as interleaved stereo shorts
- /// true if processing finished; only possible with lastbatch = true
- public bool process(double factor, bool lastBatch, Queue input, Queue output)
+ public void ResampleChunk(Queue input, Queue output, bool finish)
{
LeftBuffer lb = new LeftBuffer(input, output);
SampleBuffers rb = lb.GetRightBuffer();
- bool doneleft = left.process(factor, lb, lastBatch);
- bool doneright = right.process(factor, rb, lastBatch);
+ bool doneleft = left.process(ratio, lb, finish);
+ bool doneright = right.process(ratio, rb, finish);
- return doneleft && doneright;
+ if (finish)
+ {
+ left = null;
+ right = null;
+ }
+ }
+
+ private Resampler left;
+ private Resampler right;
+
+ ///
+ ///
+ ///
+ /// true for high quality resampling
+ public BizhawkResampler(bool highQuality)
+ {
+ this.highQuality = highQuality;
}
///
@@ -635,10 +642,7 @@ namespace BizHawk.Emulation.Sound.Utilities
}
}
}
-
}
-
-
}
}