Browse Source

Complete APU triangle channel

master
Nathaniel Walizer 11 months ago
parent
commit
10cb978bc3
2 changed files with 85 additions and 11 deletions
  1. +77
    -9
      src/apu.c
  2. +8
    -2
      src/apu.h

+ 77
- 9
src/apu.c View File

@@ -63,10 +63,23 @@ static void nes_apu_write_square(nes_apu_Channel* channel,
// TODO // 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, static void nes_apu_write_triangle(nes_apu_Channel* channel,
int reg, uint8_t val) { int reg, uint8_t val) {
APU_LOG("APU: Triangle %d < %02x\n", reg, 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, 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[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].reg[1] &= 1;
apu->channels[apu_Channel_DMC].sample = 0; 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 && if ( chan != apu_Channel_DMC &&
apu->status & (1 << chan)) { apu->status & (1 << chan)) {
channel->length = apu_length_lut[val >> 3]; channel->length = apu_length_lut[val >> 3];
// TODO: Handle Envelope vs. Triangle
channel->envelope = 15; channel->envelope = 15;
channel->env_period = (channel->reg[0] & apu_Envelope_Volume); channel->env_period = (channel->reg[0] & apu_Envelope_Volume);
channel->env_delay = channel->env_period; 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, static inline void nes_apu_clock_length(nes_apu_Channel* channel,
uint8_t halt_mask) { uint8_t halt_mask) {
if ( channel->length > 0 && 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_Result nes_apu_run(nes_apu* apu, int cycles) {
nes_apu_run_dmc(apu, &apu->channels[apu_Channel_DMC], 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); apu->blip, run);
nes_apu_run_square(&apu->channels[apu_Channel_Square_1], nes_apu_run_square(&apu->channels[apu_Channel_Square_1],
apu->blip, run); 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; 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_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_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_length(&apu->channels[apu_Channel_Noise], apu_Envelope_Halt);
/* /*
nes_apu_clock_sweep(&apu->channels[apu_Channel_Square_0], -1); 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_Square_1]);
*/ */
nes_apu_clock_envelope(&apu->channels[apu_Channel_Noise]); nes_apu_clock_envelope(&apu->channels[apu_Channel_Noise]);
/*
nes_apu_clock_linear(&apu->channels[apu_Channel_Triangle]); nes_apu_clock_linear(&apu->channels[apu_Channel_Triangle]);
*/
} }


if (end) { if (end) {


+ 8
- 2
src/apu.h View File

@@ -89,10 +89,10 @@ typedef struct nes_apu_Channel_t {
int sample; // Current sample int sample; // Current sample
int output; // Last output (sample * gain) int output; // Last output (sample * gain)


uint16_t period; // Noise, DMC
uint16_t period;


union { union {
// Square/Triangle/Noise
// Square/Noise
struct { struct {
int phase; int phase;
int sweep; int sweep;
@@ -101,6 +101,12 @@ typedef struct nes_apu_Channel_t {
uint8_t env_delay; uint8_t env_delay;
uint16_t lfsr; uint16_t lfsr;
}; };
// Triangle
struct {
uint8_t step;
uint8_t reload;
uint8_t counter;
};
// DMC // DMC
struct { struct {
uint8_t interrupt; uint8_t interrupt;


Loading…
Cancel
Save