Emu2413 库实现

This commit is contained in:
ALIENJACK\alien 2024-08-07 17:45:38 +08:00
parent d668f7d8df
commit 8bbe264f24
21 changed files with 2176 additions and 258 deletions

View File

@ -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

View File

@ -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:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a5222bc76eba99e4c9fc92b70f4103bc
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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];

View File

@ -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)));
}
}

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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) */
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9c1aaa5374091a64a88e750483fe6f6b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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);

View File

@ -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));
}
}

View File

@ -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() ;