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

430 lines
15 KiB
C#

using System.IO;
namespace MAME.Core
{
public unsafe class K053260
{
public struct k053260_channel_def
{
public uint rate;
public uint size;
public uint start;
public uint bank;
public uint volume;
public int play;
public uint pan;
public uint pos;
public int loop;
public int ppcm;
public int ppcm_data;
};
public struct k053260_chip_def
{
public int mode;
public int[] regs;
public int rom_size;
public uint[] delta_table;
public k053260_channel_def[] channels;
};
public static byte[] k053260rom;
public static k053260_chip_def ic1;
public static void InitDeltaTable(int rate, int clock)
{
int i;
double base1 = (double)rate;
double max = (double)(clock);
uint val;
for (i = 0; i < 0x1000; i++)
{
double v = (double)(0x1000 - i);
double target = (max) / v;
double fixed1 = (double)(1 << 16);
if ((target != 0) && (base1 != 0))
{
target = fixed1 / (base1 / target);
val = (uint)target;
if (val == 0)
{
val = 1;
}
}
else
{
val = 1;
}
ic1.delta_table[i] = val;
}
}
public static void k053260_reset()
{
int i;
for (i = 0; i < 4; i++)
{
ic1.channels[i].rate = 0;
ic1.channels[i].size = 0;
ic1.channels[i].start = 0;
ic1.channels[i].bank = 0;
ic1.channels[i].volume = 0;
ic1.channels[i].play = 0;
ic1.channels[i].pan = 0;
ic1.channels[i].pos = 0;
ic1.channels[i].loop = 0;
ic1.channels[i].ppcm = 0;
ic1.channels[i].ppcm_data = 0;
}
}
public static byte k053260_read(int chip, int offset)
{
byte result = 0;
switch (offset)
{
case 0x29:
{
int i, status = 0;
for (i = 0; i < 4; i++)
{
status |= ic1.channels[i].play << i;
}
result = (byte)status;
}
break;
case 0x2e: /* read rom */
if ((ic1.mode & 1) != 0)
{
int offs = (int)(ic1.channels[0].start + (ic1.channels[0].pos >> 16) + (ic1.channels[0].bank << 16));
ic1.channels[0].pos += (1 << 16);
if (offs > ic1.rom_size)
{
result = 0;
}
result = k053260rom[offs];
}
break;
default:
result = (byte)ic1.regs[offset];
break;
}
return result;
}
public static byte k053260_0_r(int offset)
{
return k053260_read(0, offset);
}
public static void k053260_update(int offset, int length)
{
long[] dpcmcnv = new long[] { 0, 1, 2, 4, 8, 16, 32, 64, -128, -64, -32, -16, -8, -4, -2, -1 };
int i, j;
uint[] rom_offset;
int[] lvol, rvol, play, loop, ppcm_data, ppcm;
rom_offset = new uint[4];
lvol = new int[4];
rvol = new int[4];
play = new int[4];
loop = new int[4];
ppcm_data = new int[4];
ppcm = new int[4];
byte[] rom;
rom = new byte[4];
uint[] delta, end, pos;
delta = new uint[4];
end = new uint[4];
pos = new uint[4];
int dataL, dataR;
sbyte d;
for (i = 0; i < 4; i++)
{
rom_offset[i] = ic1.channels[i].start + (ic1.channels[i].bank << 16);
delta[i] = ic1.delta_table[ic1.channels[i].rate];
lvol[i] = (int)(ic1.channels[i].volume * ic1.channels[i].pan);
rvol[i] = (int)(ic1.channels[i].volume * (8 - ic1.channels[i].pan));
end[i] = ic1.channels[i].size;
pos[i] = ic1.channels[i].pos;
play[i] = ic1.channels[i].play;
loop[i] = ic1.channels[i].loop;
ppcm[i] = ic1.channels[i].ppcm;
ppcm_data[i] = ic1.channels[i].ppcm_data;
if (ppcm[i] != 0)
{
delta[i] /= 2;
}
}
for (j = 0; j < length; j++)
{
dataL = dataR = 0;
for (i = 0; i < 4; i++)
{
if (play[i] != 0)
{
if ((pos[i] >> 16) >= end[i])
{
ppcm_data[i] = 0;
if (loop[i] != 0)
{
pos[i] = 0;
}
else
{
play[i] = 0;
continue;
}
}
if (ppcm[i] != 0)
{
if (pos[i] == 0 || ((pos[i] ^ (pos[i] - delta[i])) & 0x8000) == 0x8000)
{
int newdata;
if ((pos[i] & 0x8000) != 0)
{
newdata = (k053260rom[rom_offset[i] + (pos[i] >> 16)] >> 4) & 0x0f;
}
else
{
newdata = k053260rom[rom_offset[i] + (pos[i] >> 16)] & 0x0f;
}
ppcm_data[i] = (int)(((ppcm_data[i] * 62) >> 6) + dpcmcnv[newdata]);
if (ppcm_data[i] > 127)
{
ppcm_data[i] = 127;
}
else
{
if (ppcm_data[i] < -128)
{
ppcm_data[i] = -128;
}
}
}
d = (sbyte)ppcm_data[i];
pos[i] += delta[i];
}
else
{
d = (sbyte)k053260rom[rom_offset[i] + (pos[i] >> 16)];
pos[i] += delta[i];
}
if ((ic1.mode & 2) != 0)
{
dataL += (d * lvol[i]) >> 2;
dataR += (d * rvol[i]) >> 2;
}
}
}
if (dataL < -32768)
{
dataL = -32768;
}
else if (dataL > 32767)
{
dataL = 32767;
}
if (dataR < -32768)
{
dataR = -32768;
}
else if (dataR > 32767)
{
dataR = 32767;
}
Sound.k053260stream.streamoutput_Ptrs[1][offset + j] = dataL;
Sound.k053260stream.streamoutput_Ptrs[0][offset + j] = dataR;
}
for (i = 0; i < 4; i++)
{
ic1.channels[i].pos = pos[i];
ic1.channels[i].play = play[i];
ic1.channels[i].ppcm_data = ppcm_data[i];
}
}
public static void k053260_start(int clock)
{
int rate = clock / 32;
int i;
ic1.regs = new int[0x30];
ic1.channels = new k053260_channel_def[4];
ic1.mode = 0;
ic1.rom_size = k053260rom.Length - 1;
k053260_reset();
for (i = 0; i < 0x30; i++)
{
ic1.regs[i] = 0;
}
ic1.delta_table = new uint[0x1000];
InitDeltaTable(rate, clock);
}
public static void check_bounds(int channel)
{
int channel_start = (int)((ic1.channels[channel].bank << 16) + ic1.channels[channel].start);
int channel_end = (int)(channel_start + ic1.channels[channel].size - 1);
if (channel_start > ic1.rom_size)
{
ic1.channels[channel].play = 0;
return;
}
if (channel_end > ic1.rom_size)
{
ic1.channels[channel].size = (uint)(ic1.rom_size - channel_start);
}
}
public static void k053260_write(int chip, int offset, byte data)
{
int i, t;
int r = offset;
int v = data;
if (r > 0x2f)
{
return;
}
Sound.k053260stream.stream_update();
if (r == 0x28)
{
t = ic1.regs[r] ^ v;
for (i = 0; i < 4; i++)
{
if ((t & (1 << i)) != 0)
{
if ((v & (1 << i)) != 0)
{
ic1.channels[i].play = 1;
ic1.channels[i].pos = 0;
ic1.channels[i].ppcm_data = 0;
check_bounds(i);
}
else
{
ic1.channels[i].play = 0;
}
}
}
ic1.regs[r] = v;
return;
}
ic1.regs[r] = v;
if (r < 8)
{
return;
}
if (r < 0x28)
{
int channel = (r - 8) / 8;
switch ((r - 8) & 0x07)
{
case 0:
ic1.channels[channel].rate &= 0x0f00;
ic1.channels[channel].rate |= (uint)v;
break;
case 1:
ic1.channels[channel].rate &= 0x00ff;
ic1.channels[channel].rate |= (uint)((v & 0x0f) << 8);
break;
case 2:
ic1.channels[channel].size &= 0xff00;
ic1.channels[channel].size |= (uint)v;
break;
case 3:
ic1.channels[channel].size &= 0x00ff;
ic1.channels[channel].size |= (uint)(v << 8);
break;
case 4:
ic1.channels[channel].start &= 0xff00;
ic1.channels[channel].start |= (uint)v;
break;
case 5:
ic1.channels[channel].start &= 0x00ff;
ic1.channels[channel].start |= (uint)(v << 8);
break;
case 6:
ic1.channels[channel].bank = (uint)(v & 0xff);
break;
case 7:
ic1.channels[channel].volume = (uint)(((v & 0x7f) << 1) | (v & 1));
break;
}
return;
}
switch (r)
{
case 0x2a:
for (i = 0; i < 4; i++)
ic1.channels[i].loop = ((v & (1 << i)) != 0 ? 1 : 0);
for (i = 4; i < 8; i++)
ic1.channels[i - 4].ppcm = ((v & (1 << i)) != 0 ? 1 : 0);
break;
case 0x2c:
ic1.channels[0].pan = (uint)(v & 7);
ic1.channels[1].pan = (uint)((v >> 3) & 7);
break;
case 0x2d:
ic1.channels[2].pan = (uint)(v & 7);
ic1.channels[3].pan = (uint)((v >> 3) & 7);
break;
case 0x2f:
ic1.mode = v & 7;
break;
}
}
public static void k053260_0_w(int offset, byte data)
{
k053260_write(0, offset, data);
}
public static void k053260_0_lsb_w(int offset, ushort data)
{
//if (ACCESSING_BITS_0_7)
{
k053260_0_w(offset, (byte)(data & 0xff));
}
}
public static void k053260_0_lsb_w2(int offset, byte data)
{
k053260_0_w(offset, data);
}
public static void SaveStateBinary(BinaryWriter writer)
{
int i;
writer.Write(ic1.mode);
for (i = 0; i < 0x30; i++)
{
writer.Write(ic1.regs[i]);
}
for (i = 0; i < 4; i++)
{
writer.Write(ic1.channels[i].rate);
writer.Write(ic1.channels[i].size);
writer.Write(ic1.channels[i].start);
writer.Write(ic1.channels[i].bank);
writer.Write(ic1.channels[i].volume);
writer.Write(ic1.channels[i].play);
writer.Write(ic1.channels[i].pan);
writer.Write(ic1.channels[i].pos);
writer.Write(ic1.channels[i].loop);
writer.Write(ic1.channels[i].ppcm);
writer.Write(ic1.channels[i].ppcm_data);
}
}
public static void LoadStateBinary(BinaryReader reader)
{
int i;
ic1.mode = reader.ReadInt32();
for (i = 0; i < 0x30; i++)
{
ic1.regs[i] = reader.ReadInt32();
}
for (i = 0; i < 4; i++)
{
ic1.channels[i].rate = reader.ReadUInt32();
ic1.channels[i].size = reader.ReadUInt32();
ic1.channels[i].start = reader.ReadUInt32();
ic1.channels[i].bank = reader.ReadUInt32();
ic1.channels[i].volume = reader.ReadUInt32();
ic1.channels[i].play = reader.ReadInt32();
ic1.channels[i].pan = reader.ReadUInt32();
ic1.channels[i].pos = reader.ReadUInt32();
ic1.channels[i].loop = reader.ReadInt32();
ic1.channels[i].ppcm = reader.ReadInt32();
ic1.channels[i].ppcm_data = reader.ReadInt32();
}
}
}
}