AxibugEmuOnline/AxibugEmuOnline.Client/Assets/Plugins/Mame.Core/sound/K054539.cs

630 lines
25 KiB
C#

using System;
using System.IO;
namespace MAME.Core
{
public unsafe class K054539
{
public struct k054539_channel
{
public int pos;
public int pfrac;
public int val;
public int pval;
}
public struct k054539_info
{
public double[] voltab;
public double[] pantab;
public double[] k054539_gain;
public byte[][] k054539_posreg_latch;
public int k054539_flags;
public byte[] regs;
public short[] ram;
public int reverb_pos;
public int cur_ptr;
public int cur_limit;
public byte[] cur_zone;
public byte[] rom;
public int rom_size;
public uint rom_mask;
public k054539_channel[] channels;
}
public static byte[] k054539rom;
public static k054539_info info;
public static int zoneflag, zonedata;
public static apanhandler apan;
public static irqhandler irq;
public delegate void apanhandler(double d1, double d2);
public delegate void irqhandler();
public static bool k054539_regupdate()
{
return (info.regs[0x22f] & 0x80) == 0;
}
public static void k054539_keyon(int channel)
{
if (k054539_regupdate())
{
info.regs[0x22c] |= (byte)(1 << channel);
}
}
public static void k054539_keyoff(int channel)
{
if (k054539_regupdate())
{
info.regs[0x22c] &= (byte)(~(1 << channel));
}
}
public static void k054539_update(int offset, int length)
{
short[] dpcm = new short[16] {
0<<8, 1<<8, 4<<8, 9<<8, 16<<8, 25<<8, 36<<8, 49<<8,
-64<<8, -49<<8, -36<<8, -25<<8, -16<<8, -9<<8, -4<<8, -1<<8
};
int j, ch, reverb_pos;
byte[] samples;
int rom_mask;
int offset1;
int base1_offset, base2_offset;
k054539_channel chan;
int cur_pos, cur_pfrac, cur_val, cur_pval;
int delta, rdelta, fdelta, pdelta;
int vol, bval, pan, i;
double gain, lvol, rvol, rbvol;
reverb_pos = info.reverb_pos;
for (i = 0; i < 2; i++)
{
for (j = 0; j < length; j++)
{
Sound.k054539stream.streamoutput_Ptrs[i][offset + j] = 0;
}
}
samples = k054539rom;//info.rom;
rom_mask = (int)info.rom_mask;
if ((info.regs[0x22f] & 1) == 0)
{
return;
}
info.reverb_pos = (reverb_pos + length) & 0x3fff;
for (ch = 0; ch < 8; ch++)
{
if ((info.regs[0x22c] & (1 << ch)) != 0)
{
base1_offset = 0x20 * ch;
base2_offset = 0x200 + 0x2 * ch;
chan = info.channels[ch];
delta = info.regs[base1_offset + 0x00] | (info.regs[base1_offset + 0x01] << 8) | (info.regs[base1_offset + 0x02] << 16);
vol = info.regs[base1_offset + 0x03];
bval = vol + info.regs[base1_offset + 0x04];
if (bval > 255)
{
bval = 255;
}
pan = info.regs[base1_offset + 0x05];
if (pan >= 0x81 && pan <= 0x8f)
{
pan -= 0x81;
}
else if (pan >= 0x11 && pan <= 0x1f)
{
pan -= 0x11;
}
else
{
pan = 0x18 - 0x11;
}
gain = info.k054539_gain[ch];
lvol = info.voltab[vol] * info.pantab[pan] * gain;
if (lvol > 1.80)
{
lvol = 1.80;
}
rvol = info.voltab[vol] * info.pantab[0xe - pan] * gain;
if (rvol > 1.80)
{
rvol = 1.80;
}
rbvol = info.voltab[bval] * gain / 2;
if (rbvol > 1.80)
{
rbvol = 1.80;
}
rdelta = (info.regs[base1_offset + 6] | (info.regs[base1_offset + 7] << 8)) >> 3;
rdelta = (int)(rdelta + reverb_pos) & 0x3fff;
cur_pos = (info.regs[base1_offset + 0x0c] | (info.regs[base1_offset + 0x0d] << 8) | (info.regs[base1_offset + 0x0e] << 16)) & rom_mask;
offset1 = offset;
if ((info.regs[base2_offset + 0] & 0x20) != 0)
{
delta = -delta;
fdelta = +0x10000;
pdelta = -1;
}
else
{
fdelta = -0x10000;
pdelta = +1;
}
if (cur_pos != chan.pos)
{
chan.pos = cur_pos;
cur_pfrac = 0;
cur_val = 0;
cur_pval = 0;
}
else
{
cur_pfrac = chan.pfrac;
cur_val = chan.val;
cur_pval = chan.pval;
}
switch (info.regs[base2_offset + 0] & 0xc)
{
case 0x0:
{
for (i = 0; i < length; i++)
{
cur_pfrac += delta;
while ((cur_pfrac & ~0xffff) != 0)
{
cur_pfrac += fdelta;
cur_pos += pdelta;
cur_pval = cur_val;
cur_val = (short)(samples[cur_pos] << 8);
if (cur_val == unchecked((short)0x8000))
{
if ((info.regs[base2_offset + 1] & 1) != 0)
{
cur_pos = (info.regs[base1_offset + 0x08] | (info.regs[base1_offset + 0x09] << 8) | (info.regs[base1_offset + 0x0a] << 16)) & rom_mask;
cur_val = (short)(samples[cur_pos] << 8);
if (cur_val != (int)(unchecked((short)0x8000)))
{
continue;
}
}
k054539_keyoff(ch);
goto end_channel_0;
}
}
Sound.k054539stream.streamoutput_Ptrs[0][offset1] += (short)(cur_val * lvol);
Sound.k054539stream.streamoutput_Ptrs[1][offset1] += (short)(cur_val * rvol);
offset1++;
info.ram[rdelta] += (short)(cur_val * rbvol);
rdelta++;
rdelta &= 0x3fff;
}
end_channel_0:
break;
}
case 0x4:
{
pdelta <<= 1;
for (i = 0; i < length; i++)
{
cur_pfrac += delta;
while ((cur_pfrac & ~0xffff) != 0)
{
cur_pfrac += fdelta;
cur_pos += pdelta;
cur_pval = cur_val;
cur_val = (short)(samples[cur_pos] | samples[cur_pos + 1] << 8);
if (cur_val == unchecked((short)0x8000))
{
if ((info.regs[base2_offset + 1] & 1) != 0)
{
cur_pos = (info.regs[base1_offset + 0x08] | (info.regs[base1_offset + 0x09] << 8) | (info.regs[base1_offset + 0x0a] << 16)) & rom_mask;
cur_val = (short)(samples[cur_pos] | samples[cur_pos + 1] << 8);
if (cur_val != unchecked((short)0x8000))
continue;
}
k054539_keyoff(ch);
goto end_channel_4;
}
}
Sound.k054539stream.streamoutput_Ptrs[0][offset1] += (short)(cur_val * lvol);
Sound.k054539stream.streamoutput_Ptrs[1][offset1] += (short)(cur_val * rvol);
offset1++;
info.ram[rdelta] += (short)(cur_val * rbvol);
rdelta++;
rdelta &= 0x3fff;
}
end_channel_4:
break;
}
case 0x8:
{
cur_pos <<= 1;
cur_pfrac <<= 1;
if ((cur_pfrac & 0x10000) != 0)
{
cur_pfrac &= 0xffff;
cur_pos |= 1;
}
for (i = 0; i < length; i++)
{
cur_pfrac += delta;
while ((cur_pfrac & ~0xffff) != 0)
{
cur_pfrac += fdelta;
cur_pos += pdelta;
cur_pval = cur_val;
cur_val = samples[cur_pos >> 1];
if (cur_val == 0x88)
{
if ((info.regs[base2_offset + 1] & 1) != 0)
{
cur_pos = ((info.regs[base1_offset + 0x08] | (info.regs[base1_offset + 0x09] << 8) | (info.regs[base1_offset + 0x0a] << 16)) & rom_mask) << 1;
cur_val = samples[cur_pos >> 1];
if (cur_val != 0x88)
goto next_iter;
}
k054539_keyoff(ch);
goto end_channel_8;
}
next_iter:
if ((cur_pos & 1) != 0)
{
cur_val >>= 4;
}
else
{
cur_val &= 15;
}
cur_val = cur_pval + dpcm[cur_val];
if (cur_val < -32768)
{
cur_val = -32768;
}
else if (cur_val > 32767)
{
cur_val = 32767;
}
}
Sound.k054539stream.streamoutput_Ptrs[0][offset1] += (short)(cur_val * lvol);
Sound.k054539stream.streamoutput_Ptrs[1][offset1] += (short)(cur_val * rvol);
offset1++;
info.ram[rdelta] += (short)(cur_val * rbvol);
rdelta++;
rdelta &= 0x3fff;
}
end_channel_8:
cur_pfrac >>= 1;
if ((cur_pos & 1) != 0)
{
cur_pfrac |= 0x8000;
}
cur_pos >>= 1;
break;
}
default:
break;
}
chan.pos = cur_pos;
chan.pfrac = cur_pfrac;
chan.pval = cur_pval;
chan.val = cur_val;
if (k054539_regupdate())
{
info.regs[base1_offset + 0x0c] = (byte)(cur_pos & 0xff);
info.regs[base1_offset + 0x0d] = (byte)(cur_pos >> 8 & 0xff);
info.regs[base1_offset + 0x0e] = (byte)(cur_pos >> 16 & 0xff);
}
}
}
if ((info.k054539_flags & 2) == 0)
{
for (i = 0; i < length; i++)
{
short val = info.ram[(i + reverb_pos) & 0x3fff];
Sound.k054539stream.streamoutput_Ptrs[0][offset + i] += val;
Sound.k054539stream.streamoutput_Ptrs[1][offset + i] += val;
}
}
if (reverb_pos + length > 0x4000)
{
i = 0x4000 - reverb_pos;
for (j = 0; j < i; j++)
{
info.ram[reverb_pos + j] = 0;
}
for (j = 0; j < length - i; j++)
{
info.ram[j] = 0;
}
}
else
{
for (j = 0; j < length; j++)
{
info.ram[reverb_pos + j] = 0;
}
}
}
public static void k054539_irq()
{
if ((info.regs[0x22f] & 0x20) != 0)
{
irq();
}
}
public static void k054539_init_chip(int clock)
{
int i;
info.k054539_flags |= 4;
info.ram = new short[0x4000 + clock / 50];
info.reverb_pos = 0;
info.cur_ptr = 0;
info.rom_size = k054539rom.Length;
info.rom_mask = 0xffffffff;
for (i = 0; i < 32; i++)
{
if ((1U << i) >= info.rom_size)
{
info.rom_mask = (1U << i) - 1;
break;
}
}
if (irq != null)
{
EmuTimer.timer_pulse_internal(new Atime(0, (long)(1e18 / 480)), EmuTimer.TIME_ACT.K054539_k054539_irq);
}
}
static void k054539_w(int chip, int offset, byte data)
{
int latch, offs, ch, pan;
int regptr_offset;
latch = ((info.k054539_flags & 4) != 0) && ((info.regs[0x22f] & 1) != 0) ? 1 : 0;
if (latch != 0 && offset < 0x100)
{
offs = (offset & 0x1f) - 0xc;
ch = offset >> 5;
if (offs >= 0 && offs <= 2)
{
info.k054539_posreg_latch[ch][offs] = data;
return;
}
}
else
{
switch (offset)
{
case 0x13f:
pan = data >= 0x11 && data <= 0x1f ? data - 0x11 : 0x18 - 0x11;
if (apan != null)
{
apan(info.pantab[pan], info.pantab[0xe - pan]);
}
break;
case 0x214:
if (latch != 0)
{
for (ch = 0; ch < 8; ch++)
{
if ((data & (1 << ch)) != 0)
{
regptr_offset = (ch << 5) + 0xc;
info.regs[regptr_offset] = info.k054539_posreg_latch[ch][0];
info.regs[regptr_offset + 1] = info.k054539_posreg_latch[ch][1];
info.regs[regptr_offset + 2] = info.k054539_posreg_latch[ch][2];
k054539_keyon(ch);
}
}
}
else
{
for (ch = 0; ch < 8; ch++)
{
if ((data & (1 << ch)) != 0)
{
k054539_keyon(ch);
}
}
}
break;
case 0x215:
for (ch = 0; ch < 8; ch++)
{
if ((data & (1 << ch)) != 0)
{
k054539_keyoff(ch);
}
}
break;
case 0x22d:
if (info.regs[0x22e] == 0x80)
{
if (zoneflag == 1)
{
if (info.cur_ptr % 2 == 0)
{
info.ram[info.cur_ptr / 2] = (short)((data << 8) | (info.ram[info.cur_ptr / 2] & 0xff));
}
else if (info.cur_ptr % 2 == 1)
{
info.ram[info.cur_ptr / 2] = (short)((info.ram[info.cur_ptr / 2] & 0xff00) | data);
}
}
else if (zoneflag == 2)
{
k054539rom[zonedata + info.cur_ptr] = data;
}
}
info.cur_ptr++;
if (info.cur_ptr == info.cur_limit)
{
info.cur_ptr = 0;
}
break;
case 0x22e:
if (data == 0x80)
{
zoneflag = 1;
}
else
{
zoneflag = 2;
zonedata = 0x20000 * data;
}
info.cur_limit = data == 0x80 ? 0x4000 : 0x20000;
info.cur_ptr = 0;
break;
default:
break;
}
}
info.regs[offset] = data;
}
public static byte k054539_r(int chip, int offset)
{
switch (offset)
{
case 0x22d:
if ((info.regs[0x22f] & 0x10) != 0)
{
byte res = 0;
if (zoneflag == 1)
{
if (info.cur_ptr % 2 == 0)
{
res = (byte)(info.ram[info.cur_ptr / 2] >> 8);
}
else if (info.cur_ptr % 2 == 1)
{
res = (byte)info.ram[info.cur_ptr / 2];
}
}
else if (zoneflag == 2)
{
res = k054539rom[zonedata + info.cur_ptr];
}
info.cur_ptr++;
if (info.cur_ptr == info.cur_limit)
{
info.cur_ptr = 0;
}
return res;
}
else
{
return 0;
}
case 0x22c:
break;
default:
break;
}
return info.regs[offset];
}
public static void k054539_start(int clock)
{
int i;
info = new k054539_info();
info.voltab = new double[256];
info.pantab = new double[0xf];
info.k054539_gain = new double[8];
info.k054539_posreg_latch = new byte[8][];
info.regs = new byte[0x230];
for (i = 0; i < 8; i++)
{
info.k054539_gain[i] = 1.0;
info.k054539_posreg_latch[i] = new byte[3];
}
info.k054539_flags = 0;
info.channels = new k054539_channel[8];
irq = null;
switch (Machine.sBoard)
{
case "Konami 68000":
switch (Machine.sName)
{
case "prmrsocr":
irq = Konami68000.sound_nmi;
break;
}
break;
}
for (i = 0; i < 256; i++)
{
info.voltab[i] = Math.Pow(10.0, (-36.0 * (double)i / (double)0x40) / 20.0) / 4.0;
}
for (i = 0; i < 0xf; i++)
{
info.pantab[i] = Math.Sqrt(i) / Math.Sqrt(0xe);
}
k054539_init_chip(clock);
}
public static void k054539_0_w(int offset, byte data)
{
k054539_w(0, offset, data);
}
public static byte k054539_0_r(int offset)
{
return k054539_r(0, offset);
}
public static void SaveStateBinary(BinaryWriter writer)
{
int i, j;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 3; j++)
{
writer.Write(info.k054539_posreg_latch[i][j]);
}
}
writer.Write(info.k054539_flags);
writer.Write(info.regs, 0, 0x230);
for (i = 0; i < info.ram.Length; i++)
{
writer.Write(info.ram[i]);
}
writer.Write(info.reverb_pos);
writer.Write(info.cur_ptr);
writer.Write(info.cur_limit);
for (i = 0; i < 8; i++)
{
writer.Write(info.channels[i].pos);
writer.Write(info.channels[i].pfrac);
writer.Write(info.channels[i].val);
writer.Write(info.channels[i].pval);
}
writer.Write(zoneflag);
writer.Write(zonedata);
}
public static void LoadStateBinary(BinaryReader reader)
{
int i, j;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 3; j++)
{
info.k054539_posreg_latch[i][j] = reader.ReadByte();
}
}
info.k054539_flags = reader.ReadInt32();
info.regs = reader.ReadBytes(0x230);
for (i = 0; i < info.ram.Length; i++)
{
info.ram[i] = reader.ReadInt16();
}
info.reverb_pos = reader.ReadInt32();
info.cur_ptr = reader.ReadInt32();
info.cur_limit = reader.ReadInt32();
for (i = 0; i < 8; i++)
{
info.channels[i].pos = reader.ReadInt32();
info.channels[i].pfrac = reader.ReadInt32();
info.channels[i].val = reader.ReadInt32();
info.channels[i].pval = reader.ReadInt32();
}
zoneflag = reader.ReadInt32();
zonedata = reader.ReadInt32();
}
}
}