APU is now being run lazily
This commit is contained in:
parent
eefc998e43
commit
594aea2d5a
116
Core/apu.c
116
Core/apu.c
@ -58,60 +58,6 @@ static int16_t step_lfsr(uint16_t lfsr, bool uses_7_bit)
|
|||||||
return lfsr;
|
return lfsr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GB_apu_get_samples_and_update_pcm_regs(GB_gameboy_t *gb, GB_sample_t *samples)
|
|
||||||
{
|
|
||||||
samples->left = samples->right = 0;
|
|
||||||
if (!gb->apu.global_enable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gb->io_registers[GB_IO_PCM_12] = 0;
|
|
||||||
gb->io_registers[GB_IO_PCM_34] = 0;
|
|
||||||
|
|
||||||
{
|
|
||||||
int16_t sample = generate_square(gb->apu.wave_channels[0].phase,
|
|
||||||
gb->apu.wave_channels[0].wave_length,
|
|
||||||
gb->apu.wave_channels[0].amplitude,
|
|
||||||
gb->apu.wave_channels[0].duty);
|
|
||||||
if (gb->apu.wave_channels[0].left_on ) samples->left += sample;
|
|
||||||
if (gb->apu.wave_channels[0].right_on) samples->right += sample;
|
|
||||||
gb->io_registers[GB_IO_PCM_12] = ((int)sample) * 0xF / MAX_CH_AMP;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
int16_t sample = generate_square(gb->apu.wave_channels[1].phase,
|
|
||||||
gb->apu.wave_channels[1].wave_length,
|
|
||||||
gb->apu.wave_channels[1].amplitude,
|
|
||||||
gb->apu.wave_channels[1].duty);
|
|
||||||
if (gb->apu.wave_channels[1].left_on ) samples->left += sample;
|
|
||||||
if (gb->apu.wave_channels[1].right_on) samples->right += sample;
|
|
||||||
gb->io_registers[GB_IO_PCM_12] |= (((int)sample) * 0xF / MAX_CH_AMP) << 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gb->apu.wave_enable)
|
|
||||||
{
|
|
||||||
int16_t sample = generate_wave(gb->apu.wave_channels[2].phase,
|
|
||||||
gb->apu.wave_channels[2].wave_length,
|
|
||||||
MAX_CH_AMP,
|
|
||||||
gb->apu.wave_form,
|
|
||||||
gb->apu.wave_shift);
|
|
||||||
if (gb->apu.wave_channels[2].left_on ) samples->left += sample;
|
|
||||||
if (gb->apu.wave_channels[2].right_on) samples->right += sample;
|
|
||||||
gb->io_registers[GB_IO_PCM_34] = ((int)sample) * 0xF / MAX_CH_AMP;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
int16_t sample = generate_noise(gb->apu.wave_channels[3].amplitude,
|
|
||||||
gb->apu.lfsr);
|
|
||||||
if (gb->apu.wave_channels[3].left_on ) samples->left += sample;
|
|
||||||
if (gb->apu.wave_channels[3].right_on) samples->right += sample;
|
|
||||||
gb->io_registers[GB_IO_PCM_34] |= (((int)sample) * 0xF / MAX_CH_AMP) << 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
samples->left *= gb->apu.left_volume;
|
|
||||||
samples->right *= gb->apu.right_volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* General Todo: The APU emulation seems to fail many accuracy tests. It might require a rewrite with
|
/* General Todo: The APU emulation seems to fail many accuracy tests. It might require a rewrite with
|
||||||
these tests in mind. */
|
these tests in mind. */
|
||||||
|
|
||||||
@ -177,14 +123,69 @@ static void GB_apu_run_internal(GB_gameboy_t *gb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GB_apu_get_samples_and_update_pcm_regs(GB_gameboy_t *gb, GB_sample_t *samples)
|
||||||
|
{
|
||||||
|
GB_apu_run_internal(gb);
|
||||||
|
|
||||||
|
samples->left = samples->right = 0;
|
||||||
|
if (!gb->apu.global_enable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb->io_registers[GB_IO_PCM_12] = 0;
|
||||||
|
gb->io_registers[GB_IO_PCM_34] = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
int16_t sample = generate_square(gb->apu.wave_channels[0].phase,
|
||||||
|
gb->apu.wave_channels[0].wave_length,
|
||||||
|
gb->apu.wave_channels[0].amplitude,
|
||||||
|
gb->apu.wave_channels[0].duty);
|
||||||
|
if (gb->apu.wave_channels[0].left_on ) samples->left += sample;
|
||||||
|
if (gb->apu.wave_channels[0].right_on) samples->right += sample;
|
||||||
|
gb->io_registers[GB_IO_PCM_12] = ((int)sample) * 0xF / MAX_CH_AMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int16_t sample = generate_square(gb->apu.wave_channels[1].phase,
|
||||||
|
gb->apu.wave_channels[1].wave_length,
|
||||||
|
gb->apu.wave_channels[1].amplitude,
|
||||||
|
gb->apu.wave_channels[1].duty);
|
||||||
|
if (gb->apu.wave_channels[1].left_on ) samples->left += sample;
|
||||||
|
if (gb->apu.wave_channels[1].right_on) samples->right += sample;
|
||||||
|
gb->io_registers[GB_IO_PCM_12] |= (((int)sample) * 0xF / MAX_CH_AMP) << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gb->apu.wave_enable)
|
||||||
|
{
|
||||||
|
int16_t sample = generate_wave(gb->apu.wave_channels[2].phase,
|
||||||
|
gb->apu.wave_channels[2].wave_length,
|
||||||
|
MAX_CH_AMP,
|
||||||
|
gb->apu.wave_form,
|
||||||
|
gb->apu.wave_shift);
|
||||||
|
if (gb->apu.wave_channels[2].left_on ) samples->left += sample;
|
||||||
|
if (gb->apu.wave_channels[2].right_on) samples->right += sample;
|
||||||
|
gb->io_registers[GB_IO_PCM_34] = ((int)sample) * 0xF / MAX_CH_AMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int16_t sample = generate_noise(gb->apu.wave_channels[3].amplitude,
|
||||||
|
gb->apu.lfsr);
|
||||||
|
if (gb->apu.wave_channels[3].left_on ) samples->left += sample;
|
||||||
|
if (gb->apu.wave_channels[3].right_on) samples->right += sample;
|
||||||
|
gb->io_registers[GB_IO_PCM_34] |= (((int)sample) * 0xF / MAX_CH_AMP) << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
samples->left *= gb->apu.left_volume;
|
||||||
|
samples->right *= gb->apu.right_volume;
|
||||||
|
}
|
||||||
|
|
||||||
void GB_apu_run(GB_gameboy_t *gb)
|
void GB_apu_run(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
|
if (gb->sample_rate == 0) return;
|
||||||
static bool should_log_overflow = true;
|
static bool should_log_overflow = true;
|
||||||
while (gb->audio_copy_in_progress);
|
while (gb->audio_copy_in_progress);
|
||||||
double ticks_per_sample = (double) CPU_FREQUENCY / gb->sample_rate;
|
double ticks_per_sample = (double) CPU_FREQUENCY / gb->sample_rate;
|
||||||
|
|
||||||
GB_apu_run_internal(gb);
|
|
||||||
|
|
||||||
if (gb->apu_sample_cycles > ticks_per_sample) {
|
if (gb->apu_sample_cycles > ticks_per_sample) {
|
||||||
gb->apu_sample_cycles -= ticks_per_sample;
|
gb->apu_sample_cycles -= ticks_per_sample;
|
||||||
if (gb->audio_position == gb->buffer_size) {
|
if (gb->audio_position == gb->buffer_size) {
|
||||||
@ -239,6 +240,7 @@ void GB_apu_init(GB_gameboy_t *gb)
|
|||||||
uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg)
|
uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg)
|
||||||
{
|
{
|
||||||
/* Todo: what happens when reading from the wave from while it's playing? */
|
/* Todo: what happens when reading from the wave from while it's playing? */
|
||||||
|
GB_apu_run_internal(gb);
|
||||||
|
|
||||||
if (reg == GB_IO_NR52) {
|
if (reg == GB_IO_NR52) {
|
||||||
uint8_t value = 0;
|
uint8_t value = 0;
|
||||||
@ -277,6 +279,8 @@ uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg)
|
|||||||
|
|
||||||
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
|
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
|
||||||
{
|
{
|
||||||
|
GB_apu_run_internal(gb);
|
||||||
|
|
||||||
static const uint8_t duties[] = {1, 2, 4, 6}; /* Values are in 1/8 */
|
static const uint8_t duties[] = {1, 2, 4, 6}; /* Values are in 1/8 */
|
||||||
uint8_t channel = 0;
|
uint8_t channel = 0;
|
||||||
|
|
||||||
|
@ -491,7 +491,7 @@ void GB_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate)
|
|||||||
free(gb->audio_buffer);
|
free(gb->audio_buffer);
|
||||||
}
|
}
|
||||||
gb->buffer_size = sample_rate / 25; // 40ms delay
|
gb->buffer_size = sample_rate / 25; // 40ms delay
|
||||||
gb->audio_buffer = malloc((gb->buffer_size + 1) * sizeof(*gb->audio_buffer));
|
gb->audio_buffer = malloc(gb->buffer_size * sizeof(*gb->audio_buffer));
|
||||||
gb->sample_rate = sample_rate;
|
gb->sample_rate = sample_rate;
|
||||||
gb->audio_position = 0;
|
gb->audio_position = 0;
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,10 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
|||||||
|
|
||||||
case GB_IO_PCM_12:
|
case GB_IO_PCM_12:
|
||||||
case GB_IO_PCM_34:
|
case GB_IO_PCM_34:
|
||||||
GB_apu_get_samples_and_update_pcm_regs(gb, &gb->audio_buffer[gb->audio_position]);
|
{
|
||||||
|
GB_sample_t dummy;
|
||||||
|
GB_apu_get_samples_and_update_pcm_regs(gb, &dummy);
|
||||||
|
}
|
||||||
case GB_IO_HDMA1:
|
case GB_IO_HDMA1:
|
||||||
case GB_IO_HDMA2:
|
case GB_IO_HDMA2:
|
||||||
case GB_IO_HDMA3:
|
case GB_IO_HDMA3:
|
||||||
|
Loading…
Reference in New Issue
Block a user