using System.IO; namespace MAME.Core { public unsafe class Namco { public struct sound_channel { public int frequency; public int counter; public int[] volume; public int noise_sw; public int noise_state; public int noise_seed; public int noise_counter; public int noise_hold; public int waveform_select; }; public struct namco_sound { public sound_channel[] channel_list; public int wave_size; public int num_voices; public int sound_enable; public sound_stream stream; public int namco_clock; public int sample_rate; public int f_fracbits; public int stereo; public short[][] waveform; }; public static byte[] namco_wavedata; public static namco_sound nam1; public static void update_namco_waveform(int offset, byte data) { if (nam1.wave_size == 1) { short wdata; int v; for (v = 0; v < 16; v++) { wdata = (short)(((data >> 4) & 0x0f) - 8); nam1.waveform[v][offset * 2] = (short)((wdata * v) * 0x100 / nam1.num_voices); wdata = (short)((data & 0x0f) - 8); nam1.waveform[v][offset * 2 + 1] = (short)((wdata * v) * 0x100 / nam1.num_voices); } } else { int v; for (v = 0; v < 16; v++) nam1.waveform[v][offset] = (short)((((data & 0x0f) - 8) * v) * 0x100 / nam1.num_voices); } } public static void build_decoded_waveform() { int offset; int v; nam1.wave_size = 1; nam1.waveform = new short[16][]; for (v = 0; v < 16; v++) { nam1.waveform[v] = new short[32 * 16]; } for (offset = 0; offset < 256; offset++) update_namco_waveform(offset, namco_wavedata[offset]); } public static uint namco_update_one(int[] buffer, int length, short[] wave, uint counter, uint freq) { int i; for (i = 0; i < length; i++) { buffer[i] += wave[((counter) >> nam1.f_fracbits) & 0x1f]; counter += freq; } return counter; } public static void namco_update_stereo(int offset, int length) { int voice; int i; int counter; for (i = 0; i < length; i++) { Sound.namcostream.streamoutput_Ptrs[0][offset + i] = 0; Sound.namcostream.streamoutput_Ptrs[1][offset + i] = 0; } for (voice = 0; voice < 8; voice++) { int lv = nam1.channel_list[voice].volume[0]; int rv = nam1.channel_list[voice].volume[1]; if (nam1.channel_list[voice].noise_sw != 0) { int f = nam1.channel_list[voice].frequency & 0xff; if ((lv != 0 || rv != 0) && f != 0) { int hold_time = 1 << (nam1.f_fracbits - 16); int hold = nam1.channel_list[voice].noise_hold; int delta = f << 4; int c = nam1.channel_list[voice].noise_counter; short l_noise_data = (short)((0x07 * (lv >> 1)) * 32); short r_noise_data = (short)((0x07 * (rv >> 1)) * 32); for (i = 0; i < length; i++) { int cnt; if (nam1.channel_list[voice].noise_state != 0) { Sound.namcostream.streamoutput_Ptrs[0][offset + i] += l_noise_data; Sound.namcostream.streamoutput_Ptrs[1][offset + i] += r_noise_data; } else { Sound.namcostream.streamoutput_Ptrs[0][offset + i] += l_noise_data; Sound.namcostream.streamoutput_Ptrs[1][offset + i] += r_noise_data; } if (hold != 0) { hold--; continue; } hold = hold_time; c += delta; cnt = (c >> 12); c &= (1 << 12) - 1; for (; cnt > 0; cnt--) { if (((nam1.channel_list[voice].noise_seed + 1) & 2) != 0) nam1.channel_list[voice].noise_state ^= 1; if ((nam1.channel_list[voice].noise_seed & 1) != 0) nam1.channel_list[voice].noise_seed ^= 0x28000; nam1.channel_list[voice].noise_seed >>= 1; } } nam1.channel_list[voice].noise_counter = c; nam1.channel_list[voice].noise_hold = hold; } } else { if (nam1.channel_list[voice].frequency != 0) { int c = nam1.channel_list[voice].counter; if (lv != 0) { counter = nam1.channel_list[voice].counter; for (i = 0; i < length; i++) { Sound.namcostream.streamoutput_Ptrs[0][offset + i] += nam1.waveform[lv][nam1.channel_list[voice].waveform_select * 32 + (counter >> nam1.f_fracbits) & 0x1f]; counter += nam1.channel_list[voice].frequency; } c = counter; } if (rv != 0) { counter = nam1.channel_list[voice].counter; for (i = 0; i < length; i++) { Sound.namcostream.streamoutput_Ptrs[1][offset + i] += nam1.waveform[rv][nam1.channel_list[voice].waveform_select * 32 + (counter >> nam1.f_fracbits) & 0x1f]; counter += nam1.channel_list[voice].frequency; } c = counter; } nam1.channel_list[voice].counter = c; } } } } public static void namco_start() { int voice; nam1.num_voices = 8; nam1.namco_clock = 192000; nam1.f_fracbits = 4 + 15; nam1.sample_rate = nam1.namco_clock; build_decoded_waveform(); nam1.channel_list = new sound_channel[8]; for (voice = 0; voice < 8; voice++) { int state_index = voice; nam1.channel_list[voice].frequency = 0; nam1.channel_list[voice].volume = new int[2]; nam1.channel_list[voice].volume[0] = nam1.channel_list[voice].volume[1] = 0; nam1.channel_list[voice].waveform_select = 0; nam1.channel_list[voice].counter = 0; nam1.channel_list[voice].noise_sw = 0; nam1.channel_list[voice].noise_state = 0; nam1.channel_list[voice].noise_seed = 1; nam1.channel_list[voice].noise_counter = 0; nam1.channel_list[voice].noise_hold = 0; } } public static void namcos1_sound_w(int offset, byte data) { int ch, ch1; int nssw; if (offset > 63) { return; } if (namco_wavedata[0x100 + offset] == data) return; Sound.namcostream.stream_update(); namco_wavedata[0x100 + offset] = data; ch = offset / 8; if (ch >= nam1.num_voices) return; ch1 = ch; switch (offset - ch * 8) { case 0x00: nam1.channel_list[ch1].volume[0] = data & 0x0f; break; case 0x01: nam1.channel_list[ch1].waveform_select = (data >> 4) & 15; nam1.channel_list[ch1].frequency = (namco_wavedata[0x100 + ch * 8 + 0x01] & 15) << 16; nam1.channel_list[ch1].frequency += namco_wavedata[0x100 + ch * 8 + 0x02] << 8; nam1.channel_list[ch1].frequency += namco_wavedata[0x100 + ch * 8 + 0x03]; break; case 0x02: case 0x03: nam1.channel_list[ch1].frequency = (namco_wavedata[0x100 + ch * 8 + 0x01] & 15) << 16; nam1.channel_list[ch1].frequency += namco_wavedata[0x100 + ch * 8 + 0x02] << 8; nam1.channel_list[ch1].frequency += namco_wavedata[0x100 + ch * 8 + 0x03]; break; case 0x04: nam1.channel_list[ch1].volume[1] = data & 0x0f; nssw = ((data & 0x80) >> 7); if (ch1 == 7) { ch1 = 0; } nam1.channel_list[ch1].noise_sw = nssw; break; } } public static void namcos1_cus30_w(int offset, byte data) { if (offset < 0x100) { if (namco_wavedata[offset] != data) { Sound.namcostream.stream_update(); namco_wavedata[offset] = data; update_namco_waveform(offset, data); } } else if (offset < 0x140) namcos1_sound_w(offset - 0x100, data); else namco_wavedata[offset] = data; } public static byte namcos1_cus30_r(int offset) { return namco_wavedata[offset]; } public static void SaveStateBinary(BinaryWriter writer) { int i, j; writer.Write(nam1.num_voices); writer.Write(nam1.sound_enable); for (i = 0; i < 16; i++) { for (j = 0; j < 32 * 16; j++) { writer.Write(nam1.waveform[i][j]); } } for (i = 0; i < 8; i++) { writer.Write(nam1.channel_list[i].frequency); writer.Write(nam1.channel_list[i].counter); writer.Write(nam1.channel_list[i].volume[0]); writer.Write(nam1.channel_list[i].volume[1]); writer.Write(nam1.channel_list[i].noise_sw); writer.Write(nam1.channel_list[i].noise_state); writer.Write(nam1.channel_list[i].noise_seed); writer.Write(nam1.channel_list[i].noise_hold); writer.Write(nam1.channel_list[i].noise_counter); writer.Write(nam1.channel_list[i].waveform_select); } writer.Write(namco_wavedata, 0, 0x400); } public static void LoadStateBinary(BinaryReader reader) { int i, j; nam1.num_voices = reader.ReadInt32(); nam1.sound_enable = reader.ReadInt32(); for (i = 0; i < 16; i++) { for (j = 0; j < 32 * 16; j++) { nam1.waveform[i][j] = reader.ReadInt16(); } } for (i = 0; i < 8; i++) { nam1.channel_list[i].frequency = reader.ReadInt32(); nam1.channel_list[i].counter = reader.ReadInt32(); nam1.channel_list[i].volume[0] = reader.ReadInt32(); nam1.channel_list[i].volume[1] = reader.ReadInt32(); nam1.channel_list[i].noise_sw = reader.ReadInt32(); nam1.channel_list[i].noise_state = reader.ReadInt32(); nam1.channel_list[i].noise_seed = reader.ReadInt32(); nam1.channel_list[i].noise_hold = reader.ReadInt32(); nam1.channel_list[i].noise_counter = reader.ReadInt32(); nam1.channel_list[i].waveform_select = reader.ReadInt32(); } namco_wavedata = reader.ReadBytes(0x400); } } }