2011-01-11 02:55:51 +00:00
|
|
|
|
using System;
|
2011-01-21 03:59:50 +00:00
|
|
|
|
using System.Collections.Generic;
|
2011-01-11 02:55:51 +00:00
|
|
|
|
using System.IO;
|
2013-11-04 00:36:15 +00:00
|
|
|
|
using BizHawk.Common;
|
2014-12-05 00:39:02 +00:00
|
|
|
|
using System.ComponentModel;
|
2011-01-11 02:55:51 +00:00
|
|
|
|
|
2013-11-04 01:39:19 +00:00
|
|
|
|
namespace BizHawk.Emulation.Common
|
2011-01-11 02:55:51 +00:00
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
[CoreAttributes("NullHawk", "", false, true)]
|
2014-12-05 00:39:02 +00:00
|
|
|
|
public class NullEmulator : IEmulator, IVideoProvider, ISyncSoundProvider, ISoundProvider, ISettable<NullEmulator.NullEmulatorSettings, object>
|
2011-07-11 23:26:20 +00:00
|
|
|
|
{
|
2014-12-05 00:39:02 +00:00
|
|
|
|
public NullEmulator(CoreComm comm, object settings)
|
2014-12-04 03:38:30 +00:00
|
|
|
|
{
|
|
|
|
|
ServiceProvider = new BasicServiceProvider(this);
|
|
|
|
|
CoreComm = comm;
|
2014-12-05 00:39:02 +00:00
|
|
|
|
_settings = (NullEmulatorSettings)settings ?? new NullEmulatorSettings();
|
2014-12-04 03:38:30 +00:00
|
|
|
|
|
|
|
|
|
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; }
|
|
|
|
|
|
2011-07-11 23:26:20 +00:00
|
|
|
|
public string SystemId { get { return "NULL"; } }
|
|
|
|
|
public static readonly ControllerDefinition NullController = new ControllerDefinition { Name = "Null Controller" };
|
2011-01-12 02:05:48 +00:00
|
|
|
|
|
2013-08-24 16:54:22 +00:00
|
|
|
|
public string BoardName { get { return null; } }
|
|
|
|
|
|
2016-02-29 00:03:01 +00:00
|
|
|
|
private bool frameBufferClear = true;
|
2013-11-04 03:12:50 +00:00
|
|
|
|
private readonly int[] frameBuffer = new int[256 * 192];
|
|
|
|
|
private readonly Random rand = new Random();
|
2012-12-10 00:43:43 +00:00
|
|
|
|
public CoreComm CoreComm { get; private set; }
|
2011-07-11 23:26:20 +00:00
|
|
|
|
public ISoundProvider SoundProvider { get { return this; } }
|
2013-12-18 19:36:17 +00:00
|
|
|
|
public ISyncSoundProvider SyncSoundProvider { get { return this; } }
|
sound api changes. added a new ISyncSoundProvider, which works similarly to ISoundProvider except the source (not the sink) determines the number of samples to process. Added facilities to metaspu, dcfilter, speexresampler to work with ISyncSoundProvider. Add ISyncSoundProvider to IEmulator. All IEmulators must provide sync sound, but they need not provide async sound. When async is needed and an IEmulator doesn't provide it, the frontend will wrap it in a vecna metaspu. SNES, GB changed to provide sync sound only. All other emulator cores mostly unchanged; they just provide stub fakesync alongside async, for now. For the moment, the only use of the sync sound is for realtime audio throttling, where it works and sounds quite nice. In the future, sync sound will be supported for AV dumping as well.
2012-10-11 00:44:59 +00:00
|
|
|
|
public bool StartAsyncSound() { return true; }
|
|
|
|
|
public void EndAsyncSound() { }
|
2013-12-18 19:36:17 +00:00
|
|
|
|
|
2013-11-03 16:29:51 +00:00
|
|
|
|
public void ResetCounters()
|
2011-07-30 20:49:36 +00:00
|
|
|
|
{
|
|
|
|
|
Frame = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-20 19:52:47 +00:00
|
|
|
|
public void FrameAdvance(bool render, bool rendersound)
|
2011-07-11 23:26:20 +00:00
|
|
|
|
{
|
|
|
|
|
if (render == false) return;
|
2014-12-05 00:39:02 +00:00
|
|
|
|
if (!_settings.SnowyDisplay)
|
2013-11-04 03:12:50 +00:00
|
|
|
|
{
|
2014-07-12 20:42:44 +00:00
|
|
|
|
if (frameBufferClear) return;
|
|
|
|
|
frameBufferClear = true;
|
|
|
|
|
Array.Clear(frameBuffer, 0, 256 * 192);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-02-29 00:03:01 +00:00
|
|
|
|
|
2014-07-12 20:42:44 +00:00
|
|
|
|
frameBufferClear = false;
|
|
|
|
|
if (xmas)
|
2014-12-05 00:39:02 +00:00
|
|
|
|
{
|
2014-07-12 20:42:44 +00:00
|
|
|
|
for (int i = 0; i < 256 * 192; i++)
|
|
|
|
|
{
|
|
|
|
|
byte b = (byte)rand.Next();
|
2013-12-18 20:37:32 +00:00
|
|
|
|
frameBuffer[i] = Colors.ARGB(b, (byte)(255 - b), 0, 255);
|
2014-07-12 20:42:44 +00:00
|
|
|
|
}
|
2014-12-05 00:39:02 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-02-29 00:03:01 +00:00
|
|
|
|
for (int i = 0; i < 256*192; i++)
|
|
|
|
|
{
|
|
|
|
|
frameBuffer[i] = Colors.Luminosity((byte) rand.Next());
|
|
|
|
|
}
|
2014-12-05 00:39:02 +00:00
|
|
|
|
}
|
2016-02-29 00:03:01 +00:00
|
|
|
|
|
2014-11-30 20:01:36 +00:00
|
|
|
|
Frame++;
|
2011-07-11 23:26:20 +00:00
|
|
|
|
}
|
|
|
|
|
public ControllerDefinition ControllerDefinition { get { return NullController; } }
|
|
|
|
|
public IController Controller { get; set; }
|
2011-02-26 21:36:46 +00:00
|
|
|
|
|
2011-07-11 23:26:20 +00:00
|
|
|
|
public int Frame { get; set; }
|
2012-10-03 15:31:04 +00:00
|
|
|
|
public bool DeterministicEmulation { get { return true; } }
|
2014-11-30 20:01:36 +00:00
|
|
|
|
|
2011-07-11 23:26:20 +00:00
|
|
|
|
public int[] GetVideoBuffer() { return frameBuffer; }
|
2013-11-06 02:15:29 +00:00
|
|
|
|
public int VirtualWidth { get { return 256; } }
|
2014-04-30 23:48:37 +00:00
|
|
|
|
public int VirtualHeight { get { return 192; } }
|
2013-11-06 02:15:29 +00:00
|
|
|
|
public int BufferWidth { get { return 256; } }
|
2011-07-11 23:26:20 +00:00
|
|
|
|
public int BufferHeight { get { return 192; } }
|
|
|
|
|
public int BackgroundColor { get { return 0; } }
|
2014-09-01 18:43:41 +00:00
|
|
|
|
|
2011-07-11 23:26:20 +00:00
|
|
|
|
public void Dispose() { }
|
2013-11-11 03:20:33 +00:00
|
|
|
|
|
2016-02-29 00:03:01 +00:00
|
|
|
|
private bool xmas;
|
|
|
|
|
private Pleg pleg;
|
2013-12-18 19:36:17 +00:00
|
|
|
|
|
2016-02-29 00:03:01 +00:00
|
|
|
|
private short[] sampbuff = new short[735 * 2];
|
2013-12-18 19:36:17 +00:00
|
|
|
|
|
|
|
|
|
public void GetSamples(out short[] samples, out int nsamp)
|
|
|
|
|
{
|
|
|
|
|
nsamp = 735;
|
|
|
|
|
samples = sampbuff;
|
2014-12-05 00:39:02 +00:00
|
|
|
|
if (!_settings.SnowyDisplay)
|
2014-07-12 20:42:44 +00:00
|
|
|
|
return;
|
2013-12-18 20:37:32 +00:00
|
|
|
|
if (xmas)
|
|
|
|
|
pleg.Generate(samples);
|
2013-12-18 19:36:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DiscardSamples()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void GetSamples(short[] samples)
|
|
|
|
|
{
|
2014-12-05 00:39:02 +00:00
|
|
|
|
if (!_settings.SnowyDisplay)
|
2014-07-13 17:12:26 +00:00
|
|
|
|
return;
|
2013-12-18 20:37:32 +00:00
|
|
|
|
if (xmas)
|
|
|
|
|
pleg.Generate(samples);
|
2013-12-18 19:36:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int MaxVolume
|
|
|
|
|
{
|
|
|
|
|
get;
|
|
|
|
|
set;
|
|
|
|
|
}
|
2014-12-05 00:39:02 +00:00
|
|
|
|
|
|
|
|
|
private NullEmulatorSettings _settings;
|
|
|
|
|
|
|
|
|
|
public class NullEmulatorSettings
|
|
|
|
|
{
|
2015-06-11 13:13:11 +00:00
|
|
|
|
[DefaultValue(false)]
|
2014-12-05 00:39:02 +00:00
|
|
|
|
public bool SnowyDisplay { get; set; }
|
|
|
|
|
|
|
|
|
|
public NullEmulatorSettings()
|
|
|
|
|
{
|
|
|
|
|
SettingsUtil.SetDefaultValues(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public NullEmulatorSettings Clone()
|
|
|
|
|
{
|
|
|
|
|
return (NullEmulatorSettings)MemberwiseClone();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public NullEmulatorSettings GetSettings()
|
|
|
|
|
{
|
|
|
|
|
return _settings.Clone();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public object GetSyncSettings()
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool PutSettings(NullEmulatorSettings o)
|
|
|
|
|
{
|
|
|
|
|
_settings = o;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool PutSyncSettings(object o)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2011-07-11 23:26:20 +00:00
|
|
|
|
}
|
2011-06-02 02:59:18 +00:00
|
|
|
|
|
2013-12-18 20:37:32 +00:00
|
|
|
|
#region super tone generator
|
|
|
|
|
|
2014-12-17 19:52:30 +00:00
|
|
|
|
class Bell
|
|
|
|
|
{
|
|
|
|
|
// ms ima adpcm
|
|
|
|
|
const string dataz = "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
|
|
|
|
|
|
2016-02-29 00:03:01 +00:00
|
|
|
|
private static readonly int[] AdaptationTable = { 230, 230, 230, 230, 307, 409, 512, 614, 768, 614, 512, 409, 307, 230, 230, 230 };
|
|
|
|
|
private static readonly int[] AdaptCoeff1 = { 256, 512, 0, 192, 240, 460, 392 };
|
|
|
|
|
private static readonly int[] AdaptCoeff2 = { 0, -256, 0, 64, 0, -208, -232 };
|
2014-12-17 19:52:30 +00:00
|
|
|
|
|
2016-02-29 00:03:01 +00:00
|
|
|
|
private byte[] data;
|
2014-12-17 19:52:30 +00:00
|
|
|
|
|
|
|
|
|
public Bell()
|
|
|
|
|
{
|
|
|
|
|
var gz = new System.IO.Compression.GZipStream(
|
|
|
|
|
new MemoryStream(Convert.FromBase64String(dataz), false),
|
|
|
|
|
System.IO.Compression.CompressionMode.Decompress);
|
|
|
|
|
var ms = new MemoryStream();
|
|
|
|
|
gz.CopyTo(ms);
|
|
|
|
|
data = ms.ToArray();
|
|
|
|
|
for (int i = 0; i < 3800; i++) // compenstate for sample start point
|
|
|
|
|
Next();
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-29 00:03:01 +00:00
|
|
|
|
private int blockpredictor;
|
|
|
|
|
private int sample1;
|
|
|
|
|
private int sample2;
|
|
|
|
|
private int delta;
|
2014-12-17 19:52:30 +00:00
|
|
|
|
|
2016-02-29 00:03:01 +00:00
|
|
|
|
private int idx = 0;
|
|
|
|
|
private bool top = false;
|
2014-12-17 19:52:30 +00:00
|
|
|
|
|
|
|
|
|
private int samplectr = 0;
|
|
|
|
|
private const int sampleloop = 15360;
|
|
|
|
|
|
|
|
|
|
public short Next()
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if ((idx & 0x3ff) == 0) // start block
|
|
|
|
|
{
|
|
|
|
|
blockpredictor = data[idx] % 7;
|
|
|
|
|
delta = (short)(data[idx + 1] | data[idx + 2] << 8);
|
|
|
|
|
sample1 = (short)(data[idx + 3] | data[idx + 4] << 8);
|
|
|
|
|
sample2 = (short)(data[idx + 5] | data[idx + 6] << 8);
|
|
|
|
|
|
|
|
|
|
ret = sample2;
|
|
|
|
|
idx++;
|
|
|
|
|
}
|
|
|
|
|
else if ((idx & 0x3ff) == 1)
|
|
|
|
|
{
|
|
|
|
|
ret = sample1;
|
|
|
|
|
top = true;
|
|
|
|
|
idx += 6;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int nibble = data[idx];
|
|
|
|
|
if (top)
|
|
|
|
|
nibble >>= 4;
|
|
|
|
|
else
|
|
|
|
|
idx++;
|
|
|
|
|
top ^= true;
|
|
|
|
|
nibble <<= 28;
|
|
|
|
|
nibble >>= 28;
|
|
|
|
|
|
|
|
|
|
int predictor = sample1 * AdaptCoeff1[blockpredictor] + sample2 * AdaptCoeff2[blockpredictor];
|
|
|
|
|
predictor >>= 8;
|
|
|
|
|
predictor += nibble * delta;
|
|
|
|
|
if (predictor >= 32767) predictor = 32767;
|
|
|
|
|
if (predictor <= -32768) predictor = -32768;
|
|
|
|
|
ret = predictor;
|
|
|
|
|
sample2 = sample1;
|
|
|
|
|
sample1 = predictor;
|
|
|
|
|
delta = AdaptationTable[nibble & 15] * delta;
|
|
|
|
|
delta >>= 8;
|
|
|
|
|
if (delta < 16) delta = 16;
|
|
|
|
|
}
|
|
|
|
|
samplectr++;
|
|
|
|
|
if (samplectr == sampleloop)
|
|
|
|
|
{
|
|
|
|
|
samplectr = 0;
|
|
|
|
|
idx = 0;
|
|
|
|
|
}
|
|
|
|
|
return (short)ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-18 19:36:17 +00:00
|
|
|
|
class Pleg
|
|
|
|
|
{
|
2014-12-17 19:52:30 +00:00
|
|
|
|
const 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=";
|
2013-12-18 19:36:17 +00:00
|
|
|
|
List<string> Lines = new List<string>();
|
|
|
|
|
int LineIDX = 0;
|
2014-12-17 19:52:30 +00:00
|
|
|
|
Bell bell = new Bell();
|
2013-12-18 19:36:17 +00:00
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2013-12-18 20:37:32 +00:00
|
|
|
|
foreach (var s in SinMen)
|
2013-12-18 19:36:17 +00:00
|
|
|
|
{
|
2013-12-18 20:37:32 +00:00
|
|
|
|
if (s.c == c && s.n == n && !s.fading)
|
|
|
|
|
s.fading = true;
|
2013-12-18 19:36:17 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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;
|
2013-12-18 20:37:32 +00:00
|
|
|
|
for (int i = 0; i < SinMen.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var s = SinMen[i];
|
|
|
|
|
if (s.Done)
|
|
|
|
|
{
|
|
|
|
|
SinMen.RemoveAt(i);
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret += s.Next();
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-12-18 19:36:17 +00:00
|
|
|
|
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();
|
2014-12-17 19:52:30 +00:00
|
|
|
|
n += bell.Next();
|
2013-12-18 19:36:17 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2013-12-18 20:37:32 +00:00
|
|
|
|
public bool fading = false;
|
|
|
|
|
|
|
|
|
|
public bool Done { get { return amp < 2.0; } }
|
|
|
|
|
|
2013-12-18 19:36:17 +00:00
|
|
|
|
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;
|
2013-12-18 20:37:32 +00:00
|
|
|
|
if (fading)
|
|
|
|
|
amp *= 0.87;
|
2013-12-18 19:36:17 +00:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public SinMan(int amp, int note)
|
|
|
|
|
{
|
|
|
|
|
this.amp = amp;
|
|
|
|
|
this.freq = GetFreq(note);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2013-12-18 20:37:32 +00:00
|
|
|
|
|
|
|
|
|
#endregion
|
2011-01-11 02:55:51 +00:00
|
|
|
|
}
|