Bläddra i källkod

Complete APU triangle channel

master
Nathaniel Walizer 11 månader sedan
förälder
incheckning
10cb978bc3
2 ändrade filer med 85 tillägg och 11 borttagningar
  1. +77
    -9
      src/apu.c
  2. +8
    -2
      src/apu.h

+ 77
- 9
src/apu.c Visa fil

@@ -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) {


+ 8
- 2
src/apu.h Visa fil

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

uint16_t period; // Noise, DMC
uint16_t period;

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


Laddar…
Avbryt
Spara