|
|
|
@@ -63,10 +63,23 @@ static void nes_apu_write_square(nes_apu_Channel* channel, |
|
|
|
// TODO |
|
|
|
} |
|
|
|
|
|
|
|
static inline void apu_channel_update_timer( |
|
|
|
nes_apu_Channel *channel) { |
|
|
|
channel->period = ( |
|
|
|
channel->reg[2] | |
|
|
|
(((uint16_t)channel->reg[3] & 0x7U) << 8) |
|
|
|
) * nes_clock_cpu_div; |
|
|
|
} |
|
|
|
|
|
|
|
static void nes_apu_write_triangle(nes_apu_Channel* channel, |
|
|
|
int reg, uint8_t val) { |
|
|
|
APU_LOG("APU: Triangle %d < %02x\n", reg, val); |
|
|
|
// TODO |
|
|
|
|
|
|
|
if (2 <= reg) { |
|
|
|
channel->reg[reg] = val; |
|
|
|
apu_channel_update_timer(channel); |
|
|
|
if (3 == reg) channel->reload = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void nes_apu_write_noise(nes_apu_Channel* channel, |
|
|
|
@@ -149,7 +162,7 @@ void nes_apu_reset(nes_apu* apu) { |
|
|
|
apu->channels[chan].length = 0; |
|
|
|
} |
|
|
|
|
|
|
|
apu->channels[apu_Channel_Triangle].sample = 15; |
|
|
|
apu->channels[apu_Channel_Triangle].step = 31; |
|
|
|
apu->channels[apu_Channel_DMC].reg[1] &= 1; |
|
|
|
apu->channels[apu_Channel_DMC].sample = 0; |
|
|
|
} |
|
|
|
@@ -190,6 +203,7 @@ void nes_apu_write(nes_apu* apu, uint16_t addr, uint8_t val) { |
|
|
|
if ( chan != apu_Channel_DMC && |
|
|
|
apu->status & (1 << chan)) { |
|
|
|
channel->length = apu_length_lut[val >> 3]; |
|
|
|
// TODO: Handle Envelope vs. Triangle |
|
|
|
channel->envelope = 15; |
|
|
|
channel->env_period = (channel->reg[0] & apu_Envelope_Volume); |
|
|
|
channel->env_delay = channel->env_period; |
|
|
|
@@ -330,6 +344,49 @@ static void nes_apu_run_noise(nes_apu* apu, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static uint8_t triangle_steps[32] = { |
|
|
|
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, |
|
|
|
}; |
|
|
|
|
|
|
|
static void nes_apu_run_triangle(nes_apu* apu, |
|
|
|
nes_apu_Channel* channel, |
|
|
|
int cycles) { |
|
|
|
if ( channel->length <= 0 || |
|
|
|
channel->period <= 0 || |
|
|
|
channel->counter <= 0) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
int time = apu->time; |
|
|
|
|
|
|
|
while (cycles > 0) { |
|
|
|
int run = cycles; |
|
|
|
if (run > channel->delay) { |
|
|
|
run = channel->delay; |
|
|
|
} |
|
|
|
|
|
|
|
channel->delay -= run; |
|
|
|
time += run; |
|
|
|
|
|
|
|
if (channel->delay <= 0) { |
|
|
|
channel->delay = channel->period; |
|
|
|
|
|
|
|
channel->step = ((channel->step + 1) & 31U); |
|
|
|
|
|
|
|
channel->sample = triangle_steps[channel->step]; |
|
|
|
|
|
|
|
int delta = channel_update(channel); |
|
|
|
if (delta) { |
|
|
|
blip_add_delta(apu->blip, time, delta); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
cycles -= run; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static inline void nes_apu_clock_length(nes_apu_Channel* channel, |
|
|
|
uint8_t halt_mask) { |
|
|
|
if ( channel->length > 0 && |
|
|
|
@@ -350,6 +407,17 @@ static inline void nes_apu_clock_envelope(nes_apu_Channel* channel) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static inline void nes_apu_clock_linear(nes_apu_Channel* channel) { |
|
|
|
if (channel->reload) { |
|
|
|
channel->counter = (channel->reg[0] & apu_Triangle_Count); |
|
|
|
} else if (channel->counter > 0) { |
|
|
|
channel->counter--; |
|
|
|
} |
|
|
|
if (!(channel->reg[0] & apu_Triangle_Halt)) { |
|
|
|
channel->reload = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
nes_apu_Result nes_apu_run(nes_apu* apu, int cycles) { |
|
|
|
nes_apu_run_dmc(apu, &apu->channels[apu_Channel_DMC], cycles); |
|
|
|
|
|
|
|
@@ -363,11 +431,13 @@ nes_apu_Result nes_apu_run(nes_apu* apu, int cycles) { |
|
|
|
apu->blip, run); |
|
|
|
nes_apu_run_square(&apu->channels[apu_Channel_Square_1], |
|
|
|
apu->blip, run); |
|
|
|
nes_apu_run_triangle(&apu->channels[apu_Channel_Triangle], |
|
|
|
apu->blip, run); |
|
|
|
*/ |
|
|
|
nes_apu_run_noise(apu, &apu->channels[apu_Channel_Noise], |
|
|
|
run); |
|
|
|
nes_apu_run_triangle( |
|
|
|
apu, &apu->channels[apu_Channel_Triangle], run |
|
|
|
); |
|
|
|
nes_apu_run_noise( |
|
|
|
apu, &apu->channels[apu_Channel_Noise], run |
|
|
|
); |
|
|
|
|
|
|
|
apu->frame_delay -= run; |
|
|
|
|
|
|
|
@@ -400,8 +470,8 @@ nes_apu_Result nes_apu_run(nes_apu* apu, int cycles) { |
|
|
|
/* |
|
|
|
nes_apu_clock_length(&apu->channels[apu_Channel_Square_0], apu_Envelope_Halt); |
|
|
|
nes_apu_clock_length(&apu->channels[apu_Channel_Square_1], apu_Envelope_Halt); |
|
|
|
nes_apu_clock_length(&apu->channels[apu_Channel_Triangle], apu_Triangle_Halt); |
|
|
|
*/ |
|
|
|
nes_apu_clock_length(&apu->channels[apu_Channel_Triangle], apu_Triangle_Halt); |
|
|
|
nes_apu_clock_length(&apu->channels[apu_Channel_Noise], apu_Envelope_Halt); |
|
|
|
/* |
|
|
|
nes_apu_clock_sweep(&apu->channels[apu_Channel_Square_0], -1); |
|
|
|
@@ -415,9 +485,7 @@ nes_apu_Result nes_apu_run(nes_apu* apu, int cycles) { |
|
|
|
nes_apu_clock_envelope(&apu->channels[apu_Channel_Square_1]); |
|
|
|
*/ |
|
|
|
nes_apu_clock_envelope(&apu->channels[apu_Channel_Noise]); |
|
|
|
/* |
|
|
|
nes_apu_clock_linear(&apu->channels[apu_Channel_Triangle]); |
|
|
|
*/ |
|
|
|
} |
|
|
|
|
|
|
|
if (end) { |
|
|
|
|