diff --git a/Core/apu.c b/Core/apu.c index e0e0b89..1cd038a 100755 --- a/Core/apu.c +++ b/Core/apu.c @@ -3,243 +3,72 @@ #include #include "gb.h" -#undef max -#define max(a,b) \ -({ __typeof__ (a) _a = (a); \ -__typeof__ (b) _b = (b); \ -_a > _b ? _a : _b; }) +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) -#undef min -#define min(a,b) \ -({ __typeof__ (a) _a = (a); \ -__typeof__ (b) _b = (b); \ -_a < _b ? _a : _b; }) - -#define APU_FREQUENCY 0x80000 - -static int16_t generate_square(uint64_t phase, uint32_t wave_length, int16_t amplitude, uint8_t duty) +static void update_sample(GB_gameboy_t *gb, unsigned index, uint8_t value) { - if (!wave_length) return 0; - if (phase % wave_length > wave_length * duty / 8) { - return amplitude; - } - return 0; + gb->apu.samples[index] = value; } -static int16_t generate_wave(uint64_t phase, uint32_t wave_length, int16_t amplitude, int8_t *wave, uint8_t shift) +void GB_apu_div_event(GB_gameboy_t *gb) { - if (!wave_length) wave_length = 1; - phase = phase % wave_length; - return ((wave[(int)(phase * 32 / wave_length)]) >> shift) * (int)amplitude / 0xF; -} - -static int16_t generate_noise(int16_t amplitude, uint16_t lfsr) -{ - if (lfsr & 1) { - return amplitude; - } - return 0; -} - -static int16_t step_lfsr(uint16_t lfsr, bool uses_7_bit) -{ - bool xor = (lfsr & 1) ^ ((lfsr & 2) >> 1); - lfsr >>= 1; - if (xor) { - lfsr |= 0x4000; - } - if (uses_7_bit) { - lfsr &= ~0x40; - if (xor) { - lfsr |= 0x40; + if (gb->apu.is_active[GB_WAVE] && gb->apu.wave_channel.length_enabled) { + if (gb->apu.wave_channel.pulse_length) { + gb->apu.wave_channel.pulse_length--; + } + else { + gb->apu.is_active[GB_WAVE] = false; + gb->apu.wave_channel.current_sample = 0; + update_sample(gb, GB_WAVE, 0); } } - return lfsr; } -/* General Todo: The APU emulation seems to fail many accuracy tests. It might require a rewrite with - these tests in mind. */ - -static void GB_apu_run_internal(GB_gameboy_t *gb) +static void render(GB_gameboy_t *gb) { + while (gb->audio_copy_in_progress); while (!__sync_bool_compare_and_swap(&gb->apu_lock, false, true)); - uint32_t steps = gb->apu.apu_cycles / (CPU_FREQUENCY/APU_FREQUENCY); - if (!steps) goto exit; - - gb->apu.apu_cycles %= (CPU_FREQUENCY/APU_FREQUENCY); - for (uint8_t i = 0; i < 4; i++) { - /* Phase */ - gb->apu.wave_channels[i].phase += steps; - while (gb->apu.wave_channels[i].wave_length && gb->apu.wave_channels[i].phase >= gb->apu.wave_channels[i].wave_length) { - if (i == 3) { - gb->apu.lfsr = step_lfsr(gb->apu.lfsr, gb->apu.lfsr_7_bit); - } - - gb->apu.wave_channels[i].phase -= gb->apu.wave_channels[i].wave_length; - } - /* Stop on Length */ - if (gb->apu.wave_channels[i].stop_on_length) { - if (gb->apu.wave_channels[i].sound_length > 0) { - gb->apu.wave_channels[i].sound_length -= steps; - } - if (gb->apu.wave_channels[i].sound_length <= 0) { - gb->apu.wave_channels[i].amplitude = 0; - gb->apu.wave_channels[i].is_playing = false; - gb->apu.wave_channels[i].sound_length = i == 2? APU_FREQUENCY : APU_FREQUENCY / 4; - } - } + if (gb->audio_position >= gb->buffer_size) { + gb->apu_lock = false; + return; } - - gb->apu.envelope_step_timer += steps; - while (gb->apu.envelope_step_timer >= APU_FREQUENCY / 64) { - gb->apu.envelope_step_timer -= APU_FREQUENCY / 64; - for (uint8_t i = 0; i < 4; i++) { - if (gb->apu.wave_channels[i].envelope_steps && !--gb->apu.wave_channels[i].cur_envelope_steps) { - gb->apu.wave_channels[i].amplitude = min(max(gb->apu.wave_channels[i].amplitude + gb->apu.wave_channels[i].envelope_direction * CH_STEP, 0), MAX_CH_AMP); - gb->apu.wave_channels[i].cur_envelope_steps = gb->apu.wave_channels[i].envelope_steps; - } - } - } - - gb->apu.sweep_step_timer += steps; - while (gb->apu.sweep_step_timer >= APU_FREQUENCY / 128) { - gb->apu.sweep_step_timer -= APU_FREQUENCY / 128; - if (gb->apu.wave_channels[0].sweep_steps && !--gb->apu.wave_channels[0].cur_sweep_steps) { - - // Convert back to GB format - uint16_t temp = 2048 - gb->apu.wave_channels[0].wave_length / (APU_FREQUENCY / 131072); - - // Apply sweep - temp = temp + gb->apu.wave_channels[0].sweep_direction * - (temp / (1 << gb->apu.wave_channels[0].sweep_shift)); - if (temp > 2047) { - temp = 0; - } - - // Back to frequency - gb->apu.wave_channels[0].wave_length = (2048 - temp) * (APU_FREQUENCY / 131072); - - - gb->apu.wave_channels[0].cur_sweep_steps = gb->apu.wave_channels[0].sweep_steps; - } - } -exit: + gb->audio_buffer[gb->audio_position++] = (GB_sample_t) {gb->apu.samples[GB_WAVE] * CH_STEP, + gb->apu.samples[GB_WAVE] * CH_STEP}; gb->apu_lock = false; } -void GB_apu_get_samples_and_update_pcm_regs(GB_gameboy_t *gb, GB_sample_t *samples) +void GB_apu_run(GB_gameboy_t *gb, uint8_t cycles) { - GB_apu_run_internal(gb); - - samples->left = samples->right = 0; - if (!gb->apu.global_enable) { - return; + /* Convert 4MHZ to 2MHz. cycles is always even. */ + cycles >>= 1; + + double cycles_per_sample = gb->sample_rate ? CPU_FREQUENCY / (double)gb->sample_rate : 0; // TODO: this should be cached! + + if (gb->sample_rate && gb->apu_sample_cycles > cycles_per_sample) { + gb->apu_sample_cycles -= cycles_per_sample; + render(gb); } - - 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_channels[2].is_playing) - { - 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 = (int) samples->left * gb->apu.left_volume / 7; - samples->right = (int) samples->right * gb->apu.right_volume / 7; -} - -void GB_apu_run(GB_gameboy_t *gb) -{ - if (gb->sample_rate == 0) { - if (gb->apu.apu_cycles > 0xFF00) { - GB_sample_t dummy; - GB_apu_get_samples_and_update_pcm_regs(gb, &dummy); + + gb->apu.wave_channel.wave_form_just_read = false; + if (gb->apu.is_active[GB_WAVE]) { + uint8_t cycles_left = cycles; + while (unlikely(cycles_left > gb->apu.wave_channel.sample_countdown)) { + cycles_left -= gb->apu.wave_channel.sample_countdown + 1; + gb->apu.wave_channel.sample_countdown = gb->apu.wave_channel.sample_length; + gb->apu.wave_channel.current_sample_index++; + gb->apu.wave_channel.current_sample_index &= 0x1F; + gb->apu.wave_channel.current_sample = + gb->apu.wave_channel.wave_form[gb->apu.wave_channel.current_sample_index]; + update_sample(gb, GB_WAVE, gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift); + gb->apu.wave_channel.wave_form_just_read = true; } - return; - } - while (gb->audio_copy_in_progress); - double ticks_per_sample = (double) CPU_FREQUENCY / gb->sample_rate; - - if (gb->audio_quality == 0) { - GB_sample_t sample; - GB_apu_get_samples_and_update_pcm_regs(gb, &sample); - gb->current_supersample.left += sample.left; - gb->current_supersample.right += sample.right; - gb->n_subsamples++; - } - else if (gb->audio_quality != 1) { - double ticks_per_subsample = ticks_per_sample / gb->audio_quality; - if (ticks_per_subsample < 1) { - ticks_per_subsample = 1; - } - if (gb->apu_subsample_cycles > ticks_per_subsample) { - gb->apu_subsample_cycles -= ticks_per_subsample; - } - - GB_sample_t sample; - GB_apu_get_samples_and_update_pcm_regs(gb, &sample); - gb->current_supersample.left += sample.left; - gb->current_supersample.right += sample.right; - gb->n_subsamples++; - } - - if (gb->apu_sample_cycles > ticks_per_sample) { - gb->apu_sample_cycles -= ticks_per_sample; - if (gb->audio_position == gb->buffer_size) { - /* - if (!gb->turbo) { - GB_log(gb, "Audio overflow\n"); - } - */ - } - else { - if (gb->audio_quality == 1) { - GB_apu_get_samples_and_update_pcm_regs(gb, &gb->audio_buffer[gb->audio_position++]); - } - else { - gb->audio_buffer[gb->audio_position].left = round(gb->current_supersample.left / gb->n_subsamples); - gb->audio_buffer[gb->audio_position].right = round(gb->current_supersample.right / gb->n_subsamples); - gb->n_subsamples = 0; - gb->current_supersample = (GB_double_sample_t){0, }; - gb->audio_position++; - } + if (cycles_left) { + gb->apu.wave_channel.sample_countdown -= cycles_left; + gb->apu.wave_channel.wave_form_just_read = false; } } + } void GB_apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, unsigned int count) @@ -274,24 +103,23 @@ void GB_apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, unsigned int count) void GB_apu_init(GB_gameboy_t *gb) { memset(&gb->apu, 0, sizeof(gb->apu)); - gb->apu.wave_channels[0].duty = gb->apu.wave_channels[1].duty = 4; - gb->apu.lfsr = 0x7FFF; + // gb->apu.wave_channels[0].duty = gb->apu.wave_channels[1].duty = 4; + // gb->apu.lfsr = 0x7FFF; gb->apu.left_volume = 7; gb->apu.right_volume = 7; for (int i = 0; i < 4; i++) { - gb->apu.wave_channels[i].left_on = gb->apu.wave_channels[i].right_on = 1; + gb->apu.left_enabled[i] = gb->apu.right_enabled[i] = true; } + gb->apu.wave_channel.sample_length = 0x7FF; } uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg) { - GB_apu_run_internal(gb); - if (reg == GB_IO_NR52) { uint8_t value = 0; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < GB_N_CHANNELS; i++) { value >>= 1; - if (gb->apu.wave_channels[i].is_playing) { + if (gb->apu.is_active[i]) { value |= 0x8; } } @@ -315,12 +143,11 @@ uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg) 0, /* ... */ }; - if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END && gb->apu.wave_channels[2].is_playing) { - if (gb->apu.wave_channels[2].wave_length == 0) { - return gb->apu.wave_form[0]; + if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END && gb->apu.is_active[GB_WAVE]) { + if (!gb->is_cgb && !gb->apu.wave_channel.wave_form_just_read) { + return 0xFF; } - gb->apu.wave_channels[2].phase %= gb->apu.wave_channels[2].wave_length; - return gb->apu.wave_form[(int)(gb->apu.wave_channels[2].phase * 32 / gb->apu.wave_channels[2].wave_length)]; + reg = GB_IO_WAV_START + gb->apu.wave_channel.current_sample_index / 2; } return gb->io_registers[reg] | read_mask[reg - GB_IO_NR10]; @@ -328,145 +155,23 @@ 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; - if (!gb->apu.global_enable && reg != GB_IO_NR52) { return; } + if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END && gb->apu.is_active[GB_WAVE]) { + if (!gb->is_cgb && !gb->apu.wave_channel.wave_form_just_read) { + return; + } + reg = GB_IO_WAV_START + gb->apu.wave_channel.current_sample_index / 2; + } + gb->io_registers[reg] = value; - switch (reg) { - case GB_IO_NR10: - case GB_IO_NR11: - case GB_IO_NR12: - case GB_IO_NR13: - case GB_IO_NR14: - channel = 0; - break; - case GB_IO_NR21: - case GB_IO_NR22: - case GB_IO_NR23: - case GB_IO_NR24: - channel = 1; - break; - case GB_IO_NR33: - case GB_IO_NR34: - channel = 2; - break; - case GB_IO_NR41: - case GB_IO_NR42: - channel = 3; - default: - break; - } switch (reg) { - case GB_IO_NR10: - gb->apu.wave_channels[channel].sweep_direction = value & 8? -1 : 1; - gb->apu.wave_channels[channel].cur_sweep_steps = - gb->apu.wave_channels[channel].sweep_steps = (value & 0x70) >> 4; - gb->apu.wave_channels[channel].sweep_shift = value & 7; - break; - case GB_IO_NR11: - case GB_IO_NR21: - case GB_IO_NR41: - gb->apu.wave_channels[channel].duty = duties[value >> 6]; - gb->apu.wave_channels[channel].sound_length = (64 - (value & 0x3F)) * (APU_FREQUENCY / 256); - if (gb->apu.wave_channels[channel].sound_length == 0) { - gb->apu.wave_channels[channel].is_playing = false; - } - break; - case GB_IO_NR12: - case GB_IO_NR22: - case GB_IO_NR42: - gb->apu.wave_channels[channel].start_amplitude = - gb->apu.wave_channels[channel].amplitude = CH_STEP * (value >> 4); - if (value >> 4 == 0) { - gb->apu.wave_channels[channel].is_playing = false; - } - gb->apu.wave_channels[channel].envelope_direction = value & 8? 1 : -1; - gb->apu.wave_channels[channel].cur_envelope_steps = - gb->apu.wave_channels[channel].envelope_steps = value & 7; - break; - case GB_IO_NR13: - case GB_IO_NR23: - case GB_IO_NR33: - gb->apu.wave_channels[channel].NRX3_X4_temp = (gb->apu.wave_channels[channel].NRX3_X4_temp & 0xFF00) | value; - gb->apu.wave_channels[channel].wave_length = (2048 - gb->apu.wave_channels[channel].NRX3_X4_temp) * (APU_FREQUENCY / 131072); - if (channel == 2) { - gb->apu.wave_channels[channel].wave_length *= 2; - } - break; - case GB_IO_NR14: - case GB_IO_NR24: - case GB_IO_NR34: - gb->apu.wave_channels[channel].stop_on_length = value & 0x40; - if ((value & 0x80) && (channel != 2 || gb->apu.wave_enable)) { - gb->apu.wave_channels[channel].is_playing = true; - gb->apu.wave_channels[channel].phase = 0; - gb->apu.wave_channels[channel].amplitude = gb->apu.wave_channels[channel].start_amplitude; - gb->apu.wave_channels[channel].cur_envelope_steps = gb->apu.wave_channels[channel].envelope_steps; - } - - gb->apu.wave_channels[channel].NRX3_X4_temp = (gb->apu.wave_channels[channel].NRX3_X4_temp & 0xFF) | ((value & 0x7) << 8); - gb->apu.wave_channels[channel].wave_length = (2048 - gb->apu.wave_channels[channel].NRX3_X4_temp) * (APU_FREQUENCY / 131072); - if (channel == 2) { - gb->apu.wave_channels[channel].wave_length *= 2; - } - break; - case GB_IO_NR30: - gb->apu.wave_enable = value & 0x80; - gb->apu.wave_channels[2].is_playing &= gb->apu.wave_enable; - break; - case GB_IO_NR31: - gb->apu.wave_channels[2].sound_length = (256 - value) * (APU_FREQUENCY / 256); - if (gb->apu.wave_channels[2].sound_length == 0) { - gb->apu.wave_channels[2].is_playing = false; - } - break; - case GB_IO_NR32: - gb->apu.wave_shift = ((value >> 5) + 3) & 3; - if (gb->apu.wave_shift == 3) { - gb->apu.wave_shift = 4; - } - break; - case GB_IO_NR43: - { - double r = value & 0x7; - if (r == 0) r = 0.5; - uint8_t s = value >> 4; - gb->apu.wave_channels[3].wave_length = r * (1 << s) * (APU_FREQUENCY / 262144) ; - gb->apu.lfsr_7_bit = value & 0x8; - break; - } - case GB_IO_NR44: - gb->apu.wave_channels[3].stop_on_length = value & 0x40; - if (value & 0x80) { - gb->apu.wave_channels[3].is_playing = true; - gb->apu.lfsr = 0x7FFF; - gb->apu.wave_channels[3].amplitude = gb->apu.wave_channels[3].start_amplitude; - gb->apu.wave_channels[3].cur_envelope_steps = gb->apu.wave_channels[3].envelope_steps; - } - break; - - case GB_IO_NR50: - gb->apu.left_volume = (value & 7); - gb->apu.right_volume = ((value >> 4) & 7); - break; - - case GB_IO_NR51: - for (int i = 0; i < 4; i++) { - gb->apu.wave_channels[i].left_on = value & 1; - gb->apu.wave_channels[i].right_on = value & 0x10; - value >>= 1; - } - break; + /* Globals */ case GB_IO_NR52: - if ((value & 0x80) && !gb->apu.global_enable) { GB_apu_init(gb); gb->apu.global_enable = true; @@ -474,21 +179,71 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value) else if (!(value & 0x80) && gb->apu.global_enable) { memset(&gb->apu, 0, sizeof(gb->apu)); memset(gb->io_registers + GB_IO_NR10, 0, GB_IO_WAV_START - GB_IO_NR10); + gb->apu.global_enable = false; } break; - + + /* Wave channel */ + case GB_IO_NR30: + gb->apu.wave_channel.enable = value & 0x80; + if (!gb->apu.wave_channel.enable) { + gb->apu.is_active[GB_WAVE] = false; + gb->apu.wave_channel.current_sample = 0; + update_sample(gb, GB_WAVE, 0); + } + break; + case GB_IO_NR31: + break; + case GB_IO_NR32: + gb->apu.wave_channel.shift = (uint8_t[]){4, 0, 1, 2}[(value >> 5) & 3]; + update_sample(gb, GB_WAVE, gb->apu.wave_channel.current_sample >> gb->apu.wave_channel.shift); + break; + case GB_IO_NR33: + gb->apu.wave_channel.sample_length &= ~0xFF; + gb->apu.wave_channel.sample_length |= (~value) & 0xFF; + break; + case GB_IO_NR34: + gb->apu.wave_channel.length_enabled = value & 0x40; + gb->apu.wave_channel.sample_length &= 0xFF; + gb->apu.wave_channel.sample_length |= ((~value) & 7) << 8; + if ((value & 0x80) && gb->apu.wave_channel.enable) { + /* DMG bug: wave RAM gets corrupted if the channel is retriggerred 1 cycle before the APU + reads from it. */ + if (!gb->is_cgb && gb->apu.is_active[GB_WAVE] && gb->apu.wave_channel.sample_countdown == 0) { + unsigned offset = ((gb->apu.wave_channel.current_sample_index + 1) >> 1) & 0xF; + + /* On SGB2 (and probably SGB1 and MGB as well) this behavior is not accurate, + however these systems are not currently emulated. */ + if (offset < 4) { + gb->io_registers[GB_IO_WAV_START] = gb->io_registers[GB_IO_WAV_START + offset]; + gb->apu.wave_channel.wave_form[0] = gb->apu.wave_channel.wave_form[offset / 2]; + gb->apu.wave_channel.wave_form[1] = gb->apu.wave_channel.wave_form[offset / 2 + 1]; + } + else { + memcpy(gb->io_registers + GB_IO_WAV_START, + gb->io_registers + GB_IO_WAV_START + (offset & ~3), + 4); + memcpy(gb->apu.wave_channel.wave_form, + gb->apu.wave_channel.wave_form + (offset & ~3) * 2, + 8); + } + } + gb->apu.is_active[GB_WAVE] = true; + gb->apu.wave_channel.pulse_length = ~gb->io_registers[GB_IO_NR31]; + gb->apu.wave_channel.sample_countdown = gb->apu.wave_channel.sample_length + 3; + gb->apu.wave_channel.current_sample_index = 0; + /* Note that we don't change the sample just yet! This was verified on hardware. */ + } + break; + default: if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END) { - gb->apu.wave_form[(reg - GB_IO_WAV_START) * 2] = value >> 4; - gb->apu.wave_form[(reg - GB_IO_WAV_START) * 2 + 1] = value & 0xF; + gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2] = value >> 4; + gb->apu.wave_channel.wave_form[(reg - GB_IO_WAV_START) * 2 + 1] = value & 0xF; } - break; } -} -void GB_set_audio_quality(GB_gameboy_t *gb, unsigned quality) -{ - gb->audio_quality = quality; + } unsigned GB_apu_get_current_buffer_length(GB_gameboy_t *gb) diff --git a/Core/apu.h b/Core/apu.h index ffc530e..beec027 100644 --- a/Core/apu.h +++ b/Core/apu.h @@ -3,10 +3,16 @@ #include #include #include "gb_struct_def.h" + + +#ifdef GB_INTERNAL /* Divides nicely and never overflows with 4 channels */ #define MAX_CH_AMP 0x1E00 -#define CH_STEP (0x1E00/0xF) +#define CH_STEP (MAX_CH_AMP/0xF) +#endif +/* Lengths are in either DIV ticks (256Hz, triggered by the DIV register) or + APU ticks (2MHz, triggered by an internal APU clock)*/ typedef struct { @@ -20,59 +26,51 @@ typedef struct double right; } GB_double_sample_t; -/* Not all used on all channels */ -/* All lengths are in APU ticks */ -typedef struct -{ - uint32_t phase; - uint32_t wave_length; - int32_t sound_length; - bool stop_on_length; - uint8_t duty; - int16_t amplitude; - int16_t start_amplitude; - uint8_t envelope_steps; - uint8_t cur_envelope_steps; - int8_t envelope_direction; - uint8_t sweep_steps; - uint8_t cur_sweep_steps; - int8_t sweep_direction; - uint8_t sweep_shift; - bool is_playing; - uint16_t NRX3_X4_temp; - bool left_on; - bool right_on; -} GB_apu_channel_t; +enum GB_CHANNELS { + GB_SQUARE_1, + GB_SQUARE_2, + GB_WAVE, + GB_NOISE, + GB_N_CHANNELS +}; typedef struct { - uint16_t apu_cycles; bool global_enable; - uint32_t envelope_step_timer; - uint32_t sweep_step_timer; - int8_t wave_form[32]; - uint8_t wave_shift; - bool wave_enable; - uint16_t lfsr; - bool lfsr_7_bit; uint8_t left_volume; uint8_t right_volume; - GB_apu_channel_t wave_channels[4]; + + uint8_t samples[GB_N_CHANNELS]; + bool left_enabled[GB_N_CHANNELS]; + bool right_enabled[GB_N_CHANNELS]; + bool is_active[GB_N_CHANNELS]; + + struct { + bool enable; // NR30 + uint8_t pulse_length; // Reloaded from NR31 (xorred), in DIV ticks + uint8_t shift; // NR32 + uint16_t sample_length; // NR33, NR34, in APU ticks + bool length_enabled; // NR34 + + uint16_t sample_countdown; // in APU ticks + uint8_t current_sample_index; + uint8_t current_sample; // Current sample before shifting. + + int8_t wave_form[32]; + bool wave_form_just_read; + } wave_channel; } GB_apu_t; void GB_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate); -/* Quality is the number of subsamples per sampling, for the sake of resampling. - 1 means on resampling at all, 0 is maximum quality. Default is 4. */ -void GB_set_audio_quality(GB_gameboy_t *gb, unsigned quality); void GB_apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, unsigned int count); unsigned GB_apu_get_current_buffer_length(GB_gameboy_t *gb); #ifdef GB_INTERNAL void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value); uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg); -void GB_apu_get_samples_and_update_pcm_regs(GB_gameboy_t *gb, GB_sample_t *samples); +void GB_apu_div_event(GB_gameboy_t *gb); void GB_apu_init(GB_gameboy_t *gb); -void GB_apu_run(GB_gameboy_t *gb); +void GB_apu_run(GB_gameboy_t *gb, uint8_t cycles); #endif #endif /* apu_h */ diff --git a/Core/gb.c b/Core/gb.c index 56697a1..88099b1 100755 --- a/Core/gb.c +++ b/Core/gb.c @@ -92,7 +92,6 @@ void GB_init(GB_gameboy_t *gb) gb->input_callback = default_input_callback; gb->async_input_callback = default_async_input_callback; gb->cartridge_type = &GB_cart_defs[0]; // Default cartridge type - gb->audio_quality = 4; GB_reset(gb); } @@ -107,7 +106,6 @@ void GB_init_cgb(GB_gameboy_t *gb) gb->input_callback = default_input_callback; gb->async_input_callback = default_async_input_callback; gb->cartridge_type = &GB_cart_defs[0]; // Default cartridge type - gb->audio_quality = 4; GB_reset(gb); } diff --git a/Core/gb.h b/Core/gb.h index 8260882..fd7f4e0 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -419,11 +419,6 @@ struct GB_gameboy_internal_s { volatile bool audio_copy_in_progress; volatile bool apu_lock; double apu_sample_cycles; - double apu_subsample_cycles; - GB_double_sample_t current_supersample; - unsigned n_subsamples; - unsigned audio_quality; - /* Callbacks */ void *user_data; diff --git a/Core/memory.c b/Core/memory.c index c914e55..085afe8 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -148,13 +148,11 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) return gb->io_registers[GB_IO_DMG_EMULATION_INDICATION] | 0xFE; case GB_IO_PCM_12: - case GB_IO_PCM_34: - { if (!gb->is_cgb) return 0xFF; - GB_sample_t dummy; - GB_apu_get_samples_and_update_pcm_regs(gb, &dummy); - } - /* Fall through */ + return (gb->apu.samples[GB_SQUARE_2] << 4) | gb->apu.samples[GB_SQUARE_1]; + case GB_IO_PCM_34: + if (!gb->is_cgb) return 0xFF; + return (gb->apu.samples[GB_NOISE] << 4) | gb->apu.samples[GB_WAVE]; case GB_IO_JOYP: case GB_IO_TMA: case GB_IO_LCDC: diff --git a/Core/timing.c b/Core/timing.c index 77348fe..0d4d215 100644 --- a/Core/timing.c +++ b/Core/timing.c @@ -134,14 +134,12 @@ void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles) // Not affected by speed boost gb->hdma_cycles += cycles; gb->apu_sample_cycles += cycles; - gb->apu_subsample_cycles += cycles; - gb->apu.apu_cycles += cycles; gb->cycles_since_ir_change += cycles; gb->cycles_since_input_ir_change += cycles; gb->cycles_since_last_sync += cycles; GB_dma_run(gb); GB_hdma_run(gb); - GB_apu_run(gb); + GB_apu_run(gb, cycles); GB_display_run(gb, cycles); GB_ir_run(gb); } @@ -172,6 +170,9 @@ void GB_set_internal_div_counter(GB_gameboy_t *gb, uint32_t value) counter_overflow_check(gb->div_cycles, value, GB_TAC_RATIOS[gb->io_registers[GB_IO_TAC] & 3])) { increase_tima(gb); } + if (counter_overflow_check(gb->div_cycles, value, gb->cgb_double_speed? 0x4000 : 0x2000)) { + GB_apu_div_event(gb); + } gb->div_cycles = value; }