314 lines
13 KiB
C#
314 lines
13 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|