namespace MAME.Core { public class YMDeltat { public struct YM_DELTAT { public int output_pointer; public int pan_offset; public double freqbase; public int memory_size; public int output_range; public int now_addr; public int now_step; public int step; public int start; public int limit; public int end; public int delta; public int volume; public int acc; public int adpcmd; public int adpcml; public int prev_acc; public byte now_data; public byte CPU_data; public byte portstate; public byte control2; public byte portshift; public byte DRAMportshift; public byte memread; public status_callback status_set_handler; public status_callback status_reset_handler; public byte status_change_EOS_bit; public byte status_change_BRDY_bit; public byte status_change_ZERO_bit; public byte PCM_BSY; public byte[] reg; public byte emulation_mode; } public delegate void status_callback(byte b1); public static YM_DELTAT DELTAT; public static byte[] ymsnddeltatrom; private static int YM_DELTAT_DELTA_MAX = 24576; private static int YM_DELTAT_DELTA_MIN = 127; private static int YM_DELTAT_DELTA_DEF = 127; private static int YM_DELTAT_DECODE_RANGE = 32768; private static int YM_DELTAT_DECODE_MIN = -YM_DELTAT_DECODE_RANGE; private static int YM_DELTAT_DECODE_MAX = YM_DELTAT_DECODE_RANGE - 1; private static int[] ym_deltat_decode_tableB1 = new int[16]{ 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, }; private static int[] ym_deltat_decode_tableB2 = new int[16]{ 57, 57, 57, 57, 77, 102, 128, 153, 57, 57, 57, 57, 77, 102, 128, 153 }; private static byte[] dram_rightshift = new byte[4] { 3, 0, 0, 0 }; public static void YM_DELTAT_ADPCM_Write(int r, byte v) { if (r >= 0x10) { return; } DELTAT.reg[r] = v; switch (r) { case 0x00: if (DELTAT.emulation_mode == 1) { v |= 0x20; } DELTAT.portstate = (byte)(v & (0x80 | 0x40 | 0x20 | 0x10 | 0x01)); if ((DELTAT.portstate & 0x80) != 0) { DELTAT.PCM_BSY = 1; DELTAT.now_step = 0; DELTAT.acc = 0; DELTAT.prev_acc = 0; DELTAT.adpcml = 0; DELTAT.adpcmd = YM_DELTAT_DELTA_DEF; DELTAT.now_data = 0; } if ((DELTAT.portstate & 0x20) != 0) { DELTAT.now_addr = DELTAT.start << 1; DELTAT.memread = 2; if (ymsnddeltatrom == null) { DELTAT.portstate = 0x00; DELTAT.PCM_BSY = 0; } else { if (DELTAT.end >= DELTAT.memory_size) { DELTAT.end = DELTAT.memory_size - 1; } if (DELTAT.start >= DELTAT.memory_size) { DELTAT.portstate = 0x00; DELTAT.PCM_BSY = 0; } } } else { DELTAT.now_addr = 0; } if ((DELTAT.portstate & 0x01) != 0) { DELTAT.portstate = 0x00; DELTAT.PCM_BSY = 0; if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_BRDY_bit); } } } break; case 0x01: /* handle emulation mode */ if (DELTAT.emulation_mode == 1) { v |= 0x01; } DELTAT.pan_offset = (v >> 6) & 0x03; if ((DELTAT.control2 & 3) != (v & 3)) { if (DELTAT.DRAMportshift != dram_rightshift[v & 3]) { DELTAT.DRAMportshift = dram_rightshift[v & 3]; DELTAT.start = (DELTAT.reg[0x3] * 0x0100 | DELTAT.reg[0x2]) << (DELTAT.portshift - DELTAT.DRAMportshift); DELTAT.end = (DELTAT.reg[0x5] * 0x0100 | DELTAT.reg[0x4]) << (DELTAT.portshift - DELTAT.DRAMportshift); DELTAT.end += (1 << (DELTAT.portshift - DELTAT.DRAMportshift)) - 1; DELTAT.limit = (DELTAT.reg[0xd] * 0x0100 | DELTAT.reg[0xc]) << (DELTAT.portshift - DELTAT.DRAMportshift); } } DELTAT.control2 = v; break; case 0x02: case 0x03: DELTAT.start = (DELTAT.reg[0x3] * 0x0100 | DELTAT.reg[0x2]) << (DELTAT.portshift - DELTAT.DRAMportshift); break; case 0x04: case 0x05: DELTAT.end = (DELTAT.reg[0x5] * 0x0100 | DELTAT.reg[0x4]) << (DELTAT.portshift - DELTAT.DRAMportshift); DELTAT.end += (1 << (DELTAT.portshift - DELTAT.DRAMportshift)) - 1; break; case 0x06: case 0x07: break; case 0x08: if ((DELTAT.portstate & 0xe0) == 0x60) { if (DELTAT.memread != 0) { DELTAT.now_addr = DELTAT.start << 1; DELTAT.memread = 0; } if (DELTAT.now_addr != (DELTAT.end << 1)) { ymsnddeltatrom[DELTAT.now_addr >> 1] = v; DELTAT.now_addr += 2; if (DELTAT.status_reset_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_reset_handler(DELTAT.status_change_BRDY_bit); } } if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_BRDY_bit); } } } else { if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_EOS_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_EOS_bit); } } } return; } if ((DELTAT.portstate & 0xe0) == 0x80) { DELTAT.CPU_data = v; if (DELTAT.status_reset_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_reset_handler(DELTAT.status_change_BRDY_bit); } } return; } break; case 0x09: case 0x0a: DELTAT.delta = (DELTAT.reg[0xa] * 0x0100 | DELTAT.reg[0x9]); DELTAT.step = (int)(DELTAT.delta * DELTAT.freqbase); break; case 0x0b: { int oldvol = DELTAT.volume; DELTAT.volume = (v & 0xff) * (DELTAT.output_range / 256) / YM_DELTAT_DECODE_RANGE; if (oldvol != 0) { DELTAT.adpcml = (int)((double)DELTAT.adpcml / (double)oldvol * (double)DELTAT.volume); } } break; case 0x0c: case 0x0d: DELTAT.limit = (DELTAT.reg[0xd] * 0x0100 | DELTAT.reg[0xc]) << (DELTAT.portshift - DELTAT.DRAMportshift); break; } } public static void YM_DELTAT_ADPCM_Reset(int pan, int emulation_mode) { DELTAT.now_addr = 0; DELTAT.now_step = 0; DELTAT.step = 0; DELTAT.start = 0; DELTAT.end = 0; DELTAT.limit = -1; DELTAT.volume = 0; DELTAT.pan_offset = 0; DELTAT.acc = 0; DELTAT.prev_acc = 0; DELTAT.adpcmd = 127; DELTAT.adpcml = 0; DELTAT.emulation_mode = (byte)emulation_mode; DELTAT.portstate = (emulation_mode == 1) ? (byte)0x20 : (byte)0; DELTAT.control2 = (emulation_mode == 1) ? (byte)0x01 : (byte)0; DELTAT.DRAMportshift = dram_rightshift[DELTAT.control2 & 3]; if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_BRDY_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_BRDY_bit); } } } public static void YM_DELTAT_postload(byte[] regs, int offset) { int r; DELTAT.volume = 0; for (r = 1; r < 16; r++) { YM_DELTAT_ADPCM_Write(r, regs[offset + r]); } DELTAT.reg[0] = regs[offset]; if (ymsnddeltatrom != null) { DELTAT.now_data = ymsnddeltatrom[DELTAT.now_addr >> 1]; } } private static int Limit(int val, int max, int min) { if (val > max) { return max; } else if (val < min) { return min; } else { return val; } } private static void YM_DELTAT_synthesis_from_external_memory() { int step; int data; DELTAT.now_step += DELTAT.step; if (DELTAT.now_step >= (1 << 16)) { step = DELTAT.now_step >> 16; DELTAT.now_step &= (1 << 16) - 1; do { if (DELTAT.now_addr == (DELTAT.limit << 1)) { DELTAT.now_addr = 0; } if (DELTAT.now_addr == (DELTAT.end << 1)) { if ((DELTAT.portstate & 0x10) != 0) { DELTAT.now_addr = DELTAT.start << 1; DELTAT.acc = 0; DELTAT.adpcmd = YM_DELTAT_DELTA_DEF; DELTAT.prev_acc = 0; } else { if (DELTAT.status_set_handler != null) { if (DELTAT.status_change_EOS_bit != 0) { DELTAT.status_set_handler(DELTAT.status_change_EOS_bit); } } DELTAT.PCM_BSY = 0; DELTAT.portstate = 0; DELTAT.adpcml = 0; DELTAT.prev_acc = 0; return; } } if ((DELTAT.now_addr & 1) != 0) { data = DELTAT.now_data & 0x0f; } else { DELTAT.now_data = ymsnddeltatrom[DELTAT.now_addr >> 1]; data = DELTAT.now_data >> 4; } DELTAT.now_addr++; DELTAT.now_addr &= ((1 << (24 + 1)) - 1); DELTAT.prev_acc = DELTAT.acc; DELTAT.acc += (ym_deltat_decode_tableB1[data] * DELTAT.adpcmd / 8); DELTAT.acc = Limit(DELTAT.acc, YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); DELTAT.adpcmd = (DELTAT.adpcmd * ym_deltat_decode_tableB2[data]) / 64; DELTAT.adpcmd = Limit(DELTAT.adpcmd, YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN); } while ((--step) != 0); } DELTAT.adpcml = DELTAT.prev_acc * (int)((1 << 16) - DELTAT.now_step); DELTAT.adpcml += (DELTAT.acc * (int)DELTAT.now_step); DELTAT.adpcml = (DELTAT.adpcml >> 16) * (int)DELTAT.volume; FM.out_delta[DELTAT.pan_offset] += DELTAT.adpcml; } private static void YM_DELTAT_synthesis_from_CPU_memory() { int step; int data; DELTAT.now_step += DELTAT.step; if (DELTAT.now_step >= (1 << 16)) { step = DELTAT.now_step >> 16; DELTAT.now_step &= (1 << 16) - 1; do { if ((DELTAT.now_addr & 1) != 0) { data = DELTAT.now_data & 0x0f; DELTAT.now_data = DELTAT.CPU_data; if (DELTAT.status_set_handler != null) if (DELTAT.status_change_BRDY_bit != 0) DELTAT.status_set_handler(DELTAT.status_change_BRDY_bit); } else { data = DELTAT.now_data >> 4; } DELTAT.now_addr++; DELTAT.prev_acc = DELTAT.acc; DELTAT.acc += (ym_deltat_decode_tableB1[data] * DELTAT.adpcmd / 8); DELTAT.acc = Limit(DELTAT.acc, YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN); DELTAT.adpcmd = (DELTAT.adpcmd * ym_deltat_decode_tableB2[data]) / 64; DELTAT.adpcmd = Limit(DELTAT.adpcmd, YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN); } while ((--step) != 0); } DELTAT.adpcml = DELTAT.prev_acc * (int)((1 << 16) - DELTAT.now_step); DELTAT.adpcml += (DELTAT.acc * (int)DELTAT.now_step); DELTAT.adpcml = (DELTAT.adpcml >> 16) * (int)DELTAT.volume; FM.out_delta[DELTAT.pan_offset] += DELTAT.adpcml; } public static void YM_DELTAT_ADPCM_CALC() { if ((DELTAT.portstate & 0xe0) == 0xa0) { YM_DELTAT_synthesis_from_external_memory(); return; } if ((DELTAT.portstate & 0xe0) == 0x80) { YM_DELTAT_synthesis_from_CPU_memory(); return; } return; } } }