libsnes sound is functioning. very quick, very dirty
This commit is contained in:
parent
ff8a58a9b7
commit
25e213f157
|
@ -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<MemoryDomain> MemoryDomains { get { return new List<MemoryDomain>(); } }
|
||||
public MemoryDomain MainMemory { get { return new MemoryDomain(); } }
|
||||
|
||||
|
||||
Queue<short> AudioBuffer = new Queue<short>();
|
||||
|
||||
GCHandle _gc_snes_audio_sample;
|
||||
void snes_audio_sample(ushort left, ushort right)
|
||||
{
|
||||
AudioBuffer.Enqueue((short)left);
|
||||
AudioBuffer.Enqueue((short)right);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// basic linear audio resampler. sampling rate is inferred from buffer sizes
|
||||
/// </summary>
|
||||
/// <param name="input">stereo s16</param>
|
||||
/// <param name="output">stereo s16</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue