mirror of https://github.com/mgba-emu/mgba.git
PSP2: Fix RingFIFO misuse causing bad audio
This commit is contained in:
parent
4a3c942332
commit
c657255009
1
CHANGES
1
CHANGES
|
@ -44,6 +44,7 @@ Bugfixes:
|
||||||
- Core: Fix ROM patches not being unloaded when disabled (fixes mgba.io/i/962)
|
- Core: Fix ROM patches not being unloaded when disabled (fixes mgba.io/i/962)
|
||||||
- GBA I/O: Fix writing to DISPCNT CGB flag (fixes mgba.io/i/902)
|
- GBA I/O: Fix writing to DISPCNT CGB flag (fixes mgba.io/i/902)
|
||||||
- GBA Memory: Partially revert prefetch changes (fixes mgba.io/i/840)
|
- GBA Memory: Partially revert prefetch changes (fixes mgba.io/i/840)
|
||||||
|
- PSP2: Fix issues causing poor audio
|
||||||
Misc:
|
Misc:
|
||||||
- GBA Timer: Use global cycles for timers
|
- GBA Timer: Use global cycles for timers
|
||||||
- GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)
|
- GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)
|
||||||
|
|
|
@ -153,7 +153,7 @@ int main() {
|
||||||
.teardown = mPSP2Teardown,
|
.teardown = mPSP2Teardown,
|
||||||
.gameLoaded = mPSP2LoadROM,
|
.gameLoaded = mPSP2LoadROM,
|
||||||
.gameUnloaded = mPSP2UnloadROM,
|
.gameUnloaded = mPSP2UnloadROM,
|
||||||
.prepareForFrame = mPSP2PrepareForFrame,
|
.prepareForFrame = NULL,
|
||||||
.drawFrame = mPSP2Draw,
|
.drawFrame = mPSP2Draw,
|
||||||
.drawScreenshot = mPSP2DrawScreenshot,
|
.drawScreenshot = mPSP2DrawScreenshot,
|
||||||
.paused = mPSP2Paused,
|
.paused = mPSP2Paused,
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include <mgba-util/memory.h>
|
#include <mgba-util/memory.h>
|
||||||
#include <mgba-util/circle-buffer.h>
|
#include <mgba-util/circle-buffer.h>
|
||||||
#include <mgba-util/math.h>
|
#include <mgba-util/math.h>
|
||||||
#include <mgba-util/ring-fifo.h>
|
|
||||||
#include <mgba-util/threading.h>
|
#include <mgba-util/threading.h>
|
||||||
#include <mgba-util/vfs.h>
|
#include <mgba-util/vfs.h>
|
||||||
#include <mgba-util/platform/psp2/sce-vfs.h>
|
#include <mgba-util/platform/psp2/sce-vfs.h>
|
||||||
|
@ -71,16 +70,20 @@ static struct mSceImageSource {
|
||||||
size_t bufferOffset;
|
size_t bufferOffset;
|
||||||
} camera;
|
} camera;
|
||||||
|
|
||||||
|
static struct mAVStream stream;
|
||||||
|
|
||||||
bool frameLimiter = true;
|
bool frameLimiter = true;
|
||||||
|
|
||||||
extern const uint8_t _binary_backdrop_png_start[];
|
extern const uint8_t _binary_backdrop_png_start[];
|
||||||
static vita2d_texture* backdrop = 0;
|
static vita2d_texture* backdrop = 0;
|
||||||
|
|
||||||
#define PSP2_SAMPLES 256
|
#define PSP2_SAMPLES 512
|
||||||
#define PSP2_AUDIO_BUFFER_SIZE (PSP2_SAMPLES * 20)
|
#define PSP2_AUDIO_BUFFER_SIZE (PSP2_SAMPLES * 16)
|
||||||
|
|
||||||
static struct mPSP2AudioContext {
|
static struct mPSP2AudioContext {
|
||||||
struct RingFIFO buffer;
|
struct GBAStereoSample buffer[PSP2_AUDIO_BUFFER_SIZE];
|
||||||
|
size_t writeOffset;
|
||||||
|
size_t readOffset;
|
||||||
size_t samples;
|
size_t samples;
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
Condition cond;
|
Condition cond;
|
||||||
|
@ -93,26 +96,25 @@ void mPSP2MapKey(struct mInputMap* map, int pspKey, int key) {
|
||||||
|
|
||||||
static THREAD_ENTRY _audioThread(void* context) {
|
static THREAD_ENTRY _audioThread(void* context) {
|
||||||
struct mPSP2AudioContext* audio = (struct mPSP2AudioContext*) context;
|
struct mPSP2AudioContext* audio = (struct mPSP2AudioContext*) context;
|
||||||
|
uint32_t zeroBuffer[PSP2_SAMPLES] = {0};
|
||||||
int audioPort = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, PSP2_SAMPLES, 48000, SCE_AUDIO_OUT_MODE_STEREO);
|
int audioPort = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, PSP2_SAMPLES, 48000, SCE_AUDIO_OUT_MODE_STEREO);
|
||||||
while (audio->running) {
|
while (audio->running) {
|
||||||
MutexLock(&audio->mutex);
|
MutexLock(&audio->mutex);
|
||||||
int len = audio->samples;
|
void* buffer;
|
||||||
if (len > PSP2_SAMPLES) {
|
if (audio->samples >= PSP2_SAMPLES) {
|
||||||
len = PSP2_SAMPLES;
|
buffer = &audio->buffer[audio->readOffset];
|
||||||
|
audio->samples -= PSP2_SAMPLES;
|
||||||
|
audio->readOffset += PSP2_SAMPLES;
|
||||||
|
if (audio->readOffset >= PSP2_AUDIO_BUFFER_SIZE) {
|
||||||
|
audio->readOffset = 0;
|
||||||
}
|
}
|
||||||
struct GBAStereoSample* buffer = audio->buffer.readPtr;
|
|
||||||
RingFIFORead(&audio->buffer, NULL, len * 4);
|
|
||||||
audio->samples -= len;
|
|
||||||
ConditionWake(&audio->cond);
|
ConditionWake(&audio->cond);
|
||||||
|
} else {
|
||||||
MutexUnlock(&audio->mutex);
|
buffer = zeroBuffer;
|
||||||
sceAudioOutOutput(audioPort, buffer);
|
|
||||||
MutexLock(&audio->mutex);
|
|
||||||
|
|
||||||
if (audio->samples < PSP2_SAMPLES) {
|
|
||||||
ConditionWait(&audio->cond, &audio->mutex);
|
|
||||||
}
|
}
|
||||||
MutexUnlock(&audio->mutex);
|
MutexUnlock(&audio->mutex);
|
||||||
|
|
||||||
|
sceAudioOutOutput(audioPort, buffer);
|
||||||
}
|
}
|
||||||
sceAudioOutReleasePort(audioPort);
|
sceAudioOutReleasePort(audioPort);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -229,6 +231,29 @@ static void _requestImage(struct mImageSource* source, const void** buffer, size
|
||||||
sceCameraRead(imageSource->cam - 1, &read);
|
sceCameraRead(imageSource->cam - 1, &read);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right) {
|
||||||
|
UNUSED(stream);
|
||||||
|
MutexLock(&audioContext.mutex);
|
||||||
|
struct GBAStereoSample* samples = &audioContext.buffer[audioContext.writeOffset];
|
||||||
|
while (audioContext.samples == PSP2_AUDIO_BUFFER_SIZE) {
|
||||||
|
if (!frameLimiter) {
|
||||||
|
blip_clear(left);
|
||||||
|
blip_clear(right);
|
||||||
|
MutexUnlock(&audioContext.mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ConditionWait(&audioContext.cond, &audioContext.mutex);
|
||||||
|
}
|
||||||
|
blip_read_samples(left, &samples[0].left, PSP2_SAMPLES, true);
|
||||||
|
blip_read_samples(right, &samples[0].right, PSP2_SAMPLES, true);
|
||||||
|
audioContext.samples += PSP2_SAMPLES;
|
||||||
|
audioContext.writeOffset += PSP2_SAMPLES;
|
||||||
|
if (audioContext.writeOffset >= PSP2_AUDIO_BUFFER_SIZE) {
|
||||||
|
audioContext.writeOffset = 0;
|
||||||
|
}
|
||||||
|
MutexUnlock(&audioContext.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t mPSP2PollInput(struct mGUIRunner* runner) {
|
uint16_t mPSP2PollInput(struct mGUIRunner* runner) {
|
||||||
SceCtrlData pad;
|
SceCtrlData pad;
|
||||||
sceCtrlPeekBufferPositive(0, &pad, 1);
|
sceCtrlPeekBufferPositive(0, &pad, 1);
|
||||||
|
@ -285,6 +310,7 @@ void mPSP2Setup(struct mGUIRunner* runner) {
|
||||||
|
|
||||||
outputBuffer = vita2d_texture_get_datap(tex);
|
outputBuffer = vita2d_texture_get_datap(tex);
|
||||||
runner->core->setVideoBuffer(runner->core, outputBuffer, 256);
|
runner->core->setVideoBuffer(runner->core, outputBuffer, 256);
|
||||||
|
runner->core->setAudioBufferSize(runner->core, PSP2_SAMPLES);
|
||||||
|
|
||||||
rotation.d.sample = _sampleRotation;
|
rotation.d.sample = _sampleRotation;
|
||||||
rotation.d.readTiltX = _readTiltX;
|
rotation.d.readTiltX = _readTiltX;
|
||||||
|
@ -303,6 +329,13 @@ void mPSP2Setup(struct mGUIRunner* runner) {
|
||||||
camera.cam = 1;
|
camera.cam = 1;
|
||||||
runner->core->setPeripheral(runner->core, mPERIPH_IMAGE_SOURCE, &camera.d);
|
runner->core->setPeripheral(runner->core, mPERIPH_IMAGE_SOURCE, &camera.d);
|
||||||
|
|
||||||
|
|
||||||
|
stream.videoDimensionsChanged = NULL;
|
||||||
|
stream.postAudioFrame = NULL;
|
||||||
|
stream.postAudioBuffer = _postAudioBuffer;
|
||||||
|
stream.postVideoFrame = NULL;
|
||||||
|
runner->core->setAVStream(runner->core, &stream);
|
||||||
|
|
||||||
frameLimiter = true;
|
frameLimiter = true;
|
||||||
backdrop = vita2d_load_PNG_buffer(_binary_backdrop_png_start);
|
backdrop = vita2d_load_PNG_buffer(_binary_backdrop_png_start);
|
||||||
|
|
||||||
|
@ -341,37 +374,15 @@ void mPSP2LoadROM(struct mGUIRunner* runner) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
RingFIFOInit(&audioContext.buffer, PSP2_AUDIO_BUFFER_SIZE * sizeof(struct GBAStereoSample));
|
|
||||||
MutexInit(&audioContext.mutex);
|
MutexInit(&audioContext.mutex);
|
||||||
ConditionInit(&audioContext.cond);
|
ConditionInit(&audioContext.cond);
|
||||||
|
memset(audioContext.buffer, 0, sizeof(audioContext.buffer));
|
||||||
|
audioContext.readOffset = 0;
|
||||||
|
audioContext.writeOffset = 0;
|
||||||
audioContext.running = true;
|
audioContext.running = true;
|
||||||
ThreadCreate(&audioThread, _audioThread, &audioContext);
|
ThreadCreate(&audioThread, _audioThread, &audioContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mPSP2PrepareForFrame(struct mGUIRunner* runner) {
|
|
||||||
int nSamples = 0;
|
|
||||||
while (blip_samples_avail(runner->core->getAudioChannel(runner->core, 0)) >= PSP2_SAMPLES) {
|
|
||||||
struct GBAStereoSample* samples = audioContext.buffer.writePtr;
|
|
||||||
if (nSamples > (PSP2_AUDIO_BUFFER_SIZE >> 2) + (PSP2_AUDIO_BUFFER_SIZE >> 1)) { // * 0.75
|
|
||||||
if (!frameLimiter) {
|
|
||||||
blip_clear(runner->core->getAudioChannel(runner->core, 0));
|
|
||||||
blip_clear(runner->core->getAudioChannel(runner->core, 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
blip_read_samples(runner->core->getAudioChannel(runner->core, 0), &samples[0].left, PSP2_SAMPLES, true);
|
|
||||||
blip_read_samples(runner->core->getAudioChannel(runner->core, 1), &samples[0].right, PSP2_SAMPLES, true);
|
|
||||||
while (!RingFIFOWrite(&audioContext.buffer, NULL, PSP2_SAMPLES * 4)) {
|
|
||||||
ConditionWake(&audioContext.cond);
|
|
||||||
// Spinloooooooop!
|
|
||||||
}
|
|
||||||
MutexLock(&audioContext.mutex);
|
|
||||||
audioContext.samples += PSP2_SAMPLES;
|
|
||||||
nSamples = audioContext.samples;
|
|
||||||
ConditionWake(&audioContext.cond);
|
|
||||||
MutexUnlock(&audioContext.mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mPSP2UnloadROM(struct mGUIRunner* runner) {
|
void mPSP2UnloadROM(struct mGUIRunner* runner) {
|
||||||
switch (runner->core->platform(runner->core)) {
|
switch (runner->core->platform(runner->core)) {
|
||||||
|
|
Loading…
Reference in New Issue