forked from sin365/AxibugEmuOnline
Merge pull request 'master' (#27) from Alienjack/AxibugEmuOnline:master into master
Reviewed-on: sin365/AxibugEmuOnline#27
This commit is contained in:
commit
73e3a744ae
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -1,5 +1,6 @@
|
||||
using AxibugEmuOnline.Client.ClientCore;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
using VirtualNes.Core;
|
||||
@ -74,8 +75,8 @@ namespace AxibugEmuOnline.Client
|
||||
var db = Resources.Load<RomDB>("NES/ROMDB");
|
||||
db.Clear();
|
||||
|
||||
var dbFile = Resources.Load<TextAsset>("NES/nes20db");
|
||||
var xml = XDocument.Parse(dbFile.text);
|
||||
var xmlStr = File.ReadAllText("nes20db.xml");
|
||||
var xml = XDocument.Parse(xmlStr);
|
||||
var games = xml.Element("nes20db").Elements("game");
|
||||
foreach (var game in games)
|
||||
{
|
||||
@ -84,9 +85,11 @@ namespace AxibugEmuOnline.Client
|
||||
|
||||
var mapper = int.Parse($"{game.Element("pcb").Attribute("mapper").Value}");
|
||||
|
||||
if (mapper > 255) continue;
|
||||
db.AddInfo(new RomDB.RomInfo { CRC = crc, Mapper = mapper });
|
||||
}
|
||||
|
||||
UnityEditor.EditorUtility.SetDirty(db);
|
||||
UnityEditor.AssetDatabase.SaveAssets();
|
||||
}
|
||||
#endif
|
||||
|
@ -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:
|
||||
|
BIN
AxibugEmuOnline.Client/Assets/StreamingAssets/NES/Roms/msg.nes
Normal file
BIN
AxibugEmuOnline.Client/Assets/StreamingAssets/NES/Roms/msg.nes
Normal file
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31d7b6b33f06e3d468b409ab9e71bf1f
|
||||
TextScriptImporter:
|
||||
guid: a5222bc76eba99e4c9fc92b70f4103bc
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
@ -4,28 +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)
|
||||
@ -33,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)
|
||||
{
|
||||
@ -60,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];
|
||||
@ -94,6 +437,36 @@ namespace VirtualNes.Core
|
||||
public int now_volume;
|
||||
public int now_freq;
|
||||
public int output;
|
||||
|
||||
public void ZeroMemory()
|
||||
{
|
||||
Array.Clear(reg, 0, reg.Length);
|
||||
volenv_mode = 0;
|
||||
volenv_gain = 0;
|
||||
volenv_decay = 0;
|
||||
volenv_phaseacc = 0.0;
|
||||
swpenv_mode = 0;
|
||||
swpenv_gain = 0;
|
||||
swpenv_decay = 0;
|
||||
swpenv_phaseacc = 0.0;
|
||||
envelope_enable = 0;
|
||||
envelope_speed = 0;
|
||||
wave_setup = 0;
|
||||
master_volume = 0;
|
||||
Array.Clear(main_wavetable, 0, main_wavetable.Length);
|
||||
main_enable = 0;
|
||||
main_frequency = 0;
|
||||
main_addr = 0;
|
||||
Array.Clear(lfo_wavetable, 0, lfo_wavetable.Length);
|
||||
lfo_enable = 0;
|
||||
lfo_frequency = 0;
|
||||
lfo_addr = 0;
|
||||
lfo_phaseacc = 0.0;
|
||||
sweep_bias = 0;
|
||||
now_volume = 0;
|
||||
now_freq = 0;
|
||||
output = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1192,5 +1192,222 @@ namespace VirtualNes.Core
|
||||
break;
|
||||
}
|
||||
}
|
||||
public class RECTANGLE
|
||||
{
|
||||
public byte[] reg = new byte[4]; // register
|
||||
|
||||
public byte enable; // enable
|
||||
public byte holdnote; // holdnote
|
||||
public byte volume; // volume
|
||||
public byte complement;
|
||||
|
||||
// For Render
|
||||
public int phaseacc;
|
||||
public int freq;
|
||||
public int freqlimit;
|
||||
public int adder;
|
||||
public int duty;
|
||||
public int len_count;
|
||||
|
||||
public int nowvolume;
|
||||
|
||||
// For Envelope
|
||||
public byte env_fixed;
|
||||
public byte env_decay;
|
||||
public byte env_count;
|
||||
public byte dummy0;
|
||||
public int env_vol;
|
||||
|
||||
// For Sweep
|
||||
public byte swp_on;
|
||||
public byte swp_inc;
|
||||
public byte swp_shift;
|
||||
public byte swp_decay;
|
||||
public byte swp_count;
|
||||
public byte[] dummy1 = new byte[3];
|
||||
|
||||
// For sync;
|
||||
public byte[] sync_reg = new byte[4];
|
||||
public byte sync_output_enable;
|
||||
public byte sync_enable;
|
||||
public byte sync_holdnote;
|
||||
public byte dummy2;
|
||||
public int sync_len_count;
|
||||
|
||||
public void ZeroMemory()
|
||||
{
|
||||
Array.Clear(reg, 0, reg.Length);
|
||||
enable = 0;
|
||||
holdnote = 0;
|
||||
volume = 0;
|
||||
complement = 0;
|
||||
|
||||
phaseacc = 0;
|
||||
freq = 0;
|
||||
freqlimit = 0;
|
||||
adder = 0;
|
||||
duty = 0;
|
||||
len_count = 0;
|
||||
|
||||
nowvolume = 0;
|
||||
|
||||
env_fixed = 0;
|
||||
env_decay = 0;
|
||||
env_count = 0;
|
||||
dummy0 = 0;
|
||||
env_vol = 0;
|
||||
|
||||
swp_on = 0;
|
||||
swp_inc = 0;
|
||||
swp_shift = 0;
|
||||
swp_decay = 0;
|
||||
swp_count = 0;
|
||||
Array.Clear(dummy1, 0, dummy1.Length);
|
||||
|
||||
Array.Clear(sync_reg, 0, sync_reg.Length);
|
||||
sync_output_enable = 0;
|
||||
sync_enable = 0;
|
||||
sync_holdnote = 0;
|
||||
dummy2 = 0;
|
||||
sync_len_count = 0;
|
||||
}
|
||||
}
|
||||
public class TRIANGLE
|
||||
{
|
||||
public byte[] reg = new byte[4];
|
||||
|
||||
public byte enable;
|
||||
public byte holdnote;
|
||||
public byte counter_start;
|
||||
public byte dummy0;
|
||||
|
||||
public int phaseacc;
|
||||
public int freq;
|
||||
public int len_count;
|
||||
public int lin_count;
|
||||
public int adder;
|
||||
|
||||
public int nowvolume;
|
||||
|
||||
// For sync;
|
||||
public byte[] sync_reg = new byte[4];
|
||||
public byte sync_enable;
|
||||
public byte sync_holdnote;
|
||||
public byte sync_counter_start;
|
||||
// public byte dummy1;
|
||||
public int sync_len_count;
|
||||
public int sync_lin_count;
|
||||
|
||||
internal void ZeroMemory()
|
||||
{
|
||||
Array.Clear(reg, 0, reg.Length);
|
||||
|
||||
enable = 0;
|
||||
holdnote = 0;
|
||||
counter_start = 0;
|
||||
dummy0 = 0;
|
||||
phaseacc = 0;
|
||||
freq = 0;
|
||||
len_count = 0;
|
||||
lin_count = 0;
|
||||
adder = 0;
|
||||
nowvolume = 0;
|
||||
Array.Clear(sync_reg, 0, sync_reg.Length);
|
||||
sync_enable = 0;
|
||||
sync_holdnote = 0;
|
||||
sync_counter_start = 0;
|
||||
|
||||
sync_len_count = 0;
|
||||
sync_lin_count = 0;
|
||||
}
|
||||
}
|
||||
public class DPCM
|
||||
{
|
||||
public byte[] reg = new byte[4];
|
||||
public byte enable;
|
||||
public byte looping;
|
||||
public byte cur_byte;
|
||||
public byte dpcm_value;
|
||||
|
||||
public int freq;
|
||||
public int phaseacc;
|
||||
public int output;
|
||||
|
||||
public ushort address, cache_addr;
|
||||
public int dmalength, cache_dmalength;
|
||||
public int dpcm_output_real, dpcm_output_fake, dpcm_output_old, dpcm_output_offset;
|
||||
|
||||
// For sync
|
||||
public byte[] sync_reg = new byte[4];
|
||||
public byte sync_enable;
|
||||
public byte sync_looping;
|
||||
public byte sync_irq_gen;
|
||||
public byte sync_irq_enable;
|
||||
public int sync_cycles, sync_cache_cycles;
|
||||
public int sync_dmalength, sync_cache_dmalength;
|
||||
}
|
||||
public class NOISE
|
||||
{
|
||||
public byte[] reg = new byte[4]; // register
|
||||
|
||||
public byte enable; // enable
|
||||
public byte holdnote; // holdnote
|
||||
public byte volume; // volume
|
||||
public byte xor_tap;
|
||||
public int shift_reg;
|
||||
|
||||
// For Render
|
||||
public int phaseacc;
|
||||
public int freq;
|
||||
public int len_count;
|
||||
|
||||
public int nowvolume;
|
||||
public int output;
|
||||
|
||||
// For Envelope
|
||||
public byte env_fixed;
|
||||
public byte env_decay;
|
||||
public byte env_count;
|
||||
public byte dummy0;
|
||||
public int env_vol;
|
||||
|
||||
// For sync;
|
||||
public byte[] sync_reg = new byte[4];
|
||||
public byte sync_output_enable;
|
||||
public byte sync_enable;
|
||||
public byte sync_holdnote;
|
||||
public byte dummy1;
|
||||
public int sync_len_count;
|
||||
|
||||
internal void ZeroMemory()
|
||||
{
|
||||
Array.Clear(reg, 0, reg.Length);
|
||||
|
||||
enable = 0;
|
||||
holdnote = 0;
|
||||
volume = 0;
|
||||
xor_tap = 0;
|
||||
shift_reg = 0;
|
||||
|
||||
phaseacc = 0;
|
||||
freq = 0;
|
||||
len_count = 0;
|
||||
nowvolume = 0;
|
||||
output = 0;
|
||||
|
||||
env_fixed = 0;
|
||||
env_decay = 0;
|
||||
env_count = 0;
|
||||
dummy0 = 0;
|
||||
env_vol = 0;
|
||||
|
||||
Array.Clear(sync_reg, 0, sync_reg.Length);
|
||||
sync_output_enable = 0;
|
||||
sync_enable = 0;
|
||||
sync_holdnote = 0;
|
||||
dummy1 = 0;
|
||||
sync_len_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,6 +270,35 @@ namespace VirtualNes.Core
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override int GetFreq(int channel)
|
||||
{
|
||||
if (channel == 0 || channel == 1)
|
||||
{
|
||||
RECTANGLE ch = null;
|
||||
if (channel == 0) ch = ch0;
|
||||
else ch = ch1;
|
||||
|
||||
if (ch.enable == 0 || ch.vbl_length <= 0)
|
||||
return 0;
|
||||
if (ch.freq < INT2FIX(8))
|
||||
return 0;
|
||||
if (ch.fixed_envelope != 0)
|
||||
{
|
||||
if (ch.volume == 0)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((0x0F - ch.env_vol) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)(256.0f * cpu_clock / (FIX2INT(ch.freq) * 16.0f));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int RectangleRender(RECTANGLE ch)
|
||||
{
|
||||
if (ch.enable == 0 || ch.vbl_length <= 0)
|
||||
|
@ -1,26 +1,245 @@
|
||||
namespace VirtualNes.Core
|
||||
using RECTANGLE = VirtualNes.Core.APU_VRC6.RECTANGLE;
|
||||
using SAWTOOTH = VirtualNes.Core.APU_VRC6.SAWTOOTH;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class APU_N106 : APU_INTERFACE
|
||||
{
|
||||
RECTANGLE ch0 = new RECTANGLE();
|
||||
RECTANGLE ch1 = new RECTANGLE();
|
||||
SAWTOOTH ch2 = new SAWTOOTH();
|
||||
float cpu_clock;
|
||||
int cycle_rate;
|
||||
|
||||
public APU_N106()
|
||||
{
|
||||
Reset(APU_CLOCK, 22050);
|
||||
}
|
||||
|
||||
public override void Reset(float fClock, int nRate)
|
||||
{
|
||||
//todo : 实现
|
||||
ch0.ZeroMemory();
|
||||
ch1.ZeroMemory();
|
||||
ch2.ZeroMemory();
|
||||
|
||||
Setup(fClock, nRate);
|
||||
}
|
||||
|
||||
public override void Setup(float fClock, int nRate)
|
||||
{
|
||||
//todo : 实现
|
||||
cpu_clock = fClock;
|
||||
cycle_rate = (int)(fClock * 65536.0f / nRate);
|
||||
}
|
||||
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
//todo : 实现
|
||||
switch (addr)
|
||||
{
|
||||
// VRC6 CH0 rectangle
|
||||
case 0x9000:
|
||||
ch0.reg[0] = data;
|
||||
ch0.gate = (byte)(data & 0x80);
|
||||
ch0.volume = (byte)(data & 0x0F);
|
||||
ch0.duty_pos = (byte)((data >> 4) & 0x07);
|
||||
break;
|
||||
case 0x9001:
|
||||
ch0.reg[1] = data;
|
||||
ch0.freq = INT2FIX((((ch0.reg[2] & 0x0F) << 8) | data) + 1);
|
||||
break;
|
||||
case 0x9002:
|
||||
ch0.reg[2] = data;
|
||||
ch0.enable = (byte)(data & 0x80);
|
||||
ch0.freq = INT2FIX((((data & 0x0F) << 8) | ch0.reg[1]) + 1);
|
||||
break;
|
||||
// VRC6 CH1 rectangle
|
||||
case 0xA000:
|
||||
ch1.reg[0] = data;
|
||||
ch1.gate = (byte)(data & 0x80);
|
||||
ch1.volume = (byte)(data & 0x0F);
|
||||
ch1.duty_pos = (byte)((data >> 4) & 0x07);
|
||||
break;
|
||||
case 0xA001:
|
||||
ch1.reg[1] = data;
|
||||
ch1.freq = INT2FIX((((ch1.reg[2] & 0x0F) << 8) | data) + 1);
|
||||
break;
|
||||
case 0xA002:
|
||||
ch1.reg[2] = data;
|
||||
ch1.enable = (byte)(data & 0x80);
|
||||
ch1.freq = INT2FIX((((data & 0x0F) << 8) | ch1.reg[1]) + 1);
|
||||
break;
|
||||
// VRC6 CH2 sawtooth
|
||||
case 0xB000:
|
||||
ch2.reg[1] = data;
|
||||
ch2.phaseaccum = (byte)(data & 0x3F);
|
||||
break;
|
||||
case 0xB001:
|
||||
ch2.reg[1] = data;
|
||||
ch2.freq = INT2FIX((((ch2.reg[2] & 0x0F) << 8) | data) + 1);
|
||||
break;
|
||||
case 0xB002:
|
||||
ch2.reg[2] = data;
|
||||
ch2.enable = (byte)(data & 0x80);
|
||||
ch2.freq = INT2FIX((((data & 0x0F) << 8) | ch2.reg[1]) + 1);
|
||||
// ch2.adder = 0; // クリアするとノイズの原因になる
|
||||
// ch2.accum = 0; // クリアするとノイズの原因になる
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Process(int channel)
|
||||
{
|
||||
//todo : 实现
|
||||
switch (channel)
|
||||
{
|
||||
case 0:
|
||||
return RectangleRender(ch0);
|
||||
case 1:
|
||||
return RectangleRender(ch1);
|
||||
case 2:
|
||||
return SawtoothRender(ch2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override int GetFreq(int channel)
|
||||
{
|
||||
if (channel == 0 || channel == 1)
|
||||
{
|
||||
RECTANGLE ch;
|
||||
if (channel == 0) ch = ch0;
|
||||
else ch = ch1;
|
||||
if (ch.enable == 0 || ch.gate != 0 || ch.volume == 0)
|
||||
return 0;
|
||||
if (ch.freq < INT2FIX(8))
|
||||
return 0;
|
||||
return (int)((256.0f * cpu_clock / (FIX2INT(ch.freq) * 16.0f)));
|
||||
}
|
||||
if (channel == 2)
|
||||
{
|
||||
SAWTOOTH ch = ch2;
|
||||
if (ch.enable == 0 || ch.phaseaccum == 0)
|
||||
return 0;
|
||||
if (ch.freq < INT2FIX(8))
|
||||
return 0;
|
||||
return (int)(256.0f * cpu_clock / (FIX2INT(ch.freq) * 14.0f));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RectangleRender(RECTANGLE ch)
|
||||
{
|
||||
// Enable?
|
||||
if (ch.enable == 0)
|
||||
{
|
||||
ch.output_vol = 0;
|
||||
ch.adder = 0;
|
||||
return ch.output_vol;
|
||||
}
|
||||
|
||||
// Digitized output
|
||||
if (ch.gate != 0)
|
||||
{
|
||||
ch.output_vol = ch.volume << APU_VRC6.RECTANGLE_VOL_SHIFT;
|
||||
return ch.output_vol;
|
||||
}
|
||||
|
||||
// 一定以上の周波数は処理しない(無駄)
|
||||
if (ch.freq < INT2FIX(8))
|
||||
{
|
||||
ch.output_vol = 0;
|
||||
return ch.output_vol;
|
||||
}
|
||||
|
||||
ch.phaseacc -= cycle_rate;
|
||||
if (ch.phaseacc >= 0)
|
||||
return ch.output_vol;
|
||||
|
||||
int output = ch.volume << APU_VRC6.RECTANGLE_VOL_SHIFT;
|
||||
|
||||
if (ch.freq > cycle_rate)
|
||||
{
|
||||
// add 1 step
|
||||
ch.phaseacc += ch.freq;
|
||||
ch.adder = (byte)((ch.adder + 1) & 0x0F);
|
||||
if (ch.adder <= ch.duty_pos)
|
||||
ch.output_vol = output;
|
||||
else
|
||||
ch.output_vol = -output;
|
||||
}
|
||||
else
|
||||
{
|
||||
// average calculate
|
||||
int num_times, total;
|
||||
num_times = total = 0;
|
||||
while (ch.phaseacc < 0)
|
||||
{
|
||||
ch.phaseacc += ch.freq;
|
||||
ch.adder = (byte)((ch.adder + 1) & 0x0F);
|
||||
if (ch.adder <= ch.duty_pos)
|
||||
total += output;
|
||||
else
|
||||
total += -output;
|
||||
num_times++;
|
||||
}
|
||||
ch.output_vol = total / num_times;
|
||||
}
|
||||
|
||||
return ch.output_vol;
|
||||
}
|
||||
|
||||
int SawtoothRender(SAWTOOTH ch)
|
||||
{
|
||||
// Digitized output
|
||||
if (ch.enable == 0)
|
||||
{
|
||||
ch.output_vol = 0;
|
||||
return ch.output_vol;
|
||||
}
|
||||
|
||||
// 一定以上の周波数は処理しない(無駄)
|
||||
if (ch.freq < INT2FIX(9))
|
||||
{
|
||||
return ch.output_vol;
|
||||
}
|
||||
|
||||
ch.phaseacc -= cycle_rate / 2;
|
||||
if (ch.phaseacc >= 0)
|
||||
return ch.output_vol;
|
||||
|
||||
if (ch.freq > cycle_rate / 2)
|
||||
{
|
||||
// add 1 step
|
||||
ch.phaseacc += ch.freq;
|
||||
if (++ch.adder >= 7)
|
||||
{
|
||||
ch.adder = 0;
|
||||
ch.accum = 0;
|
||||
}
|
||||
ch.accum += ch.phaseaccum;
|
||||
ch.output_vol = ch.accum << APU_VRC6.SAWTOOTH_VOL_SHIFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// average calculate
|
||||
int num_times, total;
|
||||
num_times = total = 0;
|
||||
while (ch.phaseacc < 0)
|
||||
{
|
||||
ch.phaseacc += ch.freq;
|
||||
if (++ch.adder >= 7)
|
||||
{
|
||||
ch.adder = 0;
|
||||
ch.accum = 0;
|
||||
}
|
||||
ch.accum += ch.phaseaccum;
|
||||
total += ch.accum << APU_VRC6.SAWTOOTH_VOL_SHIFT;
|
||||
num_times++;
|
||||
}
|
||||
ch.output_vol = (total / num_times);
|
||||
}
|
||||
|
||||
return ch.output_vol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ namespace VirtualNes.Core
|
||||
return ch.output_vol;
|
||||
}
|
||||
|
||||
private class RECTANGLE
|
||||
public class RECTANGLE
|
||||
{
|
||||
public byte[] reg = new byte[3];
|
||||
|
||||
@ -276,7 +276,7 @@ namespace VirtualNes.Core
|
||||
}
|
||||
}
|
||||
|
||||
private class SAWTOOTH
|
||||
public class SAWTOOTH
|
||||
{
|
||||
public byte[] reg = new byte[3];
|
||||
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,28 +0,0 @@
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class DPCM
|
||||
{
|
||||
public byte[] reg = new byte[4];
|
||||
public byte enable;
|
||||
public byte looping;
|
||||
public byte cur_byte;
|
||||
public byte dpcm_value;
|
||||
|
||||
public int freq;
|
||||
public int phaseacc;
|
||||
public int output;
|
||||
|
||||
public ushort address, cache_addr;
|
||||
public int dmalength, cache_dmalength;
|
||||
public int dpcm_output_real, dpcm_output_fake, dpcm_output_old, dpcm_output_offset;
|
||||
|
||||
// For sync
|
||||
public byte[] sync_reg = new byte[4];
|
||||
public byte sync_enable;
|
||||
public byte sync_looping;
|
||||
public byte sync_irq_gen;
|
||||
public byte sync_irq_enable;
|
||||
public int sync_cycles, sync_cache_cycles;
|
||||
public int sync_dmalength, sync_cache_dmalength;
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6289a516ac91b541b2b1807bb07e2b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,68 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class NOISE
|
||||
{
|
||||
public byte[] reg = new byte[4]; // register
|
||||
|
||||
public byte enable; // enable
|
||||
public byte holdnote; // holdnote
|
||||
public byte volume; // volume
|
||||
public byte xor_tap;
|
||||
public int shift_reg;
|
||||
|
||||
// For Render
|
||||
public int phaseacc;
|
||||
public int freq;
|
||||
public int len_count;
|
||||
|
||||
public int nowvolume;
|
||||
public int output;
|
||||
|
||||
// For Envelope
|
||||
public byte env_fixed;
|
||||
public byte env_decay;
|
||||
public byte env_count;
|
||||
public byte dummy0;
|
||||
public int env_vol;
|
||||
|
||||
// For sync;
|
||||
public byte[] sync_reg = new byte[4];
|
||||
public byte sync_output_enable;
|
||||
public byte sync_enable;
|
||||
public byte sync_holdnote;
|
||||
public byte dummy1;
|
||||
public int sync_len_count;
|
||||
|
||||
internal void ZeroMemory()
|
||||
{
|
||||
Array.Clear(reg, 0, reg.Length);
|
||||
|
||||
enable = 0;
|
||||
holdnote = 0;
|
||||
volume = 0;
|
||||
xor_tap = 0;
|
||||
shift_reg = 0;
|
||||
|
||||
phaseacc = 0;
|
||||
freq = 0;
|
||||
len_count = 0;
|
||||
nowvolume = 0;
|
||||
output = 0;
|
||||
|
||||
env_fixed = 0;
|
||||
env_decay = 0;
|
||||
env_count = 0;
|
||||
dummy0 = 0;
|
||||
env_vol = 0;
|
||||
|
||||
Array.Clear(sync_reg, 0, sync_reg.Length);
|
||||
sync_output_enable = 0;
|
||||
sync_enable = 0;
|
||||
sync_holdnote = 0;
|
||||
dummy1 = 0;
|
||||
sync_len_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8680ce7dbdceb504dbda3b98dbdb1297
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,85 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class RECTANGLE
|
||||
{
|
||||
public byte[] reg = new byte[4]; // register
|
||||
|
||||
public byte enable; // enable
|
||||
public byte holdnote; // holdnote
|
||||
public byte volume; // volume
|
||||
public byte complement;
|
||||
|
||||
// For Render
|
||||
public int phaseacc;
|
||||
public int freq;
|
||||
public int freqlimit;
|
||||
public int adder;
|
||||
public int duty;
|
||||
public int len_count;
|
||||
|
||||
public int nowvolume;
|
||||
|
||||
// For Envelope
|
||||
public byte env_fixed;
|
||||
public byte env_decay;
|
||||
public byte env_count;
|
||||
public byte dummy0;
|
||||
public int env_vol;
|
||||
|
||||
// For Sweep
|
||||
public byte swp_on;
|
||||
public byte swp_inc;
|
||||
public byte swp_shift;
|
||||
public byte swp_decay;
|
||||
public byte swp_count;
|
||||
public byte[] dummy1 = new byte[3];
|
||||
|
||||
// For sync;
|
||||
public byte[] sync_reg = new byte[4];
|
||||
public byte sync_output_enable;
|
||||
public byte sync_enable;
|
||||
public byte sync_holdnote;
|
||||
public byte dummy2;
|
||||
public int sync_len_count;
|
||||
|
||||
public void ZeroMemory()
|
||||
{
|
||||
Array.Clear(reg, 0, reg.Length);
|
||||
enable = 0;
|
||||
holdnote = 0;
|
||||
volume = 0;
|
||||
complement = 0;
|
||||
|
||||
phaseacc = 0;
|
||||
freq = 0;
|
||||
freqlimit = 0;
|
||||
adder = 0;
|
||||
duty = 0;
|
||||
len_count = 0;
|
||||
|
||||
nowvolume = 0;
|
||||
|
||||
env_fixed = 0;
|
||||
env_decay = 0;
|
||||
env_count = 0;
|
||||
dummy0 = 0;
|
||||
env_vol = 0;
|
||||
|
||||
swp_on = 0;
|
||||
swp_inc = 0;
|
||||
swp_shift = 0;
|
||||
swp_decay = 0;
|
||||
swp_count = 0;
|
||||
Array.Clear(dummy1, 0, dummy1.Length);
|
||||
|
||||
Array.Clear(sync_reg, 0, sync_reg.Length);
|
||||
sync_output_enable = 0;
|
||||
sync_enable = 0;
|
||||
sync_holdnote = 0;
|
||||
dummy2 = 0;
|
||||
sync_len_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e50831f6c445fe489d7e1737269296e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -1,54 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class TRIANGLE
|
||||
{
|
||||
public byte[] reg = new byte[4];
|
||||
|
||||
public byte enable;
|
||||
public byte holdnote;
|
||||
public byte counter_start;
|
||||
public byte dummy0;
|
||||
|
||||
public int phaseacc;
|
||||
public int freq;
|
||||
public int len_count;
|
||||
public int lin_count;
|
||||
public int adder;
|
||||
|
||||
public int nowvolume;
|
||||
|
||||
// For sync;
|
||||
public byte[] sync_reg = new byte[4];
|
||||
public byte sync_enable;
|
||||
public byte sync_holdnote;
|
||||
public byte sync_counter_start;
|
||||
// public byte dummy1;
|
||||
public int sync_len_count;
|
||||
public int sync_lin_count;
|
||||
|
||||
internal void ZeroMemory()
|
||||
{
|
||||
Array.Clear(reg, 0, reg.Length);
|
||||
|
||||
enable = 0;
|
||||
holdnote = 0;
|
||||
counter_start = 0;
|
||||
dummy0 = 0;
|
||||
phaseacc = 0;
|
||||
freq = 0;
|
||||
len_count = 0;
|
||||
lin_count = 0;
|
||||
adder = 0;
|
||||
nowvolume = 0;
|
||||
Array.Clear(sync_reg, 0, sync_reg.Length);
|
||||
sync_enable = 0;
|
||||
sync_holdnote = 0;
|
||||
sync_counter_start = 0;
|
||||
|
||||
sync_len_count = 0;
|
||||
sync_lin_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<byte> 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<byte>(MMU.RAM, 0x0100, MMU.RAM.Length - 0x100);
|
||||
|
||||
// Zero/Negative FLAG
|
||||
ZN_Table[0] = Z_FLAG;
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
namespace VirtualNes.Core
|
||||
{
|
||||
public class ByteArrayRef
|
||||
public class ArrayRef<T>
|
||||
{
|
||||
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>(T[] array)
|
||||
{
|
||||
return new ByteArrayRef(array);
|
||||
return new ArrayRef<T>(array);
|
||||
}
|
||||
|
||||
public static implicit operator Span<byte>(ByteArrayRef array)
|
||||
public static implicit operator Span<T>(ArrayRef<T> array)
|
||||
{
|
||||
return new Span<byte>(array.m_rawArray, array.Offset, array.m_length);
|
||||
return new Span<T>(array.m_rawArray, array.Offset, array.m_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5b90f721bfc1ac4ea985c0f564d1c6e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load Diff
@ -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) */
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ed2788da33fe474facc1d7ce1b34d03
|
||||
guid: 9c1aaa5374091a64a88e750483fe6f6b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
@ -6,11 +6,11 @@ namespace VirtualNes
|
||||
public static class MMU
|
||||
{
|
||||
// CPU 儊儌儕僶儞僋
|
||||
public static ByteArrayRef[] CPU_MEM_BANK = new ByteArrayRef[8]; // 8K扨埵
|
||||
public static ArrayRef<byte>[] CPU_MEM_BANK = new ArrayRef<byte>[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<byte>[] PPU_MEM_BANK = new ArrayRef<byte>[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<byte>(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<byte> 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<byte>(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<byte> 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<byte>(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<byte>(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<byte>(VRAM, 0x0400 * bank, VRAM.Length - 0x0400 * bank);
|
||||
PPU_MEM_TYPE[page] = BANKTYPE_VRAM;
|
||||
PPU_MEM_PAGE[page] = bank;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace VirtualNes.Core
|
||||
byte sda;
|
||||
byte scl_old, sda_old;
|
||||
|
||||
ByteArrayRef pEEPDATA;
|
||||
ArrayRef<byte> pEEPDATA;
|
||||
|
||||
public X24C01()
|
||||
{
|
||||
@ -34,7 +34,7 @@ namespace VirtualNes.Core
|
||||
pEEPDATA = null;
|
||||
}
|
||||
|
||||
public void Reset(ByteArrayRef ptr)
|
||||
public void Reset(ArrayRef<byte> 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<byte> pEEPDATA;
|
||||
|
||||
public X24C02()
|
||||
{
|
||||
@ -236,7 +236,7 @@ namespace VirtualNes.Core
|
||||
pEEPDATA = null;
|
||||
}
|
||||
|
||||
public void Reset(ByteArrayRef ptr)
|
||||
public void Reset(ArrayRef<byte> ptr)
|
||||
{
|
||||
now_state = X24C02_IDLE;
|
||||
next_state = X24C02_IDLE;
|
||||
|
@ -132,7 +132,7 @@ namespace VirtualNes.Core
|
||||
}
|
||||
}
|
||||
|
||||
private ByteArrayRef _PROM_BANK = new ByteArrayRef();
|
||||
private ArrayRef<byte> _PROM_BANK = new ArrayRef<byte>();
|
||||
//void Mapper001::Write(WORD addr, BYTE data)
|
||||
public override void Write(ushort addr, byte data)
|
||||
{
|
||||
|
@ -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<byte>[] BG_MEM_BANK = new ArrayRef<byte>[8]{
|
||||
new ArrayRef<byte>(),
|
||||
new ArrayRef<byte>(),
|
||||
new ArrayRef<byte>(),
|
||||
new ArrayRef<byte>(),
|
||||
new ArrayRef<byte>(),
|
||||
new ArrayRef<byte>(),
|
||||
new ArrayRef<byte>(),
|
||||
new ArrayRef<byte>(),
|
||||
};
|
||||
BYTE[] BG_MEM_PAGE = new byte[8];
|
||||
|
||||
@ -433,7 +433,7 @@ namespace VirtualNes.Core
|
||||
}
|
||||
}
|
||||
|
||||
private ByteArrayRef _prom_bank = new ByteArrayRef();
|
||||
private ArrayRef<byte> _prom_bank = new ArrayRef<byte>();
|
||||
void SetBank_SRAM(BYTE page, BYTE data)
|
||||
{
|
||||
if (sram_size == 0) data = (byte)((data > 3) ? 8 : 0);
|
||||
|
@ -139,7 +139,7 @@ namespace VirtualNes.Core
|
||||
{
|
||||
nes.SetSAVERAM_SIZE(384);
|
||||
x24c02.Reset(WRAM);
|
||||
x24c01.Reset(new ByteArrayRef(WRAM, 256));
|
||||
x24c01.Reset(new ArrayRef<byte>(WRAM, 256));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1157,6 +1157,11 @@ namespace VirtualNes.Core
|
||||
bExtMono = bMode;
|
||||
}
|
||||
|
||||
internal int GetScanlineNo()
|
||||
{
|
||||
return ScanlineNo;
|
||||
}
|
||||
|
||||
public struct Sprite
|
||||
{
|
||||
public byte y
|
||||
|
Loading…
Reference in New Issue
Block a user