完美音效!

This commit is contained in:
ALIENJACK\alien 2024-07-17 12:43:43 +08:00
parent 5f6687d8fc
commit cad555d7ab
11 changed files with 140 additions and 72 deletions

2
.gitignore vendored
View File

@ -11,3 +11,5 @@
/AxibugEmuOnline.Client/ProjectSettings/Packages/
/AxibugEmuOnline.Web/config.cfg
/AxibugEmuOnline.Client/ProjectSettings/ProjectVersion.txt
/AxibugEmuOnline.Client/ProjectSettings/AutoStreamingSettings.asset
/AxibugEmuOnline.Client/Logs

View File

@ -5169,6 +5169,7 @@ namespace MyNes.Core
{
Tracer.WriteLine("Running in a thread ... using custom frame limiter.");
FrameLimiterEnabled = true;
currentFrame = 0;
mainThread = new Thread(EmuClock);
mainThread.Start();
}
@ -5263,9 +5264,6 @@ namespace MyNes.Core
if (mainThread != null)
{
Tracer.WriteLine("Aborting thread ..");
while (mainThread.IsAlive)
{
}
mainThread.Abort();
mainThread = null;
}
@ -5274,43 +5272,29 @@ namespace MyNes.Core
NesEmu.EmuShutdown?.Invoke(null, new EventArgs());
}
internal static void EMUClockFrame()
{
emu_frame_done = false;
while (!emu_frame_done && ON)
{
if (!PAUSED)
{
CPUClock();
}
else
{
Thread.Sleep(100);
}
}
}
public static void ExecuteOneFrame()
{
while (!ppu_frame_finished)
{
CPUClock();
}
FrameFinished();
}
private static Stopwatch sw = new Stopwatch();
private static double fixTime;
public static int currentFrame;
private static void EmuClock()
{
while (ON)
{
if (!PAUSED)
{
CPUClock();
if (ppu_frame_finished)
var waitTime = GetTime() + fps_time_period + fixTime;
while (!ppu_frame_finished)
CPUClock();
FrameFinished();
fixTime = waitTime - GetTime();
while (fixTime > 0)
{
FrameFinished();
}
fixTime = waitTime - GetTime();
};
continue;
}
render_audio_get_is_playing(out render_audio_is_playing);
@ -5408,24 +5392,6 @@ namespace MyNes.Core
audio_timer = 0.0;
}
fps_time_token = GetTime() - fps_time_start;
if (FrameLimiterEnabled)
{
if (fps_time_token > 0.0)
{
fps_time_dead = fps_time_period - fps_time_token;
if (fps_time_dead > 0.0)
{
Thread.Sleep((int)Math.Floor(fps_time_dead * 1000.0));
fps_time_dead = GetTime() - fps_time_start;
while (fps_time_period - fps_time_dead > 0.0)
{
fps_time_dead = GetTime() - fps_time_start;
}
}
}
fps_time_last = GetTime();
fps_time_frame_time = fps_time_last - fps_time_start;
}
fps_time_start = GetTime();
}
@ -5445,6 +5411,11 @@ namespace MyNes.Core
fps_time_period = period;
}
public static void RevertFramePeriod()
{
fps_time_period = 1 / emu_time_target_fps;
}
public static void ApplyRegionSetting()
{
switch ((RegionSetting)MyNesMain.EmuSettings.RegionSetting)

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4933f61382c34574db545f3d9e72b51d
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -815,7 +815,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &2100984176
RectTransform:
m_ObjectHideFlags: 0

View File

@ -23,7 +23,7 @@ namespace AxibugEmuOnline.Client
private AudioSource m_as;
private Stopwatch sw = Stopwatch.StartNew();
private Queue<short> _buffer = new Queue<short>(2048);
private RingBuffer<short> _buffer = new RingBuffer<short>(4096);
public double FPS { get; private set; }
@ -43,9 +43,27 @@ namespace AxibugEmuOnline.Client
{
int step = channels;
var bufferCount = _buffer.Available();
if (bufferCount < 4096)
{
double fps = 1 / 61d;
NesEmu.SetFramePeriod(ref fps);
}
else if (bufferCount > 8124)
{
double fps = 1 / 59d;
NesEmu.SetFramePeriod(ref fps);
}
else
{
NesEmu.RevertFramePeriod();
}
for (int i = 0; i < data.Length; i += step)
{
var rawFloat = _buffer.Count <= 0 ? lastData : _buffer.Dequeue() / 124f;
float rawFloat = lastData;
if (_buffer.TryRead(out short rawData))
rawFloat = rawData / 124f;
data[i] = rawFloat;
for (int fill = 1; fill < step; fill++)
data[i + fill] = rawFloat;
@ -63,14 +81,9 @@ namespace AxibugEmuOnline.Client
FPS = 1d / delta.TotalSeconds;
if (_buffer.Count > 2048)
{
_buffer.Clear();
}
for (int i = 0; i < samples_a; i++)
{
_buffer.Enqueue(buffer[i]);
_buffer.Write(buffer[i]);
}
}

View File

@ -44,14 +44,14 @@ namespace AxibugEmuOnline.Client
res.b = b / 255f;
}
public void Update()
public void Update()
{
var colors = m_texRawBuffer;
m_rawBufferWarper.SetPixels(colors);
m_rawBufferWarper.Apply();
Graphics.Blit(m_rawBufferWarper, m_drawCanvas.texture as RenderTexture);
m_fpsText.text = $"Audio:{NesCoreProxy.Instance.AudioCom.FPS}";
m_fpsText.text = $"fps:{NesCoreProxy.Instance.AudioCom.FPS}";
}
public void WriteErrorNotification(string message, bool instant)

View File

@ -10,12 +10,8 @@ namespace AxibugEmuOnline.Client.Manager
public void Init(IVideoProvider videoCom, IAudioProvider audioCom)
{
MyNesMain.Initialize(this, videoCom, audioCom);
NesEmu.LoadGame("kirby.nes", out var successed, true);
}
public void ExecuteFrameLogic()
{
//NesEmu.ExecuteOneFrame();
NesEmu.LoadGame("tortoise4.nes", out var successed, true);
}
public void Dispose()

View File

@ -21,11 +21,6 @@ namespace AxibugEmuOnline.Client
m_appEnum.Init(VideoCom, AudioCom);
}
private void Update()
{
m_appEnum.ExecuteFrameLogic();
}
private void OnDestroy()
{
Instance = null;

View File

@ -0,0 +1,73 @@
using System;
using System.Threading;
public class RingBuffer<T>
{
private readonly T[] buffer;
private readonly int capacity;
private int writePos;
private int readPos;
private int count;
public RingBuffer(int capacity)
{
this.capacity = capacity;
this.buffer = new T[capacity];
this.writePos = 0;
this.readPos = 0;
this.count = 0;
}
public void Write(T item)
{
int localWritePos;
int localReadPos;
do
{
localWritePos = Volatile.Read(ref writePos);
localReadPos = Volatile.Read(ref readPos);
int nextWritePos = (localWritePos + 1) % capacity;
if (nextWritePos == localReadPos)
{
// 缓冲区已满,覆盖最旧的未读数据
Interlocked.CompareExchange(ref readPos, (localReadPos + 1) % capacity, localReadPos);
}
}
while (Interlocked.CompareExchange(ref writePos, (localWritePos + 1) % capacity, localWritePos) != localWritePos);
buffer[localWritePos] = item;
Interlocked.Increment(ref count);
}
public bool TryRead(out T item)
{
item = default(T);
int localReadPos;
int localWritePos;
do
{
localReadPos = Volatile.Read(ref readPos);
localWritePos = Volatile.Read(ref writePos);
if (localReadPos == localWritePos)
{
return false; // 缓冲区为空
}
}
while (Interlocked.CompareExchange(ref readPos, (localReadPos + 1) % capacity, localReadPos) != localReadPos);
item = buffer[localReadPos];
Interlocked.Decrement(ref count);
return true;
}
public int Available()
{
return Volatile.Read(ref count);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6bd0f6c1647ed3f49a59e7f06406f49b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: