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

421 lines
16 KiB
C#
Raw Normal View History

using System.IO;
namespace MAME.Core
{
public unsafe class Upd7759
{
public struct upd7759_chip
{
public uint pos;
public uint step;
public Atime clock_period;
public EmuTimer.emu_timer timer;
public byte fifo_in;
public byte reset;
public byte start;
public byte drq;
public drqcallback drqcallback;
public sbyte state;
public int clocks_left;
public ushort nibbles_left;
public byte repeat_count;
public sbyte post_drq_state;
public int post_drq_clocks;
public byte req_sample;
public byte last_sample;
public byte block_header;
public byte sample_rate;
public byte first_valid_header;
public uint offset;
public uint repeat_offset;
public sbyte adpcm_state;
public byte adpcm_data;
public short sample;
public int rombase;
public uint romoffset;
}
public static int[,] upd7759_step = new int[16, 16]
{
{ 0, 0, 1, 2, 3, 5, 7, 10, 0, 0, -1, -2, -3, -5, -7, -10 },
{ 0, 1, 2, 3, 4, 6, 8, 13, 0, -1, -2, -3, -4, -6, -8, -13 },
{ 0, 1, 2, 4, 5, 7, 10, 15, 0, -1, -2, -4, -5, -7, -10, -15 },
{ 0, 1, 3, 4, 6, 9, 13, 19, 0, -1, -3, -4, -6, -9, -13, -19 },
{ 0, 2, 3, 5, 8, 11, 15, 23, 0, -2, -3, -5, -8, -11, -15, -23 },
{ 0, 2, 4, 7, 10, 14, 19, 29, 0, -2, -4, -7, -10, -14, -19, -29 },
{ 0, 3, 5, 8, 12, 16, 22, 33, 0, -3, -5, -8, -12, -16, -22, -33 },
{ 1, 4, 7, 10, 15, 20, 29, 43, -1, -4, -7, -10, -15, -20, -29, -43 },
{ 1, 4, 8, 13, 18, 25, 35, 53, -1, -4, -8, -13, -18, -25, -35, -53 },
{ 1, 6, 10, 16, 22, 31, 43, 64, -1, -6, -10, -16, -22, -31, -43, -64 },
{ 2, 7, 12, 19, 27, 37, 51, 76, -2, -7, -12, -19, -27, -37, -51, -76 },
{ 2, 9, 16, 24, 34, 46, 64, 96, -2, -9, -16, -24, -34, -46, -64, -96 },
{ 3, 11, 19, 29, 41, 57, 79, 117, -3, -11, -19, -29, -41, -57, -79, -117 },
{ 4, 13, 24, 36, 50, 69, 96, 143, -4, -13, -24, -36, -50, -69, -96, -143 },
{ 4, 16, 29, 44, 62, 85, 118, 175, -4, -16, -29, -44, -62, -85, -118, -175 },
{ 6, 20, 36, 54, 76, 104, 144, 214, -6, -20, -36, -54, -76, -104, -144, -214 },
};
public static int[] upd7759_state = new int[16] { -1, -1, 0, 0, 1, 2, 2, 3, -1, -1, 0, 0, 1, 2, 2, 3 };
public static upd7759_chip chip;
public static byte[] updrom;
public delegate void drqcallback(int irq);
public static void update_adpcm(int data)
{
chip.sample += (short)upd7759_step[chip.adpcm_state, data];
chip.adpcm_state += (sbyte)upd7759_state[data];
if (chip.adpcm_state < 0)
{
chip.adpcm_state = 0;
}
else if (chip.adpcm_state > 15)
{
chip.adpcm_state = 15;
}
}
public static void advance_state()
{
switch (chip.state)
{
case 0:
chip.clocks_left = 4;
break;
case 1:
chip.drq = 0;
chip.clocks_left = chip.post_drq_clocks;
chip.state = chip.post_drq_state;
break;
case 2:
chip.req_sample = (byte)(updrom != null ? chip.fifo_in : 0x10);
chip.clocks_left = 70;
chip.state = 3;
break;
case 3:
chip.drq = 1;
chip.clocks_left = 44;
chip.state = 4;
break;
case 4:
chip.last_sample = updrom != null ? updrom[0] : chip.fifo_in;
chip.drq = 1;
chip.clocks_left = 28;
chip.state = (sbyte)((chip.req_sample > chip.last_sample) ? 0 : 5);
break;
case 5:
chip.drq = 1;
chip.clocks_left = 32;
chip.state = 6;
break;
case 6:
chip.offset = (uint)((updrom != null ? updrom[chip.req_sample * 2 + 5] : chip.fifo_in) << 9);
chip.drq = 1;
chip.clocks_left = 44;
chip.state = 7;
break;
case 7:
chip.offset |= (uint)((updrom != null ? updrom[chip.req_sample * 2 + 6] : chip.fifo_in) << 1);
chip.drq = 1;
chip.clocks_left = 36;
chip.state = 8;
break;
case 8:
chip.offset++;
chip.first_valid_header = 0;
chip.drq = 1;
chip.clocks_left = 36;
chip.state = 9;
break;
case 9:
if (chip.repeat_count != 0)
{
chip.repeat_count--;
chip.offset = chip.repeat_offset;
}
chip.block_header = updrom != null ? updrom[chip.offset++ & 0x1ffff] : chip.fifo_in;
chip.drq = 1;
switch (chip.block_header & 0xc0)
{
case 0x00:
chip.clocks_left = 1024 * ((chip.block_header & 0x3f) + 1);
chip.state = (sbyte)((chip.block_header == 0 && chip.first_valid_header != 0) ? 0 : 9);
chip.sample = 0;
chip.adpcm_state = 0;
break;
case 0x40:
chip.sample_rate = (byte)((chip.block_header & 0x3f) + 1);
chip.nibbles_left = 256;
chip.clocks_left = 36;
chip.state = 11;
break;
case 0x80:
chip.sample_rate = (byte)((chip.block_header & 0x3f) + 1);
chip.clocks_left = 36;
chip.state = 10;
break;
case 0xc0:
chip.repeat_count = (byte)((chip.block_header & 7) + 1);
chip.repeat_offset = chip.offset;
chip.clocks_left = 36;
chip.state = 9;
break;
}
if (chip.block_header != 0)
{
chip.first_valid_header = 1;
}
break;
case 10:
chip.nibbles_left = (ushort)((updrom != null ? updrom[chip.offset++ & 0x1ffff] : chip.fifo_in) + 1);
chip.drq = 1;
chip.clocks_left = 36;
chip.state = 11;
break;
case 11:
chip.adpcm_data = updrom != null ? updrom[chip.offset++ & 0x1ffff] : chip.fifo_in;
update_adpcm(chip.adpcm_data >> 4);
chip.drq = 1;
chip.clocks_left = chip.sample_rate * 4;
if (--chip.nibbles_left == 0)
{
chip.state = 9;
}
else
{
chip.state = 12;
}
break;
case 12:
update_adpcm(chip.adpcm_data & 15);
chip.clocks_left = chip.sample_rate * 4;
if (--chip.nibbles_left == 0)
{
chip.state = 9;
}
else
{
chip.state = 11;
}
break;
}
if (chip.drq != 0)
{
chip.post_drq_state = chip.state;
chip.post_drq_clocks = chip.clocks_left - 21;
chip.state = 1;
chip.clocks_left = 21;
}
}
public static void upd7759_update(int offset, int length)
{
int clocks_left = chip.clocks_left;
short sample = chip.sample;
uint step = chip.step;
uint pos = chip.pos;
int i = 0, j;
if (chip.state != 0)
{
for (i = 0; i < length; i++)
{
Sound.upd7759stream.streamoutput_Ptrs[0][offset + i] = sample << 7;
pos += step;
while (updrom != null && pos >= 0x100000)
{
int clocks_this_time = (int)(pos >> 20);
if (clocks_this_time > clocks_left)
{
clocks_this_time = clocks_left;
}
pos -= (uint)(clocks_this_time * 0x100000);
clocks_left -= clocks_this_time;
if (clocks_left == 0)
{
advance_state();
if (chip.state == 0)
{
break;
}
clocks_left = chip.clocks_left;
sample = chip.sample;
}
}
}
}
if (i < length - 1)
{
for (j = i; j < length; j++)
{
Sound.upd7759stream.streamoutput_Ptrs[0][offset + j] = 0;
}
}
chip.clocks_left = clocks_left;
chip.pos = pos;
}
public static void upd7759_slave_update()
{
byte olddrq = chip.drq;
Sound.upd7759stream.stream_update();
//stream_update(chip.channel);
advance_state();
if (olddrq != chip.drq && chip.drqcallback != null)
{
chip.drqcallback(chip.drq);
}
if (chip.state != 0)
{
EmuTimer.timer_adjust_periodic(chip.timer, Attotime.attotime_mul(chip.clock_period, (uint)chip.clocks_left), Attotime.ATTOTIME_NEVER);
}
}
public static void upd7759_reset()
{
chip.pos = 0;
chip.fifo_in = 0;
chip.drq = 0;
chip.state = 0;
chip.clocks_left = 0;
chip.nibbles_left = 0;
chip.repeat_count = 0;
chip.post_drq_state = 0;
chip.post_drq_clocks = 0;
chip.req_sample = 0;
chip.last_sample = 0;
chip.block_header = 0;
chip.sample_rate = 0;
chip.first_valid_header = 0;
chip.offset = 0;
chip.repeat_offset = 0;
chip.adpcm_state = 0;
chip.adpcm_data = 0;
chip.sample = 0;
if (chip.timer != null)
{
EmuTimer.timer_adjust_periodic(chip.timer, Attotime.ATTOTIME_NEVER, Attotime.ATTOTIME_NEVER);
}
}
public static void upd7759_start(int clock)
{
chip = new upd7759_chip();
chip.step = 4 * 0x100000;
chip.clock_period = new Atime(0, (long)(1e18 / clock));
chip.state = 0;
chip.rombase = 0;
if (updrom == null)
{
chip.timer = EmuTimer.timer_alloc_common(EmuTimer.TIME_ACT.Upd7759_upd7759_slave_update, false);
}
chip.reset = 1;
chip.start = 1;
upd7759_reset();
}
public static void upd7759_reset_w(int which, byte data)
{
byte oldreset = chip.reset;
chip.reset = (byte)((data != 0) ? 1 : 0);
Sound.upd7759stream.stream_update();
if (oldreset != 0 && chip.reset == 0)
{
upd7759_reset();
}
}
public static void upd7759_start_w(int which, byte data)
{
byte oldstart = chip.start;
chip.start = (byte)((data != 0) ? 1 : 0);
Sound.upd7759stream.stream_update();
if (chip.state == 0 && oldstart == 0 && chip.start != 0 && chip.reset != 0)
{
chip.state = 2;
if (chip.timer != null)
{
EmuTimer.timer_adjust_periodic(chip.timer, Attotime.ATTOTIME_ZERO, Attotime.ATTOTIME_NEVER);
}
}
}
public static void upd7759_port_w(int which, byte data)
{
chip.fifo_in = data;
}
public static int upd7759_busy_r(int which)
{
return (chip.state == 0) ? 1 : 0;
}
public static void upd7759_set_bank_base(int which, uint base1)
{
//chip.rom = chip.rombase + base1;
chip.romoffset = base1;
}
public static void upd7759_0_start_w(byte data)
{
upd7759_start_w(0, data);
}
public static void upd7759_0_reset_w(byte data)
{
upd7759_reset_w(0, data);
}
public static void upd7759_0_port_w(byte data)
{
upd7759_port_w(0, data);
}
public static byte upd7759_0_busy_r()
{
return (byte)upd7759_busy_r(0);
}
public static void SaveStateBinary(BinaryWriter writer)
{
writer.Write(chip.pos);
writer.Write(chip.step);
writer.Write(chip.fifo_in);
writer.Write(chip.reset);
writer.Write(chip.start);
writer.Write(chip.drq);
writer.Write(chip.state);
writer.Write(chip.clocks_left);
writer.Write(chip.nibbles_left);
writer.Write(chip.repeat_count);
writer.Write(chip.post_drq_state);
writer.Write(chip.post_drq_clocks);
writer.Write(chip.req_sample);
writer.Write(chip.last_sample);
writer.Write(chip.block_header);
writer.Write(chip.sample_rate);
writer.Write(chip.first_valid_header);
writer.Write(chip.offset);
writer.Write(chip.repeat_offset);
writer.Write(chip.adpcm_state);
writer.Write(chip.adpcm_data);
writer.Write(chip.sample);
writer.Write(chip.romoffset);
writer.Write(chip.rombase);
}
public static void LoadStateBinary(BinaryReader reader)
{
chip.pos = reader.ReadUInt32();
chip.step = reader.ReadUInt32();
chip.fifo_in = reader.ReadByte();
chip.reset = reader.ReadByte();
chip.start = reader.ReadByte();
chip.drq = reader.ReadByte();
chip.state = reader.ReadSByte();
chip.clocks_left = reader.ReadInt32();
chip.nibbles_left = reader.ReadUInt16();
chip.repeat_count = reader.ReadByte();
chip.post_drq_state = reader.ReadSByte();
chip.post_drq_clocks = reader.ReadInt32();
chip.req_sample = reader.ReadByte();
chip.last_sample = reader.ReadByte();
chip.block_header = reader.ReadByte();
chip.sample_rate = reader.ReadByte();
chip.first_valid_header = reader.ReadByte();
chip.offset = reader.ReadUInt32();
chip.repeat_offset = reader.ReadUInt32();
chip.adpcm_state = reader.ReadSByte();
chip.adpcm_data = reader.ReadByte();
chip.sample = reader.ReadInt16();
chip.romoffset = reader.ReadUInt32();
chip.rombase = reader.ReadInt32();
}
}
}