diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Audio/CGBAudio.cs b/Assets/Plugins/Essgee.Unity/Emulation/Audio/CGBAudio.cs index 1663c0c..4d9144d 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Audio/CGBAudio.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Audio/CGBAudio.cs @@ -6,10 +6,13 @@ namespace Essgee.Emulation.Audio { public CGBAudio() { - channelSampleBuffer = new List[numChannels]; - for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List(); + //channelSampleBuffer = new List[numChannels]; + //for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List(); + //mixedSampleBuffer = new List(); - mixedSampleBuffer = new List(); + //改为二维数组 + channelSampleBuffer_Init(numChannels, 1470); + mixedSampleBuffer_set = new short[1470]; channel1 = new Square(true); channel2 = new Square(false); diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs b/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs index a99ba17..228d692 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs @@ -4,10 +4,11 @@ using Essgee.Utilities; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; namespace Essgee.Emulation.Audio { - public partial class DMGAudio : IAudio + public unsafe partial class DMGAudio : IAudio { // https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware // http://emudev.de/gameboy-emulator/bleeding-ears-time-to-add-audio/ @@ -34,8 +35,55 @@ namespace Essgee.Emulation.Audio protected int frameSequencerReload, frameSequencerCounter, frameSequencer; - protected List[] channelSampleBuffer; - protected List mixedSampleBuffer; + //protected List[] channelSampleBuffer; + #region //指针化 channelSampleBuffer + static short[][] channelSampleBuffer_src; + static GCHandle[] channelSampleBuffer_handle; + public static short*[] channelSampleBuffer; + public static int[] channelSampleBufferLength; + public static int channelSampleBuffer_writePos; + public static bool channelSampleBuffer_IsNull => channelSampleBuffer == null; + public static void channelSampleBuffer_Init(int length1, int Lenght2) + { + if (channelSampleBuffer_src != null) + { + for (int i = 0; i < channelSampleBuffer_src.Length; i++) + channelSampleBuffer_handle[i].ReleaseGCHandle(); + } + + channelSampleBuffer_src = new short[length1][]; + channelSampleBuffer_handle = new GCHandle[length1]; + channelSampleBuffer = new short*[length1]; + channelSampleBuffer_writePos = 0; + for (int i = 0; i < channelSampleBuffer_src.Length; i++) + { + channelSampleBuffer_src[i] = new short[Lenght2]; + channelSampleBuffer_src[i].GetObjectPtr(ref channelSampleBuffer_handle[i], ref channelSampleBuffer[i]); + } + } + #endregion + //protected List mixedSampleBuffer; + + #region //指针化 mixedSampleBuffer + short[] mixedSampleBuffer_src; + GCHandle mixedSampleBuffer_handle; + public short* mixedSampleBuffer; + public int mixedSampleBufferLength; + public int mixedSampleBuffer_writePos; + public bool mixedSampleBuffer_IsNull => mixedSampleBuffer == null; + public short[] mixedSampleBuffer_set + { + set + { + mixedSampleBuffer_handle.ReleaseGCHandle(); + mixedSampleBuffer_src = value; + mixedSampleBufferLength = value.Length; + mixedSampleBuffer_writePos = 0; + mixedSampleBuffer_src.GetObjectPtr(ref mixedSampleBuffer_handle, ref mixedSampleBuffer); + } + } + #endregion + public virtual event EventHandler EnqueueSamples; public virtual void OnEnqueueSamples(EnqueueSamplesEventArgs e) { EnqueueSamples?.Invoke(this, e); } @@ -60,10 +108,14 @@ namespace Essgee.Emulation.Audio public DMGAudio() { - channelSampleBuffer = new List[numChannels]; - for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List(); + //channelSampleBuffer = new List[numChannels]; + //for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List(); + //mixedSampleBuffer = new List(); + + //改为二维数组 + channelSampleBuffer_Init(numChannels, 1470); + mixedSampleBuffer_set = new short[1470]; - mixedSampleBuffer = new List(); channel1 = new Square(true); channel2 = new Square(false); @@ -263,13 +315,22 @@ namespace Essgee.Emulation.Audio sampleCycleCount -= cyclesPerSample; } - if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels)) + //if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels)) + if (mixedSampleBuffer_writePos >= (samplesPerFrame * numOutputChannels)) { + //EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create( + // numChannels, + // channelSampleBuffer.Select(x => x.ToArray()).ToArray(), + // new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable }, + // mixedSampleBuffer.ToArray()); + EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create( numChannels, - channelSampleBuffer.Select(x => x.ToArray()).ToArray(), + channelSampleBuffer, new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable }, - mixedSampleBuffer.ToArray()); + mixedSampleBuffer, + mixedSampleBuffer_writePos); + OnEnqueueSamples(eventArgs); FlushSamples(); @@ -295,10 +356,18 @@ namespace Essgee.Emulation.Audio var ch3 = (short)(((channel3Enable[i] ? channel3.OutputVolume : 0) * (volumeRightLeft[i] + 1)) << 8); var ch4 = (short)(((channel4Enable[i] ? channel4.OutputVolume : 0) * (volumeRightLeft[i] + 1)) << 8); - channelSampleBuffer[0].Add(ch1); - channelSampleBuffer[1].Add(ch2); - channelSampleBuffer[2].Add(ch3); - channelSampleBuffer[3].Add(ch4); + //废弃旧的数组方式 + //channelSampleBuffer[0].Add(ch1); + //channelSampleBuffer[1].Add(ch2); + //channelSampleBuffer[2].Add(ch3); + //channelSampleBuffer[3].Add(ch4); + + //二维指针下标 + channelSampleBuffer_writePos++; + channelSampleBuffer[0][channelSampleBuffer_writePos] = ch1; + channelSampleBuffer[1][channelSampleBuffer_writePos] = ch2; + channelSampleBuffer[2][channelSampleBuffer_writePos] = ch3; + channelSampleBuffer[3][channelSampleBuffer_writePos] = ch4; /* Mix samples */ var mixed = 0; @@ -308,16 +377,22 @@ namespace Essgee.Emulation.Audio if (channel4ForceEnable) mixed += ch4; mixed /= numChannels; - mixedSampleBuffer.Add((short)mixed); + //废弃旧的方式 + //mixedSampleBuffer.Add((short)mixed); + //指针下标 + mixedSampleBuffer_writePos++; + mixedSampleBuffer[mixedSampleBuffer_writePos] = (short)mixed; } } public void FlushSamples() { - for (int i = 0; i < numChannels; i++) - channelSampleBuffer[i].Clear(); + //for (int i = 0; i < numChannels; i++) + // channelSampleBuffer[i].Clear(); + channelSampleBuffer_writePos = 0; - mixedSampleBuffer.Clear(); + //mixedSampleBuffer.Clear(); + mixedSampleBuffer_writePos = 0; } public virtual byte ReadPort(byte port) diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Audio/SN76489.cs b/Assets/Plugins/Essgee.Unity/Emulation/Audio/SN76489.cs index 258a807..3596751 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Audio/SN76489.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Audio/SN76489.cs @@ -4,11 +4,12 @@ using Essgee.Utilities; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using static Essgee.Emulation.Utilities; namespace Essgee.Emulation.Audio { - public class SN76489 : IAudio + public unsafe class SN76489 : IAudio { /* http://www.smspower.org/Development/SN76489 */ /* Differences in various system's PSGs: http://forums.nesdev.com/viewtopic.php?p=190216#p190216 */ @@ -26,8 +27,60 @@ namespace Essgee.Emulation.Audio protected virtual int noiseBitShift => 14; /* Sample generation & event handling */ - protected List[] channelSampleBuffer; - protected List mixedSampleBuffer; + //protected List[] channelSampleBuffer; + + + #region //指针化 channelSampleBuffer + static short[][] channelSampleBuffer_src; + static GCHandle[] channelSampleBuffer_handle; + public static short*[] channelSampleBuffer; + public static int[] channelSampleBufferLength; + public static int channelSampleBuffer_writePos; + public static bool channelSampleBuffer_IsNull => channelSampleBuffer == null; + public static void channelSampleBuffer_Init(int length1, int Lenght2) + { + if (channelSampleBuffer_src != null) + { + for (int i = 0; i < channelSampleBuffer_src.Length; i++) + channelSampleBuffer_handle[i].ReleaseGCHandle(); + } + + channelSampleBuffer_src = new short[length1][]; + channelSampleBuffer_handle = new GCHandle[length1]; + channelSampleBuffer = new short*[length1]; + channelSampleBuffer_writePos = 0; + for (int i = 0; i < channelSampleBuffer_src.Length; i++) + { + channelSampleBuffer_src[i] = new short[Lenght2]; + channelSampleBuffer_src[i].GetObjectPtr(ref channelSampleBuffer_handle[i], ref channelSampleBuffer[i]); + } + } + #endregion + + + //protected List mixedSampleBuffer; + + #region //指针化 mixedSampleBuffer + short[] mixedSampleBuffer_src; + GCHandle mixedSampleBuffer_handle; + public short* mixedSampleBuffer; + public int mixedSampleBufferLength; + public int mixedSampleBuffer_writePos; + public bool mixedSampleBuffer_IsNull => mixedSampleBuffer == null; + public short[] mixedSampleBuffer_set + { + set + { + mixedSampleBuffer_handle.ReleaseGCHandle(); + mixedSampleBuffer_src = value; + mixedSampleBufferLength = value.Length; + mixedSampleBuffer_writePos = 0; + mixedSampleBuffer_src.GetObjectPtr(ref mixedSampleBuffer_handle, ref mixedSampleBuffer); + } + } + #endregion + + public virtual event EventHandler EnqueueSamples; public virtual void OnEnqueueSamples(EnqueueSamplesEventArgs e) { EnqueueSamples?.Invoke(this, e); } @@ -76,10 +129,14 @@ namespace Essgee.Emulation.Audio public SN76489() { - channelSampleBuffer = new List[numChannels]; - for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List(); + //channelSampleBuffer = new List[numChannels]; + //for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List(); + //mixedSampleBuffer = new List(); + + //改为二维数组 + channelSampleBuffer_Init(numChannels, 1470); + mixedSampleBuffer_set = new short[1470]; - mixedSampleBuffer = new List(); volumeRegisters = new ushort[numChannels]; toneRegisters = new ushort[numChannels]; @@ -211,13 +268,21 @@ namespace Essgee.Emulation.Audio sampleCycleCount -= cyclesPerSample; } - if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels)) + //if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels)) + if (mixedSampleBuffer_writePos >= (samplesPerFrame * numOutputChannels)) { + //EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create( + // numChannels, + // channelSampleBuffer.Select(x => x.ToArray()).ToArray(), + // new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable }, + // mixedSampleBuffer.ToArray()); + EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create( numChannels, - channelSampleBuffer.Select(x => x.ToArray()).ToArray(), + channelSampleBuffer, new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable }, - mixedSampleBuffer.ToArray()); + mixedSampleBuffer, + mixedSampleBufferLength); OnEnqueueSamples(eventArgs); @@ -291,10 +356,19 @@ namespace Essgee.Emulation.Audio var ch3 = (short)(volumeTable[volumeRegisters[2]] * ((toneRegisters[2] < 2 ? true : channelOutput[2]) ? 1.0 : 0.0)); var ch4 = (short)(volumeTable[volumeRegisters[3]] * (noiseLfsr & 0x1)); - channelSampleBuffer[0].Add(ch1); - channelSampleBuffer[1].Add(ch2); - channelSampleBuffer[2].Add(ch3); - channelSampleBuffer[3].Add(ch4); + //废弃旧的数组方式 + //channelSampleBuffer[0].Add(ch1); + //channelSampleBuffer[1].Add(ch2); + //channelSampleBuffer[2].Add(ch3); + //channelSampleBuffer[3].Add(ch4); + + //二维指针下标 + channelSampleBuffer_writePos++; + channelSampleBuffer[0][channelSampleBuffer_writePos] = ch1; + channelSampleBuffer[1][channelSampleBuffer_writePos] = ch2; + channelSampleBuffer[2][channelSampleBuffer_writePos] = ch3; + channelSampleBuffer[3][channelSampleBuffer_writePos] = ch4; + /* Mix samples */ var mixed = 0; @@ -304,16 +378,22 @@ namespace Essgee.Emulation.Audio if (channel4ForceEnable) mixed += ch4; mixed /= numChannels; - mixedSampleBuffer.Add((short)mixed); + //废弃旧的方式 + //mixedSampleBuffer.Add((short)mixed); + //指针下标 + mixedSampleBuffer_writePos++; + mixedSampleBuffer[mixedSampleBuffer_writePos] = (short)mixed; } } public void FlushSamples() { - for (int i = 0; i < numChannels; i++) - channelSampleBuffer[i].Clear(); + //for (int i = 0; i < numChannels; i++) + // channelSampleBuffer[i].Clear(); + channelSampleBuffer_writePos = 0; - mixedSampleBuffer.Clear(); + //mixedSampleBuffer.Clear(); + mixedSampleBuffer_writePos = 0; } private ushort CheckParity(ushort val) diff --git a/Assets/Plugins/Essgee.Unity/Emulation/Audio/SegaGGPSG.cs b/Assets/Plugins/Essgee.Unity/Emulation/Audio/SegaGGPSG.cs index ca596ba..f1ce6f5 100644 --- a/Assets/Plugins/Essgee.Unity/Emulation/Audio/SegaGGPSG.cs +++ b/Assets/Plugins/Essgee.Unity/Emulation/Audio/SegaGGPSG.cs @@ -2,7 +2,7 @@ namespace Essgee.Emulation.Audio { - public class SegaGGPSG : SegaSMSPSG + public unsafe class SegaGGPSG : SegaSMSPSG { public const int PortStereoControl = 0x06; @@ -34,10 +34,19 @@ namespace Essgee.Emulation.Audio var ch3 = (channel2Enable[i] ? (short)(volumeTable[volumeRegisters[2]] * ((toneRegisters[2] < 2 ? true : channelOutput[2]) ? 1.0 : 0.0)) : (short)0); var ch4 = (channel3Enable[i] ? (short)(volumeTable[volumeRegisters[3]] * (noiseLfsr & 0x1)) : (short)0); - channelSampleBuffer[0].Add(ch1); - channelSampleBuffer[1].Add(ch2); - channelSampleBuffer[2].Add(ch3); - channelSampleBuffer[3].Add(ch4); + + //废弃旧的数组方式 + //channelSampleBuffer[0].Add(ch1); + //channelSampleBuffer[1].Add(ch2); + //channelSampleBuffer[2].Add(ch3); + //channelSampleBuffer[3].Add(ch4); + + //二维指针下标 + channelSampleBuffer_writePos++; + channelSampleBuffer[0][channelSampleBuffer_writePos] = ch1; + channelSampleBuffer[1][channelSampleBuffer_writePos] = ch2; + channelSampleBuffer[2][channelSampleBuffer_writePos] = ch3; + channelSampleBuffer[3][channelSampleBuffer_writePos] = ch4; /* Mix samples */ var mixed = 0; @@ -47,7 +56,11 @@ namespace Essgee.Emulation.Audio if (channel4ForceEnable) mixed += ch4; mixed /= numChannels; - mixedSampleBuffer.Add((short)mixed); + //废弃旧的方式 + //mixedSampleBuffer.Add((short)mixed); + //指针下标 + mixedSampleBuffer_writePos++; + mixedSampleBuffer[mixedSampleBuffer_writePos] = (short)mixed; } } diff --git a/Assets/Plugins/Essgee.Unity/EventArguments/EnqueueSamplesEventArgs.cs b/Assets/Plugins/Essgee.Unity/EventArguments/EnqueueSamplesEventArgs.cs index 654d900..5f4e193 100644 --- a/Assets/Plugins/Essgee.Unity/EventArguments/EnqueueSamplesEventArgs.cs +++ b/Assets/Plugins/Essgee.Unity/EventArguments/EnqueueSamplesEventArgs.cs @@ -2,12 +2,14 @@ namespace Essgee.EventArguments { - public class EnqueueSamplesEventArgs : EventArgs + public unsafe class EnqueueSamplesEventArgs : EventArgs { public int NumChannels { get; set; } - public short[][] ChannelSamples { get; set; } + //public short[][] ChannelSamples { get; set; } + public short*[] ChannelSamples { get; set; } public bool[] IsChannelMuted { get; set; } - public short[] MixedSamples { get; set; } + public short* MixedSamples { get; set; } + public int MixedSamplesLength { get; set; } //public EnqueueSamplesEventArgs(int numChannels, short[][] channelSamples, bool[] isMuted, short[] mixedSamples) //{ @@ -17,17 +19,19 @@ namespace Essgee.EventArguments // MixedSamples = mixedSamples; //} - public static EnqueueSamplesEventArgs Create(int numChannels, short[][] channelSamples, bool[] isMuted, short[] mixedSamples) + //public static EnqueueSamplesEventArgs Create(int numChannels, short[][] channelSamples, bool[] isMuted, short[] mixedSamples) + public static EnqueueSamplesEventArgs Create(int numChannels, short*[] channelSamples, bool[] isMuted, short* mixedSamples,int mixedSamplesLength) { var eventArgs = ObjectPoolAuto.Acquire(); eventArgs.NumChannels = numChannels; eventArgs.ChannelSamples = channelSamples; eventArgs.IsChannelMuted = isMuted; eventArgs.MixedSamples = mixedSamples; + eventArgs.MixedSamplesLength = mixedSamplesLength; return eventArgs; } } - public static class EnqueueSamplesEventArgsEx + public unsafe static class EnqueueSamplesEventArgsEx { public static void Release(this EnqueueSamplesEventArgs eventArgs) { diff --git a/Assets/Scripts/UEssgee.cs b/Assets/Scripts/UEssgee.cs index d0388c7..36ebbbf 100644 --- a/Assets/Scripts/UEssgee.cs +++ b/Assets/Scripts/UEssgee.cs @@ -346,7 +346,7 @@ public class Essgeeinit : MonoBehaviour private void LoadAndRunCartridge(string fileName) { - //Application.targetFrameRate = 60; + Application.targetFrameRate = 60; try { var (machineType, romData) = CartridgeLoader.Load(fileName, "ROM image"); @@ -698,7 +698,7 @@ public class Essgeeinit : MonoBehaviour } } - public void EnqueueSoundSamples(object sender, EnqueueSamplesEventArgs e) + public unsafe void EnqueueSoundSamples(object sender, EnqueueSamplesEventArgs e) { //if (sampleQueue.Count > MaxQueueLength) //{ @@ -718,7 +718,8 @@ public class Essgeeinit : MonoBehaviour //} //TODO Ƶ - soundHandler.SubmitSamples(e.MixedSamples, e.ChannelSamples, e.MixedSamples.Length); + //soundHandler.SubmitSamples(e.MixedSamples, e.ChannelSamples, e.MixedSamples.Length); + soundHandler.SubmitSamples(e.MixedSamples, e.ChannelSamples, e.MixedSamplesLength); } #endregion } diff --git a/Assets/Scripts/UEssgeeInterface/UEGSoundPlayer.cs b/Assets/Scripts/UEssgeeInterface/UEGSoundPlayer.cs index 567c273..434b3c2 100644 --- a/Assets/Scripts/UEssgeeInterface/UEGSoundPlayer.cs +++ b/Assets/Scripts/UEssgeeInterface/UEGSoundPlayer.cs @@ -56,7 +56,7 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer } } - public void SubmitSamples(short[] buffer, short[][] ChannelSamples, int samples_a) + public unsafe void SubmitSamples(short* buffer, short*[] ChannelSamples, int samples_a) { var current = Essgeeinit.sw.Elapsed; var delta = current - lastElapsed; @@ -74,9 +74,7 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer for (int i = 0; i < samples_a; i += 2) { - //_buffer.Write(buffer[i] / 32767.0f); - float data = (uint)(buffer[i] + 32767); - _buffer.Write(data / ushort.MaxValue); + _buffer.Write(buffer[i] / 32767.0f); //_buffer.Write(buffer[i] / 32767.0f); } }