Essgee:指针化优化 DMG音频处理效率
This commit is contained in:
parent
f53fcbfee0
commit
b4261139ad
@ -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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user