mirror of
https://github.com/digital-jellyfish/Virtu.git
synced 2025-02-17 04:32:21 +00:00
Rewrote sound emulation to be much more accurate.
Modified CPU throttling to sync with audio thread. Added CPU multiplier to machine settings. Bumped version to 0.8 for next release. --HG-- extra : convert_revision : svn%3Affd33b8c-2492-42e0-bdc5-587b920b7d6d/trunk%4043066
This commit is contained in:
parent
51d9e8e5f2
commit
ea2a892113
12
Virtu/Cpu.cs
12
Virtu/Cpu.cs
@ -3208,17 +3208,6 @@ namespace Jellyfish.Virtu
|
||||
private void OnVideoVSync(object sender, EventArgs e)
|
||||
{
|
||||
UpdateSettings();
|
||||
|
||||
if (Machine.Settings.Cpu.IsThrottled)
|
||||
{
|
||||
long elapsedTime = DateTime.UtcNow.Ticks - _lastTime;
|
||||
long ticksPerVSync = Machine.Video.TicksPerVSync;
|
||||
if (elapsedTime < ticksPerVSync)
|
||||
{
|
||||
Thread.Sleep(TimeSpan.FromTicks(ticksPerVSync - elapsedTime).Milliseconds);
|
||||
}
|
||||
_lastTime = DateTime.UtcNow.Ticks;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSettings()
|
||||
@ -3240,6 +3229,5 @@ namespace Jellyfish.Virtu
|
||||
private Memory _memory;
|
||||
|
||||
private Action[] _executeOpcode;
|
||||
private long _lastTime;
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace Jellyfish.Virtu
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pausedEvent.Close();
|
||||
_pauseEvent.Close();
|
||||
_unpauseEvent.Close();
|
||||
}
|
||||
|
||||
@ -47,13 +47,15 @@ namespace Jellyfish.Virtu
|
||||
_storageService.Load(MachineSettings.FileName, stream => Settings.Deserialize(stream));
|
||||
|
||||
State = MachineState.Starting;
|
||||
Services.ForEach(service => service.Start());
|
||||
|
||||
Thread.Start();
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
State = MachineState.Pausing;
|
||||
_pausedEvent.WaitOne();
|
||||
_pauseEvent.WaitOne();
|
||||
State = MachineState.Paused;
|
||||
}
|
||||
|
||||
@ -66,6 +68,9 @@ namespace Jellyfish.Virtu
|
||||
public void Stop()
|
||||
{
|
||||
State = MachineState.Stopping;
|
||||
Services.ForEach(service => service.Stop());
|
||||
|
||||
_pauseEvent.Set();
|
||||
_unpauseEvent.Set();
|
||||
Thread.Join();
|
||||
State = MachineState.Stopped;
|
||||
@ -89,7 +94,7 @@ namespace Jellyfish.Virtu
|
||||
|
||||
if (State == MachineState.Pausing)
|
||||
{
|
||||
_pausedEvent.Set();
|
||||
_pauseEvent.Set();
|
||||
_unpauseEvent.WaitOne();
|
||||
}
|
||||
}
|
||||
@ -115,7 +120,7 @@ namespace Jellyfish.Virtu
|
||||
|
||||
public Thread Thread { get; private set; }
|
||||
|
||||
private AutoResetEvent _pausedEvent = new AutoResetEvent(false);
|
||||
private AutoResetEvent _pauseEvent = new AutoResetEvent(false);
|
||||
private AutoResetEvent _unpauseEvent = new AutoResetEvent(false);
|
||||
|
||||
private StorageService _storageService;
|
||||
|
@ -10,7 +10,7 @@ namespace Jellyfish.Virtu.Settings
|
||||
{
|
||||
public MachineSettings()
|
||||
{
|
||||
Cpu = new CpuSettings { Is65C02 = true, IsThrottled = true };
|
||||
Cpu = new CpuSettings { Is65C02 = true, IsThrottled = true, Multiplier = 1 };
|
||||
DiskII = new DiskIISettings
|
||||
{
|
||||
Disk1 = new DiskSettings { Name = string.Empty, IsWriteProtected = false },
|
||||
@ -75,7 +75,8 @@ namespace Jellyfish.Virtu.Settings
|
||||
Cpu = new CpuSettings
|
||||
{
|
||||
Is65C02 = (bool)cpu.Attribute("Is65C02"),
|
||||
IsThrottled = (bool)cpu.Attribute("IsThrottled")
|
||||
IsThrottled = (bool)cpu.Attribute("IsThrottled"),
|
||||
Multiplier = (int)cpu.Attribute("Multiplier")
|
||||
};
|
||||
XElement diskII = root.Element(ns + "DiskII");
|
||||
XElement disk1 = diskII.Element(ns + "Disk1");
|
||||
@ -208,7 +209,8 @@ namespace Jellyfish.Virtu.Settings
|
||||
XElement xml = new XElement(ns + "MachineSettings",
|
||||
new XElement(ns + "Cpu",
|
||||
new XAttribute("Is65C02", Cpu.Is65C02),
|
||||
new XAttribute("IsThrottled", Cpu.IsThrottled)),
|
||||
new XAttribute("IsThrottled", Cpu.IsThrottled),
|
||||
new XAttribute("Multiplier", Cpu.Multiplier)),
|
||||
new XElement(ns + "DiskII",
|
||||
new XElement(ns + "Disk1",
|
||||
new XAttribute("Name", DiskII.Disk1.Name),
|
||||
@ -309,6 +311,7 @@ namespace Jellyfish.Virtu.Settings
|
||||
{
|
||||
public bool Is65C02 { get; set; }
|
||||
public bool IsThrottled { get; set; }
|
||||
public int Multiplier { get; set; }
|
||||
}
|
||||
|
||||
public sealed class DiskSettings
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
{
|
||||
@ -25,6 +26,15 @@ namespace Jellyfish.Virtu.Services
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public virtual void Start()
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Stop")]
|
||||
public virtual void Stop()
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using Jellyfish.Library;
|
||||
using Jellyfish.Virtu.Properties;
|
||||
|
||||
namespace Jellyfish.Virtu.Services
|
||||
@ -30,6 +31,11 @@ namespace Jellyfish.Virtu.Services
|
||||
_serviceProviders.Add(serviceType, serviceProvider);
|
||||
}
|
||||
|
||||
public void ForEach(Action<MachineService> action)
|
||||
{
|
||||
_serviceProviders.Values.ForEach(action);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
|
||||
public T GetService<T>()
|
||||
{
|
||||
|
@ -12,7 +12,7 @@
|
||||
</StackPanel>
|
||||
<Grid Cursor="None">
|
||||
<Image x:Name="_image" MinWidth="560" MinHeight="384"/>
|
||||
<MediaElement x:Name="_media" AutoPlay="true"/>
|
||||
<MediaElement x:Name="_media"/>
|
||||
</Grid>
|
||||
</tk:DockPanel>
|
||||
</UserControl>
|
||||
|
@ -11,9 +11,9 @@ using Jellyfish.Library;
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.7.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.7.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.7.0.0")]
|
||||
[assembly: AssemblyVersion("0.8.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.0.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
|
@ -21,17 +21,16 @@ namespace Jellyfish.Virtu.Services
|
||||
_page = page;
|
||||
_media = media;
|
||||
|
||||
_page.Loaded += (sender, e) => _media.SetSource(_mediaSource);
|
||||
_page.Loaded += (sender, e) => { _media.SetSource(_mediaSource); _media.Play(); };
|
||||
_mediaSource.Update += OnMediaSourceUpdate;
|
||||
//_page.Closed += (sender, e) => _media.Stop(); // SL is missing Closed / Unloaded event
|
||||
}
|
||||
|
||||
private void OnMediaSourceUpdate(object sender, WaveMediaStreamSourceUpdateEventArgs e)
|
||||
{
|
||||
int offset = 0;
|
||||
Update(e.BufferSize, (source, count) =>
|
||||
{
|
||||
Buffer.BlockCopy(source, 0, e.Buffer, offset, count);
|
||||
offset += count;
|
||||
Buffer.BlockCopy(source, 0, e.Buffer, 0, count);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Jellyfish.Virtu.Services;
|
||||
using System;
|
||||
using Jellyfish.Virtu.Services;
|
||||
|
||||
namespace Jellyfish.Virtu
|
||||
{
|
||||
@ -7,18 +8,51 @@ namespace Jellyfish.Virtu
|
||||
public Speaker(Machine machine) :
|
||||
base(machine)
|
||||
{
|
||||
_flushOutputEvent = FlushOutputEvent; // cache delegates; avoids garbage
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_audioService = Machine.Services.GetService<AudioService>();
|
||||
|
||||
Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent);
|
||||
}
|
||||
|
||||
public void ToggleOutput()
|
||||
{
|
||||
_audioService.ToggleOutput();
|
||||
UpdateCycles();
|
||||
_isHigh ^= true;
|
||||
}
|
||||
|
||||
private void FlushOutputEvent()
|
||||
{
|
||||
UpdateCycles();
|
||||
_audioService.Output(_highCycles * 255 / _totalCycles); // quick and dirty decimation
|
||||
_highCycles = _totalCycles = 0;
|
||||
|
||||
Machine.Events.AddEvent(CyclesPerFlush * Machine.Settings.Cpu.Multiplier, _flushOutputEvent);
|
||||
}
|
||||
|
||||
private void UpdateCycles()
|
||||
{
|
||||
int delta = (int)(Machine.Cpu.Cycles - _lastCycles);
|
||||
if (_isHigh)
|
||||
{
|
||||
_highCycles += delta;
|
||||
}
|
||||
_totalCycles += delta;
|
||||
_lastCycles = Machine.Cpu.Cycles;
|
||||
}
|
||||
|
||||
private const int CyclesPerFlush = 23;
|
||||
|
||||
private Action _flushOutputEvent;
|
||||
|
||||
private bool _isHigh;
|
||||
private int _highCycles;
|
||||
private int _totalCycles;
|
||||
private long _lastCycles;
|
||||
|
||||
private AudioService _audioService;
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,9 @@ using Jellyfish.Library;
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.7.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.7.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.7.0.0")]
|
||||
[assembly: AssemblyVersion("0.8.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.0.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
|
@ -34,11 +34,9 @@ namespace Jellyfish.Virtu.Services
|
||||
|
||||
private void OnDirectSoundUpdate(object sender, DirectSoundUpdateEventArgs e)
|
||||
{
|
||||
IntPtr buffer = e.Buffer;
|
||||
Update(e.BufferSize, (source, count) =>
|
||||
{
|
||||
Marshal.Copy(source, 0, buffer, count);
|
||||
buffer = (IntPtr)((long)buffer + count);
|
||||
Marshal.Copy(source, 0, e.Buffer, count);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ namespace Jellyfish.Virtu.Services
|
||||
_window.SizeToContent = SizeToContent.WidthAndHeight;
|
||||
}
|
||||
_isFullScreen = IsFullScreen;
|
||||
SetImageSize();
|
||||
}
|
||||
|
||||
if (_pixelsDirty)
|
||||
@ -70,7 +71,8 @@ namespace Jellyfish.Virtu.Services
|
||||
|
||||
private void SetImageSize()
|
||||
{
|
||||
int uniformScale = Math.Min((int)SystemParameters.PrimaryScreenWidth / BitmapWidth, (int)SystemParameters.PrimaryScreenHeight / BitmapHeight);
|
||||
int uniformScale = IsFullScreen ? Math.Min((int)SystemParameters.PrimaryScreenWidth / BitmapWidth, (int)SystemParameters.PrimaryScreenHeight / BitmapHeight) :
|
||||
Math.Min((int)SystemParameters.FullPrimaryScreenWidth / BitmapWidth, (int)SystemParameters.FullPrimaryScreenHeight / BitmapHeight);
|
||||
_image.Width = uniformScale * BitmapWidth;
|
||||
_image.Height = uniformScale * BitmapHeight;
|
||||
}
|
||||
|
@ -15,11 +15,11 @@ using Jellyfish.Library;
|
||||
[assembly: AssemblyCopyright("Copyright © 1995-2010 Digital Jellyfish Design Ltd")]
|
||||
[assembly: AssemblyComment("Developed by Sean Fausett & Nick Westgate")]
|
||||
|
||||
[assembly: AssemblyVersion("0.7.0.0")]
|
||||
[assembly: AssemblyVersion("0.8.0.0")]
|
||||
#if WINDOWS
|
||||
[assembly: AssemblyFileVersion("0.7.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.8.0.0")]
|
||||
#endif
|
||||
[assembly: AssemblyInformationalVersion("0.7.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("0.8.0.0")]
|
||||
|
||||
[assembly: CLSCompliant(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
|
@ -32,11 +32,9 @@ namespace Jellyfish.Virtu.Services
|
||||
|
||||
private void OnDirectSoundUpdate(object sender, DirectSoundUpdateEventArgs e)
|
||||
{
|
||||
IntPtr buffer = e.Buffer;
|
||||
Update(e.BufferSize, (source, count) =>
|
||||
{
|
||||
Marshal.Copy(source, 0, buffer, count);
|
||||
buffer = (IntPtr)((long)buffer + count);
|
||||
Marshal.Copy(source, 0, e.Buffer, count);
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user