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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user