mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-02 01:02:36 +02:00
Fix rounding errors in calls to band_limited_update, tweak BL synth parameters. Should greatly improve audio quality, fixes #713
This commit is contained in:
30
Core/apu.c
30
Core/apu.c
@@ -105,6 +105,15 @@ static void band_limited_read(GB_band_limited_t *band_limited, GB_sample_t *outp
|
||||
output->right = band_limited->output.right * multiplier / GB_BAND_LIMITED_ONE;
|
||||
}
|
||||
|
||||
static inline uint32_t sample_fraction_multiply(GB_gameboy_t *gb, unsigned multiplier)
|
||||
{
|
||||
if (unlikely(multiplier == 0)) return 0;
|
||||
if (likely(multiplier < GB_QUICK_MULTIPLY_COUNT + 1)) {
|
||||
return gb->apu_output.quick_fraction_multiply_cache[multiplier - 1];
|
||||
}
|
||||
return gb->apu_output.quick_fraction_multiply_cache[0] * multiplier;
|
||||
}
|
||||
|
||||
static const uint8_t duties[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 1,
|
||||
@@ -196,7 +205,7 @@ static void update_sample(GB_gameboy_t *gb, GB_channel_t index, int8_t value, un
|
||||
else {
|
||||
band_limited_update(&gb->apu_output.band_limited[index],
|
||||
&output,
|
||||
(gb->apu_output.cycles_since_render + cycles_offset) * GB_BAND_LIMITED_PHASES / gb->apu_output.max_cycles_per_sample);
|
||||
(((gb->apu_output.sample_fraction + sample_fraction_multiply(gb, cycles_offset)) >> 8) * GB_BAND_LIMITED_PHASES) >> 20);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +240,7 @@ static void update_sample(GB_gameboy_t *gb, GB_channel_t index, int8_t value, un
|
||||
else {
|
||||
band_limited_update(&gb->apu_output.band_limited[index],
|
||||
&output,
|
||||
(gb->apu_output.cycles_since_render + cycles_offset) * GB_BAND_LIMITED_PHASES / gb->apu_output.max_cycles_per_sample);
|
||||
(((gb->apu_output.sample_fraction + sample_fraction_multiply(gb, cycles_offset)) >> 8) * GB_BAND_LIMITED_PHASES) >> 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,6 +325,12 @@ static void render(GB_gameboy_t *gb)
|
||||
output.right += channel_output.right;
|
||||
}
|
||||
gb->apu_output.cycles_since_render = 0;
|
||||
if (unlikely(gb->apu_output.sample_fraction < (1 << 28))) {
|
||||
gb->apu_output.sample_fraction = 0;
|
||||
}
|
||||
else {
|
||||
gb->apu_output.sample_fraction -= 1 << 28;
|
||||
}
|
||||
|
||||
if (gb->sgb && gb->sgb->intro_animation < GB_SGB_INTRO_ANIMATION_LENGTH) return;
|
||||
|
||||
@@ -973,6 +988,8 @@ restart:;
|
||||
|
||||
if (gb->apu_output.sample_rate) {
|
||||
gb->apu_output.cycles_since_render += cycles;
|
||||
gb->apu_output.sample_fraction += sample_fraction_multiply(gb, cycles);
|
||||
assert(gb->apu_output.sample_fraction < (4 << 28));
|
||||
|
||||
if (gb->apu_output.sample_cycles >= clock_rate) {
|
||||
gb->apu_output.sample_cycles -= clock_rate;
|
||||
@@ -1769,6 +1786,10 @@ void GB_set_sample_rate(GB_gameboy_t *gb, unsigned sample_rate)
|
||||
if (sample_rate) {
|
||||
gb->apu_output.highpass_rate = pow(0.999958, GB_get_clock_rate(gb) / (double)sample_rate);
|
||||
gb->apu_output.max_cycles_per_sample = ceil(GB_get_clock_rate(gb) / 2.0 / sample_rate);
|
||||
gb->apu_output.quick_fraction_multiply_cache[0] = round(sample_rate * 2.0 / GB_get_clock_rate(gb) * (1 << 28));
|
||||
for (unsigned i = 1; i < GB_QUICK_MULTIPLY_COUNT; i++) {
|
||||
gb->apu_output.quick_fraction_multiply_cache[i] = gb->apu_output.quick_fraction_multiply_cache[0] * (i + 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gb->apu_output.max_cycles_per_sample = 0x400;
|
||||
@@ -1785,6 +1806,11 @@ void GB_set_sample_rate_by_clocks(GB_gameboy_t *gb, double cycles_per_sample)
|
||||
gb->apu_output.sample_rate = GB_get_clock_rate(gb) / cycles_per_sample * 2;
|
||||
gb->apu_output.highpass_rate = pow(0.999958, cycles_per_sample);
|
||||
gb->apu_output.max_cycles_per_sample = ceil(cycles_per_sample / 4);
|
||||
|
||||
gb->apu_output.quick_fraction_multiply_cache[0] = round(gb->apu_output.sample_rate * 2.0 / GB_get_clock_rate(gb) * (1 << 28));
|
||||
for (unsigned i = 1; i < GB_QUICK_MULTIPLY_COUNT; i++) {
|
||||
gb->apu_output.quick_fraction_multiply_cache[i] = gb->apu_output.quick_fraction_multiply_cache[0] * (i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned GB_get_sample_rate(GB_gameboy_t *gb)
|
||||
|
@@ -5,8 +5,10 @@
|
||||
#include <stdio.h>
|
||||
#include "defs.h"
|
||||
|
||||
#define GB_BAND_LIMITED_WIDTH 32
|
||||
#define GB_BAND_LIMITED_PHASES 512
|
||||
#define GB_BAND_LIMITED_WIDTH 64
|
||||
#define GB_BAND_LIMITED_PHASES 256
|
||||
|
||||
#define GB_QUICK_MULTIPLY_COUNT 64
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
#define GB_BAND_LIMITED_ONE 0x10000 // fixed point value equal to 1
|
||||
@@ -180,6 +182,9 @@ typedef struct {
|
||||
unsigned max_cycles_per_sample;
|
||||
|
||||
uint32_t cycles_since_render;
|
||||
uint32_t sample_fraction; // Counter in 1 / sample_rate, in 4.28 fixed format
|
||||
uint32_t quick_fraction_multiply_cache[GB_QUICK_MULTIPLY_COUNT];
|
||||
|
||||
GB_band_limited_t band_limited[GB_N_CHANNELS];
|
||||
double dac_discharge[GB_N_CHANNELS];
|
||||
bool channel_muted[GB_N_CHANNELS];
|
||||
|
Reference in New Issue
Block a user