mirror of https://github.com/bsnes-emu/bsnes.git
Added highpass filter
This commit is contained in:
parent
ca59aca4a6
commit
d04aaddcbd
57
Core/apu.c
57
Core/apu.c
|
@ -62,10 +62,46 @@ static void render(GB_gameboy_t *gb)
|
|||
gb->apu_output.cycles_since_render = 0;
|
||||
|
||||
|
||||
|
||||
GB_sample_t filtered_output = gb->apu_output.highpass_mode?
|
||||
(GB_sample_t) {output.left - gb->apu_output.highpass_diff.left,
|
||||
output.right - gb->apu_output.highpass_diff.right} :
|
||||
output;
|
||||
|
||||
switch (gb->apu_output.highpass_mode) {
|
||||
case GB_HIGHPASS_OFF:
|
||||
gb->apu_output.highpass_diff = (GB_double_sample_t) {0, 0};
|
||||
break;
|
||||
case GB_HIGHPASS_ACCURATE:
|
||||
gb->apu_output.highpass_diff = (GB_double_sample_t)
|
||||
{output.left - filtered_output.left * gb->apu_output.highpass_rate,
|
||||
output.right - filtered_output.right * gb->apu_output.highpass_rate};
|
||||
break;
|
||||
case GB_HIGHPASS_REMOVE_DC_OFFSET: {
|
||||
unsigned mask = gb->io_registers[GB_IO_NR51];
|
||||
unsigned left_volume = 0;
|
||||
unsigned right_volume = 0;
|
||||
for (unsigned i = GB_N_CHANNELS; i--;) {
|
||||
if (mask & 1) {
|
||||
left_volume += (gb->io_registers[GB_IO_NR50] & 7) * CH_STEP * 0xF;
|
||||
}
|
||||
if (mask & 0x10) {
|
||||
right_volume += ((gb->io_registers[GB_IO_NR50] >> 4) & 7) * CH_STEP * 0xF;
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
gb->apu_output.highpass_diff = (GB_double_sample_t)
|
||||
{left_volume * (1 - gb->apu_output.highpass_rate) + gb->apu_output.highpass_diff.left * gb->apu_output.highpass_rate,
|
||||
right_volume * (1 - gb->apu_output.highpass_rate) + gb->apu_output.highpass_diff.right * gb->apu_output.highpass_rate};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
while (gb->apu_output.copy_in_progress);
|
||||
while (!__sync_bool_compare_and_swap(&gb->apu_output.lock, false, true));
|
||||
if (gb->apu_output.buffer_position < gb->apu_output.buffer_size) {
|
||||
gb->apu_output.buffer[gb->apu_output.buffer_position++] = output;
|
||||
gb->apu_output.buffer[gb->apu_output.buffer_position++] = filtered_output;
|
||||
}
|
||||
gb->apu_output.lock = false;
|
||||
}
|
||||
|
@ -712,3 +748,22 @@ size_t GB_apu_get_current_buffer_length(GB_gameboy_t *gb)
|
|||
{
|
||||
return gb->apu_output.buffer_position;
|
||||
}
|
||||
|
||||
void GB_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate)
|
||||
{
|
||||
if (gb->apu_output.buffer) {
|
||||
free(gb->apu_output.buffer);
|
||||
}
|
||||
gb->apu_output.buffer_size = sample_rate / 25; // 40ms delay
|
||||
gb->apu_output.buffer = malloc(gb->apu_output.buffer_size * sizeof(*gb->apu_output.buffer));
|
||||
gb->apu_output.sample_rate = sample_rate;
|
||||
gb->apu_output.buffer_position = 0;
|
||||
if (sample_rate) {
|
||||
gb->apu_output.highpass_rate = pow(0.999958, CPU_FREQUENCY / (double)sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
void GB_set_highpass_filter_mode(GB_gameboy_t *gb, GB_highpass_mode_t mode)
|
||||
{
|
||||
gb->apu_output.highpass_mode = mode;
|
||||
}
|
||||
|
|
17
Core/apu.h
17
Core/apu.h
|
@ -19,6 +19,12 @@ typedef struct
|
|||
int16_t right;
|
||||
} GB_sample_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double left;
|
||||
double right;
|
||||
} GB_double_sample_t;
|
||||
|
||||
enum GB_CHANNELS {
|
||||
GB_SQUARE_1,
|
||||
GB_SQUARE_2,
|
||||
|
@ -90,6 +96,12 @@ typedef struct
|
|||
|
||||
} GB_apu_t;
|
||||
|
||||
typedef enum {
|
||||
GB_HIGHPASS_OFF, // Do not apply any filter, keep DC offset
|
||||
GB_HIGHPASS_ACCURATE, // Apply a highpass filter similar to the one used on hardware
|
||||
GB_HIGHPASS_REMOVE_DC_OFFSET, // Remove DC Offset without affecting the waveform
|
||||
} GB_highpass_mode_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned sample_rate;
|
||||
|
||||
|
@ -108,11 +120,16 @@ typedef struct {
|
|||
unsigned last_update[GB_N_CHANNELS];
|
||||
GB_sample_t current_sample[GB_N_CHANNELS];
|
||||
GB_sample_t summed_samples[GB_N_CHANNELS];
|
||||
|
||||
GB_highpass_mode_t highpass_mode;
|
||||
double highpass_rate;
|
||||
GB_double_sample_t highpass_diff;
|
||||
} GB_apu_output_t;
|
||||
|
||||
void GB_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate);
|
||||
void GB_apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, size_t count);
|
||||
size_t GB_apu_get_current_buffer_length(GB_gameboy_t *gb);
|
||||
void GB_set_highpass_filter_mode(GB_gameboy_t *gb, GB_highpass_mode_t mode);
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value);
|
||||
|
|
12
Core/gb.c
12
Core/gb.c
|
@ -386,17 +386,6 @@ void GB_serial_set_data(GB_gameboy_t *gb, uint8_t data)
|
|||
gb->io_registers[GB_IO_IF] |= 8;
|
||||
}
|
||||
|
||||
void GB_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate)
|
||||
{
|
||||
if (gb->apu_output.buffer) {
|
||||
free(gb->apu_output.buffer);
|
||||
}
|
||||
gb->apu_output.buffer_size = sample_rate / 25; // 40ms delay
|
||||
gb->apu_output.buffer = malloc(gb->apu_output.buffer_size * sizeof(*gb->apu_output.buffer));
|
||||
gb->apu_output.sample_rate = sample_rate;
|
||||
gb->apu_output.buffer_position = 0;
|
||||
}
|
||||
|
||||
void GB_disconnect_serial(GB_gameboy_t *gb)
|
||||
{
|
||||
gb->serial_transfer_start_callback = NULL;
|
||||
|
@ -495,7 +484,6 @@ void GB_switch_model_and_reset(GB_gameboy_t *gb, bool is_cgb)
|
|||
}
|
||||
gb->is_cgb = is_cgb;
|
||||
GB_reset(gb);
|
||||
|
||||
}
|
||||
|
||||
void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *size, uint16_t *bank)
|
||||
|
|
Loading…
Reference in New Issue