diff --git a/AxibugEmuOnline.Client/Assets/Scene/EmuTest.unity b/AxibugEmuOnline.Client/Assets/Scene/EmuTest.unity index d02b17c..8e9ca8b 100644 --- a/AxibugEmuOnline.Client/Assets/Scene/EmuTest.unity +++ b/AxibugEmuOnline.Client/Assets/Scene/EmuTest.unity @@ -325,7 +325,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 4232056521131536012, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} propertyPath: RomName - value: tortoise4.nes + value: tstd2.nes objectReference: {fileID: 0} - target: {fileID: 4232056521131536013, guid: f8bea3f8aa351bb46ada33b2274729ea, type: 3} propertyPath: m_Name diff --git a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.prefab b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.prefab index 97239ec..2c66afb 100644 --- a/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.prefab +++ b/AxibugEmuOnline.Client/Assets/Script/NesEmulator/NesEmulator.prefab @@ -44,6 +44,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a6a09b6a4cf4c2d4f994a13fd7e89d6f, type: 3} m_Name: m_EditorClassIdentifier: + NesEmu: {fileID: 0} m_as: {fileID: 8726979175317618791} --- !u!82 &8726979175317618791 AudioSource: @@ -256,6 +257,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 83fbe375412d1af4482ae76e81c1dda2, type: 3} m_Name: m_EditorClassIdentifier: + NesEmu: {fileID: 0} Image: {fileID: 4232056521759880274} --- !u!1 &4232056520494431712 GameObject: diff --git a/AxibugEmuOnline.Client/Assets/StreamingAssets/NES/Roms/msg.nes b/AxibugEmuOnline.Client/Assets/StreamingAssets/NES/Roms/msg.nes new file mode 100644 index 0000000..3a5f57d Binary files /dev/null and b/AxibugEmuOnline.Client/Assets/StreamingAssets/NES/Roms/msg.nes differ diff --git a/AxibugEmuOnline.Client/Assets/StreamingAssets/NES/Roms/msg.nes.meta b/AxibugEmuOnline.Client/Assets/StreamingAssets/NES/Roms/msg.nes.meta new file mode 100644 index 0000000..8a69b2d --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/StreamingAssets/NES/Roms/msg.nes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a5222bc76eba99e4c9fc92b70f4103bc +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs index 1c5562c..d67f9c9 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_FDS.cs @@ -4,34 +4,309 @@ namespace VirtualNes.Core { public class APU_FDS : APU_INTERFACE { - private FDSSOUND fds = new FDSSOUND(); - private FDSSOUND fds_sync = new FDSSOUND(); + FDSSOUND fds = new FDSSOUND(); + FDSSOUND fds_sync = new FDSSOUND(); + int[] output_buf = new int[8]; + int sampling_rate; public APU_FDS() { fds.ZeroMemory(); fds_sync.ZeroMemory(); + + Array.Clear(output_buf, 0, output_buf.Length); + + sampling_rate = 22050; } public override void Reset(float fClock, int nRate) { - //todo : 实现 + fds.ZeroMemory(); + fds_sync.ZeroMemory(); + + sampling_rate = 22050; } public override void Setup(float fClock, int nRate) { - //todo : 实现 + sampling_rate = nRate; + } + + int[] tbl_writesub = { 30, 20, 15, 12 }; + + private void WriteSub(ushort addr, byte data, FDSSOUND ch, double rate) + { + if (addr < 0x4040 || addr > 0x40BF) + return; + + ch.reg[addr - 0x4040] = data; + if (addr >= 0x4040 && addr <= 0x407F) + { + if (ch.wave_setup != 0) + { + ch.main_wavetable[addr - 0x4040] = 0x20 - (data & 0x3F); + } + } + else + { + switch (addr) + { + case 0x4080: // Volume Envelope + ch.volenv_mode = (byte)(data >> 6); + if ((data & 0x80) != 0) + { + ch.volenv_gain = (byte)(data & 0x3F); + + // 即時反映 + if (ch.main_addr == 0) + { + ch.now_volume = (ch.volenv_gain < 0x21) ? ch.volenv_gain : 0x20; + } + } + // エンベロープ1段階の演算 + ch.volenv_decay = (byte)(data & 0x3F); + ch.volenv_phaseacc = (double)ch.envelope_speed * (double)(ch.volenv_decay + 1) * rate / (232.0 * 960.0); + break; + + case 0x4082: // Main Frequency(Low) + ch.main_frequency = (ch.main_frequency & ~0x00FF) | data; + break; + case 0x4083: // Main Frequency(High) + ch.main_enable = (byte)((~data) & (1 << 7)); + ch.envelope_enable = (byte)((~data) & (1 << 6)); + if (ch.main_enable == 0) + { + ch.main_addr = 0; + ch.now_volume = (ch.volenv_gain < 0x21) ? ch.volenv_gain : 0x20; + } + // ch.main_frequency = (ch.main_frequency&0x00FF)|(((INT)data&0x3F)<<8); + ch.main_frequency = (ch.main_frequency & 0x00FF) | ((data & 0x0F) << 8); + break; + + case 0x4084: // Sweep Envelope + ch.swpenv_mode = (byte)(data >> 6); + if ((data & 0x80) != 0) + { + ch.swpenv_gain = (byte)(data & 0x3F); + } + // エンベロープ1段階の演算 + ch.swpenv_decay = (byte)(data & 0x3F); + ch.swpenv_phaseacc = (double)ch.envelope_speed * (double)(ch.swpenv_decay + 1) * rate / (232.0 * 960.0); + break; + + case 0x4085: // Sweep Bias + if ((data & 0x40) != 0) ch.sweep_bias = (data & 0x3f) - 0x40; + else ch.sweep_bias = data & 0x3f; + ch.lfo_addr = 0; + break; + + case 0x4086: // Effector(LFO) Frequency(Low) + ch.lfo_frequency = (ch.lfo_frequency & (~0x00FF)) | data; + break; + case 0x4087: // Effector(LFO) Frequency(High) + ch.lfo_enable = (byte)((~data & 0x80)); + ch.lfo_frequency = (ch.lfo_frequency & 0x00FF) | ((data & 0x0F) << 8); + break; + + case 0x4088: // Effector(LFO) wavetable + if (ch.lfo_enable == 0) + { + // FIFO? + for (byte i = 0; i < 31; i++) + { + ch.lfo_wavetable[i * 2 + 0] = ch.lfo_wavetable[(i + 1) * 2 + 0]; + ch.lfo_wavetable[i * 2 + 1] = ch.lfo_wavetable[(i + 1) * 2 + 1]; + } + ch.lfo_wavetable[31 * 2 + 0] = (byte)(data & 0x07); + ch.lfo_wavetable[31 * 2 + 1] = (byte)(data & 0x07); + } + break; + + case 0x4089: // Sound control + { + ch.master_volume = tbl_writesub[data & 3]; + ch.wave_setup = (byte)(data & 0x80); + } + break; + + case 0x408A: // Sound control 2 + ch.envelope_speed = data; + break; + + default: + break; + } + } } public override void Write(ushort addr, byte data) { - //todo : 实现 + WriteSub(addr, data, fds, sampling_rate); } + public override byte Read(ushort addr) + { + byte data = (byte)(addr >> 8); + + if (addr >= 0x4040 && addr <= 0x407F) + { + data = (byte)(fds.main_wavetable[addr & 0x3F] | 0x40); + } + else + if (addr == 0x4090) + { + data = (byte)((fds.volenv_gain & 0x3F) | 0x40); + } + else + if (addr == 0x4092) + { + data = (byte)((fds.swpenv_gain & 0x3F) | 0x40); + } + + return data; + } + + int[] tbl_process = { 0, 1, 2, 4, 0, -4, -2, -1 }; public override int Process(int channel) { - //todo : 实现 - return 0; + // Envelope unit + if (fds.envelope_enable != 0 && fds.envelope_speed != 0) + { + // Volume envelope + if (fds.volenv_mode < 2) + { + double decay = ((double)fds.envelope_speed * (double)(fds.volenv_decay + 1) * (double)sampling_rate) / (232.0 * 960.0); + fds.volenv_phaseacc -= 1.0; + while (fds.volenv_phaseacc < 0.0) + { + fds.volenv_phaseacc += decay; + + if (fds.volenv_mode == 0) + { + // 減少モード + if (fds.volenv_gain != 0) + fds.volenv_gain--; + } + else + if (fds.volenv_mode == 1) + { + if (fds.volenv_gain < 0x20) + fds.volenv_gain++; + } + } + } + + // Sweep envelope + if (fds.swpenv_mode < 2) + { + double decay = ((double)fds.envelope_speed * (double)(fds.swpenv_decay + 1) * (double)sampling_rate) / (232.0 * 960.0); + fds.swpenv_phaseacc -= 1.0; + while (fds.swpenv_phaseacc < 0.0) + { + fds.swpenv_phaseacc += decay; + + if (fds.swpenv_mode == 0) + { + // 減少モード + if (fds.swpenv_gain != 0) + fds.swpenv_gain--; + } + else + if (fds.swpenv_mode == 1) + { + if (fds.swpenv_gain < 0x20) + fds.swpenv_gain++; + } + } + } + } + + // Effector(LFO) unit + int sub_freq = 0; + // if( fds.lfo_enable && fds.envelope_speed && fds.lfo_frequency ) { + if (fds.lfo_enable != 0) + { + if (fds.lfo_frequency != 0) + { + fds.lfo_phaseacc -= (1789772.5 * (double)fds.lfo_frequency) / 65536.0; + while (fds.lfo_phaseacc < 0.0) + { + fds.lfo_phaseacc += (double)sampling_rate; + + if (fds.lfo_wavetable[fds.lfo_addr] == 4) + fds.sweep_bias = 0; + else + fds.sweep_bias += tbl_process[fds.lfo_wavetable[fds.lfo_addr]]; + + fds.lfo_addr = (fds.lfo_addr + 1) & 63; + } + } + + if (fds.sweep_bias > 63) + fds.sweep_bias -= 128; + else if (fds.sweep_bias < -64) + fds.sweep_bias += 128; + + int sub_multi = fds.sweep_bias * fds.swpenv_gain; + + if ((sub_multi & 0x0F) != 0) + { + // 16で割り切れない場合 + sub_multi = (sub_multi / 16); + if (fds.sweep_bias >= 0) + sub_multi += 2; // 正の場合 + else + sub_multi -= 1; // 負の場合 + } + else + { + // 16で割り切れる場合 + sub_multi = (sub_multi / 16); + } + // 193を超えると-258する(-64へラップ) + if (sub_multi > 193) + sub_multi -= 258; + // -64を下回ると+256する(192へラップ) + if (sub_multi < -64) + sub_multi += 256; + + sub_freq = (fds.main_frequency) * sub_multi / 64; + } + + // Main unit + int output = 0; + if (fds.main_enable != 0 && fds.main_frequency != 0 && fds.wave_setup == 0) + { + int freq; + int main_addr_old = fds.main_addr; + + freq = (int)((fds.main_frequency + sub_freq) * 1789772.5 / 65536.0); + + fds.main_addr = (fds.main_addr + freq + 64 * sampling_rate) % (64 * sampling_rate); + + // 1周期を超えたらボリューム更新 + if (main_addr_old > fds.main_addr) + fds.now_volume = (fds.volenv_gain < 0x21) ? fds.volenv_gain : 0x20; + + output = fds.main_wavetable[(fds.main_addr / sampling_rate) & 0x3f] * 8 * fds.now_volume * fds.master_volume / 30; + + if (fds.now_volume != 0) + fds.now_freq = freq * 4; + else + fds.now_freq = 0; + } + else + { + fds.now_freq = 0; + output = 0; + } + + // LPF + output = (output_buf[0] * 2 + output) / 3; + output_buf[0] = output; + + fds.output = output; + return fds.output; } internal void SyncWrite(ushort addr, byte data) @@ -39,10 +314,7 @@ namespace VirtualNes.Core WriteSub(addr, data, fds_sync, 1789772.5d); } - private void WriteSub(ushort addr, byte data, FDSSOUND ch, double rate) - { - //todo : 实现 - } + internal byte SyncRead(ushort addr) { @@ -66,6 +338,71 @@ namespace VirtualNes.Core return data; } + public override bool Sync(int cycles) + { + // Envelope unit + if (fds_sync.envelope_enable != 0 && fds_sync.envelope_speed != 0) + { + // Volume envelope + double decay; + if (fds_sync.volenv_mode < 2) + { + decay = ((double)fds_sync.envelope_speed * (double)(fds_sync.volenv_decay + 1) * 1789772.5) / (232.0 * 960.0); + fds_sync.volenv_phaseacc -= (double)cycles; + while (fds_sync.volenv_phaseacc < 0.0) + { + fds_sync.volenv_phaseacc += decay; + + if (fds_sync.volenv_mode == 0) + { + // 減少モード + if (fds_sync.volenv_gain != 0) + fds_sync.volenv_gain--; + } + else + if (fds_sync.volenv_mode == 1) + { + // 増加モード + if (fds_sync.volenv_gain < 0x20) + fds_sync.volenv_gain++; + } + } + } + + // Sweep envelope + if (fds_sync.swpenv_mode < 2) + { + decay = ((double)fds_sync.envelope_speed * (double)(fds_sync.swpenv_decay + 1) * 1789772.5) / (232.0 * 960.0); + fds_sync.swpenv_phaseacc -= (double)cycles; + while (fds_sync.swpenv_phaseacc < 0.0) + { + fds_sync.swpenv_phaseacc += decay; + + if (fds_sync.swpenv_mode == 0) + { + // 減少モード + if (fds_sync.swpenv_gain != 0) + fds_sync.swpenv_gain--; + } + else + if (fds_sync.swpenv_mode == 1) + { + // 増加モード + if (fds_sync.swpenv_gain < 0x20) + fds_sync.swpenv_gain++; + } + } + } + } + + return false; + } + + public override int GetFreq(int channel) + { + return fds.now_freq; + } + private class FDSSOUND { public byte[] reg = new byte[0x80]; diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC7.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC7.cs index d7acd97..83b2e79 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC7.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/ApuEX/APU_VRC7.cs @@ -1,5 +1,5 @@ using System; -using System.Net; +using VirtualNes.Core.Emu2413; namespace VirtualNes.Core { @@ -86,7 +86,7 @@ namespace VirtualNes.Core if ((VRC7_OPLL.reg[0x20 + channel] & 0x10) != 0) { - return (int)((256.0d * (double)fno * blkmul[blk]) / ((double)(1 << 18) / (3579545.0 / 72.0))); + return (int)((256.0d * fno * blkmul[blk]) / ((1 << 18) / (3579545.0 / 72.0))); } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs index 835c758..26527e7 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CPU.cs @@ -45,7 +45,7 @@ namespace VirtualNes.Core private APU apu; internal R6502 R = new R6502(); private byte[] ZN_Table = new byte[256]; - private ByteArrayRef STACK; + private ArrayRef STACK; public CPU(NES parent) { @@ -2010,7 +2010,7 @@ namespace VirtualNes.Core DMA_cycles = 0; // STACK quick access - STACK = new ByteArrayRef(MMU.RAM, 0x0100, MMU.RAM.Length - 0x100); + STACK = new ArrayRef(MMU.RAM, 0x0100, MMU.RAM.Length - 0x100); // Zero/Negative FLAG ZN_Table[0] = Z_FLAG; diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs index c84dcff..3126a59 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/ByteArrayRef.cs @@ -2,9 +2,9 @@ namespace VirtualNes.Core { - public class ByteArrayRef + public class ArrayRef { - private byte[] m_rawArray; + private T[] m_rawArray; private int m_offset; private int m_length; @@ -18,30 +18,30 @@ namespace VirtualNes.Core } } - public ByteArrayRef() { } - public ByteArrayRef(byte[] array, int offset, int length) + public ArrayRef() { } + public ArrayRef(T[] array, int offset, int length) { SetArray(array, offset, length); } - public ByteArrayRef(byte[] array) : this(array, 0, array.Length) { } - public ByteArrayRef(byte[] array, int offset) : this(array, offset, array.Length - offset) { } + public ArrayRef(T[] array) : this(array, 0, array.Length) { } + public ArrayRef(T[] array, int offset) : this(array, offset, array.Length - offset) { } - public void SetArray(byte[] array, int offset, int length) + public void SetArray(T[] array, int offset, int length) { m_rawArray = array; m_offset = offset; m_length = length; } - public void SetArray(byte[] array, int offset) + public void SetArray(T[] array, int offset) { m_rawArray = array; m_offset = offset; m_length = array.Length - offset; } - public byte this[int index] + public T this[int index] { get { @@ -53,14 +53,14 @@ namespace VirtualNes.Core } } - public static implicit operator ByteArrayRef(byte[] array) + public static implicit operator ArrayRef(T[] array) { - return new ByteArrayRef(array); + return new ArrayRef(array); } - public static implicit operator Span(ByteArrayRef array) + public static implicit operator Span(ArrayRef array) { - return new Span(array.m_rawArray, array.Offset, array.m_length); + return new Span(array.m_rawArray, array.Offset, array.m_length); } } } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413.cs deleted file mode 100644 index d37e6ec..0000000 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System; - -namespace VirtualNes.Core -{ - public class OPLL_PATCH - { - public uint TL, FB, EG, ML, AR, DR, SL, RR, KR, KL, AM, PM, WF; - } - - public class OPLL_SLOT - { - public OPLL_PATCH patch; - - public int type; /* 0 : modulator 1 : carrier */ - - /* OUTPUT */ - public Int32 feedback; - public Int32[] output = new Int32[5]; /* Output value of slot */ - - /* for Phase Generator (PG) */ - public UInt32 sintbl; /* Wavetable */ - public UInt32 phase; /* Phase */ - public UInt32 dphase; /* Phase increment amount */ - public UInt32 pgout; /* output */ - - /* for Envelope Generator (EG) */ - public int fnum; /* F-Number */ - public int block; /* Block */ - public int volume; /* Current volume */ - public int sustine; /* Sustine 1 = ON, 0 = OFF */ - public UInt32 tll; /* Total Level + Key scale level*/ - public UInt32 rks; /* Key scale offset (Rks) */ - public int eg_mode; /* Current state */ - public UInt32 eg_phase; /* Phase */ - public UInt32 eg_dphase; /* Phase increment amount */ - public UInt32 egout; /* output */ - - - /* refer to opll-> */ - public UInt32 plfo_pm; - public UInt32 plfo_am; - } - - public class OPLL_CH - { - public int patch_number; - public int key_status; - public OPLL_SLOT mod; - public OPLL_SLOT car; - } - - public class OPLL - { - public UInt32 adr; - public Int32[] output = new Int32[2]; - - /* Register */ - public byte[] reg = new byte[0x40]; - public int[] slot_on_flag = new int[18]; - - /* Rythm Mode : 0 = OFF, 1 = ON */ - public int rythm_mode; - - /* Pitch Modulator */ - public UInt32 pm_phase; - public Int32 lfo_pm; - - /* Amp Modulator */ - public Int32 am_phase; - public Int32 lfo_am; - - /* Noise Generator */ - public UInt32 noise_seed; - public UInt32 whitenoise; - public UInt32 noiseA; - public UInt32 noiseB; - public UInt32 noiseA_phase; - public UInt32 noiseB_phase; - public UInt32 noiseA_idx; - public UInt32 noiseB_idx; - public UInt32 noiseA_dphase; - public UInt32 noiseB_dphase; - - public int masterVolume; /* 0min -- 64 -- 127 max (Liner) */ - } - - public static class Emu2413API - { - /* Bits for Pitch and Amp modulator */ - public const int PM_PG_BITS = 8; - public const int PM_PG_WIDTH = 1 << PM_PG_BITS; - public const int PM_DP_BITS = 16; - public const int PM_DP_WIDTH = (1 << PM_DP_BITS); - public const int AM_PG_BITS = 8; - public const int AM_PG_WIDTH = (1 << AM_PG_BITS); - public const int AM_DP_BITS = 16; - public const int AM_DP_WIDTH = (1 << AM_DP_BITS); - - /* PM table is calcurated by PM_AMP * pow(2,PM_DEPTH*sin(x)/1200) */ - public const int PM_AMP_BITS = 8; - public const int PM_AMP = (1 << PM_AMP_BITS); - - /* PM speed(Hz) and depth(cent) */ - public const double PM_SPEED = 6.4d; - public const double PM_DEPTH = 13.75d; - - public const int OPLL_2413_TONE = 0; - public const int OPLL_VRC7_TONE = 1; - - static int[] pmtable = new int[PM_PG_WIDTH]; - static int[] amtable = new int[AM_PG_WIDTH]; - - public static void OPLL_init(UInt32 c, UInt32 r) - { - makePmTable(); - makeAmTable(); - makeDB2LinTable(); - makeAdjustTable(); - makeTllTable(); - makeRksTable(); - makeSinTable(); - makeDefaultPatch(); - OPLL_setClock(c, r); - } - - internal static void OPLL_setClock(uint c, uint r) - { - throw new NotImplementedException(); - } - - private static void makeDefaultPatch() - { - throw new NotImplementedException(); - } - - private static void makeSinTable() - { - throw new NotImplementedException(); - } - - private static void makeRksTable() - { - throw new NotImplementedException(); - } - - private static void makeTllTable() - { - throw new NotImplementedException(); - } - - private static void makeAdjustTable() - { - throw new NotImplementedException(); - } - - private static void makeDB2LinTable() - { - throw new NotImplementedException(); - } - - private static void makeAmTable() - { - throw new NotImplementedException(); - } - - private static void makePmTable() - { - int i; - - for (i = 0; i < PM_PG_WIDTH; i++) - pmtable[i] = (int)(PM_AMP * Math.Pow(2, PM_DEPTH * Math.Sin(2.0 * Math.PI * i / PM_PG_WIDTH) / 1200)); - } - - internal static OPLL OPLL_new() - { - throw new NotImplementedException(); - } - - internal static void OPLL_reset(OPLL vRC7_OPLL) - { - throw new NotImplementedException(); - } - - internal static void OPLL_reset_patch(OPLL vRC7_OPLL, int oPLL_VRC7_TONE) - { - throw new NotImplementedException(); - } - - internal static void OPLL_delete(OPLL vRC7_OPLL) - { - throw new NotImplementedException(); - } - - internal static void OPLL_writeReg(OPLL opll, UInt32 reg, UInt32 data) - { - throw new NotImplementedException(); - } - - internal static int OPLL_calc(OPLL opll) - { - throw new NotImplementedException(); - } - } -} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413.meta new file mode 100644 index 0000000..3a84c86 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5b90f721bfc1ac4ea985c0f564d1c6e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413.cs new file mode 100644 index 0000000..bcea6fd --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413.cs @@ -0,0 +1,1545 @@ +using System; +using System.Runtime.ConstrainedExecution; +using System.Runtime.Remoting.Lifetime; +namespace VirtualNes.Core.Emu2413 +{ + public static class Emu2413API + { + static sbyte[][] default_inst = Const.Create_Default_Inst(); + + public const int OPLL_TONE_NUM = 2; + + /* Size of Sintable ( 1 -- 18 can be used, but 7 -- 14 recommended.)*/ + public const int PG_BITS = 9; + public const int PG_WIDTH = (1 << PG_BITS); + + /* Phase increment counter */ + public const int DP_BITS = 18; + public const int DP_WIDTH = (1 << DP_BITS); + public const int DP_BASE_BITS = (DP_BITS - PG_BITS); + + /* Dynamic range */ + public const double DB_STEP = 0.375; + public const int DB_BITS = 7; + public const int DB_MUTE = (1 << DB_BITS); + + /* Dynamic range of envelope */ + public const double EG_STEP = 0.375; + public const int EG_BITS = 7; + //public const int EG_MUTE = (1 << EB_BITS); ?? 原文如此 EB_BITS 根本不存在 + public const int EG_MUTE = (1 << EG_BITS); + + /* Dynamic range of total level */ + public const double TL_STEP = 0.75; + public const int TL_BITS = 6; + public const int TL_MUTE = (1 << TL_BITS); + + /* Dynamic range of sustine level */ + public const double SL_STEP = 3.0; + public const int SL_BITS = 4; + public const int SL_MUTE = (1 << SL_BITS); + + static int EG2DB(int d) + { + return (d * (int)(EG_STEP / DB_STEP)); + } + + static uint TL2EG(int d) + { + return (uint)(d * (int)(TL_STEP / EG_STEP)); + } + + static int SL2EG(int d) + { + return (d * (int)(SL_STEP / EG_STEP)); + } + + /* Volume of Noise (dB) */ + public const double DB_NOISE = 24; + + static uint DB_POS(double x) + { + return (uint)(x / DB_STEP); + } + + static uint DB_NEG(double x) + { + return (uint)(DB_MUTE + DB_MUTE + x / DB_STEP); + } + + /* Bits for liner value */ + public const int DB2LIN_AMP_BITS = 10; + public const int SLOT_AMP_BITS = (DB2LIN_AMP_BITS); + + /* Bits for envelope phase incremental counter */ + public const int EG_DP_BITS = 22; + public const int EG_DP_WIDTH = (1 << EG_DP_BITS); + + /* Bits for Pitch and Amp modulator */ + public const int PM_PG_BITS = 8; + public const int PM_PG_WIDTH = 1 << PM_PG_BITS; + public const int PM_DP_BITS = 16; + public const int PM_DP_WIDTH = (1 << PM_DP_BITS); + public const int AM_PG_BITS = 8; + public const int AM_PG_WIDTH = (1 << AM_PG_BITS); + public const int AM_DP_BITS = 16; + public const int AM_DP_WIDTH = (1 << AM_DP_BITS); + + /* Mask */ + static int OPLL_MASK_CH(int x) + { + return 1 << x; + } + public const int OPLL_MASK_HH = 1 << 9; + public const int OPLL_MASK_CYM = (1 << (10)); + public const int OPLL_MASK_TOM = (1 << (11)); + public const int OPLL_MASK_SD = (1 << (12)); + public const int OPLL_MASK_BD = (1 << (13)); + public const int OPLL_MASK_RYTHM = OPLL_MASK_HH | OPLL_MASK_CYM | OPLL_MASK_TOM | OPLL_MASK_SD | OPLL_MASK_BD; + + /* PM table is calcurated by PM_AMP * pow(2,PM_DEPTH*sin(x)/1200) */ + public const int PM_AMP_BITS = 8; + public const int PM_AMP = (1 << PM_AMP_BITS); + + /* PM speed(Hz) and depth(cent) */ + public const double PM_SPEED = 6.4d; + public const double PM_DEPTH = 13.75d; + + /* AM speed(Hz) and depth(dB) */ + public const double AM_SPEED = 3.7; + public const double AM_DEPTH = 4.8; + + /* Cut the lower b bit(s) off. */ + static int HIGHBITS(int c, int b) + { + return c >> b; + } + + /* Leave the lower b bit(s). */ + static int LOWBITS(int c, int b) + { + return c & ((1 << b) - 1); + } + + /* Expand x which is s bits to d bits. */ + static int EXPAND_BITS(int x, int s, int d) + { + return (x << (d - s)); + } + + /* Expand x which is s bits to d bits and fill expanded bits '1' */ + static int EXPAND_BITS_X(int x, int s, int d) + { + return ((x << (d - s)) | ((1 << (d - s)) - 1)); + } + + /* Adjust envelope speed which depends on sampling rate. */ + static uint rate_adjust(int x) + { + return (uint)((double)x * clk / 72 / rate + 0.5); /* +0.5 to round */ + } + + static OPLL_SLOT MOD(this OPLL opll, int x) + { + return opll.ch[x].mod; + } + static OPLL_SLOT CAR(this OPLL opll, int x) + { + return opll.ch[x].car; + } + + /* Sampling rate */ + static uint rate; + /* Input clock */ + static uint clk; + + /* WaveTable for each envelope amp */ + static uint[] fullsintable = new uint[PG_WIDTH]; + static uint[] halfsintable = new uint[PG_WIDTH]; + static uint[] snaretable = new uint[PG_WIDTH]; + + static int[] noiseAtable = new int[64] + { + -1,1,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0, + -1,1,0,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0,-1,1,0,0 + }; + + static int[] noiseBtable = new int[8] + { + -1,1,-1,1,0,0,0,0 + }; + + static uint[][] waveform = new uint[5][] + { + fullsintable, halfsintable,snaretable,null,null + }; + + /* Noise and LFO */ + static uint pm_dphase; + static uint am_dphase; + + /* dB to Liner table */ + static int[] DB2LIN_TABLE = new int[(DB_MUTE + DB_MUTE) * 2]; + + /* Liner to Log curve conversion table (for Attack rate). */ + static uint[] AR_ADJUST_TABLE = new uint[1 << EG_BITS]; + + /* Empty voice data */ + static OPLL_PATCH null_patch = new OPLL_PATCH(); + + /* Basic voice Data */ + static OPLL_PATCH[][] default_patch = Const.Create_Default_Patch(); + + /* Definition of envelope mode */ + enum EnvelopeMode { SETTLE, ATTACK, DECAY, SUSHOLD, SUSTINE, RELEASE, FINISH }; + + /* Phase incr table for Attack */ + static uint[][] dphaseARTable = new uint[16][] + { + new uint[16],new uint[16],new uint[16],new uint[16],new uint[16], + new uint[16],new uint[16],new uint[16],new uint[16],new uint[16], + new uint[16],new uint[16],new uint[16],new uint[16],new uint[16], + new uint[16], + }; + /* Phase incr table for Decay and Release */ + static uint[][] dphaseDRTable = new uint[16][] + { + new uint[16],new uint[16],new uint[16],new uint[16],new uint[16], + new uint[16],new uint[16],new uint[16],new uint[16],new uint[16], + new uint[16],new uint[16],new uint[16],new uint[16],new uint[16], + new uint[16], + }; + + /* KSL + TL Table */ + static uint[,,,] tllTable = Const.Create_tllTable(); + static int[,,] rksTable = Const.Create_rksTable(); + + /* Phase incr table for PG */ + static uint[,,] dphaseTable = Const.Create_dphaseTable(); + + public const int OPLL_2413_TONE = 0; + public const int OPLL_VRC7_TONE = 1; + + static int[] pmtable = new int[PM_PG_WIDTH]; + static int[] amtable = new int[AM_PG_WIDTH]; + + static int Min(int i, int j) + { + if (i < j) return i; else return j; + } + + /* Table for AR to LogCurve. */ + static void makeAdjustTable() + { + int i; + + AR_ADJUST_TABLE[0] = (1 << EG_BITS); + for (i = 1; i < 128; i++) + AR_ADJUST_TABLE[i] = (uint)((double)(1 << EG_BITS) - 1 - (1 << EG_BITS) * Math.Log(i) / Math.Log(128)); + } + + /* Table for dB(0 -- (1<= DB_MUTE) DB2LIN_TABLE[i] = 0; + DB2LIN_TABLE[i + DB_MUTE + DB_MUTE] = -DB2LIN_TABLE[i]; + } + } + + /* Liner(+0.0 - +1.0) to dB((1< 0) noiseAtable[i] = (int)DB_POS(0); + else if (noiseAtable[i] < 0) noiseAtable[i] = (int)DB_NEG(0); + else noiseAtable[i] = DB_MUTE - 1; + } + + for (i = 0; i < 8; i++) + { + if (noiseBtable[i] > 0) noiseBtable[i] = (int)DB_POS(0); + else if (noiseBtable[i] < 0) noiseBtable[i] = (int)DB_NEG(0); + else noiseBtable[i] = DB_MUTE - 1; + } + + } + + /* Table for Amp Modulator */ + static void makeAmTable() + { + int i; + + for (i = 0; i < AM_PG_WIDTH; i++) + amtable[i] = (int)((double)AM_DEPTH / 2 / DB_STEP * (1.0 + Math.Sin(2.0 * Math.PI * i / PM_PG_WIDTH))); + } + + static uint[] mltable_makeDphaseTable = new uint[16] { 1, 1 * 2, 2 * 2, 3 * 2, 4 * 2, 5 * 2, 6 * 2, 7 * 2, 8 * 2, 9 * 2, 10 * 2, 10 * 2, 12 * 2, 12 * 2, 15 * 2, 15 * 2 }; + /* Phase increment counter table */ + static void makeDphaseTable() + { + uint fnum, block, ML; + + for (fnum = 0; fnum < 512; fnum++) + for (block = 0; block < 8; block++) + for (ML = 0; ML < 16; ML++) + dphaseTable[fnum, block, ML] = rate_adjust((int)((fnum * mltable_makeDphaseTable[ML]) << (int)block) >> (20 - DP_BITS)); + } + + static uint dB2(double x) + { + return (uint)(x * 2); + } + + static uint[] kltable = new uint[16] + { + dB2( 0.000),dB2( 9.000),dB2(12.000),dB2(13.875),dB2(15.000),dB2(16.125),dB2(16.875),dB2(17.625), + dB2(18.000),dB2(18.750),dB2(19.125),dB2(19.500),dB2(19.875),dB2(20.250),dB2(20.625),dB2(21.000) + }; + + static void makeTllTable() + { + int tmp; + int fnum, block, TL, KL; + + for (fnum = 0; fnum < 16; fnum++) + for (block = 0; block < 8; block++) + for (TL = 0; TL < 64; TL++) + for (KL = 0; KL < 4; KL++) + { + if (KL == 0) + { + tllTable[fnum, block, TL, KL] = TL2EG(TL); + } + else + { + tmp = (int)(kltable[fnum] - dB2(3.000) * (7 - block)); + if (tmp <= 0) + tllTable[fnum, block, TL, KL] = TL2EG(TL); + else + tllTable[fnum, block, TL, KL] = (uint)((tmp >> (3 - KL)) / EG_STEP) + TL2EG(TL); + } + } + } + + /* Rate Table for Attack */ + static void makeDphaseARTable() + { + int AR, Rks, RM, RL; + + for (AR = 0; AR < 16; AR++) + for (Rks = 0; Rks < 16; Rks++) + { + RM = AR + (Rks >> 2); + if (RM > 15) RM = 15; + RL = Rks & 3; + switch (AR) + { + case 0: + dphaseARTable[AR][Rks] = 0; + break; + case 15: + dphaseARTable[AR][Rks] = EG_DP_WIDTH; + break; + default: + dphaseARTable[AR][Rks] = rate_adjust((3 * (RL + 4) << (RM + 1))); + break; + } + } + } + + /* Rate Table for Decay */ + static void makeDphaseDRTable() + { + int DR, Rks, RM, RL; + + for (DR = 0; DR < 16; DR++) + for (Rks = 0; Rks < 16; Rks++) + { + RM = DR + (Rks >> 2); + RL = Rks & 3; + if (RM > 15) RM = 15; + switch (DR) + { + case 0: + dphaseDRTable[DR][Rks] = 0; + break; + default: + dphaseDRTable[DR][Rks] = rate_adjust((RL + 4) << (RM - 1)); + break; + } + } + } + + static void makeRksTable() + { + + int fnum8, block, KR; + + for (fnum8 = 0; fnum8 < 2; fnum8++) + for (block = 0; block < 8; block++) + for (KR = 0; KR < 2; KR++) + { + if (KR != 0) + rksTable[fnum8, block, KR] = (block << 1) + fnum8; + else + rksTable[fnum8, block, KR] = block >> 1; + } + } + + private static void makePmTable() + { + int i; + + for (i = 0; i < PM_PG_WIDTH; i++) + pmtable[i] = (int)(PM_AMP * Math.Pow(2, PM_DEPTH * Math.Sin(2.0 * Math.PI * i / PM_PG_WIDTH) / 1200)); + } + + static void dump2patch(ArrayRef dump, ArrayRef patch) + { + patch[0].AM = (uint)((dump[0] >> 7) & 1); + patch[1].AM = (uint)((dump[1] >> 7) & 1); + patch[0].PM = (uint)((dump[0] >> 6) & 1); + patch[1].PM = (uint)((dump[1] >> 6) & 1); + patch[0].EG = (uint)((dump[0] >> 5) & 1); + patch[1].EG = (uint)((dump[1] >> 5) & 1); + patch[0].KR = (uint)((dump[0] >> 4) & 1); + patch[1].KR = (uint)((dump[1] >> 4) & 1); + patch[0].ML = (uint)((dump[0]) & 15); + patch[1].ML = (uint)((dump[1]) & 15); + patch[0].KL = (uint)((dump[2] >> 6) & 3); + patch[1].KL = (uint)((dump[3] >> 6) & 3); + patch[0].TL = (uint)((dump[2]) & 63); + patch[0].FB = (uint)((dump[3]) & 7); + patch[0].WF = (uint)((dump[3] >> 3) & 1); + patch[1].WF = (uint)((dump[3] >> 4) & 1); + patch[0].AR = (uint)((dump[4] >> 4) & 15); + patch[1].AR = (uint)((dump[5] >> 4) & 15); + patch[0].DR = (uint)((dump[4]) & 15); + patch[1].DR = (uint)((dump[5]) & 15); + patch[0].SL = (uint)((dump[6] >> 4) & 15); + patch[1].SL = (uint)((dump[7] >> 4) & 15); + patch[0].RR = (uint)((dump[6]) & 15); + patch[1].RR = (uint)((dump[7]) & 15); + } + + static ArrayRef instSpan = new ArrayRef(); + static ArrayRef patchSpan = new ArrayRef(); + static void makeDefaultPatch() + { + int i, j; + + for (i = 0; i < OPLL_TONE_NUM; i++) + for (j = 0; j < 19; j++) + { + instSpan.SetArray(default_inst[i], j * 16); + patchSpan.SetArray(default_patch[i], j * 2); + dump2patch(instSpan, patchSpan); + } + } + + static uint calc_eg_dphase(OPLL_SLOT slot) + { + + switch ((EnvelopeMode)slot.eg_mode) + { + case EnvelopeMode.ATTACK: + return dphaseARTable[slot.patch.AR][slot.rks]; + + case EnvelopeMode.DECAY: + return dphaseDRTable[slot.patch.DR][slot.rks]; + + case EnvelopeMode.SUSHOLD: + return 0; + + case EnvelopeMode.SUSTINE: + return dphaseDRTable[slot.patch.RR][slot.rks]; + + case EnvelopeMode.RELEASE: + if (slot.sustine != 0) + return dphaseDRTable[5][slot.rks]; + else if (slot.patch.EG != 0) + return dphaseDRTable[slot.patch.RR][slot.rks]; + else + return dphaseDRTable[7][slot.rks]; + + case EnvelopeMode.FINISH: + return 0; + + default: + return 0; + } + } + + public const int SLOT_BD1 = 12; + public const int SLOT_BD2 = 13; + public const int SLOT_HH = 14; + public const int SLOT_SD = 15; + public const int SLOT_TOM = 16; + public const int SLOT_CYM = 17; + + static void UPDATE_PG(OPLL_SLOT S) + { + S.dphase = dphaseTable[S.fnum, S.block, S.patch.ML]; + } + + static void UPDATE_TLL(OPLL_SLOT S) + { + if (S.type == 0) + { + S.tll = tllTable[S.fnum >> 5, S.block, S.patch.TL, S.patch.KL]; + } + else + { + S.tll = tllTable[S.fnum >> 5, S.block, S.volume, S.patch.KL]; + } + } + + static void UPDATE_RKS(OPLL_SLOT S) + { + S.rks = (uint)rksTable[(S.fnum) >> 8, S.block, S.patch.KR]; + } + + static void UPDATE_WF(OPLL_SLOT S) + { + S.sintbl = waveform[S.patch.WF]; + } + + static void UPDATE_EG(OPLL_SLOT S) + { + S.eg_dphase = calc_eg_dphase(S); + } + + static void UPDATE_ALL(OPLL_SLOT S) + { + UPDATE_PG(S); + UPDATE_TLL(S); + UPDATE_RKS(S); + UPDATE_WF(S); + UPDATE_EG(S); /* G should be last */ + } + + /* Force Refresh (When external program changes some parameters). */ + static void OPLL_forceRefresh(OPLL opll) + { + int i; + + if (opll == null) return; + + for (i = 0; i < 18; i++) + { + UPDATE_PG(opll.slot[i]); + UPDATE_RKS(opll.slot[i]); + UPDATE_TLL(opll.slot[i]); + UPDATE_WF(opll.slot[i]); + UPDATE_EG(opll.slot[i]); + } + } + + /* Slot key on */ + static void slotOn(OPLL_SLOT slot) + { + slot.eg_mode = (int)EnvelopeMode.ATTACK; + slot.phase = 0; + slot.eg_phase = 0; + } + + /* Slot key off */ + static void slotOff(OPLL_SLOT slot) + { + if (slot.eg_mode == (int)EnvelopeMode.ATTACK) + slot.eg_phase = (uint)EXPAND_BITS((int)AR_ADJUST_TABLE[HIGHBITS((int)slot.eg_phase, EG_DP_BITS - EG_BITS)], EG_BITS, EG_DP_BITS); + slot.eg_mode = (int)EnvelopeMode.RELEASE; + } + + /* Channel key on */ + static void keyOn(OPLL opll, int i) + { + if (opll.slot_on_flag[i * 2] == 0) slotOn(opll.MOD(i)); + if (opll.slot_on_flag[i * 2 + 1] == 0) slotOn(opll.CAR(i)); + opll.ch[i].key_status = 1; + } + + static void keyOff(OPLL opll, int i) + { + if (opll.slot_on_flag[i * 2 + 1] != 0) slotOff(opll.CAR(i)); + opll.ch[i].key_status = 0; + } + + static void keyOn_BD(OPLL opll) { keyOn(opll, 6); } + static void keyOn_SD(OPLL opll) { if (opll.slot_on_flag[SLOT_SD] == 0) slotOn(opll.CAR(7)); } + static void keyOn_TOM(OPLL opll) { if (opll.slot_on_flag[SLOT_TOM] == 0) slotOn(opll.MOD(8)); } + static void keyOn_HH(OPLL opll) { if (opll.slot_on_flag[SLOT_HH] == 0) slotOn(opll.MOD(7)); } + static void keyOn_CYM(OPLL opll) { if (opll.slot_on_flag[SLOT_CYM] == 0) slotOn(opll.CAR(8)); } + + /* Drum key off */ + + static void keyOff_BD(OPLL opll) { keyOff(opll, 6); } + static void keyOff_SD(OPLL opll) { if (opll.slot_on_flag[SLOT_SD] != 0) slotOff(opll.CAR(7)); } + static void keyOff_TOM(OPLL opll) { if (opll.slot_on_flag[SLOT_TOM] != 0) slotOff(opll.MOD(8)); } + static void keyOff_HH(OPLL opll) { if (opll.slot_on_flag[SLOT_HH] != 0) slotOff(opll.MOD(7)); } + static void keyOff_CYM(OPLL opll) { if (opll.slot_on_flag[SLOT_CYM] != 0) slotOff(opll.CAR(8)); } + + /* Change a voice */ + static void setPatch(OPLL opll, int i, int num) + { + opll.ch[i].patch_number = num; + opll.MOD(i).patch = opll.patch[num * 2 + 0]; + opll.CAR(i).patch = opll.patch[num * 2 + 1]; + } + + /* Change a rythm voice */ + static void setSlotPatch(OPLL_SLOT slot, OPLL_PATCH patch) + { + slot.patch = patch; + } + + /* Set sustine parameter */ + static void setSustine(OPLL opll, int c, int sustine) + { + opll.CAR(c).sustine = sustine; + if (opll.MOD(c).type != 0) opll.MOD(c).sustine = sustine; + } + + /* Volume : 6bit ( Volume register << 2 ) */ + static void setVolume(OPLL opll, int c, int volume) + { + opll.CAR(c).volume = volume; + } + + static void setSlotVolume(OPLL_SLOT slot, int volume) + { + slot.volume = volume; + } + + /* Set F-Number ( fnum : 9bit ) */ + static void setFnumber(OPLL opll, int c, int fnum) + { + opll.CAR(c).fnum = fnum; + opll.MOD(c).fnum = fnum; + } + + /* Set Block data (block : 3bit ) */ + static void setBlock(OPLL opll, int c, int block) + { + opll.CAR(c).block = block; + opll.MOD(c).block = block; + } + + /* Change Rythm Mode */ + static void setRythmMode(OPLL opll, int mode) + { + opll.rythm_mode = mode; + + if (mode != 0) + { + opll.ch[6].patch_number = 16; + opll.ch[7].patch_number = 17; + opll.ch[8].patch_number = 18; + setSlotPatch(opll.slot[SLOT_BD1], opll.patch[16 * 2 + 0]); + setSlotPatch(opll.slot[SLOT_BD2], opll.patch[16 * 2 + 1]); + setSlotPatch(opll.slot[SLOT_HH], opll.patch[17 * 2 + 0]); + setSlotPatch(opll.slot[SLOT_SD], opll.patch[17 * 2 + 1]); + opll.slot[SLOT_HH].type = 1; + setSlotPatch(opll.slot[SLOT_TOM], opll.patch[18 * 2 + 0]); + setSlotPatch(opll.slot[SLOT_CYM], opll.patch[18 * 2 + 1]); + opll.slot[SLOT_TOM].type = 1; + } + else + { + setPatch(opll, 6, opll.reg[0x36] >> 4); + setPatch(opll, 7, opll.reg[0x37] >> 4); + opll.slot[SLOT_HH].type = 0; + setPatch(opll, 8, opll.reg[0x38] >> 4); + opll.slot[SLOT_TOM].type = 0; + } + + if (opll.slot_on_flag[SLOT_BD1] == 0) + opll.slot[SLOT_BD1].eg_mode = (int)EnvelopeMode.FINISH; + if (opll.slot_on_flag[SLOT_BD2] == 0) + opll.slot[SLOT_BD2].eg_mode = (int)EnvelopeMode.FINISH; + if (opll.slot_on_flag[SLOT_HH] == 0) + opll.slot[SLOT_HH].eg_mode = (int)EnvelopeMode.FINISH; + if (opll.slot_on_flag[SLOT_SD] == 0) + opll.slot[SLOT_SD].eg_mode = (int)EnvelopeMode.FINISH; + if (opll.slot_on_flag[SLOT_TOM] == 0) + opll.slot[SLOT_TOM].eg_mode = (int)EnvelopeMode.FINISH; + if (opll.slot_on_flag[SLOT_CYM] == 0) + opll.slot[SLOT_CYM].eg_mode = (int)EnvelopeMode.FINISH; + } + + static void OPLL_copyPatch(OPLL opll, int num, OPLL_PATCH patch) + { + opll.patch[num].Copy(patch); + } + + static void OPLL_SLOT_reset(OPLL_SLOT slot) + { + slot.sintbl = waveform[0]; + slot.phase = 0; + slot.dphase = 0; + slot.output[0] = 0; + slot.output[1] = 0; + slot.feedback = 0; + slot.eg_mode = (int)EnvelopeMode.SETTLE; + slot.eg_phase = EG_DP_WIDTH; + slot.eg_dphase = 0; + slot.rks = 0; + slot.tll = 0; + slot.sustine = 0; + slot.fnum = 0; + slot.block = 0; + slot.volume = 0; + slot.pgout = 0; + slot.egout = 0; + slot.patch = null_patch; + } + + static OPLL_SLOT OPLL_SLOT_new() + { + OPLL_SLOT slot; + slot = new OPLL_SLOT(); + + return slot; + } + + static void OPLL_SLOT_delete(OPLL_SLOT slot) + { + //free(slot); // c# just do nothing + } + + static void OPLL_CH_reset(OPLL_CH ch) + { + if (ch.mod != null) OPLL_SLOT_reset(ch.mod); + if (ch.car != null) OPLL_SLOT_reset(ch.car); + ch.key_status = 0; + } + + static OPLL_CH OPLL_CH_new() + { + OPLL_CH ch; + OPLL_SLOT mod, car; + + mod = OPLL_SLOT_new(); + if (mod == null) return null; + + car = OPLL_SLOT_new(); + if (car == null) + { + OPLL_SLOT_delete(mod); + return null; + } + + ch = new OPLL_CH(); + if (ch == null) + { + OPLL_SLOT_delete(mod); + OPLL_SLOT_delete(car); + return null; + } + + mod.type = 0; + car.type = 1; + ch.mod = mod; + ch.car = car; + + return ch; + } + + static void OPLL_CH_delete(OPLL_CH ch) + { + OPLL_SLOT_delete(ch.mod); + OPLL_SLOT_delete(ch.car); + //free(ch); C# just do nothing + } + + public static OPLL OPLL_new() + { + OPLL opll; + OPLL_CH[] ch = new OPLL_CH[9]; + OPLL_PATCH[] patch = new OPLL_PATCH[19 * 2]; + int i, j; + + for (i = 0; i < 19 * 2; i++) + { + patch[i] = new OPLL_PATCH(); + } + + for (i = 0; i < 9; i++) + { + ch[i] = OPLL_CH_new(); + } + + opll = new OPLL(); + + for (i = 0; i < 19 * 2; i++) + opll.patch[i] = patch[i]; + + + for (i = 0; i < 9; i++) + { + opll.ch[i] = ch[i]; + opll.slot[i * 2 + 0] = opll.ch[i].mod; + opll.slot[i * 2 + 1] = opll.ch[i].car; + } + + for (i = 0; i < 18; i++) + { + opll.slot[i].SetHost(opll); + } + + opll.mask = 0; + + OPLL_reset(opll); + OPLL_reset_patch(opll, 0); + + opll.masterVolume = 32; + + return opll; + } + + public static void OPLL_delete(OPLL opll) + { + int i; + + for (i = 0; i < 9; i++) + OPLL_CH_delete(opll.ch[i]); + + //for (i = 0; i < 19 * 2; i++) + // free(opll->patch[i]); + + //free(opll); + } + + /* Reset patch datas by system default. */ + public static void OPLL_reset_patch(OPLL opll, int type) + { + int i; + + for (i = 0; i < 19 * 2; i++) + OPLL_copyPatch(opll, i, default_patch[type % OPLL_TONE_NUM][i]); + } + + /* Reset whole of OPLL except patch datas. */ + public static void OPLL_reset(OPLL opll) + { + int i; + + if (opll == null) return; + + opll.adr = 0; + + opll.output[0] = 0; + opll.output[1] = 0; + + opll.pm_phase = 0; + opll.am_phase = 0; + + opll.noise_seed = 0xffff; + opll.noiseA = 0; + opll.noiseB = 0; + opll.noiseA_phase = 0; + opll.noiseB_phase = 0; + opll.noiseA_dphase = 0; + opll.noiseB_dphase = 0; + opll.noiseA_idx = 0; + opll.noiseB_idx = 0; + + for (i = 0; i < 9; i++) + { + OPLL_CH_reset(opll.ch[i]); + setPatch(opll, i, 0); + } + + for (i = 0; i < 0x40; i++) OPLL_writeReg(opll, (uint)i, 0); + } + + public static void OPLL_setClock(uint c, uint r) + { + clk = c; + rate = r; + makeDphaseTable(); + makeDphaseARTable(); + makeDphaseDRTable(); + pm_dphase = rate_adjust((int)(PM_SPEED * PM_DP_WIDTH / (clk / 72))); + am_dphase = rate_adjust((int)(AM_SPEED * AM_DP_WIDTH / (clk / 72))); + } + + public static void OPLL_init(uint c, uint r) + { + makePmTable(); + makeAmTable(); + makeDB2LinTable(); + makeAdjustTable(); + makeTllTable(); + makeRksTable(); + makeSinTable(); + makeDefaultPatch(); + OPLL_setClock(c, r); + } + static void OPLL_close() + { + } + + static int wave2_2pi(int e) + { + return (e) >> (SLOT_AMP_BITS - PG_BITS); + } + + static int wave2_4pi(int e) + { + return e; + } + + static int wave2_8pi(int e) + { + return (e) << (2 + PG_BITS - SLOT_AMP_BITS); + } + + /* 16bit rand */ + static uint mrand(uint seed) + { + return ((seed >> 15) ^ ((seed >> 12) & 1)) | ((seed << 1) & 0xffff); + } + + static uint DEC(uint db) + { + if (db < DB_MUTE + DB_MUTE) + { + return (uint)Min((int)(db + DB_POS(0.375 * 2)), DB_MUTE - 1); + } + else + { + return (uint)Min((int)(db + DB_POS(0.375 * 2)), DB_MUTE + DB_MUTE + DB_MUTE - 1); + } + } + + /* Update Noise unit */ + static void update_noise(OPLL opll) + { + opll.noise_seed = mrand(opll.noise_seed); + opll.whitenoise = opll.noise_seed & 1; + + opll.noiseA_phase = (opll.noiseA_phase + opll.noiseA_dphase); + opll.noiseB_phase = (opll.noiseB_phase + opll.noiseB_dphase); + + if (opll.noiseA_phase < (1 << 11)) + { + if (opll.noiseA_phase > 16) opll.noiseA = DB_MUTE - 1; + } + else + { + opll.noiseA_phase &= (1 << 11) - 1; + opll.noiseA_idx = (opll.noiseA_idx + 1) & 63; + opll.noiseA = (uint)noiseAtable[opll.noiseA_idx]; + } + + if (opll.noiseB_phase < (1 << 12)) + { + if (opll.noiseB_phase > 16) opll.noiseB = DB_MUTE - 1; + } + else + { + opll.noiseB_phase &= (1 << 12) - 1; + opll.noiseB_idx = (opll.noiseB_idx + 1) & 7; + opll.noiseB = (uint)noiseBtable[opll.noiseB_idx]; + } + } + + /* Update AM, PM unit */ + static void update_ampm(OPLL opll) + { + opll.pm_phase = (opll.pm_phase + pm_dphase) & (PM_DP_WIDTH - 1); + opll.am_phase = (int)(opll.am_phase + am_dphase) & (AM_DP_WIDTH - 1); + opll.lfo_am = amtable[HIGHBITS(opll.am_phase, AM_DP_BITS - AM_PG_BITS)]; + opll.lfo_pm = pmtable[HIGHBITS((int)(opll.pm_phase), PM_DP_BITS - PM_PG_BITS)]; + } + + /* PG */ + static uint calc_phase(OPLL_SLOT slot) + { + if (slot.patch.PM != 0) + slot.phase = (uint)(slot.phase + (slot.dphase * (slot.plfo_pm)) >> PM_AMP_BITS); + else + slot.phase += slot.dphase; + + slot.phase &= (DP_WIDTH - 1); + + return (uint)HIGHBITS((int)slot.phase, DP_BASE_BITS); + } + + static uint S2E(int x) + { + return (uint)(SL2EG((int)(x / SL_STEP)) << (EG_DP_BITS - EG_BITS)); + } + + static uint[] SL = new uint[16] + { + S2E( 0), S2E( 3), S2E( 6), S2E( 9), S2E(12), S2E(15), S2E(18), S2E(21), + S2E(24), S2E(27), S2E(30), S2E(33), S2E(36), S2E(39), S2E(42), S2E(48) + }; + + /* EG */ + static uint calc_envelope(OPLL_SLOT slot) + { + uint egout; + + switch ((EnvelopeMode)slot.eg_mode) + { + + case EnvelopeMode.ATTACK: + slot.eg_phase += slot.eg_dphase; + if ((EG_DP_WIDTH & slot.eg_phase) != 0) + { + egout = 0; + slot.eg_phase = 0; + slot.eg_mode = (int)EnvelopeMode.DECAY; + UPDATE_EG(slot); + } + else + { + egout = AR_ADJUST_TABLE[HIGHBITS((int)slot.eg_phase, EG_DP_BITS - EG_BITS)]; + } + break; + + case EnvelopeMode.DECAY: + slot.eg_phase += slot.eg_dphase; + egout = (uint)HIGHBITS((int)slot.eg_phase, EG_DP_BITS - EG_BITS); + if (slot.eg_phase >= SL[slot.patch.SL]) + { + if (slot.patch.EG != 0) + { + slot.eg_phase = SL[slot.patch.SL]; + slot.eg_mode = (int)EnvelopeMode.SUSHOLD; + UPDATE_EG(slot); + } + else + { + slot.eg_phase = SL[slot.patch.SL]; + slot.eg_mode = (int)EnvelopeMode.SUSTINE; + UPDATE_EG(slot); + } + egout = (uint)HIGHBITS((int)slot.eg_phase, EG_DP_BITS - EG_BITS); + } + break; + + case EnvelopeMode.SUSHOLD: + egout = (uint)HIGHBITS((int)slot.eg_phase, EG_DP_BITS - EG_BITS); + if (slot.patch.EG == 0) + { + slot.eg_mode = (int)EnvelopeMode.SUSTINE; + UPDATE_EG(slot); + } + break; + + case EnvelopeMode.SUSTINE: + case EnvelopeMode.RELEASE: + slot.eg_phase += slot.eg_dphase; + egout = (uint)HIGHBITS((int)slot.eg_phase, EG_DP_BITS - EG_BITS); + if (egout >= (1 << EG_BITS)) + { + slot.eg_mode = (int)EnvelopeMode.FINISH; + egout = (1 << EG_BITS) - 1; + } + break; + + case EnvelopeMode.FINISH: + egout = (1 << EG_BITS) - 1; + break; + + default: + egout = (1 << EG_BITS) - 1; + break; + } + + if (slot.patch.AM != 0) egout = (uint)(EG2DB((int)(egout + slot.tll)) + (slot.plfo_am)); + else egout = (uint)EG2DB((int)(egout + slot.tll)); + + if (egout >= DB_MUTE) egout = DB_MUTE - 1; + return egout; + } + + static int calc_slot_car(OPLL_SLOT slot, int fm) + { + slot.egout = calc_envelope(slot); + slot.pgout = calc_phase(slot); + if (slot.egout >= (DB_MUTE - 1)) return 0; + + return DB2LIN_TABLE[slot.sintbl[(slot.pgout + wave2_8pi(fm)) & (PG_WIDTH - 1)] + slot.egout]; + } + + static int calc_slot_mod(OPLL_SLOT slot) + { + int fm; + + slot.output[1] = slot.output[0]; + slot.egout = calc_envelope(slot); + slot.pgout = calc_phase(slot); + + if (slot.egout >= (DB_MUTE - 1)) + { + slot.output[0] = 0; + } + else if (slot.patch.FB != 0) + { + fm = (wave2_4pi(slot.feedback) >> (int)(7 - slot.patch.FB)); + slot.output[0] = DB2LIN_TABLE[slot.sintbl[(slot.pgout + fm) & (PG_WIDTH - 1)] + slot.egout]; + } + else + { + slot.output[0] = DB2LIN_TABLE[slot.sintbl[slot.pgout] + slot.egout]; + } + + slot.feedback = (slot.output[1] + slot.output[0]) >> 1; + + return slot.feedback; + } + + static int calc_slot_tom(OPLL_SLOT slot) + { + slot.egout = calc_envelope(slot); + slot.pgout = calc_phase(slot); + if (slot.egout >= (DB_MUTE - 1)) return 0; + + return DB2LIN_TABLE[slot.sintbl[slot.pgout] + slot.egout]; + } + + /* calc SNARE slot */ + static int calc_slot_snare(OPLL_SLOT slot, uint whitenoise) + { + slot.egout = calc_envelope(slot); + slot.pgout = calc_phase(slot); + if (slot.egout >= (DB_MUTE - 1)) return 0; + + if (whitenoise != 0) + return DB2LIN_TABLE[snaretable[slot.pgout] + slot.egout] + DB2LIN_TABLE[slot.egout + 6]; + else + return DB2LIN_TABLE[snaretable[slot.pgout] + slot.egout]; + } + + static int calc_slot_cym(OPLL_SLOT slot, int a, int b, int c) + { + slot.egout = calc_envelope(slot); + if (slot.egout >= (DB_MUTE - 1)) return 0; + + return DB2LIN_TABLE[slot.egout + a] + + ((DB2LIN_TABLE[slot.egout + b] + DB2LIN_TABLE[slot.egout + c]) >> 2); + } + + static int calc_slot_hat(OPLL_SLOT slot, int a, int b, int c, uint whitenoise) + { + slot.egout = calc_envelope(slot); + if (slot.egout >= (DB_MUTE - 1)) return 0; + + if (whitenoise != 0) + { + return DB2LIN_TABLE[slot.egout + a] + + ((DB2LIN_TABLE[slot.egout + b] + DB2LIN_TABLE[slot.egout + c]) >> 2); + } + else + { + return 0; + } + } + + public static short OPLL_calc(OPLL opll) + { + int inst = 0, perc = 0, @out = 0; + int rythmC = 0, rythmH = 0; + int i; + + update_ampm(opll); + update_noise(opll); + + for (i = 0; i < 6; i++) + if ((opll.mask & OPLL_MASK_CH(i)) == 0 && (opll.CAR(i).eg_mode != (int)EnvelopeMode.FINISH)) + inst += calc_slot_car(opll.CAR(i), calc_slot_mod(opll.MOD(i))); + + if (opll.rythm_mode == 0) + { + for (i = 6; i < 9; i++) + if ((opll.mask & OPLL_MASK_CH(i)) == 0 && (opll.CAR(i).eg_mode != (int)EnvelopeMode.FINISH)) + inst += calc_slot_car(opll.CAR(i), calc_slot_mod(opll.MOD(i))); + } + else + { + opll.MOD(7).pgout = calc_phase(opll.MOD(7)); + opll.CAR(8).pgout = calc_phase(opll.CAR(8)); + if (opll.MOD(7).phase < 256) rythmH = (int)DB_NEG(12.0); else rythmH = DB_MUTE - 1; + if (opll.CAR(8).phase < 256) rythmC = (int)DB_NEG(12.0); else rythmC = DB_MUTE - 1; + + if ((opll.mask & OPLL_MASK_BD) == 0 && (opll.CAR(6).eg_mode != (int)EnvelopeMode.FINISH)) + perc += calc_slot_car(opll.CAR(6), calc_slot_mod(opll.MOD(6))); + + if ((opll.mask & OPLL_MASK_HH) == 0 && (opll.MOD(7).eg_mode != (int)EnvelopeMode.FINISH)) + perc += calc_slot_hat(opll.MOD(7), (int)opll.noiseA, (int)opll.noiseB, rythmH, opll.whitenoise); + + if ((opll.mask & OPLL_MASK_SD) == 0 && (opll.CAR(7).eg_mode != (int)EnvelopeMode.FINISH)) + perc += calc_slot_snare(opll.CAR(7), opll.whitenoise); + + if ((opll.mask & OPLL_MASK_TOM) == 0 && (opll.MOD(8).eg_mode != (int)EnvelopeMode.FINISH)) + perc += calc_slot_tom(opll.MOD(8)); + + if ((opll.mask & OPLL_MASK_CYM) == 0 && (opll.CAR(8).eg_mode != (int)EnvelopeMode.FINISH)) + perc += calc_slot_cym(opll.CAR(8), (int)opll.noiseA, (int)opll.noiseB, rythmC); + } + + inst = (inst >> (SLOT_AMP_BITS - 8)); + perc = (perc >> (SLOT_AMP_BITS - 9)); + + @out = ((inst + perc) * opll.masterVolume) >> 2; + + if (@out > 32767) return 32767; + if (@out < -32768) return -32768; + + return (short)@out; + } + + static uint OPLL_setMask(OPLL opll, uint mask) + { + uint ret; + + if (opll != null) + { + ret = opll.mask; + opll.mask = mask; + return ret; + } + else return 0; + } + + static uint OPLL_toggleMask(OPLL opll, uint mask) + { + uint ret; + + if (opll != null) + { + ret = opll.mask; + opll.mask ^= mask; + return ret; + } + else return 0; + } + + public static void OPLL_writeReg(OPLL opll, uint reg, uint data) + { + + int i, v, ch; + + data = data & 0xff; + reg = reg & 0x3f; + + switch (reg) + { + case 0x00: + opll.patch[0].AM = (data >> 7) & 1; + opll.patch[0].PM = (data >> 6) & 1; + opll.patch[0].EG = (data >> 5) & 1; + opll.patch[0].KR = (data >> 4) & 1; + opll.patch[0].ML = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll.ch[i].patch_number == 0) + { + UPDATE_PG(opll.MOD(i)); + UPDATE_RKS(opll.MOD(i)); + UPDATE_EG(opll.MOD(i)); + } + } + break; + + case 0x01: + opll.patch[1].AM = (data >> 7) & 1; + opll.patch[1].PM = (data >> 6) & 1; + opll.patch[1].EG = (data >> 5) & 1; + opll.patch[1].KR = (data >> 4) & 1; + opll.patch[1].ML = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll.ch[i].patch_number == 0) + { + UPDATE_PG(opll.CAR(i)); + UPDATE_RKS(opll.CAR(i)); + UPDATE_EG(opll.CAR(i)); + } + } + break; + + case 0x02: + opll.patch[0].KL = (data >> 6) & 3; + opll.patch[0].TL = (data) & 63; + for (i = 0; i < 9; i++) + { + if (opll.ch[i].patch_number == 0) + { + UPDATE_TLL(opll.MOD(i)); + } + } + break; + + case 0x03: + opll.patch[1].KL = (data >> 6) & 3; + opll.patch[1].WF = (data >> 4) & 1; + opll.patch[0].WF = (data >> 3) & 1; + opll.patch[0].FB = (data) & 7; + for (i = 0; i < 9; i++) + { + if (opll.ch[i].patch_number == 0) + { + UPDATE_WF(opll.MOD(i)); + UPDATE_WF(opll.CAR(i)); + } + } + break; + + case 0x04: + opll.patch[0].AR = (data >> 4) & 15; + opll.patch[0].DR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll.ch[i].patch_number == 0) + { + UPDATE_EG(opll.MOD(i)); + } + } + break; + + case 0x05: + opll.patch[1].AR = (data >> 4) & 15; + opll.patch[1].DR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll.ch[i].patch_number == 0) + { + UPDATE_EG(opll.CAR(i)); + } + } + break; + + case 0x06: + opll.patch[0].SL = (data >> 4) & 15; + opll.patch[0].RR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll.ch[i].patch_number == 0) + { + UPDATE_EG(opll.MOD(i)); + } + } + break; + + case 0x07: + opll.patch[1].SL = (data >> 4) & 15; + opll.patch[1].RR = (data) & 15; + for (i = 0; i < 9; i++) + { + if (opll.ch[i].patch_number == 0) + { + UPDATE_EG(opll.CAR(i)); + } + } + break; + + case 0x0e: + + if (opll.rythm_mode != 0) + { + opll.slot_on_flag[SLOT_BD1] = (opll.reg[0x0e] & 0x10) | (opll.reg[0x26] & 0x10); + opll.slot_on_flag[SLOT_BD2] = (opll.reg[0x0e] & 0x10) | (opll.reg[0x26] & 0x10); + opll.slot_on_flag[SLOT_SD] = (opll.reg[0x0e] & 0x08) | (opll.reg[0x27] & 0x10); + opll.slot_on_flag[SLOT_HH] = (opll.reg[0x0e] & 0x01) | (opll.reg[0x27] & 0x10); + opll.slot_on_flag[SLOT_TOM] = (opll.reg[0x0e] & 0x04) | (opll.reg[0x28] & 0x10); + opll.slot_on_flag[SLOT_CYM] = (opll.reg[0x0e] & 0x02) | (opll.reg[0x28] & 0x10); + } + else + { + opll.slot_on_flag[SLOT_BD1] = (opll.reg[0x26] & 0x10); + opll.slot_on_flag[SLOT_BD2] = (opll.reg[0x26] & 0x10); + opll.slot_on_flag[SLOT_SD] = (opll.reg[0x27] & 0x10); + opll.slot_on_flag[SLOT_HH] = (opll.reg[0x27] & 0x10); + opll.slot_on_flag[SLOT_TOM] = (opll.reg[0x28] & 0x10); + opll.slot_on_flag[SLOT_CYM] = (opll.reg[0x28] & 0x10); + } + + if ((((data >> 5) & 1) ^ (opll.rythm_mode)) != 0) + { + setRythmMode(opll, (int)(data & 32) >> 5); + } + + if (opll.rythm_mode != 0) + { + if ((data & 0x10) != 0) keyOn_BD(opll); else keyOff_BD(opll); + if ((data & 0x8) != 0) keyOn_SD(opll); else keyOff_SD(opll); + if ((data & 0x4) != 0) keyOn_TOM(opll); else keyOff_TOM(opll); + if ((data & 0x2) != 0) keyOn_CYM(opll); else keyOff_CYM(opll); + if ((data & 0x1) != 0) keyOn_HH(opll); else keyOff_HH(opll); + } + + UPDATE_ALL(opll.MOD(6)); + UPDATE_ALL(opll.CAR(6)); + UPDATE_ALL(opll.MOD(7)); + UPDATE_ALL(opll.CAR(7)); + UPDATE_ALL(opll.MOD(8)); + UPDATE_ALL(opll.CAR(8)); + break; + + case 0x0f: + break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + ch = (int)(reg - 0x10); + setFnumber(opll, ch, (int)(data + ((opll.reg[0x20 + ch] & 1) << 8))); + UPDATE_ALL(opll.MOD(ch)); + UPDATE_ALL(opll.CAR(ch)); + switch (reg) + { + case 0x17: + opll.noiseA_dphase = (uint)((data + ((opll.reg[0x27] & 1) << 8)) << ((opll.reg[0x27] >> 1) & 7)); + break; + case 0x18: + opll.noiseB_dphase = (uint)((data + ((opll.reg[0x28] & 1) << 8)) << ((opll.reg[0x28] >> 1) & 7)); + break; + default: + break; + } + break; + + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + + ch = (int)(reg - 0x20); + setFnumber(opll, ch, (int)(((data & 1) << 8) + opll.reg[0x10 + ch])); + setBlock(opll, ch, (int)((data >> 1) & 7)); + opll.slot_on_flag[ch * 2] = opll.slot_on_flag[ch * 2 + 1] = (opll.reg[reg]) & 0x10; + + if (opll.rythm_mode != 0) + { + switch (reg) + { + case 0x26: + opll.slot_on_flag[SLOT_BD1] |= (opll.reg[0x0e]) & 0x10; + opll.slot_on_flag[SLOT_BD2] |= (opll.reg[0x0e]) & 0x10; + break; + + case 0x27: + opll.noiseA_dphase = (uint)((int)((data & 1) << 8 + opll.reg[0x17]) << (int)((data >> 1) & 7)); + opll.slot_on_flag[SLOT_SD] |= (opll.reg[0x0e]) & 0x08; + opll.slot_on_flag[SLOT_HH] |= (opll.reg[0x0e]) & 0x01; + break; + + case 0x28: + opll.noiseB_dphase = (uint)((int)((data & 1) << 8) + opll.reg[0x18]) << (int)((data >> 1) & 7); + opll.slot_on_flag[SLOT_TOM] |= (opll.reg[0x0e]) & 0x04; + opll.slot_on_flag[SLOT_CYM] |= (opll.reg[0x0e]) & 0x02; + break; + + default: + break; + } + } + + if (((opll.reg[reg] ^ data) & 0x20) != 0) setSustine(opll, ch, (int)((data >> 5) & 1)); + if ((data & 0x10) != 0) keyOn(opll, ch); else keyOff(opll, ch); + UPDATE_ALL(opll.MOD(ch)); + UPDATE_ALL(opll.CAR(ch)); + break; + + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + i = (int)((data >> 4) & 15); + v = (int)(data & 15); + if ((opll.rythm_mode) != 0 && (reg >= 0x36)) + { + switch (reg) + { + case 0x37: + setSlotVolume(opll.MOD(7), i << 2); + break; + case 0x38: + setSlotVolume(opll.MOD(8), i << 2); + break; + } + } + else + { + setPatch(opll, (int)(reg - 0x30), i); + } + + setVolume(opll, (int)(reg - 0x30), v << 2); + UPDATE_ALL(opll.MOD((int)(reg - 0x30))); + UPDATE_ALL(opll.CAR((int)(reg - 0x30))); + break; + + default: + break; + + } + + opll.reg[reg] = (byte)data; + } + + static void OPLL_writeIO(OPLL opll, uint adr, uint val) + { + adr &= 0xff; + if (adr == 0x7C) opll.adr = val; + else if (adr == 0x7D) OPLL_writeReg(opll, opll.adr, val); + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413.cs.meta similarity index 100% rename from AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413.cs.meta rename to AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413.cs.meta diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413_Class.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413_Class.cs new file mode 100644 index 0000000..57ce8e2 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413_Class.cs @@ -0,0 +1,208 @@ +using System; + +namespace VirtualNes.Core.Emu2413 +{ + public static class Const + { + internal static sbyte[][] Create_Default_Inst() + { + unchecked + { + sbyte[][] res = new sbyte[Emu2413API.OPLL_TONE_NUM][] + { + new sbyte[] + { + (sbyte)0x00,(sbyte) 0x00, (sbyte)0x00, (sbyte)0x00,(sbyte) 0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x61,(sbyte) 0x61, (sbyte)0x1e, (sbyte)0x17,(sbyte) 0xf0, (sbyte)0x7f, (sbyte)0x07, (sbyte)0x17, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x13,(sbyte) 0x41, (sbyte)0x0f, (sbyte)0x0d,(sbyte) 0xce, (sbyte)0xd2, (sbyte)0x43, (sbyte)0x13, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x03,(sbyte) 0x01, (sbyte)0x99, (sbyte)0x04,(sbyte) 0xff, (sbyte)0xc3, (sbyte)0x03, (sbyte)0x73, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x21,(sbyte) 0x61, (sbyte)0x1b, (sbyte)0x07,(sbyte) 0xaf, (sbyte)0x63, (sbyte)0x40, (sbyte)0x28, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x22,(sbyte) 0x21, (sbyte)0x1e, (sbyte)0x06,(sbyte) 0xf0, (sbyte)0x76, (sbyte)0x08, (sbyte)0x28, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x31,(sbyte) 0x22, (sbyte)0x16, (sbyte)0x05,(sbyte) 0x90, (sbyte)0x71, (sbyte)0x00, (sbyte)0x18, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x21,(sbyte) 0x61, (sbyte)0x1d, (sbyte)0x07,(sbyte) 0x82, (sbyte)0x81, (sbyte)0x10, (sbyte)0x17, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x23,(sbyte) 0x21, (sbyte)0x2d, (sbyte)0x16,(sbyte) 0xc0, (sbyte)0x70, (sbyte)0x07, (sbyte)0x07, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x61,(sbyte) 0x21, (sbyte)0x1b, (sbyte)0x06,(sbyte) 0x64, (sbyte)0x65, (sbyte)0x18, (sbyte)0x18, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x61,(sbyte) 0x61, (sbyte)0x0c, (sbyte)0x18,(sbyte) 0x85, (sbyte)0xa0, (sbyte)0x79, (sbyte)0x07, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x23,(sbyte) 0x21, (sbyte)0x87, (sbyte)0x11,(sbyte) 0xf0, (sbyte)0xa4, (sbyte)0x00, (sbyte)0xf7, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x97,(sbyte) 0xe1, (sbyte)0x28, (sbyte)0x07,(sbyte) 0xff, (sbyte)0xf3, (sbyte)0x02, (sbyte)0xf8, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x61,(sbyte) 0x10, (sbyte)0x0c, (sbyte)0x05,(sbyte) 0xf2, (sbyte)0xc4, (sbyte)0x40, (sbyte)0xc8, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x01,(sbyte) 0x01, (sbyte)0x56, (sbyte)0x03,(sbyte) 0xb4, (sbyte)0xb2, (sbyte)0x23, (sbyte)0x58, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x61,(sbyte) 0x41, (sbyte)0x89, (sbyte)0x03,(sbyte) 0xf1, (sbyte)0xf4, (sbyte)0xf0, (sbyte)0x13, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x04,(sbyte) 0x21, (sbyte)0x28, (sbyte)0x00,(sbyte) 0xdf, (sbyte)0xf8, (sbyte)0xff, (sbyte)0xf8, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x23,(sbyte) 0x22, (sbyte)0x00, (sbyte)0x00,(sbyte) 0xd8, (sbyte)0xf8, (sbyte)0xf8, (sbyte)0xf8, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x25,(sbyte) 0x18, (sbyte)0x00, (sbyte)0x00,(sbyte) 0xf8, (sbyte)0xda, (sbyte)0xf8, (sbyte)0x55, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + }, + new sbyte[] + { + (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x33, (sbyte)0x01, (sbyte)0x09, (sbyte)0x0e, (sbyte)0x94, (sbyte)0x90, (sbyte)0x40, (sbyte)0x01, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x13, (sbyte)0x41, (sbyte)0x0f, (sbyte)0x0d, (sbyte)0xce, (sbyte)0xd3, (sbyte)0x43, (sbyte)0x13, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x01, (sbyte)0x12, (sbyte)0x1b, (sbyte)0x06, (sbyte)0xff, (sbyte)0xd2, (sbyte)0x00, (sbyte)0x32, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x61, (sbyte)0x61, (sbyte)0x1b, (sbyte)0x07, (sbyte)0xaf, (sbyte)0x63, (sbyte)0x20, (sbyte)0x28, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x22, (sbyte)0x21, (sbyte)0x1e, (sbyte)0x06, (sbyte)0xf0, (sbyte)0x76, (sbyte)0x08, (sbyte)0x28, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x66, (sbyte)0x21, (sbyte)0x15, (sbyte)0x00, (sbyte)0x93, (sbyte)0x94, (sbyte)0x20, (sbyte)0xf8, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x21, (sbyte)0x61, (sbyte)0x1c, (sbyte)0x07, (sbyte)0x82, (sbyte)0x81, (sbyte)0x10, (sbyte)0x17, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x23, (sbyte)0x21, (sbyte)0x20, (sbyte)0x1f, (sbyte)0xc0, (sbyte)0x71, (sbyte)0x07, (sbyte)0x47, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x25, (sbyte)0x31, (sbyte)0x26, (sbyte)0x05, (sbyte)0x64, (sbyte)0x41, (sbyte)0x18, (sbyte)0xf8, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x17, (sbyte)0x21, (sbyte)0x28, (sbyte)0x07, (sbyte)0xff, (sbyte)0x83, (sbyte)0x02, (sbyte)0xf8, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x97, (sbyte)0x81, (sbyte)0x25, (sbyte)0x07, (sbyte)0xcf, (sbyte)0xc8, (sbyte)0x02, (sbyte)0x14, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x21, (sbyte)0x21, (sbyte)0x54, (sbyte)0x0f, (sbyte)0x80, (sbyte)0x7f, (sbyte)0x07, (sbyte)0x07, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x01, (sbyte)0x01, (sbyte)0x56, (sbyte)0x03, (sbyte)0xd3, (sbyte)0xb2, (sbyte)0x43, (sbyte)0x58, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x31, (sbyte)0x21, (sbyte)0x0c, (sbyte)0x03, (sbyte)0x82, (sbyte)0xc0, (sbyte)0x40, (sbyte)0x07, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x21, (sbyte)0x01, (sbyte)0x0c, (sbyte)0x03, (sbyte)0xd4, (sbyte)0xd3, (sbyte)0x40, (sbyte)0x84, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x04, (sbyte)0x21, (sbyte)0x28, (sbyte)0x00, (sbyte)0xdf, (sbyte)0xf8, (sbyte)0xff, (sbyte)0xf8, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x23, (sbyte)0x22, (sbyte)0x00, (sbyte)0x00, (sbyte)0xa8, (sbyte)0xf8, (sbyte)0xf8, (sbyte)0xf8, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + (sbyte)0x25, (sbyte)0x18, (sbyte)0x00, (sbyte)0x00, (sbyte)0xf8, (sbyte)0xa9, (sbyte)0xf8, (sbyte)0x55, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, (sbyte)0x00, + } + }; + + return res; + } + } + + internal static OPLL_PATCH[][] Create_Default_Patch() + { + OPLL_PATCH[][] res = new OPLL_PATCH[Emu2413API.OPLL_TONE_NUM][] + { + new OPLL_PATCH[(16 + 3) * 2], + new OPLL_PATCH[(16 + 3) * 2], + }; + + for (int x = 0; x < Emu2413API.OPLL_TONE_NUM; x++) + for (int y = 0; y < (16 + 3) * 2; y++) + res[x][y] = new OPLL_PATCH(); + + return res; + } + + internal static uint[,,,] Create_tllTable() + { + var res = new uint[16, 8, 1 << Emu2413API.TL_BITS, 4]; + return res; + } + + internal static Int32[,,] Create_rksTable() + { + return new int[2, 8, 2]; + } + + internal static UInt32[,,] Create_dphaseTable() + { + return new uint[512, 8, 16]; + } + } + public class OPLL_PATCH + { + public uint TL, FB, EG, ML, AR, DR, SL, RR, KR, KL, AM, PM, WF; + + public void Copy(OPLL_PATCH other) + { + TL = other.TL; + FB = other.FB; + EG = other.EG; + ML = other.ML; + AR = other.AR; + DR = other.DR; + SL = other.SL; + RR = other.RR; + KR = other.KR; + KL = other.KL; + AM = other.AM; + PM = other.PM; + WF = other.WF; + } + } + + public class OPLL_SLOT + { + public OPLL_PATCH patch; + + public int type; /* 0 : modulator 1 : carrier */ + + /* OUTPUT */ + public Int32 feedback; + public Int32[] output = new Int32[5]; /* Output value of slot */ + + /* for Phase Generator (PG) */ + public UInt32[] sintbl; /* Wavetable */ + public UInt32 phase; /* Phase */ + public UInt32 dphase; /* Phase increment amount */ + public UInt32 pgout; /* output */ + + /* for Envelope Generator (EG) */ + public int fnum; /* F-Number */ + public int block; /* Block */ + public int volume; /* Current volume */ + public int sustine; /* Sustine 1 = ON, 0 = OFF */ + public UInt32 tll; /* Total Level + Key scale level*/ + public UInt32 rks; /* Key scale offset (Rks) */ + public int eg_mode; /* Current state */ + public UInt32 eg_phase; /* Phase */ + public UInt32 eg_dphase; /* Phase increment amount */ + public UInt32 egout; /* output */ + + + /* refer to opll-> */ + public int plfo_pm => m_host.lfo_pm; + public int plfo_am => m_host.lfo_am; + + private OPLL m_host; + public void SetHost(OPLL host) + { + m_host = host; + } + } + + public class OPLL_CH + { + public int patch_number; + public int key_status; + public OPLL_SLOT mod; + public OPLL_SLOT car; + } + + public class OPLL + { + public UInt32 adr; + public Int32[] output = new Int32[2]; + + /* Register */ + public byte[] reg = new byte[0x40]; + public int[] slot_on_flag = new int[18]; + + /* Rythm Mode : 0 = OFF, 1 = ON */ + public int rythm_mode; + + /* Pitch Modulator */ + public UInt32 pm_phase; + public Int32 lfo_pm; + + /* Amp Modulator */ + public Int32 am_phase; + public Int32 lfo_am; + + /* Noise Generator */ + public UInt32 noise_seed; + public UInt32 whitenoise; + public UInt32 noiseA; + public UInt32 noiseB; + public UInt32 noiseA_phase; + public UInt32 noiseB_phase; + public UInt32 noiseA_idx; + public UInt32 noiseB_idx; + public UInt32 noiseA_dphase; + public UInt32 noiseB_dphase; + + /* Channel & Slot */ + public OPLL_CH[] ch = new OPLL_CH[9]; + public OPLL_SLOT[] slot = new OPLL_SLOT[18]; + + /* Voice Data */ + public OPLL_PATCH[] patch = new OPLL_PATCH[19 * 2]; + public int[] patch_update = new int[2]; /* flag for check patch update */ + + public UInt32 mask; + + public int masterVolume; /* 0min -- 64 -- 127 max (Liner) */ + } +} \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413_Class.cs.meta b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413_Class.cs.meta new file mode 100644 index 0000000..23ad2bb --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/CoreLibs/Emu2413/Emu2413_Class.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9c1aaa5374091a64a88e750483fe6f6b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs index 4386337..da7fe18 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/MMU.cs @@ -6,11 +6,11 @@ namespace VirtualNes public static class MMU { // CPU 儊儌儕僶儞僋 - public static ByteArrayRef[] CPU_MEM_BANK = new ByteArrayRef[8]; // 8K扨埵 + public static ArrayRef[] CPU_MEM_BANK = new ArrayRef[8]; // 8K扨埵 public static byte[] CPU_MEM_TYPE = new byte[8]; public static int[] CPU_MEM_PAGE = new int[8]; // 僗僥乕僩僙乕僽梡 // PPU 儊儌儕僶儞僋 - public static ByteArrayRef[] PPU_MEM_BANK = new ByteArrayRef[12]; // 1K扨埵 + public static ArrayRef[] PPU_MEM_BANK = new ArrayRef[12]; // 1K扨埵 public static byte[] PPU_MEM_TYPE = new byte[12]; public static int[] PPU_MEM_PAGE = new int[12]; // 僗僥乕僩僙乕僽梡 public static byte[] CRAM_USED = new byte[16]; // 僗僥乕僩僙乕僽梡 @@ -73,12 +73,12 @@ namespace VirtualNes internal static void SetPROM_Bank(byte page, byte[] ptr, byte type) { - CPU_MEM_BANK[page] = new ByteArrayRef(ptr, 0, ptr.Length); + CPU_MEM_BANK[page] = new ArrayRef(ptr, 0, ptr.Length); CPU_MEM_TYPE[page] = type; CPU_MEM_PAGE[page] = 0; } - internal static void SetPROM_Bank(byte page, ByteArrayRef ptr, byte type) + internal static void SetPROM_Bank(byte page, ArrayRef ptr, byte type) { CPU_MEM_BANK[page] = ptr; CPU_MEM_TYPE[page] = type; @@ -88,7 +88,7 @@ namespace VirtualNes internal static void SetPROM_8K_Bank(byte page, int bank) { bank %= PROM_8K_SIZE; - CPU_MEM_BANK[page] = new ByteArrayRef(MMU.PROM, 0x2000 * bank, MMU.PROM.Length - 0x2000 * bank); + CPU_MEM_BANK[page] = new ArrayRef(MMU.PROM, 0x2000 * bank, MMU.PROM.Length - 0x2000 * bank); CPU_MEM_TYPE[page] = BANKTYPE_ROM; CPU_MEM_PAGE[page] = bank; } @@ -116,7 +116,7 @@ namespace VirtualNes } // PPU VROM bank - internal static void SetVROM_Bank(byte page, ByteArrayRef ptr, byte type) + internal static void SetVROM_Bank(byte page, ArrayRef ptr, byte type) { PPU_MEM_BANK[page] = ptr; PPU_MEM_TYPE[page] = type; @@ -126,7 +126,7 @@ namespace VirtualNes internal static void SetVROM_1K_Bank(byte page, int bank) { bank %= VROM_1K_SIZE; - PPU_MEM_BANK[page] = new ByteArrayRef(VROM, 0x0400 * bank, VROM.Length - (0x0400 * bank)); + PPU_MEM_BANK[page] = new ArrayRef(VROM, 0x0400 * bank, VROM.Length - (0x0400 * bank)); PPU_MEM_TYPE[page] = BANKTYPE_VROM; PPU_MEM_PAGE[page] = bank; } @@ -169,7 +169,7 @@ namespace VirtualNes internal static void SetCRAM_1K_Bank(byte page, int bank) { bank &= 0x1F; - PPU_MEM_BANK[page] = new ByteArrayRef(MMU.CRAM, 0x0400 * bank, MMU.CRAM.Length - 0x0400 * bank); + PPU_MEM_BANK[page] = new ArrayRef(MMU.CRAM, 0x0400 * bank, MMU.CRAM.Length - 0x0400 * bank); PPU_MEM_TYPE[page] = BANKTYPE_CRAM; PPU_MEM_PAGE[page] = bank; @@ -201,7 +201,7 @@ namespace VirtualNes internal static void SetVRAM_1K_Bank(byte page, int bank) { bank &= 3; - PPU_MEM_BANK[page] = new ByteArrayRef(VRAM, 0x0400 * bank, VRAM.Length - 0x0400 * bank); + PPU_MEM_BANK[page] = new ArrayRef(VRAM, 0x0400 * bank, VRAM.Length - 0x0400 * bank); PPU_MEM_TYPE[page] = BANKTYPE_VRAM; PPU_MEM_PAGE[page] = bank; } diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/EEPROM.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/EEPROM.cs index 7f6c4a0..5a8ae76 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/EEPROM.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/EEPROM.cs @@ -19,7 +19,7 @@ namespace VirtualNes.Core byte sda; byte scl_old, sda_old; - ByteArrayRef pEEPDATA; + ArrayRef pEEPDATA; public X24C01() { @@ -34,7 +34,7 @@ namespace VirtualNes.Core pEEPDATA = null; } - public void Reset(ByteArrayRef ptr) + public void Reset(ArrayRef ptr) { now_state = X24C01_IDLE; next_state = X24C01_IDLE; @@ -220,7 +220,7 @@ namespace VirtualNes.Core byte sda; byte scl_old, sda_old; - ByteArrayRef pEEPDATA; + ArrayRef pEEPDATA; public X24C02() { @@ -236,7 +236,7 @@ namespace VirtualNes.Core pEEPDATA = null; } - public void Reset(ByteArrayRef ptr) + public void Reset(ArrayRef ptr) { now_state = X24C02_IDLE; next_state = X24C02_IDLE; diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper001.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper001.cs index 45bef19..fd0324a 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper001.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper001.cs @@ -132,7 +132,7 @@ namespace VirtualNes.Core } } - private ByteArrayRef _PROM_BANK = new ByteArrayRef(); + private ArrayRef _PROM_BANK = new ArrayRef(); //void Mapper001::Write(WORD addr, BYTE data) public override void Write(ushort addr, byte data) { diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper005.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper005.cs index b18017d..b5f15c1 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper005.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper005.cs @@ -39,15 +39,15 @@ namespace VirtualNes.Core //BYTE chr_page[2][8]; BYTE[,] chr_page = new byte[2, 8]; // $5120-$512B // BGパターン用バンク - ByteArrayRef[] BG_MEM_BANK = new ByteArrayRef[8]{ - new ByteArrayRef(), - new ByteArrayRef(), - new ByteArrayRef(), - new ByteArrayRef(), - new ByteArrayRef(), - new ByteArrayRef(), - new ByteArrayRef(), - new ByteArrayRef(), + ArrayRef[] BG_MEM_BANK = new ArrayRef[8]{ + new ArrayRef(), + new ArrayRef(), + new ArrayRef(), + new ArrayRef(), + new ArrayRef(), + new ArrayRef(), + new ArrayRef(), + new ArrayRef(), }; BYTE[] BG_MEM_PAGE = new byte[8]; @@ -433,7 +433,7 @@ namespace VirtualNes.Core } } - private ByteArrayRef _prom_bank = new ByteArrayRef(); + private ArrayRef _prom_bank = new ArrayRef(); void SetBank_SRAM(BYTE page, BYTE data) { if (sram_size == 0) data = (byte)((data > 3) ? 8 : 0); diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper016.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper016.cs index 4b9bce8..ecc5fe3 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper016.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper016.cs @@ -139,7 +139,7 @@ namespace VirtualNes.Core { nes.SetSAVERAM_SIZE(384); x24c02.Reset(WRAM); - x24c01.Reset(new ByteArrayRef(WRAM, 256)); + x24c01.Reset(new ArrayRef(WRAM, 256)); } } diff --git a/References/virtuanessrc097-master/NES/ApuEX/emu2413/emu2413.c b/References/virtuanessrc097-master/NES/ApuEX/emu2413/emu2413.c index b11fecb..4e49f0b 100644 --- a/References/virtuanessrc097-master/NES/ApuEX/emu2413/emu2413.c +++ b/References/virtuanessrc097-master/NES/ApuEX/emu2413/emu2413.c @@ -146,9 +146,11 @@ static unsigned char default_inst[OPLL_TONE_NUM][(16+3)*16]= /* Adjust envelope speed which depends on sampling rate. */ #define rate_adjust(x) (uint32)((double)(x)*clk/72/rate + 0.5) /* +0.5 to round */ + #define MOD(x) ch[x]->mod #define CAR(x) ch[x]->car + /* Sampling rate */ static uint32 rate ; /* Input clock */ @@ -555,6 +557,7 @@ INLINE static void slotOff(OPLL_SLOT *slot) /* Channel key on */ INLINE static void keyOn(OPLL *opll, int i) { + if(!opll->slot_on_flag[i*2]) slotOn(opll->MOD(i)) ; if(!opll->slot_on_flag[i*2+1]) slotOn(opll->CAR(i)) ; opll->ch[i]->key_status = 1 ; @@ -894,6 +897,7 @@ void OPLL_setClock(uint32 c, uint32 r) void OPLL_init(uint32 c, uint32 r) { + makePmTable() ; makeAmTable() ; makeDB2LinTable() ; diff --git a/References/virtuanessrc097-master/NES/ApuEX/emu2413/emu2413.h b/References/virtuanessrc097-master/NES/ApuEX/emu2413/emu2413.h index c10558b..f0e9051 100644 Binary files a/References/virtuanessrc097-master/NES/ApuEX/emu2413/emu2413.h and b/References/virtuanessrc097-master/NES/ApuEX/emu2413/emu2413.h differ