APU is now being run lazily

This commit is contained in:
Lior Halphon 2016-09-13 17:33:48 +03:00
parent eefc998e43
commit 594aea2d5a
3 changed files with 65 additions and 58 deletions

View File

@ -58,60 +58,6 @@ static int16_t step_lfsr(uint16_t lfsr, bool uses_7_bit)
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
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)
{
if (gb->sample_rate == 0) return;
static bool should_log_overflow = true;
while (gb->audio_copy_in_progress);
double ticks_per_sample = (double) CPU_FREQUENCY / gb->sample_rate;
GB_apu_run_internal(gb);
if (gb->apu_sample_cycles > ticks_per_sample) {
gb->apu_sample_cycles -= ticks_per_sample;
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)
{
/* Todo: what happens when reading from the wave from while it's playing? */
GB_apu_run_internal(gb);
if (reg == GB_IO_NR52) {
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)
{
GB_apu_run_internal(gb);
static const uint8_t duties[] = {1, 2, 4, 6}; /* Values are in 1/8 */
uint8_t channel = 0;

View File

@ -491,7 +491,7 @@ void GB_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate)
free(gb->audio_buffer);
}
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->audio_position = 0;
}

View File

@ -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_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_HDMA2:
case GB_IO_HDMA3: