[NES] noise channel
This commit is contained in:
parent
a62b3009ef
commit
f84de1750e
|
@ -37,6 +37,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
|
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||||
};
|
};
|
||||||
|
static int[] NOISE_TABLE =
|
||||||
|
{
|
||||||
|
4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068 //NTSC
|
||||||
|
//4, 7, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778 //PAL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class PulseUnit
|
class PulseUnit
|
||||||
|
@ -148,12 +153,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
swp_divider_counter = sweep_divider_cnt + 1;
|
swp_divider_counter = sweep_divider_cnt + 1;
|
||||||
sweep_reload = false;
|
sweep_reload = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//env_loopdoubles as "halt length counter"
|
//env_loopdoubles as "halt length counter"
|
||||||
if (env_loop == 0 && len_cnt > 0)
|
if (env_loop == 0 && len_cnt > 0)
|
||||||
|
@ -191,12 +191,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
|
|
||||||
public void Run()
|
public void Run()
|
||||||
{
|
{
|
||||||
//sweep units are figured out during memory writes to the regs
|
if (timer_counter > 0) timer_counter--;
|
||||||
//that set the timer, length counter are figured out in the
|
|
||||||
//writes and frame counter, and envelope is set through the memory
|
|
||||||
//regs also, so we just need to deal with the timer and sequencer here
|
|
||||||
|
|
||||||
timer_counter--;
|
|
||||||
if (timer_counter == 0)
|
if (timer_counter == 0)
|
||||||
{
|
{
|
||||||
duty_step = (duty_step + 1) & 7;
|
duty_step = (duty_step + 1) & 7;
|
||||||
|
@ -219,6 +214,116 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NoiseUnit
|
||||||
|
{
|
||||||
|
//reg0 (sweep)
|
||||||
|
int env_cnt_value, env_loop, env_constant;
|
||||||
|
|
||||||
|
//reg2 (mode and period)
|
||||||
|
int mode_cnt, period_cnt;
|
||||||
|
|
||||||
|
//reg3 (length counter and envelop trigger)
|
||||||
|
int len_cnt;
|
||||||
|
|
||||||
|
//set from apu:
|
||||||
|
int lenctr_en;
|
||||||
|
|
||||||
|
//state
|
||||||
|
int shift_register = 1;
|
||||||
|
int timer_counter;
|
||||||
|
public int sample;
|
||||||
|
int env_output, env_start_flag, env_divider, env_counter;
|
||||||
|
|
||||||
|
public bool IsLenCntNonZero() { return len_cnt > 0; }
|
||||||
|
|
||||||
|
public void WriteReg(int addr, byte val)
|
||||||
|
{
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
env_cnt_value = val & 0xF;
|
||||||
|
env_constant = (val >> 4) & 1;
|
||||||
|
env_loop = (val>>5)&1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
period_cnt = NOISE_TABLE[val & 0xF];
|
||||||
|
mode_cnt = (val>>7)&1;
|
||||||
|
//Console.WriteLine("noise period: {0}, vol: {1}", (val & 0xF), env_cnt_value);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
len_cnt = LENGTH_TABLE[(val >> 3) & 0x1F];
|
||||||
|
set_lenctr_en(lenctr_en);
|
||||||
|
env_start_flag = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set_lenctr_en(int value)
|
||||||
|
{
|
||||||
|
lenctr_en = value;
|
||||||
|
//Console.WriteLine("noise lenctr_en: " + lenctr_en);
|
||||||
|
//if the length counter is not enabled, then we must disable the length system in this way
|
||||||
|
if (lenctr_en == 0) len_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clock_env() {}
|
||||||
|
public void clock_length_and_sweep()
|
||||||
|
{
|
||||||
|
if (env_start_flag == 1)
|
||||||
|
{
|
||||||
|
env_start_flag = 0;
|
||||||
|
env_divider = (env_cnt_value + 1);
|
||||||
|
env_counter = 15;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (env_divider != 0) env_divider--;
|
||||||
|
if (env_divider == 0)
|
||||||
|
{
|
||||||
|
env_divider = (env_cnt_value + 1);
|
||||||
|
if (env_counter == 0)
|
||||||
|
{
|
||||||
|
if (env_loop == 1)
|
||||||
|
{
|
||||||
|
env_counter = 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else env_counter--;
|
||||||
|
}
|
||||||
|
if (env_constant == 1)
|
||||||
|
env_output = env_cnt_value;
|
||||||
|
else env_output = env_counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len_cnt > 0 && env_loop == 0)
|
||||||
|
len_cnt--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
if (timer_counter > 0) timer_counter--;
|
||||||
|
if (timer_counter == 0)
|
||||||
|
{
|
||||||
|
//reload timer
|
||||||
|
timer_counter = period_cnt;
|
||||||
|
int feedback_bit;
|
||||||
|
if (mode_cnt == 1) feedback_bit = (shift_register >> 6) & 1;
|
||||||
|
else feedback_bit = (shift_register >> 1) & 1;
|
||||||
|
int feedback = feedback_bit ^ (shift_register & 1);
|
||||||
|
shift_register >>= 1;
|
||||||
|
shift_register &= ~(1 << 14);
|
||||||
|
shift_register |= (feedback << 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
sample = env_output;
|
||||||
|
if ((shift_register & 1) == 0) sample = 0;
|
||||||
|
if (len_cnt == 0)
|
||||||
|
sample = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TriangleUnit
|
class TriangleUnit
|
||||||
{
|
{
|
||||||
//reg0
|
//reg0
|
||||||
|
@ -303,9 +408,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PulseUnit[] pulse = { new PulseUnit(0), new PulseUnit(1) };
|
PulseUnit[] pulse = { new PulseUnit(0), new PulseUnit(1) };
|
||||||
TriangleUnit triangle = new TriangleUnit();
|
TriangleUnit triangle = new TriangleUnit();
|
||||||
|
NoiseUnit noise = new NoiseUnit();
|
||||||
|
|
||||||
int sequencer_counter, sequencer_step, sequencer_mode, sequencer_irq_inhibit;
|
int sequencer_counter, sequencer_step, sequencer_mode, sequencer_irq_inhibit;
|
||||||
void sequencer_reset()
|
void sequencer_reset()
|
||||||
|
@ -336,11 +441,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
pulse[0].clock_env();
|
pulse[0].clock_env();
|
||||||
pulse[1].clock_env();
|
pulse[1].clock_env();
|
||||||
triangle.clock_linear_counter();
|
triangle.clock_linear_counter();
|
||||||
|
noise.clock_env();
|
||||||
if (sequencer_step == 2 || sequencer_step == 4)
|
if (sequencer_step == 2 || sequencer_step == 4)
|
||||||
{
|
{
|
||||||
pulse[0].clock_length_and_sweep();
|
pulse[0].clock_length_and_sweep();
|
||||||
pulse[1].clock_length_and_sweep();
|
pulse[1].clock_length_and_sweep();
|
||||||
triangle.clock_length_and_sweep();
|
triangle.clock_length_and_sweep();
|
||||||
|
noise.clock_length_and_sweep();
|
||||||
}
|
}
|
||||||
if (sequencer_step == 4)
|
if (sequencer_step == 4)
|
||||||
{
|
{
|
||||||
|
@ -357,12 +464,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
pulse[0].clock_env();
|
pulse[0].clock_env();
|
||||||
pulse[1].clock_env();
|
pulse[1].clock_env();
|
||||||
triangle.clock_linear_counter();
|
triangle.clock_linear_counter();
|
||||||
|
noise.clock_env();
|
||||||
}
|
}
|
||||||
if (sequencer_step == 1 || sequencer_step == 3)
|
if (sequencer_step == 1 || sequencer_step == 3)
|
||||||
{
|
{
|
||||||
pulse[0].clock_length_and_sweep();
|
pulse[0].clock_length_and_sweep();
|
||||||
pulse[1].clock_length_and_sweep();
|
pulse[1].clock_length_and_sweep();
|
||||||
triangle.clock_length_and_sweep();
|
triangle.clock_length_and_sweep();
|
||||||
|
noise.clock_length_and_sweep();
|
||||||
}
|
}
|
||||||
if (sequencer_step == 5)
|
if (sequencer_step == 5)
|
||||||
sequencer_step = 0;
|
sequencer_step = 0;
|
||||||
|
@ -384,9 +493,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
case 0x4008: case 0x4009: case 0x400A: case 0x400B:
|
case 0x4008: case 0x4009: case 0x400A: case 0x400B:
|
||||||
triangle.WriteReg(addr - 0x4008, val);
|
triangle.WriteReg(addr - 0x4008, val);
|
||||||
break;
|
break;
|
||||||
|
case 0x400C: case 0x400D: case 0x400E: case 0x400F:
|
||||||
|
noise.WriteReg(addr - 0x400C, val);
|
||||||
|
break;
|
||||||
case 0x4015:
|
case 0x4015:
|
||||||
pulse[0].set_lenctr_en(val & 1);
|
pulse[0].set_lenctr_en(val & 1);
|
||||||
pulse[1].set_lenctr_en((val >> 1) & 1);
|
pulse[1].set_lenctr_en((val >> 1) & 1);
|
||||||
|
//todo - triangle length counter?
|
||||||
|
noise.set_lenctr_en((val >> 3) & 1);
|
||||||
break;
|
break;
|
||||||
case 0x4017:
|
case 0x4017:
|
||||||
sequencer_mode = (val>>7)&1;
|
sequencer_mode = (val>>7)&1;
|
||||||
|
@ -408,7 +522,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
//if an interrupt flag was set at the same moment of the read, it will read back as 1 but it will not be cleared.
|
//if an interrupt flag was set at the same moment of the read, it will read back as 1 but it will not be cleared.
|
||||||
int dmc_irq_flag = 0; //todo
|
int dmc_irq_flag = 0; //todo
|
||||||
int dmc_nonzero = 0; //todo
|
int dmc_nonzero = 0; //todo
|
||||||
int noise_nonzero = 0; //todo
|
int noise_nonzero = noise.IsLenCntNonZero() ? 1 : 0;
|
||||||
int tri_nonzero = 0; //todo
|
int tri_nonzero = 0; //todo
|
||||||
int pulse1_nonzero = pulse[1].IsLenCntNonZero() ? 1 : 0;
|
int pulse1_nonzero = pulse[1].IsLenCntNonZero() ? 1 : 0;
|
||||||
int pulse0_nonzero = pulse[0].IsLenCntNonZero() ? 1 : 0;
|
int pulse0_nonzero = pulse[0].IsLenCntNonZero() ? 1 : 0;
|
||||||
|
@ -437,11 +551,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
pulse[0].Run();
|
pulse[0].Run();
|
||||||
pulse[1].Run();
|
pulse[1].Run();
|
||||||
triangle.Run();
|
triangle.Run();
|
||||||
|
noise.Run();
|
||||||
|
|
||||||
int mix = 0;
|
int mix = 0;
|
||||||
mix += pulse[0].sample;
|
mix += pulse[0].sample;
|
||||||
mix += pulse[1].sample;
|
mix += pulse[1].sample;
|
||||||
mix += triangle.sample;
|
mix += triangle.sample;
|
||||||
|
mix += noise.sample;
|
||||||
|
|
||||||
EmitSample(mix);
|
EmitSample(mix);
|
||||||
|
|
||||||
|
@ -485,7 +601,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
double factional_remainder = (this_samp - last_hwsamp) * (1-ratio);
|
double factional_remainder = (this_samp - last_hwsamp) * (1-ratio);
|
||||||
accumulate += fractional;
|
accumulate += fractional;
|
||||||
|
|
||||||
accumulate *= 600;
|
accumulate *= 540; //32768/(15*4) -- adjust later for other sound channels
|
||||||
int outsamp = (int)(accumulate / kInvMixRate);
|
int outsamp = (int)(accumulate / kInvMixRate);
|
||||||
if (CFG_USE_METASPU)
|
if (CFG_USE_METASPU)
|
||||||
metaspu.buffer.enqueue_sample((short)outsamp, (short)outsamp);
|
metaspu.buffer.enqueue_sample((short)outsamp, (short)outsamp);
|
||||||
|
@ -502,13 +618,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo
|
||||||
if (CFG_USE_METASPU)
|
if (CFG_USE_METASPU)
|
||||||
{
|
{
|
||||||
metaspu.GetSamples(samples);
|
metaspu.GetSamples(samples);
|
||||||
//foreach(short sample in samples) bw.Write((short)sample);
|
foreach(short sample in samples) bw.Write((short)sample);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
MyGetSamples(samples);
|
MyGetSamples(samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
//static BinaryWriter bw = new BinaryWriter(File.OpenWrite("d:\\out.raw"));
|
static BinaryWriter bw = new BinaryWriter(File.OpenWrite("d:\\out.raw"));
|
||||||
void MyGetSamples(short[] samples)
|
void MyGetSamples(short[] samples)
|
||||||
{
|
{
|
||||||
//Console.WriteLine("a: {0} with todo: {1}",squeue.Count,samples.Length/2);
|
//Console.WriteLine("a: {0} with todo: {1}",squeue.Count,samples.Length/2);
|
||||||
|
|
Loading…
Reference in New Issue