2011-01-11 02:55:51 +00:00
|
|
|
|
using System;
|
2011-01-21 03:59:50 +00:00
|
|
|
|
using System.Collections.Generic;
|
2016-12-16 21:47:19 +00:00
|
|
|
|
using System.ComponentModel;
|
2011-01-11 02:55:51 +00:00
|
|
|
|
using System.IO;
|
2016-12-16 21:47:19 +00:00
|
|
|
|
|
2013-11-04 00:36:15 +00:00
|
|
|
|
using BizHawk.Common;
|
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)]
|
2016-12-09 16:28:27 +00:00
|
|
|
|
[ServiceNotApplicable(typeof(IStatable), typeof(ISaveRam), typeof(IDriveLight), typeof(ICodeDataLogger), typeof(IMemoryDomains),
|
|
|
|
|
typeof(IDebuggable), typeof(IDisassemblable), typeof(IInputPollable), typeof(IRegionable), typeof(ITraceable))]
|
2016-12-11 17:14:42 +00:00
|
|
|
|
public class NullEmulator : IEmulator, IVideoProvider, 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
|
|
|
|
{
|
2016-12-11 17:14:42 +00:00
|
|
|
|
SyncMode = SyncSoundMode.Sync;
|
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;
|
2016-12-16 21:47:19 +00:00
|
|
|
|
_xmas = d.Month == 12 && d.Day >= 17 && d.Day <= 27;
|
|
|
|
|
if (_xmas)
|
|
|
|
|
{
|
|
|
|
|
_pleg = new Pleg();
|
|
|
|
|
}
|
2014-12-04 03:38:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
#region IEmulator
|
2013-08-24 16:54:22 +00:00
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
public IEmulatorServiceProvider ServiceProvider { get; private set; }
|
2013-12-18 19:36:17 +00:00
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
public ControllerDefinition ControllerDefinition
|
2011-07-30 20:49:36 +00:00
|
|
|
|
{
|
2016-12-17 05:34:18 +00:00
|
|
|
|
get { return NullController.Instance.Definition; }
|
2011-07-30 20:49:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
public IController Controller { get; set; }
|
|
|
|
|
|
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
|
|
|
|
{
|
2016-12-16 21:47:19 +00:00
|
|
|
|
if (_frameBufferClear) return;
|
|
|
|
|
_frameBufferClear = true;
|
|
|
|
|
Array.Clear(FrameBuffer, 0, 256 * 192);
|
2014-07-12 20:42:44 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2016-02-29 00:03:01 +00:00
|
|
|
|
|
2016-12-16 21:47:19 +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++)
|
|
|
|
|
{
|
2016-12-16 21:47:19 +00:00
|
|
|
|
byte b = (byte)Rand.Next();
|
|
|
|
|
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-12-16 21:47:19 +00:00
|
|
|
|
for (int i = 0; i < 256 * 192; i++)
|
2016-02-29 00:03:01 +00:00
|
|
|
|
{
|
2016-12-16 21:47:19 +00:00
|
|
|
|
FrameBuffer[i] = Colors.Luminosity((byte)Rand.Next());
|
2016-02-29 00:03:01 +00:00
|
|
|
|
}
|
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
|
|
|
|
}
|
2011-02-26 21:36:46 +00:00
|
|
|
|
|
2011-07-11 23:26:20 +00:00
|
|
|
|
public int Frame { get; set; }
|
2016-12-16 21:47:19 +00:00
|
|
|
|
|
|
|
|
|
public string SystemId { get { return "NULL"; } }
|
|
|
|
|
|
2012-10-03 15:31:04 +00:00
|
|
|
|
public bool DeterministicEmulation { get { return true; } }
|
2014-11-30 20:01:36 +00:00
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
public void ResetCounters()
|
|
|
|
|
{
|
|
|
|
|
Frame = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string BoardName { get { return null; } }
|
|
|
|
|
|
|
|
|
|
public CoreComm CoreComm { get; private set; }
|
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-12-16 21:47:19 +00:00
|
|
|
|
#endregion
|
2013-12-18 19:36:17 +00:00
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
#region IVideoProvider
|
|
|
|
|
|
|
|
|
|
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; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
2013-12-18 19:36:17 +00:00
|
|
|
|
|
2016-12-11 17:14:42 +00:00
|
|
|
|
#region ISoundProvider
|
|
|
|
|
|
|
|
|
|
public void GetSamplesSync(out short[] samples, out int nsamp)
|
2013-12-18 19:36:17 +00:00
|
|
|
|
{
|
2016-12-11 17:14:42 +00:00
|
|
|
|
if (SyncMode != SyncSoundMode.Sync)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("Attempt to call a Sync method in async mode");
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-18 19:36:17 +00:00
|
|
|
|
nsamp = 735;
|
2016-12-16 21:47:19 +00:00
|
|
|
|
samples = SampleBuffer;
|
2014-12-05 00:39:02 +00:00
|
|
|
|
if (!_settings.SnowyDisplay)
|
2016-12-16 21:47:19 +00:00
|
|
|
|
{
|
2014-07-12 20:42:44 +00:00
|
|
|
|
return;
|
2016-12-16 21:47:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_xmas)
|
|
|
|
|
{
|
|
|
|
|
_pleg.Generate(samples);
|
|
|
|
|
}
|
2013-12-18 19:36:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DiscardSamples()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-11 17:14:42 +00:00
|
|
|
|
public void GetSamplesAsync(short[] samples)
|
2013-12-18 19:36:17 +00:00
|
|
|
|
{
|
2016-12-11 17:14:42 +00:00
|
|
|
|
if (SyncMode != SyncSoundMode.Async)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("Attempt to call an Async method in sync mode");
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-05 00:39:02 +00:00
|
|
|
|
if (!_settings.SnowyDisplay)
|
2016-12-16 21:47:19 +00:00
|
|
|
|
{
|
2014-07-13 17:12:26 +00:00
|
|
|
|
return;
|
2016-12-16 21:47:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_xmas)
|
|
|
|
|
{
|
|
|
|
|
_pleg.Generate(samples);
|
|
|
|
|
}
|
2013-12-18 19:36:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-11 17:14:42 +00:00
|
|
|
|
public bool CanProvideAsync
|
|
|
|
|
{
|
|
|
|
|
get { return true; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public SyncSoundMode SyncMode { get; private set; }
|
|
|
|
|
|
|
|
|
|
public void SetSyncMode(SyncSoundMode mode)
|
2013-12-18 19:36:17 +00:00
|
|
|
|
{
|
2016-12-11 17:14:42 +00:00
|
|
|
|
SyncMode = mode;
|
2013-12-18 19:36:17 +00:00
|
|
|
|
}
|
2014-12-05 00:39:02 +00:00
|
|
|
|
|
2016-12-11 17:14:42 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
#region ISettable
|
2014-12-05 00:39:02 +00:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
2016-12-16 21:47:19 +00:00
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
private readonly int[] FrameBuffer = new int[256 * 192];
|
|
|
|
|
private readonly short[] SampleBuffer = new short[735 * 2];
|
|
|
|
|
private readonly Random Rand = new Random();
|
|
|
|
|
|
|
|
|
|
private bool _frameBufferClear = true;
|
|
|
|
|
|
|
|
|
|
private bool _xmas;
|
|
|
|
|
private Pleg _pleg;
|
|
|
|
|
|
|
|
|
|
private NullEmulatorSettings _settings;
|
|
|
|
|
|
|
|
|
|
public class NullEmulatorSettings
|
|
|
|
|
{
|
|
|
|
|
[DefaultValue(false)]
|
|
|
|
|
public bool SnowyDisplay { get; set; }
|
|
|
|
|
|
|
|
|
|
public NullEmulatorSettings()
|
|
|
|
|
{
|
|
|
|
|
SettingsUtil.SetDefaultValues(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public NullEmulatorSettings Clone()
|
|
|
|
|
{
|
|
|
|
|
return (NullEmulatorSettings)MemberwiseClone();
|
|
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
internal class Bell
|
2014-12-17 19:52:30 +00:00
|
|
|
|
{
|
|
|
|
|
// ms ima adpcm
|
2016-12-16 21:47:19 +00:00
|
|
|
|
private const string dataz = "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
|
2014-12-17 19:52:30 +00:00
|
|
|
|
|
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
|
2016-12-16 21:47:19 +00:00
|
|
|
|
{
|
2014-12-17 19:52:30 +00:00
|
|
|
|
Next();
|
2016-12-16 21:47:19 +00:00
|
|
|
|
}
|
2014-12-17 19:52:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
2016-12-16 21:47:19 +00:00
|
|
|
|
|
2014-12-17 19:52:30 +00:00
|
|
|
|
samplectr++;
|
|
|
|
|
if (samplectr == sampleloop)
|
|
|
|
|
{
|
|
|
|
|
samplectr = 0;
|
|
|
|
|
idx = 0;
|
|
|
|
|
}
|
2016-12-16 21:47:19 +00:00
|
|
|
|
|
2014-12-17 19:52:30 +00:00
|
|
|
|
return (short)ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
internal class Pleg
|
2013-12-18 19:36:17 +00:00
|
|
|
|
{
|
2016-12-16 21:47:19 +00:00
|
|
|
|
private 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=";
|
|
|
|
|
private readonly List<SinMan> SinMen = new List<SinMan>();
|
|
|
|
|
private readonly List<string> Lines = new List<string>();
|
|
|
|
|
private readonly Bell Bell = new Bell();
|
|
|
|
|
|
|
|
|
|
private int LineIDX = 0;
|
|
|
|
|
private int deadtime = 0;
|
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)
|
2016-12-16 21:47:19 +00:00
|
|
|
|
{
|
2013-12-18 19:36:17 +00:00
|
|
|
|
Lines.Add(line);
|
2016-12-16 21:47:19 +00:00
|
|
|
|
}
|
2013-12-18 19:36:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
private void Off(int c, int n)
|
2013-12-18 19:36:17 +00:00
|
|
|
|
{
|
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)
|
2016-12-16 21:47:19 +00:00
|
|
|
|
{
|
2013-12-18 20:37:32 +00:00
|
|
|
|
s.fading = true;
|
2016-12-16 21:47:19 +00:00
|
|
|
|
}
|
2013-12-18 19:36:17 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-16 21:47:19 +00:00
|
|
|
|
|
|
|
|
|
private void On(int c, int n)
|
2013-12-18 19:36:17 +00:00
|
|
|
|
{
|
|
|
|
|
if (c == 9)
|
2016-12-16 21:47:19 +00:00
|
|
|
|
{
|
2013-12-18 19:36:17 +00:00
|
|
|
|
return;
|
2016-12-16 21:47:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-18 19:36:17 +00:00
|
|
|
|
var s = new SinMan(1500, n);
|
|
|
|
|
s.c = c;
|
|
|
|
|
s.n = n;
|
|
|
|
|
SinMen.Add(s);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
private short Next()
|
2013-12-18 19:36:17 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
private string FetchNext()
|
2013-12-18 19:36:17 +00:00
|
|
|
|
{
|
|
|
|
|
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();
|
2016-12-16 21:47:19 +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]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
internal class SinMan
|
2013-12-18 19:36:17 +00:00
|
|
|
|
{
|
|
|
|
|
public int c;
|
|
|
|
|
public int n;
|
|
|
|
|
|
|
|
|
|
double theta;
|
|
|
|
|
double freq;
|
|
|
|
|
double amp;
|
|
|
|
|
|
2013-12-18 20:37:32 +00:00
|
|
|
|
public bool fading = false;
|
|
|
|
|
|
2016-12-16 21:47:19 +00:00
|
|
|
|
public bool Done
|
|
|
|
|
{
|
|
|
|
|
get { return amp < 2.0; }
|
|
|
|
|
}
|
2013-12-18 20:37:32 +00:00
|
|
|
|
|
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
|
|
|
|
}
|