From 25e213f157cddb859914559dc1cef518c7cafb86 Mon Sep 17 00:00:00 2001 From: goyuken Date: Tue, 4 Sep 2012 01:21:14 +0000 Subject: [PATCH] libsnes sound is functioning. very quick, very dirty --- .../Consoles/Nintendo/SNES/LibsnesCore.cs | 92 ++++++++++++++++++- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs index 2d9aea9bfa..d6050867be 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/SNES/LibsnesCore.cs @@ -37,9 +37,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void snes_video_refresh_t(ushort *data, int width, int height); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void snes_input_poll_t(); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void snes_input_poll_t(); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate ushort snes_input_state_t(int port, int device, int index, int id); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void snes_audio_sample_t(ushort left, ushort right); [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_set_video_refresh(snes_video_refresh_t video_refresh); @@ -47,6 +49,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES public static extern void snes_set_input_poll(snes_input_poll_t input_poll); [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void snes_set_input_state(snes_input_state_t input_state); + [DllImport("snes.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void snes_set_audio_sample(snes_audio_sample_t audio_sample); public enum Device : uint { @@ -79,7 +83,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES //TODO - libsnes needs to be modified to support multiple instances //TODO - rename snes.dll so nobody thinks it's a stock snes.dll (we'll be editing it substantially at some point) - public unsafe class LibsnesCore : IEmulator, IVideoProvider + public unsafe class LibsnesCore : IEmulator, IVideoProvider, ISoundProvider { static LibsnesCore() { @@ -90,6 +94,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES { LibsnesDll.snes_term(); _gc_snes_video_refresh.Free(); + _gc_snes_audio_sample.Free(); } public LibsnesCore(byte[] romData) @@ -114,7 +119,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES var inputcb = new LibsnesDll.snes_input_state_t(snes_input_state); _gc_snes_input_state = GCHandle.Alloc(inputcb); BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_input_state(inputcb); - + + var soundcb = new LibsnesDll.snes_audio_sample_t(snes_audio_sample); + _gc_snes_audio_sample = GCHandle.Alloc(soundcb); + BizHawk.Emulation.Consoles.Nintendo.SNES.LibsnesDll.snes_set_audio_sample(soundcb); + LibsnesDll.snes_power(); } @@ -195,7 +204,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES int vidWidth=256, vidHeight=256; public IVideoProvider VideoProvider { get { return this; } } - public ISoundProvider SoundProvider { get { return new NullSound(); } } + public ISoundProvider SoundProvider { get { return this; } } public ControllerDefinition ControllerDefinition { get { return SNESController; } } IController controller; @@ -238,5 +247,78 @@ namespace BizHawk.Emulation.Consoles.Nintendo.SNES // ----- Client Debugging API stuff ----- public IList MemoryDomains { get { return new List(); } } public MemoryDomain MainMemory { get { return new MemoryDomain(); } } + + + Queue AudioBuffer = new Queue(); + + GCHandle _gc_snes_audio_sample; + void snes_audio_sample(ushort left, ushort right) + { + AudioBuffer.Enqueue((short)left); + AudioBuffer.Enqueue((short)right); + } + + + /// + /// basic linear audio resampler. sampling rate is inferred from buffer sizes + /// + /// stereo s16 + /// stereo s16 + static void LinearDownsampler(short[] input, short[] output) + { + // TODO - this also appears in YM2612.cs ... move to common if it's found useful + + double samplefactor = (input.Length - 2) / (double)output.Length; + + for (int i = 0; i < output.Length / 2; i++) + { + // exact position on input stream + double inpos = i * samplefactor; + // selected interpolation points and weights + int pt0 = (int)inpos; // pt1 = pt0 + 1 + double wt1 = inpos - pt0; // wt0 = 1 - wt1 + double wt0 = 1.0 - wt1; + + output[i * 2 + 0] = (short)(input[pt0 * 2 + 0] * wt0 + input[pt0 * 2 + 2] * wt1); + output[i * 2 + 1] = (short)(input[pt0 * 2 + 1] * wt0 + input[pt0 * 2 + 3] * wt1); + } + } + + + public void GetSamples(short[] samples) + { + // resample approximately 32k->44k + int inputcount = samples.Length * 32040 / 44100; + inputcount /= 2; + + if (inputcount < 2) inputcount = 2; + + short[] input = new short[inputcount * 2]; + + int i; + + for (i = 0; i < inputcount * 2 && AudioBuffer.Count > 0; i++) + input[i] = AudioBuffer.Dequeue(); + for (; i < inputcount * 2; i++) + input[i] = 0; + + LinearDownsampler(input, samples); + + // drop if too many + if (AudioBuffer.Count > samples.Length * 3) + AudioBuffer.Clear(); + } + + public void DiscardSamples() + { + AudioBuffer.Clear(); + } + + // ignore for now + public int MaxVolume + { + get; + set; + } } } \ No newline at end of file