diff --git a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/AxiMemory.cs b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/AxiMemory.cs index a32d7f94..da5cfafa 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/AxiMemory.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/AxiMemory.cs @@ -20,6 +20,12 @@ namespace Essgee.Utilities GetObjectPtr(srcObj, ref handle, out intptr); ptr = (uint*)intptr; } + public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref bool* ptr) + { + IntPtr intptr; + GetObjectPtr(srcObj, ref handle, out intptr); + ptr = (bool*)intptr; + } public static void GetObjectPtr(this object srcObj, ref GCHandle handle, ref short* ptr) { diff --git a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/CGBAudio.Wave.cs b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/CGBAudio.Wave.cs index b80bf49a..3bff8c5a 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/CGBAudio.Wave.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/CGBAudio.Wave.cs @@ -5,14 +5,19 @@ //本身wave就继承了IDMGAudioChannel public class CGBWave : Wave//, IDMGAudioChannel { - public override void Reset() + public unsafe override void Reset() { base.Reset(); - for (var i = 0; i < sampleBuffer.Length; i += 2) + //for (var i = 0; i < sampleBuffer.Length; i += 2) + //{ + // sampleBuffer[i + 0] = 0x00; + // sampleBuffer[i + 1] = 0xFF; + //} + for (var i = 0; i < sampleBufferLength; i += 2) { - sampleBuffer[i + 0] = 0x00; - sampleBuffer[i + 1] = 0xFF; + *(sampleBuffer + i) = 0x00; + *(sampleBuffer + i + 1) = 0xFF; } } } diff --git a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Noise.cs b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Noise.cs index ba36a8f7..4f1e2426 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Noise.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Noise.cs @@ -1,15 +1,36 @@ -using System; +using Essgee.Utilities; +using System; +using System.Runtime.InteropServices; namespace Essgee.Emulation.Audio { public partial class DMGAudio { - public class Noise : IDMGAudioChannel + public unsafe class Noise : IDMGAudioChannel { - static readonly int[] divisors = new int[] + //static readonly int[] divisors = new int[] + //{ + // 8, 16, 32, 48, 64, 80, 96, 112 + //}; + + #region //指针化 divisors + int[] divisors_src; + static GCHandle divisors_handle; + public int* divisors; + public int divisorsLength; + public bool divisors_IsNull => divisors == null; + public int[] divisors_set { - 8, 16, 32, 48, 64, 80, 96, 112 - }; + set + { + divisors_handle.ReleaseGCHandle(); + divisors_src = value; + divisorsLength = value.Length; + divisors_src.GetObjectPtr(ref divisors_handle, ref divisors); + } + } + #endregion + // NR41 byte lengthLoad; @@ -23,7 +44,7 @@ namespace Essgee.Emulation.Audio bool lfsrWidthMode; // NR44 - bool trigger, lengthEnable; + public bool trigger, lengthEnable; // @@ -36,8 +57,8 @@ namespace Essgee.Emulation.Audio bool isEnvelopeUpdateEnabled; // Misc - bool isChannelEnabled, isDacEnabled; - int lengthCounter; + public bool isChannelEnabled, isDacEnabled; + public int lengthCounter; //public int OutputVolume { get; private set; } @@ -46,6 +67,12 @@ namespace Essgee.Emulation.Audio public Noise() { // + + //初始化一下 + divisors_set = new int[] + { + 8, 16, 32, 48, 64, 80, 96, 112 + }; } public override void Reset() @@ -106,7 +133,8 @@ namespace Essgee.Emulation.Audio noiseCounter--; if (noiseCounter == 0) { - noiseCounter = divisors[divisorCode] << clockShift; + //noiseCounter = divisors[divisorCode] << clockShift; + noiseCounter = *(divisors + divisorCode) << clockShift; var result = (lfsr & 0b1) ^ ((lfsr >> 1) & 0b1); lfsr = (ushort)((lfsr >> 1) | (result << 14)); @@ -124,7 +152,8 @@ namespace Essgee.Emulation.Audio if (lengthCounter == 0) lengthCounter = 64; - noiseCounter = divisors[divisorCode] << clockShift; + //noiseCounter = divisors[divisorCode] << clockShift; + noiseCounter = *(divisors + divisorCode) << clockShift; volume = envelopeStartingVolume; envelopeCounter = envelopePeriodReload; isEnvelopeUpdateEnabled = true; diff --git a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Square.cs b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Square.cs index 01cfc0b5..d487461b 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Square.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Square.cs @@ -1,10 +1,12 @@ -using System; +using Essgee.Utilities; +using System; +using System.Runtime.InteropServices; namespace Essgee.Emulation.Audio { public partial class DMGAudio { - public class Square : IDMGAudioChannel + public unsafe class Square : IDMGAudioChannel { //static readonly bool[,] dutyCycleTable = new bool[,] // { @@ -15,45 +17,56 @@ namespace Essgee.Emulation.Audio //}; // 1. 初始化 - 假设原始数组是 4行 x 8列 - private const int Rows = 4; - private const int Cols = 8; - private readonly bool[] _dutyCycleTable1D = new bool[Rows * Cols] - { - // 第一行 (索引 0-7) - false, false, false, false, false, false, false, true, - // 第二行 (索引 8-15) - true, false, false, false, false, false, false, true, - // 第三行 (索引 16-23) - true, false, false, false, false, true, true, true, - // 第四行 (索引 24-31) - false, true, true, true, true, true, true, false - }; + public const int Rows = 4; + public const int Cols = 8; + //private readonly bool[] _dutyCycleTable1D = new bool[Rows * Cols] + //{ + // // 第一行 (索引 0-7) + // false, false, false, false, false, false, false, true, + // // 第二行 (索引 8-15) + // true, false, false, false, false, false, false, true, + // // 第三行 (索引 16-23) + // true, false, false, false, false, true, true, true, + // // 第四行 (索引 24-31) + // false, true, true, true, true, true, true, false + //}; - // 2. 访问方法 - 替代原来的 dutyCycleTable[row, col] - public bool GetValue(int row, int col) + + #region //指针化 _dutyCycleTable1D + bool[] _dutyCycleTable1D_src; + GCHandle _dutyCycleTable1D_handle; + public bool* _dutyCycleTable1D; + public int _dutyCycleTable1DLength; + public bool _dutyCycleTable1D_IsNull => _dutyCycleTable1D == null; + public bool[] _dutyCycleTable1D_set { - // 重要的边界检查(在稳定后可通过条件编译移除以极致优化) - // if (row < 0 || row >= Rows || col < 0 || col >= Cols) return false; - return _dutyCycleTable1D[row * Cols + col]; + set + { + _dutyCycleTable1D_handle.ReleaseGCHandle(); + _dutyCycleTable1D_src = value; + _dutyCycleTable1DLength = value.Length; + _dutyCycleTable1D_src.GetObjectPtr(ref _dutyCycleTable1D_handle, ref _dutyCycleTable1D); + } } + #endregion // NR10/20 byte sweepPeriodReload, sweepShift; bool sweepNegate; // NR11/21 - byte dutyCycle, lengthLoad; + public byte dutyCycle, lengthLoad; // NR12/22 byte envelopeStartingVolume, envelopePeriodReload; bool envelopeAddMode; // NR13/23 - byte frequencyLSB; + public byte frequencyLSB; // NR14/24 - bool trigger, lengthEnable; - byte frequencyMSB; + public bool trigger, lengthEnable; + public byte frequencyMSB; // @@ -64,15 +77,15 @@ namespace Essgee.Emulation.Audio int sweepCounter, sweepFreqShadow; // Frequency - int frequencyCounter; + public int frequencyCounter; // Envelope - int volume, envelopeCounter; + public int volume, envelopeCounter; bool isEnvelopeUpdateEnabled; // Misc - bool isChannelEnabled, isDacEnabled; - int lengthCounter, dutyCounter; + public bool isChannelEnabled, isDacEnabled; + public int lengthCounter, dutyCounter; //public int OutputVolume { get; private set; } @@ -81,6 +94,19 @@ namespace Essgee.Emulation.Audio public Square(bool hasSweep) { channelSupportsSweep = hasSweep; + + //初始化一下 + _dutyCycleTable1D_set = new bool[Rows * Cols] + { + // 第一行 (索引 0-7) + false, false, false, false, false, false, false, true, + // 第二行 (索引 8-15) + true, false, false, false, false, false, false, true, + // 第三行 (索引 16-23) + true, false, false, false, false, true, true, true, + // 第四行 (索引 24-31) + false, true, true, true, true, true, true, false + }; } public override void Reset() @@ -169,7 +195,8 @@ namespace Essgee.Emulation.Audio //OutputVolume = isDacEnabled && dutyCycleTable[dutyCycle, dutyCounter] ? volume : 0; //改为一维数组访问 - OutputVolume = isDacEnabled && _dutyCycleTable1D[dutyCycle * Cols + dutyCounter] ? volume : 0; + //OutputVolume = isDacEnabled && _dutyCycleTable1D[dutyCycle * Cols + dutyCounter] ? volume : 0; + OutputVolume = isDacEnabled && *(_dutyCycleTable1D+(dutyCycle * Cols + dutyCounter)) ? volume : 0; } private void Trigger() diff --git a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Wave.cs b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Wave.cs index a4cf721a..c38807a5 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Wave.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.Wave.cs @@ -1,8 +1,10 @@ -using System; +using Essgee.Utilities; +using System; +using System.Runtime.InteropServices; namespace Essgee.Emulation.Audio { - public partial class DMGAudio + public unsafe partial class DMGAudio { public class Wave : IDMGAudioChannel { @@ -19,16 +21,35 @@ namespace Essgee.Emulation.Audio byte frequencyLSB; // NR34 - bool trigger, lengthEnable; + public bool trigger, lengthEnable; byte frequencyMSB; // Wave - protected byte[] sampleBuffer; + //protected byte[] sampleBuffer; + + #region //指针化 sampleBuffer + byte[] sampleBuffer_src; + GCHandle sampleBuffer_handle; + public byte* sampleBuffer; + public int sampleBufferLength; + public bool sampleBuffer_IsNull => sampleBuffer == null; + public byte[] sampleBuffer_set + { + set + { + sampleBuffer_handle.ReleaseGCHandle(); + sampleBuffer_src = value; + sampleBufferLength = value.Length; + sampleBuffer_src.GetObjectPtr(ref sampleBuffer_handle, ref sampleBuffer); + } + } + #endregion + int frequencyCounter, positionCounter, volume; // Misc - bool isChannelEnabled; - int lengthCounter; + public bool isChannelEnabled; + public int lengthCounter; //public int OutputVolume { get; private set; } @@ -36,12 +57,15 @@ namespace Essgee.Emulation.Audio public Wave() { - sampleBuffer = new byte[16]; + //sampleBuffer = new byte[16]; + sampleBuffer_set = new byte[16]; } public override void Reset() { - for (var i = 0; i < sampleBuffer.Length; i++) sampleBuffer[i] = (byte)EmuStandInfo.Random.Next(255); + //for (var i = 0; i < sampleBuffer.Length; i++) sampleBuffer[i] = (byte)EmuStandInfo.Random.Next(255); + byte* ptr = sampleBuffer; + for (var i = 0; i < sampleBufferLength; i++, ptr++) *ptr = 0;// (byte)EmuStandInfo.Random.Next(255); frequencyCounter = positionCounter = 0; volume = 15; @@ -82,7 +106,8 @@ namespace Essgee.Emulation.Audio positionCounter++; positionCounter %= 32; - var value = sampleBuffer[positionCounter / 2]; + //var value = sampleBuffer[positionCounter / 2]; + var value = *(sampleBuffer + (positionCounter / 2)); if ((positionCounter & 0b1) == 0) value >>= 4; value &= 0b1111; @@ -168,16 +193,23 @@ namespace Essgee.Emulation.Audio public override void WriteWaveRam(byte offset, byte value) { + //if (!isDacEnabled) + // sampleBuffer[offset & (sampleBuffer.Length - 1)] = value; + //else + // sampleBuffer[positionCounter & (sampleBuffer.Length - 1)] = value; if (!isDacEnabled) - sampleBuffer[offset & (sampleBuffer.Length - 1)] = value; + *(sampleBuffer + (offset & (sampleBufferLength - 1))) = value; else - sampleBuffer[positionCounter & (sampleBuffer.Length - 1)] = value; + *(sampleBuffer+(positionCounter & (sampleBufferLength - 1))) = value; } public override byte ReadWaveRam(byte offset) { if (!isDacEnabled) - return sampleBuffer[offset & (sampleBuffer.Length - 1)]; + { + //return sampleBuffer[offset & (sampleBufferLength - 1)]; + return *(sampleBuffer + (offset & (sampleBufferLength - 1))); + } else return 0xFF; } diff --git a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs index cba87ca7..6c05718c 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Audio/DMGAudio.cs @@ -19,7 +19,10 @@ namespace Essgee.Emulation.Audio protected const string channel3OptionName = "AudioEnableCh3Wave"; protected const string channel4OptionName = "AudioEnableCh4Noise"; - protected IDMGAudioChannel channel1, channel2, channel3, channel4; + //protected IDMGAudioChannel channel1, channel2, channel3, channel4; + protected Square channel1, channel2; + protected Wave channel3; + protected Noise channel4; // FF24 - NR50 byte[] volumeRightLeft; @@ -298,6 +301,161 @@ namespace Essgee.Emulation.Audio //独立声明,不在函数内部 private bool[] channelEnableFlags = new bool[4]; + //public void Step(int clockCyclesInStep) + //{ + // if (!isSoundHwEnabled) return; + + // sampleCycleCount += clockCyclesInStep; + // frameCycleCount += clockCyclesInStep; + + // for (int i = 0; i < clockCyclesInStep; i++) + // { + // frameSequencerCounter--; + // if (frameSequencerCounter == 0) + // { + // frameSequencerCounter = frameSequencerReload; + + // switch (frameSequencer) + // { + // case 0: + // channel1.LengthCounterClock(); + // channel2.LengthCounterClock(); + // channel3.LengthCounterClock(); + // channel4.LengthCounterClock(); + // break; + + // case 1: + // break; + + // case 2: + // channel1.SweepClock(); + // channel1.LengthCounterClock(); + // channel2.LengthCounterClock(); + // channel3.LengthCounterClock(); + // channel4.LengthCounterClock(); + // break; + + // case 3: + // break; + + // case 4: + // channel1.LengthCounterClock(); + // channel2.LengthCounterClock(); + // channel3.LengthCounterClock(); + // channel4.LengthCounterClock(); + // break; + + // case 5: + // break; + + // case 6: + // channel1.SweepClock(); + // channel1.LengthCounterClock(); + // channel2.LengthCounterClock(); + // channel3.LengthCounterClock(); + // channel4.LengthCounterClock(); + // break; + + // case 7: + // channel1.VolumeEnvelopeClock(); + // channel2.VolumeEnvelopeClock(); + // channel4.VolumeEnvelopeClock(); + // break; + // } + + // frameSequencer++; + // if (frameSequencer >= 8) + // frameSequencer = 0; + // } + + // //channel1.Step(); + // //channel2.Step(); + // //channel3.Step(); + // //channel4.Step(); + + // //手动内联 + // //channel1.Step(); + // if (channel1.isChannelEnabled) + // { + // channel1.frequencyCounter--; + // if (channel1.frequencyCounter == 0) + // { + // channel1.frequencyCounter = (2048 - ((channel1.frequencyMSB << 8) | channel1.frequencyLSB)) * 4; + // channel1.dutyCounter++; + // channel1.dutyCounter %= 8; + // } + // channel1.OutputVolume = channel1.isDacEnabled && *(channel1._dutyCycleTable1D + (channel1.dutyCycle * Square.Cols + channel1.dutyCounter)) ? channel1.volume : 0; + // } + // //channel2.Step(); + // if (channel2.isChannelEnabled) + // { + // channel2.frequencyCounter--; + // if (channel2.frequencyCounter == 0) + // { + // channel2.frequencyCounter = (2048 - ((channel2.frequencyMSB << 8) | channel2.frequencyLSB)) * 4; + // channel2.dutyCounter++; + // channel2.dutyCounter %= 8; + // } + // channel2.OutputVolume = channel2.isDacEnabled && *(channel2._dutyCycleTable1D + (channel2.dutyCycle * Square.Cols + channel2.dutyCounter)) ? channel2.volume : 0; + // } + // channel3.Step(); + // channel4.Step(); + // } + + // if (sampleCycleCount >= cyclesPerSample) + // { + // GenerateSample(); + + // sampleCycleCount -= cyclesPerSample; + // } + + // //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()); + + // //有GC + // //EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create( + // // numChannels, + // // channelSampleBuffer, + // // new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable }, + // // mixedSampleBuffer, + // // mixedSampleBuffer_writePos); + + + // // 在函数中使用 + // channelEnableFlags[0] = !channel1ForceEnable; + // channelEnableFlags[1] = !channel2ForceEnable; + // channelEnableFlags[2] = !channel3ForceEnable; + // channelEnableFlags[3] = !channel4ForceEnable; + + // EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create( + // numChannels, + // channelSampleBuffer, + // channelEnableFlags, + // mixedSampleBuffer, + // mixedSampleBuffer_writePos); + + // OnEnqueueSamples(eventArgs); + + // FlushSamples(); + + // eventArgs.Release(); + + // } + + // if (frameCycleCount >= cyclesPerFrame) + // { + // frameCycleCount -= cyclesPerFrame; + // sampleCycleCount = frameCycleCount; + // } + //} + + //手动内联 public void Step(int clockCyclesInStep) { if (!isSoundHwEnabled) return; @@ -315,10 +473,34 @@ namespace Essgee.Emulation.Audio switch (frameSequencer) { case 0: - channel1.LengthCounterClock(); - channel2.LengthCounterClock(); - channel3.LengthCounterClock(); - channel4.LengthCounterClock(); + //channel1.LengthCounterClock(); + if (channel1.lengthCounter > 0 && channel1.lengthEnable) + { + channel1.lengthCounter--; + if (channel1.lengthCounter == 0) + channel1.isChannelEnabled = false; + } + //channel2.LengthCounterClock(); + if (channel2.lengthCounter > 0 && channel2.lengthEnable) + { + channel2.lengthCounter--; + if (channel2.lengthCounter == 0) + channel2.isChannelEnabled = false; + } + //channel3.LengthCounterClock(); + if (channel3.lengthCounter > 0 && channel3.lengthEnable) + { + channel3.lengthCounter--; + if (channel3.lengthCounter == 0) + channel3.isChannelEnabled = false; + } + //channel4.LengthCounterClock(); + if (channel4.lengthCounter > 0 && channel4.lengthEnable) + { + channel4.lengthCounter--; + if (channel4.lengthCounter == 0) + channel4.isChannelEnabled = false; + } break; case 1: @@ -326,20 +508,68 @@ namespace Essgee.Emulation.Audio case 2: channel1.SweepClock(); - channel1.LengthCounterClock(); - channel2.LengthCounterClock(); - channel3.LengthCounterClock(); - channel4.LengthCounterClock(); + //channel1.LengthCounterClock(); + if (channel1.lengthCounter > 0 && channel1.lengthEnable) + { + channel1.lengthCounter--; + if (channel1.lengthCounter == 0) + channel1.isChannelEnabled = false; + } + //channel2.LengthCounterClock(); + if (channel2.lengthCounter > 0 && channel2.lengthEnable) + { + channel2.lengthCounter--; + if (channel2.lengthCounter == 0) + channel2.isChannelEnabled = false; + } + //channel3.LengthCounterClock(); + if (channel3.lengthCounter > 0 && channel3.lengthEnable) + { + channel3.lengthCounter--; + if (channel3.lengthCounter == 0) + channel3.isChannelEnabled = false; + } + //channel4.LengthCounterClock(); + if (channel4.lengthCounter > 0 && channel4.lengthEnable) + { + channel4.lengthCounter--; + if (channel4.lengthCounter == 0) + channel4.isChannelEnabled = false; + } break; case 3: break; case 4: - channel1.LengthCounterClock(); - channel2.LengthCounterClock(); - channel3.LengthCounterClock(); - channel4.LengthCounterClock(); + //channel1.LengthCounterClock(); + if (channel1.lengthCounter > 0 && channel1.lengthEnable) + { + channel1.lengthCounter--; + if (channel1.lengthCounter == 0) + channel1.isChannelEnabled = false; + } + //channel2.LengthCounterClock(); + if (channel2.lengthCounter > 0 && channel2.lengthEnable) + { + channel2.lengthCounter--; + if (channel2.lengthCounter == 0) + channel2.isChannelEnabled = false; + } + //channel3.LengthCounterClock(); + if (channel3.lengthCounter > 0 && channel3.lengthEnable) + { + channel3.lengthCounter--; + if (channel3.lengthCounter == 0) + channel3.isChannelEnabled = false; + } + //channel4.LengthCounterClock(); + if (channel4.lengthCounter > 0 && channel4.lengthEnable) + { + channel4.lengthCounter--; + if (channel4.lengthCounter == 0) + channel4.isChannelEnabled = false; + } break; case 5: @@ -347,10 +577,34 @@ namespace Essgee.Emulation.Audio case 6: channel1.SweepClock(); - channel1.LengthCounterClock(); - channel2.LengthCounterClock(); - channel3.LengthCounterClock(); - channel4.LengthCounterClock(); + //channel1.LengthCounterClock(); + if (channel1.lengthCounter > 0 && channel1.lengthEnable) + { + channel1.lengthCounter--; + if (channel1.lengthCounter == 0) + channel1.isChannelEnabled = false; + } + //channel2.LengthCounterClock(); + if (channel2.lengthCounter > 0 && channel2.lengthEnable) + { + channel2.lengthCounter--; + if (channel2.lengthCounter == 0) + channel2.isChannelEnabled = false; + } + //channel3.LengthCounterClock(); + if (channel3.lengthCounter > 0 && channel3.lengthEnable) + { + channel3.lengthCounter--; + if (channel3.lengthCounter == 0) + channel3.isChannelEnabled = false; + } + //channel4.LengthCounterClock(); + if (channel4.lengthCounter > 0 && channel4.lengthEnable) + { + channel4.lengthCounter--; + if (channel4.lengthCounter == 0) + channel4.isChannelEnabled = false; + } break; case 7: @@ -365,8 +619,36 @@ namespace Essgee.Emulation.Audio frameSequencer = 0; } - channel1.Step(); - channel2.Step(); + //channel1.Step(); + //channel2.Step(); + //channel3.Step(); + //channel4.Step(); + + //手动内联 + //channel1.Step(); + if (channel1.isChannelEnabled) + { + channel1.frequencyCounter--; + if (channel1.frequencyCounter == 0) + { + channel1.frequencyCounter = (2048 - ((channel1.frequencyMSB << 8) | channel1.frequencyLSB)) * 4; + channel1.dutyCounter++; + channel1.dutyCounter %= 8; + } + channel1.OutputVolume = channel1.isDacEnabled && *(channel1._dutyCycleTable1D + (channel1.dutyCycle * Square.Cols + channel1.dutyCounter)) ? channel1.volume : 0; + } + //channel2.Step(); + if (channel2.isChannelEnabled) + { + channel2.frequencyCounter--; + if (channel2.frequencyCounter == 0) + { + channel2.frequencyCounter = (2048 - ((channel2.frequencyMSB << 8) | channel2.frequencyLSB)) * 4; + channel2.dutyCounter++; + channel2.dutyCounter %= 8; + } + channel2.OutputVolume = channel2.isDacEnabled && *(channel2._dutyCycleTable1D + (channel2.dutyCycle * Square.Cols + channel2.dutyCounter)) ? channel2.volume : 0; + } channel3.Step(); channel4.Step(); } diff --git a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/DMGVideo.cs b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/DMGVideo.cs index bf6b7ee0..3b0b37de 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/DMGVideo.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/Essgee.Unity/Emulation/Video/Nintendo/DMGVideo.cs @@ -106,13 +106,33 @@ namespace Essgee.Emulation.Video.Nintendo //取值范例 colorValuesBgr[colorIndex * 3 + channelIndex]; const byte colorValuesBgr_singleLen = 3; // 转换后的一维数组 - readonly byte[] colorValuesBgr = new byte[] + //readonly byte[] colorValuesBgr = new byte[] + //{ + ///* White */ 0xF8, 0xF8, 0xF8, + ///* Light gray */0x9B, 0x9B, 0x9B, + ///* Dark gray */ 0x3E, 0x3E, 0x3E, + ///* Black */ 0x1F, 0x1F, 0x1F + //}; + + + #region //指针化 colorValuesBgr + byte[] colorValuesBgr_src; + GCHandle colorValuesBgr_handle; + public byte* colorValuesBgr; + public int colorValuesBgrLength; + public bool colorValuesBgr_IsNull => colorValuesBgr == null; + public byte[] colorValuesBgr_set { - /* White */ 0xF8, 0xF8, 0xF8, - /* Light gray */0x9B, 0x9B, 0x9B, - /* Dark gray */ 0x3E, 0x3E, 0x3E, - /* Black */ 0x1F, 0x1F, 0x1F - }; + set + { + colorValuesBgr_handle.ReleaseGCHandle(); + colorValuesBgr_src = value; + colorValuesBgrLength = value.Length; + colorValuesBgr_src.GetObjectPtr(ref colorValuesBgr_handle, ref colorValuesBgr); + } + } + #endregion + protected const byte screenUsageEmpty = 0; protected const byte screenUsageBackground = 1 << 0; @@ -305,6 +325,15 @@ namespace Essgee.Emulation.Video.Nintendo outputFramebufferCopy_set = new byte[numDisplayPixels * 4]; + //初始化一下 + colorValuesBgr_set = new byte[] + { + /* White */ 0xF8, 0xF8, 0xF8, + /* Light gray */0x9B, 0x9B, 0x9B, + /* Dark gray */ 0x3E, 0x3E, 0x3E, + /* Black */ 0x1F, 0x1F, 0x1F + }; + for (var y = 0; y < displayActiveHeight; y++) SetLine(y, 0xFF, 0xFF, 0xFF); } @@ -734,18 +763,24 @@ namespace Essgee.Emulation.Video.Nintendo //outputFramebuffer[address + 0] = colorValuesBgr[c & 0x03][0]; //outputFramebuffer[address + 1] = colorValuesBgr[c & 0x03][1]; //outputFramebuffer[address + 2] = colorValuesBgr[c & 0x03][2]; - outputFramebuffer[address + 0] = colorValuesBgr[(c & 0x03) * 3 + 0]; - outputFramebuffer[address + 1] = colorValuesBgr[(c & 0x03) * 3 + 1]; - outputFramebuffer[address + 2] = colorValuesBgr[(c & 0x03) * 3 + 2]; - outputFramebuffer[address + 3] = 0xFF; + + //outputFramebuffer[address + 0] = colorValuesBgr[(c & 0x03) * 3 + 0]; + //outputFramebuffer[address + 1] = colorValuesBgr[(c & 0x03) * 3 + 1]; + //outputFramebuffer[address + 2] = colorValuesBgr[(c & 0x03) * 3 + 2]; + //outputFramebuffer[address + 3] = 0xFF; + + *(outputFramebuffer + address) = colorValuesBgr[(c & 0x03) * 3 + 0]; + *(outputFramebuffer + address + 1) = colorValuesBgr[(c & 0x03) * 3 + 1]; + *(outputFramebuffer + address + 2) = colorValuesBgr[(c & 0x03) * 3 + 2]; + *(outputFramebuffer + address + 3) = 0xFF; } protected virtual void WriteColorToFramebuffer(byte b, byte g, byte r, int address) { - outputFramebuffer[address + 0] = b; - outputFramebuffer[address + 1] = g; - outputFramebuffer[address + 2] = r; - outputFramebuffer[address + 3] = 0xFF; + *(outputFramebuffer + address) = b; + *(outputFramebuffer + address + 1) = g; + *(outputFramebuffer + address + 2) = r; + *(outputFramebuffer + address + 3) = 0xFF; } protected virtual void ClearScreenUsage()