Wii: Improve audio buffering (fixes #1617)

This commit is contained in:
Vicki Pfau 2020-01-13 19:24:57 -08:00
parent 2f68ea1b48
commit d4e30b74ff
2 changed files with 39 additions and 17 deletions

View File

@ -113,6 +113,7 @@ Other fixes:
- Qt: Release held actions if they get rebound - Qt: Release held actions if they get rebound
- Vita: Fix analog controls (fixes mgba.io/i/1554) - Vita: Fix analog controls (fixes mgba.io/i/1554)
- Wii: Fix game fast-forwarding after slowing down - Wii: Fix game fast-forwarding after slowing down
- Wii: Improve audio buffering (fixes mgba.io/i/1617)
Misc: Misc:
- GB Memory: Support manual SRAM editing (fixes mgba.io/i/1580) - GB Memory: Support manual SRAM editing (fixes mgba.io/i/1580)
- GBA Audio: Redo channel 4 batching for GBA only - GBA Audio: Redo channel 4 batching for GBA only

View File

@ -64,7 +64,8 @@ static enum VideoMode {
VM_MAX VM_MAX
} videoMode = VM_AUTODETECT; } videoMode = VM_AUTODETECT;
#define SAMPLES 1024 #define SAMPLES 512
#define BUFFERS 8
#define GUI_SCALE 1.35f #define GUI_SCALE 1.35f
#define GUI_SCALE_240p 2.0f #define GUI_SCALE_240p 2.0f
@ -131,9 +132,12 @@ size_t romBufferSize;
static void* framebuffer[2] = { 0, 0 }; static void* framebuffer[2] = { 0, 0 };
static int whichFb = 0; static int whichFb = 0;
static struct GBAStereoSample audioBuffer[3][SAMPLES] __attribute__((__aligned__(32))); static struct AudioBuffer {
static volatile size_t audioBufferSize = 0; struct GBAStereoSample samples[SAMPLES] __attribute__((__aligned__(32)));
volatile size_t size;
} audioBuffer[BUFFERS] = {0};
static volatile int currentAudioBuffer = 0; static volatile int currentAudioBuffer = 0;
static volatile int nextAudioBuffer = 0;
static double audioSampleRate = 60.0 / 1.001; static double audioSampleRate = 60.0 / 1.001;
static struct GUIFont* font; static struct GUIFont* font;
@ -610,32 +614,43 @@ int main(int argc, char* argv[]) {
} }
static void _audioDMA(void) { static void _audioDMA(void) {
if (!audioBufferSize) { struct AudioBuffer* buffer = &audioBuffer[currentAudioBuffer];
if (buffer->size != SAMPLES) {
return; return;
} }
DCFlushRange(audioBuffer[currentAudioBuffer], audioBufferSize * sizeof(struct GBAStereoSample)); DCFlushRange(buffer->samples, SAMPLES * sizeof(struct GBAStereoSample));
AUDIO_InitDMA((u32) audioBuffer[currentAudioBuffer], audioBufferSize * sizeof(struct GBAStereoSample)); AUDIO_InitDMA((u32) buffer->samples, SAMPLES * sizeof(struct GBAStereoSample));
currentAudioBuffer = (currentAudioBuffer + 1) % 3; buffer->size = 0;
audioBufferSize = 0; currentAudioBuffer = (currentAudioBuffer + 1) % BUFFERS;
} }
static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right) { static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right) {
UNUSED(stream); UNUSED(stream);
u32 level = 0;
_CPU_ISR_Disable(level);
struct AudioBuffer* buffer = &audioBuffer[nextAudioBuffer];
int available = blip_samples_avail(left); int available = blip_samples_avail(left);
if (available + audioBufferSize > SAMPLES) { if (available + buffer->size > SAMPLES) {
available = SAMPLES - audioBufferSize; available = SAMPLES - buffer->size;
} }
available &= ~((32 / sizeof(struct GBAStereoSample)) - 1); // Force align to 32 bytes
if (available > 0) { if (available > 0) {
// These appear to be reversed for AUDIO_InitDMA // These appear to be reversed for AUDIO_InitDMA
blip_read_samples(left, &audioBuffer[currentAudioBuffer][audioBufferSize].right, available, true); blip_read_samples(left, &buffer->samples[buffer->size].right, available, true);
blip_read_samples(right, &audioBuffer[currentAudioBuffer][audioBufferSize].left, available, true); blip_read_samples(right, &buffer->samples[buffer->size].left, available, true);
audioBufferSize += available; buffer->size += available;
} }
if (audioBufferSize == SAMPLES && !AUDIO_GetDMAEnableFlag()) { if (buffer->size == SAMPLES) {
_audioDMA(); int next = (nextAudioBuffer + 1) % BUFFERS;
AUDIO_StartDMA(); if ((currentAudioBuffer + BUFFERS - next) % BUFFERS != 1) {
nextAudioBuffer = next;
}
if (!AUDIO_GetDMAEnableFlag()) {
_audioDMA();
AUDIO_StartDMA();
}
} }
_CPU_ISR_Restore(level);
} }
static void _drawStart(void) { static void _drawStart(void) {
@ -798,6 +813,12 @@ void _setup(struct mGUIRunner* runner) {
outputBuffer = memalign(32, TEX_W * TEX_H * BYTES_PER_PIXEL); outputBuffer = memalign(32, TEX_W * TEX_H * BYTES_PER_PIXEL);
runner->core->setVideoBuffer(runner->core, outputBuffer, TEX_W); runner->core->setVideoBuffer(runner->core, outputBuffer, TEX_W);
nextAudioBuffer = 0;
currentAudioBuffer = 0;
int i;
for (i = 0; i < BUFFERS; ++i) {
audioBuffer[i].size = 0;
}
runner->core->setAudioBufferSize(runner->core, SAMPLES); runner->core->setAudioBufferSize(runner->core, SAMPLES);
double ratio = GBAAudioCalculateRatio(1, audioSampleRate, 1); double ratio = GBAAudioCalculateRatio(1, audioSampleRate, 1);