254 lines
7.1 KiB
C#
254 lines
7.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using BizHawk.Common;
|
|
|
|
namespace BizHawk.Emulation.Common
|
|
{
|
|
[CoreAttributes("NullHawk", "")]
|
|
public class NullEmulator : IEmulator, IVideoProvider, ISyncSoundProvider, ISoundProvider
|
|
{
|
|
public NullEmulator(CoreComm comm)
|
|
{
|
|
ServiceProvider = new BasicServiceProvider(this);
|
|
CoreComm = comm;
|
|
|
|
var d = DateTime.Now;
|
|
xmas = d.Month == 12 && d.Day >= 17 && d.Day <= 27;
|
|
if (xmas)
|
|
pleg = new Pleg();
|
|
}
|
|
|
|
public IEmulatorServiceProvider ServiceProvider { get; private set; }
|
|
|
|
public string SystemId { get { return "NULL"; } }
|
|
public static readonly ControllerDefinition NullController = new ControllerDefinition { Name = "Null Controller" };
|
|
|
|
public string BoardName { get { return null; } }
|
|
|
|
bool frameBufferClear = true;
|
|
private readonly int[] frameBuffer = new int[256 * 192];
|
|
private readonly Random rand = new Random();
|
|
public CoreComm CoreComm { get; private set; }
|
|
public IVideoProvider VideoProvider { get { return this; } }
|
|
public ISoundProvider SoundProvider { get { return this; } }
|
|
public ISyncSoundProvider SyncSoundProvider { get { return this; } }
|
|
public bool StartAsyncSound() { return true; }
|
|
public void EndAsyncSound() { }
|
|
|
|
public void ResetCounters()
|
|
{
|
|
Frame = 0;
|
|
}
|
|
|
|
public void FrameAdvance(bool render, bool rendersound)
|
|
{
|
|
if (render == false) return;
|
|
if (!CoreComm.DispSnowyNullEmulator())
|
|
{
|
|
if (frameBufferClear) return;
|
|
frameBufferClear = true;
|
|
Array.Clear(frameBuffer, 0, 256 * 192);
|
|
return;
|
|
}
|
|
frameBufferClear = false;
|
|
if (xmas)
|
|
for (int i = 0; i < 256 * 192; i++)
|
|
{
|
|
byte b = (byte)rand.Next();
|
|
frameBuffer[i] = Colors.ARGB(b, (byte)(255 - b), 0, 255);
|
|
}
|
|
else
|
|
for (int i = 0; i < 256 * 192; i++)
|
|
frameBuffer[i] = Colors.Luminosity((byte) rand.Next());
|
|
|
|
Frame++;
|
|
}
|
|
public ControllerDefinition ControllerDefinition { get { return NullController; } }
|
|
public IController Controller { get; set; }
|
|
|
|
public int Frame { get; set; }
|
|
public bool DeterministicEmulation { get { return true; } }
|
|
|
|
public int[] GetVideoBuffer() { return frameBuffer; }
|
|
public int VirtualWidth { get { return 256; } }
|
|
public int VirtualHeight { get { return 192; } }
|
|
public int BufferWidth { get { return 256; } }
|
|
public int BufferHeight { get { return 192; } }
|
|
public int BackgroundColor { get { return 0; } }
|
|
|
|
public void Dispose() { }
|
|
|
|
bool xmas;
|
|
Pleg pleg;
|
|
|
|
short[] sampbuff = new short[735 * 2];
|
|
|
|
public void GetSamples(out short[] samples, out int nsamp)
|
|
{
|
|
nsamp = 735;
|
|
samples = sampbuff;
|
|
if (!CoreComm.DispSnowyNullEmulator())
|
|
return;
|
|
if (xmas)
|
|
pleg.Generate(samples);
|
|
}
|
|
|
|
public void DiscardSamples()
|
|
{
|
|
}
|
|
|
|
public void GetSamples(short[] samples)
|
|
{
|
|
if (!CoreComm.DispSnowyNullEmulator())
|
|
return;
|
|
if (xmas)
|
|
pleg.Generate(samples);
|
|
}
|
|
|
|
public int MaxVolume
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
}
|
|
|
|
#region super tone generator
|
|
|
|
class Pleg
|
|
{
|
|
string data = "H4sICI/2sVICAG91dDMudHh0AOxazdLbIAy8d6bvgkFImFsvufb936Yt3YyKvjBY5UvS6XDSxOZndyULy9H3ylLD1y8/baxHs/Lb5rNG2IT7zVKq9Msmrmf7Tb/st3qcP4ff7rdhb7itw04eXrVzsYWOTuXTt7yzl/OXvYHtDWwN+0cQi0IcqzJnxtchy9lDbo5rVODAAJvbdXWk1PiQooBiMBQPnxcOnYbhfkoCSgGUMmLxbgsoCSgdoCSgFEApwxZQArZ0uryWTp227DUBxVzDpbXLNUhlAVIGJELsZ6hb+kzACdePGqFqxPiE8QnjEualCcUZtb+mRKAUP0tlfyxHQAiIZUEsJ6gZYVXtTlVOiGWBmhk29qoS+zIQ6zQvJZ3rUHFtSwm9I++q5WJUS1At90mNAywhA/CqausZIPaPG/Jtgwhq6ug3qU5GdZMRMg+OmNR7IxfjjQwbDLXD5Q09Yta9QcfqKQfkz4Aw3fptrP0xNVfsCVu++j1S55KPJem01Yi2Bw/R27N2yxfj9znNI9TnESo1dikyT7J68aledNqi6vO1yjUI5RkQplu/mTWRf8u7LVTzZeXaaBRNeUxDTozimi8HRhuNqM/XJZOoiK5IeLJFOF5bEV3XSBGxeHiwjDSbaTXRBkhmuBUBU83T9IiK/wEPUmQOf3RIZxqxI2YVEQfDy7C3VZzJuWTqDuTkDzmW9PUT49KfXHIAlzD0s+qk6CJWx2ptFdzt9mqWsuYF6KT6aBoRAmWGK3MPMfEIkoHg2JIRPfajC39U1/K2TCeQ3SrqHi4V+YSK8VUq2hJoriKDd3So+NJYtBTUnvV4jaqq1omtCVYGsdi9RVmIyDdzqJoPNLdZ6O0q5MhzKh8LUAIFGQSIraFFA8VSg0QOagAJ+5xY1xpaBrGel2I9j2Nd63Kiv8u7tBDb5Mu7xaiYH6uovAcq0ttV5KIxvq6iMxb/HxV7CmpLPV6i6vhrGZdRHp5Us/SEPEwmD5eaXQEzycN5kIfZ5GHjDS7LediftAaxH/DN0r5riPWOLXld3xiI/unqWhgqnbCHieGzU8v9/YJK2wWrSqxHA0404bv+7yjpy1G7HwGBFAoiOIJw9PsABHVVHhBc+G8UJyAAYwv1lJASaZZAiPFbzCN6Pq7zKPq+pUWdtuy7oo9qp2YCNe59xGwe0RmWco1CWaDAfeKUA95KfXmA6+qlWKOpwieUZlTW/0NNSqH9DoAcAfmosUuYx2d5wf+MpP4ZYYbqAdBpoP5x73ExrRFHXwuKpSa+Z0R0mo+aFqsygKRrj9SerYqrZu1V3CRuqRbougPdId0qxLlfR6Psgam9PBxhT+wd+71zcKmeg05bVBWQboBkIF7Zq8xWxdXJ2iuZfILTSuil/SxIqSxDu+bX+RHOYjIxwUZTQIgeKoOuQ2Ac993tbsTdjbi7EXc34u5G3N2IuxtxdyPubsTdjbi7EXc34u5G3N2IuxtxdyPubsTdjbi7EXc34o927dAGAACEgeB27D8SEoVBleRmqGg+ORqRRqQRaUQakUakEWlEGjG1rmlEGpFGpBFpRBqRRqQRaUQakUakEWlEGpFGpBFpRBqRRqQRaUQakUakEWlEGpFGpBFpRBqRRqQRaUQakUb86OhoRBqRRqQRk+qaRqQRaUQakUakEWlEGpFGpBFvGnFXiHMetSzUwqZz46p5AAA=";
|
|
List<string> Lines = new List<string>();
|
|
int LineIDX = 0;
|
|
|
|
public Pleg()
|
|
{
|
|
var gz = new System.IO.Compression.GZipStream(
|
|
new MemoryStream(Convert.FromBase64String(data), false),
|
|
System.IO.Compression.CompressionMode.Decompress);
|
|
var tr = new StreamReader(gz);
|
|
string line;
|
|
while ((line = tr.ReadLine()) != null)
|
|
Lines.Add(line);
|
|
}
|
|
|
|
List<SinMan> SinMen = new List<SinMan>();
|
|
|
|
int deadtime = 0;
|
|
|
|
void Off(int c, int n)
|
|
{
|
|
foreach (var s in SinMen)
|
|
{
|
|
if (s.c == c && s.n == n && !s.fading)
|
|
s.fading = true;
|
|
}
|
|
}
|
|
void On(int c, int n)
|
|
{
|
|
if (c == 9)
|
|
return;
|
|
var s = new SinMan(1500, n);
|
|
s.c = c;
|
|
s.n = n;
|
|
SinMen.Add(s);
|
|
}
|
|
|
|
short Next()
|
|
{
|
|
int ret = 0;
|
|
for (int i = 0; i < SinMen.Count; i++)
|
|
{
|
|
var s = SinMen[i];
|
|
if (s.Done)
|
|
{
|
|
SinMen.RemoveAt(i);
|
|
i--;
|
|
}
|
|
else
|
|
{
|
|
ret += s.Next();
|
|
}
|
|
}
|
|
if (ret > 32767) ret = 32767;
|
|
if (ret < -32767) ret = -32767;
|
|
return (short)ret;
|
|
}
|
|
|
|
string FetchNext()
|
|
{
|
|
string ret = Lines[LineIDX];
|
|
LineIDX++;
|
|
if (LineIDX == Lines.Count)
|
|
LineIDX = 0;
|
|
return ret;
|
|
}
|
|
|
|
public void Generate(short[] dest)
|
|
{
|
|
int idx = 0;
|
|
while (idx < dest.Length)
|
|
{
|
|
if (deadtime > 0)
|
|
{
|
|
short n = Next();
|
|
dest[idx++] = n;
|
|
dest[idx++] = n;
|
|
deadtime--;
|
|
}
|
|
else
|
|
{
|
|
string[] s = FetchNext().Split(':');
|
|
char c = s[0][0];
|
|
if (c == 'A')
|
|
deadtime = int.Parse(s[1]) * 40;
|
|
else if (c == 'O')
|
|
On(int.Parse(s[2]), int.Parse(s[1]));
|
|
else if (c == 'F')
|
|
Off(int.Parse(s[2]), int.Parse(s[1]));
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
class SinMan
|
|
{
|
|
public int c;
|
|
public int n;
|
|
|
|
double theta;
|
|
double freq;
|
|
double amp;
|
|
|
|
public bool fading = false;
|
|
|
|
public bool Done { get { return amp < 2.0; } }
|
|
|
|
static double GetFreq(int note)
|
|
{
|
|
return Math.Pow(2.0, note / 12.0) * 13.0;
|
|
}
|
|
|
|
public short Next()
|
|
{
|
|
short result = (short)(Math.Sin(theta) * amp);
|
|
theta += freq * Math.PI / 22050.0;
|
|
if (theta >= Math.PI * 2.0)
|
|
theta -= Math.PI * 2.0;
|
|
if (fading)
|
|
amp *= 0.87;
|
|
return result;
|
|
}
|
|
|
|
public SinMan(int amp, int note)
|
|
{
|
|
this.amp = amp;
|
|
this.freq = GetFreq(note);
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
}
|