BizHawk/BizHawk.Emulation/Consoles/Nintendo/Gameboy/Gambatte.cs

256 lines
5.1 KiB
C#
Raw Normal View History

2012-09-08 21:36:04 +00:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
2012-09-09 02:06:07 +00:00
namespace BizHawk.Emulation.Consoles.GB
2012-09-08 21:36:04 +00:00
{
/// <summary>
/// a gameboy/gameboy color emulator wrapped around native C++ libgambatte
/// </summary>
2012-09-09 02:06:07 +00:00
public class Gameboy : IEmulator, IVideoProvider, ISoundProvider
2012-09-08 21:36:04 +00:00
{
/// <summary>
/// internal gambatte state
/// </summary>
IntPtr GambatteState = IntPtr.Zero;
2012-09-09 02:06:07 +00:00
public Gameboy(byte[] romdata)
2012-09-08 21:36:04 +00:00
{
// use temp file until we hack up the libgambatte api to take data directly
using (FileStream fs = new FileStream("gambattetmp.gb", FileMode.OpenOrCreate, FileAccess.Write))
{
fs.Write(romdata, 0, romdata.Length);
}
GambatteState = LibGambatte.gambatte_create();
if (GambatteState == IntPtr.Zero)
throw new Exception("gambatte_create() returned null???");
if (LibGambatte.gambatte_load(GambatteState, "gambattetmp.gb", 0) != 0)
throw new Exception("gambatte_load() returned non-zero (is this not a gb or gbc rom?)");
InitSound();
2012-09-08 21:36:04 +00:00
}
public IVideoProvider VideoProvider
{
get { return this; }
}
public ISoundProvider SoundProvider
{
get { return this; }
2012-09-08 21:36:04 +00:00
}
2012-09-09 02:06:07 +00:00
public static readonly ControllerDefinition GbController = new ControllerDefinition
2012-09-08 21:36:04 +00:00
{
Name = "Gameboy Controller",
BoolButtons =
{
"Up", "Down", "Left", "Right", "A", "B", "Select", "Start"
}
};
public ControllerDefinition ControllerDefinition
{
get { return GbController; }
}
public IController Controller { get; set; }
2012-09-08 21:36:04 +00:00
uint[] videoscratch = new uint[160 * 144];
public void FrameAdvance(bool render)
{
uint nsamp = 35112;
LibGambatte.gambatte_runfor(GambatteState, videoscratch, 160, soundbuff, ref nsamp);
soundbuffcontains = (int)nsamp;
2012-09-08 21:36:04 +00:00
// can't convert uint[] to int[], so we do this instead
// TODO: lie in the p/invoke layer and claim unsigned* is really int*
Buffer.BlockCopy(videoscratch, 0, VideoBuffer, 0, VideoBuffer.Length * sizeof(int));
}
public int Frame
{
get { return 0; }
}
public int LagCount { get; set; }
public bool IsLagFrame
{
get { return false; }
}
public string SystemId
{
get { return "GB"; }
}
public bool DeterministicEmulation { get; set; }
public byte[] ReadSaveRam
{
get { return new byte[0]; }
2012-09-08 21:36:04 +00:00
}
public bool SaveRamModified
{
get;
set;
2012-09-08 21:36:04 +00:00
}
public void ResetFrameCounter()
{
throw new NotImplementedException();
}
public void SaveStateText(System.IO.TextWriter writer)
{
2012-09-08 21:36:04 +00:00
}
public void LoadStateText(System.IO.TextReader reader)
{
2012-09-08 21:36:04 +00:00
}
public void SaveStateBinary(System.IO.BinaryWriter writer)
{
2012-09-08 21:36:04 +00:00
}
public void LoadStateBinary(System.IO.BinaryReader reader)
{
2012-09-08 21:36:04 +00:00
}
public byte[] SaveStateBinary()
{
return new byte[0];
2012-09-08 21:36:04 +00:00
}
public CoreInputComm CoreInputComm { get; set; }
2012-09-08 21:36:04 +00:00
CoreOutputComm GbOutputComm = new CoreOutputComm
{
VsyncNum = 262144,
VsyncDen = 4389,
2012-09-08 21:36:04 +00:00
RomStatusAnnotation = "Bizwhackin it up",
RomStatusDetails = "LEVAR BURTON"
};
public CoreOutputComm CoreOutputComm
{
get { return GbOutputComm; }
}
public IList<MemoryDomain> MemoryDomains
{
get { throw new NotImplementedException(); }
}
public MemoryDomain MainMemory
{
get { throw new NotImplementedException(); }
}
public void Dispose()
{
LibGambatte.gambatte_destroy(GambatteState);
GambatteState = IntPtr.Zero;
}
#region IVideoProvider
/// <summary>
/// stored image of most recent frame
/// </summary>
2012-09-08 21:36:04 +00:00
int[] VideoBuffer = new int[160 * 144];
public int[] GetVideoBuffer()
{
return VideoBuffer;
}
public int VirtualWidth
{
// only sgb changes this
get { return 160; }
}
public int BufferWidth
{
get { return 160; }
}
public int BufferHeight
{
get { return 144; }
}
public int BackgroundColor
{
get { return 0; }
}
#endregion
#region ISoundProvider
/// <summary>
/// sample pairs before resampling
/// </summary>
short[] soundbuff = new short[(35112 + 2064) * 2];
/// <summary>
/// how many sample pairs are in soundbuff
/// </summary>
int soundbuffcontains = 0;
Sound.Utilities.SpeexResampler resampler;
Sound.MetaspuSoundProvider metaspu;
void InitSound()
{
metaspu = new Sound.MetaspuSoundProvider(Sound.ESynchMethod.ESynchMethod_V);
2012-09-09 12:23:40 +00:00
resampler = new Sound.Utilities.SpeexResampler(2, 2097152, 44100, 2097152, 44100, metaspu.buffer.enqueue_samples);
}
public void GetSamples(short[] samples)
{
resampler.EnqueueSamples(soundbuff, soundbuffcontains);
//for (int i = 0; soundbuffcontains >= 0; soundbuffcontains--)
//{
// resampler.EnqueueSample(soundbuff[i], soundbuff[i + 1]);
// i += 2;
//}
soundbuffcontains = 0;
resampler.Flush();
metaspu.GetSamples(samples);
}
public void DiscardSamples()
{
metaspu.DiscardSamples();
}
public int MaxVolume { get; set; }
#endregion
2012-09-08 21:36:04 +00:00
}
}