完美音效!
This commit is contained in:
parent
5f6687d8fc
commit
cad555d7ab
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
||||
|
@ -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)
|
||||
|
BIN
AxibugEmuOnline.Client/Assets/Resources/Roms/tortoise4.nes.bytes
Normal file
BIN
AxibugEmuOnline.Client/Assets/Resources/Roms/tortoise4.nes.bytes
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4933f61382c34574db545f3d9e72b51d
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -21,11 +21,6 @@ namespace AxibugEmuOnline.Client
|
||||
m_appEnum.Init(VideoCom, AudioCom);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
m_appEnum.ExecuteFrameLogic();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
Instance = null;
|
||||
|
73
AxibugEmuOnline.Client/Assets/Script/RingBuffer.cs
Normal file
73
AxibugEmuOnline.Client/Assets/Script/RingBuffer.cs
Normal 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);
|
||||
}
|
||||
}
|
11
AxibugEmuOnline.Client/Assets/Script/RingBuffer.cs.meta
Normal file
11
AxibugEmuOnline.Client/Assets/Script/RingBuffer.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bd0f6c1647ed3f49a59e7f06406f49b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Reference in New Issue
Block a user