APU fully implemented and working but approx 0.25s latency to fix
This commit is contained in:
91
Desktop/DebuggerForm.Designer.cs
generated
91
Desktop/DebuggerForm.Designer.cs
generated
@@ -58,6 +58,12 @@
|
||||
richTextBox1 = new RichTextBox();
|
||||
button1 = new Button();
|
||||
CpuRun = new Button();
|
||||
groupBox1 = new GroupBox();
|
||||
lblTone0 = new Label();
|
||||
lblNoise = new Label();
|
||||
lblTone2 = new Label();
|
||||
lblTone1 = new Label();
|
||||
groupBox1.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// lblAF
|
||||
@@ -164,10 +170,10 @@
|
||||
//
|
||||
// txtMemoryView
|
||||
//
|
||||
txtMemoryView.Location = new Point(110, 100);
|
||||
txtMemoryView.Location = new Point(110, 101);
|
||||
txtMemoryView.Margin = new Padding(2);
|
||||
txtMemoryView.Name = "txtMemoryView";
|
||||
txtMemoryView.Size = new Size(553, 1118);
|
||||
txtMemoryView.Size = new Size(553, 543);
|
||||
txtMemoryView.TabIndex = 15;
|
||||
txtMemoryView.Text = "Memory View Window";
|
||||
//
|
||||
@@ -242,7 +248,7 @@
|
||||
// lblIff1
|
||||
//
|
||||
lblIff1.AutoSize = true;
|
||||
lblIff1.Location = new Point(709, 514);
|
||||
lblIff1.Location = new Point(11, 533);
|
||||
lblIff1.Margin = new Padding(4, 0, 4, 0);
|
||||
lblIff1.Name = "lblIff1";
|
||||
lblIff1.Size = new Size(45, 25);
|
||||
@@ -252,7 +258,7 @@
|
||||
// lblIff2
|
||||
//
|
||||
lblIff2.AutoSize = true;
|
||||
lblIff2.Location = new Point(709, 572);
|
||||
lblIff2.Location = new Point(11, 586);
|
||||
lblIff2.Margin = new Padding(4, 0, 4, 0);
|
||||
lblIff2.Name = "lblIff2";
|
||||
lblIff2.Size = new Size(45, 25);
|
||||
@@ -262,12 +268,12 @@
|
||||
// lblIE
|
||||
//
|
||||
lblIE.AutoSize = true;
|
||||
lblIE.Location = new Point(710, 462);
|
||||
lblIE.Location = new Point(11, 486);
|
||||
lblIE.Margin = new Padding(4, 0, 4, 0);
|
||||
lblIE.Name = "lblIE";
|
||||
lblIE.Size = new Size(133, 25);
|
||||
lblIE.Size = new Size(33, 25);
|
||||
lblIE.TabIndex = 26;
|
||||
lblIE.Text = "Interrupt Mode";
|
||||
lblIE.Text = "IM";
|
||||
//
|
||||
// btnReset
|
||||
//
|
||||
@@ -289,7 +295,7 @@
|
||||
// lblFrames
|
||||
//
|
||||
lblFrames.AutoSize = true;
|
||||
lblFrames.Location = new Point(709, 852);
|
||||
lblFrames.Location = new Point(14, 660);
|
||||
lblFrames.Margin = new Padding(2, 0, 2, 0);
|
||||
lblFrames.Name = "lblFrames";
|
||||
lblFrames.Size = new Size(149, 25);
|
||||
@@ -299,7 +305,7 @@
|
||||
// lblFPS
|
||||
//
|
||||
lblFPS.AutoSize = true;
|
||||
lblFPS.Location = new Point(824, 949);
|
||||
lblFPS.Location = new Point(129, 757);
|
||||
lblFPS.Margin = new Padding(2, 0, 2, 0);
|
||||
lblFPS.Name = "lblFPS";
|
||||
lblFPS.Size = new Size(41, 25);
|
||||
@@ -309,7 +315,7 @@
|
||||
// lblFrameTime
|
||||
//
|
||||
lblFrameTime.AutoSize = true;
|
||||
lblFrameTime.Location = new Point(755, 898);
|
||||
lblFrameTime.Location = new Point(60, 706);
|
||||
lblFrameTime.Margin = new Padding(2, 0, 2, 0);
|
||||
lblFrameTime.Name = "lblFrameTime";
|
||||
lblFrameTime.Size = new Size(104, 25);
|
||||
@@ -319,7 +325,7 @@
|
||||
// richTextBox1
|
||||
//
|
||||
richTextBox1.Enabled = false;
|
||||
richTextBox1.Location = new Point(709, 636);
|
||||
richTextBox1.Location = new Point(682, 474);
|
||||
richTextBox1.Margin = new Padding(4);
|
||||
richTextBox1.Name = "richTextBox1";
|
||||
richTextBox1.ReadOnly = true;
|
||||
@@ -329,7 +335,7 @@
|
||||
//
|
||||
// button1
|
||||
//
|
||||
button1.Location = new Point(694, 1030);
|
||||
button1.Location = new Point(1075, 756);
|
||||
button1.Margin = new Padding(4);
|
||||
button1.Name = "button1";
|
||||
button1.Size = new Size(118, 36);
|
||||
@@ -340,7 +346,7 @@
|
||||
//
|
||||
// CpuRun
|
||||
//
|
||||
CpuRun.Location = new Point(694, 1104);
|
||||
CpuRun.Location = new Point(943, 757);
|
||||
CpuRun.Margin = new Padding(4);
|
||||
CpuRun.Name = "CpuRun";
|
||||
CpuRun.Size = new Size(118, 36);
|
||||
@@ -349,11 +355,61 @@
|
||||
CpuRun.UseVisualStyleBackColor = true;
|
||||
CpuRun.Click += CpuRun_Click;
|
||||
//
|
||||
// groupBox1
|
||||
//
|
||||
groupBox1.Controls.Add(lblTone1);
|
||||
groupBox1.Controls.Add(lblTone2);
|
||||
groupBox1.Controls.Add(lblNoise);
|
||||
groupBox1.Controls.Add(lblTone0);
|
||||
groupBox1.Location = new Point(266, 658);
|
||||
groupBox1.Name = "groupBox1";
|
||||
groupBox1.Size = new Size(397, 222);
|
||||
groupBox1.TabIndex = 35;
|
||||
groupBox1.TabStop = false;
|
||||
groupBox1.Text = "Audio (SN76489)";
|
||||
//
|
||||
// lblTone0
|
||||
//
|
||||
lblTone0.AutoSize = true;
|
||||
lblTone0.Location = new Point(25, 48);
|
||||
lblTone0.Name = "lblTone0";
|
||||
lblTone0.Size = new Size(59, 25);
|
||||
lblTone0.TabIndex = 0;
|
||||
lblTone0.Text = "Tone0";
|
||||
//
|
||||
// lblNoise
|
||||
//
|
||||
lblNoise.AutoSize = true;
|
||||
lblNoise.Location = new Point(25, 160);
|
||||
lblNoise.Name = "lblNoise";
|
||||
lblNoise.Size = new Size(57, 25);
|
||||
lblNoise.TabIndex = 1;
|
||||
lblNoise.Text = "Noise";
|
||||
//
|
||||
// lblTone2
|
||||
//
|
||||
lblTone2.AutoSize = true;
|
||||
lblTone2.Location = new Point(25, 122);
|
||||
lblTone2.Name = "lblTone2";
|
||||
lblTone2.Size = new Size(59, 25);
|
||||
lblTone2.TabIndex = 2;
|
||||
lblTone2.Text = "Tone2";
|
||||
//
|
||||
// lblTone1
|
||||
//
|
||||
lblTone1.AutoSize = true;
|
||||
lblTone1.Location = new Point(25, 83);
|
||||
lblTone1.Name = "lblTone1";
|
||||
lblTone1.Size = new Size(59, 25);
|
||||
lblTone1.TabIndex = 3;
|
||||
lblTone1.Text = "Tone1";
|
||||
//
|
||||
// DebuggerForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(10F, 25F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1206, 1238);
|
||||
ClientSize = new Size(1206, 892);
|
||||
Controls.Add(groupBox1);
|
||||
Controls.Add(CpuRun);
|
||||
Controls.Add(button1);
|
||||
Controls.Add(richTextBox1);
|
||||
@@ -385,6 +441,8 @@
|
||||
Margin = new Padding(2);
|
||||
Name = "DebuggerForm";
|
||||
Text = "Debugger";
|
||||
groupBox1.ResumeLayout(false);
|
||||
groupBox1.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
@@ -420,6 +478,11 @@
|
||||
private Button button1;
|
||||
private Button CpuRun;
|
||||
public System.Windows.Forms.Timer uiUpdateTimer;
|
||||
private GroupBox groupBox1;
|
||||
private Label lblTone1;
|
||||
private Label lblTone2;
|
||||
private Label lblNoise;
|
||||
private Label lblTone0;
|
||||
//private TextBox textBox4;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using Core.Audio;
|
||||
using Core.Cpu;
|
||||
using Core.Memory;
|
||||
|
||||
@@ -100,7 +102,7 @@ namespace Desktop
|
||||
lblIY.Text = $"IY: {_cpu.IY.Word:X4}";
|
||||
lblIff1.Text = $"IFF1: {_cpu.IFF1}";
|
||||
lblIff2.Text = $"IFF2: {_cpu.IFF2}";
|
||||
lblIE.Text = $"Interrupt Mode: {_cpu.InterruptMode}";
|
||||
lblIE.Text = $"IM: {_cpu.InterruptMode}";
|
||||
lblFlags.Text = $"Flags: {_cpu.GetFlagsString()}";
|
||||
lblTStates.Text = $"T-States: {_cpu.TotalTStates}";
|
||||
lblFrames.Text = $"Frames Rendered: {_mainForm.TotalFrameCount}";
|
||||
@@ -109,11 +111,23 @@ namespace Desktop
|
||||
UpdateMemoryView();
|
||||
UpdateStackView();
|
||||
UpdateDisassemblyView();
|
||||
// --- AUDIO REGISTERS ---
|
||||
// Use _mainForm to access the Machine, and then grab the AudioProcessor!
|
||||
if (_mainForm._machine != null && _mainForm._machine.AudioProcessor != null)
|
||||
{
|
||||
ushort[] apuRegs = _mainForm._machine.AudioProcessor.Registers;
|
||||
|
||||
lblTone0.Text = $"Tone 0: 0x{apuRegs[0]:X4} (Vol: 0x{apuRegs[1]:X1})";
|
||||
lblTone1.Text = $"Tone 1: 0x{apuRegs[2]:X4} (Vol: 0x{apuRegs[3]:X1})";
|
||||
lblTone2.Text = $"Tone 2: 0x{apuRegs[4]:X4} (Vol: 0x{apuRegs[5]:X1})";
|
||||
|
||||
lblNoise.Text = $"Noise : 0x{apuRegs[6]:X1} (Vol: 0x{apuRegs[7]:X1})";
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMemoryView()
|
||||
{
|
||||
int count = 40;
|
||||
int count = 20;
|
||||
// Try to parse the hex string the user typed in
|
||||
if (!ushort.TryParse(txtMemoryStart.Text, System.Globalization.NumberStyles.HexNumber, null, out ushort startAddress))
|
||||
{
|
||||
|
||||
@@ -120,4 +120,7 @@
|
||||
<metadata name="uiUpdateTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<value>47</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -343,6 +343,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NAudio" Version="2.3.0" />
|
||||
<PackageReference Include="Vortice.XInput" Version="3.8.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
1
Desktop/Form1.Designer.cs
generated
1
Desktop/Form1.Designer.cs
generated
@@ -139,6 +139,7 @@
|
||||
Margin = new Padding(4);
|
||||
Name = "ParsonsForm1";
|
||||
Text = "Form1";
|
||||
FormClosing += ParsonsForm1_FormClosing;
|
||||
menuStrip1.ResumeLayout(false);
|
||||
menuStrip1.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
|
||||
@@ -6,14 +6,16 @@ using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Core;
|
||||
using Desktop.Audio;
|
||||
|
||||
namespace Desktop
|
||||
{
|
||||
public partial class ParsonsForm1 : Form
|
||||
{
|
||||
private SmsMachine _machine = null!;
|
||||
public SmsMachine _machine = null!;
|
||||
private DebuggerForm _debugger;
|
||||
private Bitmap _screenBitmap = new Bitmap(256, 192, PixelFormat.Format32bppArgb);
|
||||
private NAudioPlayer _audioPlayer;
|
||||
private Task _emulatorTask;
|
||||
private double TargetFrameTime = 16.667f;
|
||||
public int TotalFrameCount = 0;
|
||||
@@ -34,6 +36,8 @@ namespace Desktop
|
||||
InitializeComponent();
|
||||
this.Text = $"Parsons Master System 2026 - {_currentRomName}";
|
||||
_machine = new SmsMachine();
|
||||
_audioPlayer = new NAudioPlayer();
|
||||
_machine.AudioProcessor.AudioDevice = _audioPlayer;
|
||||
|
||||
PopulateIncludedRomsMenu();
|
||||
|
||||
@@ -157,7 +161,8 @@ namespace Desktop
|
||||
framesThisSecond = 0;
|
||||
lastFpsUpdate = currentTime;
|
||||
|
||||
BeginInvoke((System.Windows.Forms.MethodInvoker)delegate {
|
||||
BeginInvoke((System.Windows.Forms.MethodInvoker)delegate
|
||||
{
|
||||
this.Text = $"Parsons Master System - {_currentRomName} [FPS/FT: {FramesPerSecond:F0}/{FrameTime:F1}]";
|
||||
});
|
||||
}
|
||||
@@ -299,5 +304,11 @@ namespace Desktop
|
||||
_machine.IoBus.Joypad1Keyboard |= bitMask; // Target Keyboard!
|
||||
}
|
||||
}
|
||||
|
||||
private void ParsonsForm1_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
IsRunning = false;
|
||||
_audioPlayer?.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
49
Desktop/NAudioPlayer.cs
Normal file
49
Desktop/NAudioPlayer.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using Core.Interfaces;
|
||||
using Microsoft.VisualBasic;
|
||||
using NAudio.Wave;
|
||||
|
||||
namespace Desktop.Audio // Change this to match your project's namespace
|
||||
{
|
||||
public class NAudioPlayer : IAudioDevice
|
||||
{
|
||||
private WaveOutEvent _waveOut;
|
||||
private BufferedWaveProvider _buffer;
|
||||
|
||||
public NAudioPlayer()
|
||||
{
|
||||
// Set up the audio format: 44100 Hz, 32-bit IEEE float, 1 channel (Mono)
|
||||
WaveFormat format = WaveFormat.CreateIeeeFloatWaveFormat(44100, 1);
|
||||
|
||||
_buffer = new BufferedWaveProvider(format);
|
||||
|
||||
// CRITICAL FOR EMULATORS:
|
||||
// If the emulator runs slightly too fast, the audio buffer will fill up
|
||||
// and the sound will lag behind the gameplay. Discarding overflow keeps it synced!
|
||||
_buffer.DiscardOnBufferOverflow = true;
|
||||
|
||||
_waveOut = new WaveOutEvent();
|
||||
|
||||
// 100ms latency is a great sweet spot for WinForms emulators.
|
||||
// Too low = crackling audio. Too high = delayed sound effects.
|
||||
_waveOut.DesiredLatency = 100;
|
||||
_waveOut.Init(_buffer);
|
||||
_waveOut.Play();
|
||||
}
|
||||
|
||||
public void AddSample(float sample)
|
||||
{
|
||||
// Convert the float (-1.0f to 1.0f) into 4 raw bytes
|
||||
byte[] sampleBytes = BitConverter.GetBytes(sample);
|
||||
|
||||
// Push the 4 bytes to the sound card buffer!
|
||||
_buffer.AddSamples(sampleBytes, 0, 4);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_waveOut?.Stop();
|
||||
_waveOut?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user