Project

General

Profile

Actions

Emulator Issues #3573

closed

AudioDMA plays old samples/more samples than supposed to

Added by pierre almost 14 years ago.

Status:
Fixed
Priority:
Normal
Assignee:
-
Category:
DSP
% Done:

0%

Operating system:
N/A
Issue type:
Bug
Milestone:
Regression:
No
Relates to usability:
No
Relates to performance:
No
Easy:
No
Relates to maintainability:
No
Regression start:
Fixed in:

Description

Some games with AX ucode use multiple audio DMA fragments for their ringbuffer, updating g_audioDMA.SourceAddress in the audio DMA interrupt handler. The DMA of a fragment happens while the data is filled into the given fragment.

There are two things that can go wrong here:

  1. The guest CPU gets too far behind audio DMA, so audio DMA reads old samples from the last run through the ringbuffer. This happens regularly with Metroid Prime at the title screen/main menu.
  2. The guest CPU is too slow to set SourceAddress in time. This happens with interpreter and Metroid Prime at the title screen/main menu. This results in about half of the last fragment already been DMAed before SourceAddress is set(and the transfer restarted).

Metroid Prime is not using the DSP at the title screen, but decodes/streams audio using guest CPU.

Other games affected by this are Sonic Unleashed, New Super Mario Bros, but only when using DSPLLE, which does not bypass the CPU like DSPHLE.

A workaround is to read the whole audio DMA fragment in one go at the end of the DMA transfer.
Defering scheduling of the audio DMA to when the guest CPU sets g_AudioDMA.Enable does not help.

Actions #1

Updated by mylek4 almost 14 years ago

I've seen something similar happen with LLE in some games which introduces noise. It seems like sound gets pushed out to the backend while its buffer is still getting written to. I think I came up with something similar to the workaround you described:

void UpdateAudioDMA()
{
if (g_audioDMA.BlocksLeft)
{
g_audioDMA.ReadAddress += 32;
g_audioDMA.BlocksLeft--;

	if (g_audioDMA.BlocksLeft == 0)
	{
		dsp_plugin->DSP_SendAIBuffer(g_audioDMA.SourceAddress, 8*g_audioDMA.AudioDMAControl.NumBlocks); // <------

Pushing the sound out all at once before generating the interrupt seems to fix it at the expense of delaying things ~96 samples. I can't say with certainty this doesn't have any negative side effects but I haven't seen any problems with it.

Actions #2

Updated by pierre almost 14 years ago

  • Status changed from New to Fixed

Fixed in r6582.

Unknown if that is how the hardware works, or if this just papers over a timing problem in core.

Actions

Also available in: Atom PDF