dual gameboy: sound
This commit is contained in:
parent
f53f9224b6
commit
1cdc51f789
|
@ -727,11 +727,11 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// sample pairs before resampling
|
/// sample pairs before resampling
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal short[] soundbuff = new short[(35112 + 2064) * 2];
|
short[] soundbuff = new short[(35112 + 2064) * 2];
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// how many sample pairs are in soundbuff
|
/// how many sample pairs are in soundbuff
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal int soundbuffcontains = 0;
|
int soundbuffcontains = 0;
|
||||||
|
|
||||||
Sound.Utilities.SpeexResampler resampler;
|
Sound.Utilities.SpeexResampler resampler;
|
||||||
Sound.Utilities.DCFilter dcfilter;
|
Sound.Utilities.DCFilter dcfilter;
|
||||||
|
|
|
@ -8,8 +8,15 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
{
|
{
|
||||||
public class GambatteLink : IEmulator, IVideoProvider, ISyncSoundProvider
|
public class GambatteLink : IEmulator, IVideoProvider, ISyncSoundProvider
|
||||||
{
|
{
|
||||||
|
bool disposed = false;
|
||||||
|
|
||||||
Gameboy L;
|
Gameboy L;
|
||||||
Gameboy R;
|
Gameboy R;
|
||||||
|
// counter to ensure we do 35112 samples per frame
|
||||||
|
int overflowL = 0;
|
||||||
|
int overflowR = 0;
|
||||||
|
|
||||||
|
const int SampPerFrame = 35112;
|
||||||
|
|
||||||
Consoles.Nintendo.SNES.LibsnesCore.SnesSaveController LCont = new Nintendo.SNES.LibsnesCore.SnesSaveController(Gameboy.GbController);
|
Consoles.Nintendo.SNES.LibsnesCore.SnesSaveController LCont = new Nintendo.SNES.LibsnesCore.SnesSaveController(Gameboy.GbController);
|
||||||
Consoles.Nintendo.SNES.LibsnesCore.SnesSaveController RCont = new Nintendo.SNES.LibsnesCore.SnesSaveController(Gameboy.GbController);
|
Consoles.Nintendo.SNES.LibsnesCore.SnesSaveController RCont = new Nintendo.SNES.LibsnesCore.SnesSaveController(Gameboy.GbController);
|
||||||
|
@ -38,6 +45,11 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
Frame = 0;
|
Frame = 0;
|
||||||
LagCount = 0;
|
LagCount = 0;
|
||||||
IsLagFrame = false;
|
IsLagFrame = false;
|
||||||
|
|
||||||
|
blip_left = new Sound.Utilities.BlipBuffer(1024);
|
||||||
|
blip_right = new Sound.Utilities.BlipBuffer(1024);
|
||||||
|
blip_left.SetRates(2097152 * 2, 44100);
|
||||||
|
blip_right.SetRates(2097152 * 2, 44100);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IVideoProvider VideoProvider { get { return this; } }
|
public IVideoProvider VideoProvider { get { return this; } }
|
||||||
|
@ -83,19 +95,22 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
{
|
{
|
||||||
fixed (int* leftvbuff = &VideoBuffer[0])
|
fixed (int* leftvbuff = &VideoBuffer[0])
|
||||||
{
|
{
|
||||||
|
// use pitch to have both cores write to the same video buffer, interleaved
|
||||||
int* rightvbuff = leftvbuff + 160;
|
int* rightvbuff = leftvbuff + 160;
|
||||||
const int pitch = 160 * 2;
|
const int pitch = 160 * 2;
|
||||||
|
|
||||||
fixed (short* leftsbuff = L.soundbuff, rightsbuff = R.soundbuff)
|
fixed (short* leftsbuff = LeftBuffer, rightsbuff = RightBuffer)
|
||||||
{
|
{
|
||||||
|
|
||||||
const int step = 32; // could be 1024 for GB
|
const int step = 32; // could be 1024 for GB
|
||||||
|
|
||||||
int nL = 0;
|
int nL = overflowL;
|
||||||
int nR = 0;
|
int nR = overflowR;
|
||||||
|
|
||||||
for (int target = step; target <= 35112; target += step)
|
// slowly step our way through the frame, while continually checking and resolving link cable status
|
||||||
|
for (int target = 0; target < SampPerFrame;)
|
||||||
{
|
{
|
||||||
|
target += step;
|
||||||
|
|
||||||
if (nL < target)
|
if (nL < target)
|
||||||
{
|
{
|
||||||
|
@ -129,18 +144,21 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
overflowL = nL - SampPerFrame;
|
||||||
|
overflowR = nR - SampPerFrame;
|
||||||
|
if (overflowL < 0 || overflowR < 0)
|
||||||
|
throw new Exception("Sound problem?");
|
||||||
|
|
||||||
if (rendersound)
|
if (rendersound)
|
||||||
{
|
{
|
||||||
L.soundbuffcontains = nL;
|
PrepSound();
|
||||||
R.soundbuffcontains = nR;
|
|
||||||
}
|
}
|
||||||
else
|
// copy extra samples back to beginning
|
||||||
{
|
for (int i = 0; i < overflowL * 2; i++)
|
||||||
L.soundbuffcontains = 0;
|
LeftBuffer[i] = LeftBuffer[i + SampPerFrame * 2];
|
||||||
R.soundbuffcontains = 0;
|
for (int i = 0; i < overflowR * 2; i++)
|
||||||
}
|
RightBuffer[i] = RightBuffer[i + SampPerFrame * 2];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -234,6 +252,10 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
writer.Write(IsLagFrame);
|
writer.Write(IsLagFrame);
|
||||||
writer.Write(LagCount);
|
writer.Write(LagCount);
|
||||||
writer.Write(Frame);
|
writer.Write(Frame);
|
||||||
|
writer.Write(overflowL);
|
||||||
|
writer.Write(overflowR);
|
||||||
|
writer.Write(LatchL);
|
||||||
|
writer.Write(LatchR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadStateBinary(BinaryReader reader)
|
public void LoadStateBinary(BinaryReader reader)
|
||||||
|
@ -244,6 +266,10 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
IsLagFrame = reader.ReadBoolean();
|
IsLagFrame = reader.ReadBoolean();
|
||||||
LagCount = reader.ReadInt32();
|
LagCount = reader.ReadInt32();
|
||||||
Frame = reader.ReadInt32();
|
Frame = reader.ReadInt32();
|
||||||
|
overflowL = reader.ReadInt32();
|
||||||
|
overflowR = reader.ReadInt32();
|
||||||
|
LatchL = reader.ReadInt32();
|
||||||
|
LatchR = reader.ReadInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] SaveStateBinary()
|
public byte[] SaveStateBinary()
|
||||||
|
@ -271,15 +297,18 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (L != null)
|
if (!disposed)
|
||||||
{
|
{
|
||||||
L.Dispose();
|
L.Dispose();
|
||||||
L = null;
|
L = null;
|
||||||
}
|
|
||||||
if (R != null)
|
|
||||||
{
|
|
||||||
R.Dispose();
|
R.Dispose();
|
||||||
R = null;
|
R = null;
|
||||||
|
blip_left.Dispose();
|
||||||
|
blip_left = null;
|
||||||
|
blip_right.Dispose();
|
||||||
|
blip_right = null;
|
||||||
|
|
||||||
|
disposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,16 +319,66 @@ namespace BizHawk.Emulation.Consoles.GB
|
||||||
public int BufferHeight { get { return 144; } }
|
public int BufferHeight { get { return 144; } }
|
||||||
public int BackgroundColor { get { return unchecked((int)0xff000000); } }
|
public int BackgroundColor { get { return unchecked((int)0xff000000); } }
|
||||||
|
|
||||||
|
// we tried using the left and right buffers and then mixing them together... it was kind of a mess of code, and slow
|
||||||
|
|
||||||
|
Sound.Utilities.BlipBuffer blip_left;
|
||||||
|
Sound.Utilities.BlipBuffer blip_right;
|
||||||
|
|
||||||
|
|
||||||
|
short[] LeftBuffer = new short[(35112 + 2064) * 2];
|
||||||
|
short[] RightBuffer = new short[(35112 + 2064) * 2];
|
||||||
|
|
||||||
|
short[] SampleBuffer = new short[1536];
|
||||||
|
int SampleBufferContains = 0;
|
||||||
|
|
||||||
|
int LatchL;
|
||||||
|
int LatchR;
|
||||||
|
|
||||||
|
void PrepSound()
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (short* sl = LeftBuffer, sr = RightBuffer)
|
||||||
|
{
|
||||||
|
for (uint i = 0; i < SampPerFrame * 2; i += 2)
|
||||||
|
{
|
||||||
|
// gameboy audio output is mono, so ignore one sample
|
||||||
|
int s = sl[i];
|
||||||
|
if (s != LatchL)
|
||||||
|
{
|
||||||
|
blip_left.AddDelta(i, s - LatchL);
|
||||||
|
LatchL = s;
|
||||||
|
}
|
||||||
|
s = sr[i];
|
||||||
|
if (s != LatchR)
|
||||||
|
{
|
||||||
|
blip_right.AddDelta(i, s - LatchR);
|
||||||
|
LatchR = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blip_left.EndFrame(SampPerFrame * 2);
|
||||||
|
blip_right.EndFrame(SampPerFrame * 2);
|
||||||
|
int count = blip_left.SamplesAvailable();
|
||||||
|
if (count != blip_right.SamplesAvailable())
|
||||||
|
throw new Exception("Sound problem?");
|
||||||
|
|
||||||
|
blip_left.ReadSamplesLeft(SampleBuffer, count);
|
||||||
|
blip_right.ReadSamplesRight(SampleBuffer, count);
|
||||||
|
SampleBufferContains = count;
|
||||||
|
}
|
||||||
|
|
||||||
public void GetSamples(out short[] samples, out int nsamp)
|
public void GetSamples(out short[] samples, out int nsamp)
|
||||||
{
|
{
|
||||||
// TODO
|
nsamp = SampleBufferContains;
|
||||||
samples = new short[735 * 2];
|
samples = SampleBuffer;
|
||||||
nsamp = 735;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DiscardSamples()
|
public void DiscardSamples()
|
||||||
{
|
{
|
||||||
// TODO
|
SampleBufferContains = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,8 @@ namespace BizHawk.Emulation.Sound.Utilities
|
||||||
samples. Returns number of samples actually read. */
|
samples. Returns number of samples actually read. */
|
||||||
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern int blip_read_samples(IntPtr context, short[] @out, int count, int stereo);
|
public static extern int blip_read_samples(IntPtr context, short[] @out, int count, int stereo);
|
||||||
|
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern int blip_read_samples(IntPtr context, IntPtr @out, int count, int stereo);
|
||||||
|
|
||||||
/** Frees buffer. No effect if NULL is passed. */
|
/** Frees buffer. No effect if NULL is passed. */
|
||||||
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("blip_buf.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
@ -136,5 +138,24 @@ namespace BizHawk.Emulation.Sound.Utilities
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
return BlipBufDll.blip_read_samples(context, output, count, stereo ? 1 : 0);
|
return BlipBufDll.blip_read_samples(context, output, count, stereo ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int ReadSamplesLeft(short[] output, int count)
|
||||||
|
{
|
||||||
|
if (output.Length < count * 2)
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
return BlipBufDll.blip_read_samples(context, output, count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ReadSamplesRight(short[] output, int count)
|
||||||
|
{
|
||||||
|
if (output.Length < count * 2)
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
fixed (short* s = &output[1])
|
||||||
|
return BlipBufDll.blip_read_samples(context, new IntPtr(s), count, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue