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:
Sean Fausett 2010-03-14 21:54:17 +00:00
parent 51d9e8e5f2
commit ea2a892113
14 changed files with 85 additions and 42 deletions

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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

View File

@ -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)
{
}

View File

@ -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>()
{

View File

@ -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>

View File

@ -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)]

View File

@ -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);
});
}

View File

@ -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;
}
}

View File

@ -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)]

View File

@ -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);
});
}

View File

@ -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;
}

View File

@ -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)]

View File

@ -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);
});
}