all repos — mgba @ e3f0c87399e058d1fb080737079f3937f6efc15f

mGBA Game Boy Advance Emulator

PSP2: Mostly functional sound
Jeffrey Pfau jeffrey@endrift.com
Sun, 26 Jul 2015 16:13:18 -0700
commit

e3f0c87399e058d1fb080737079f3937f6efc15f

parent

a669eebaa71cf5907e76bfbee90db6306c028e6f

3 files changed, 79 insertions(+), 1 deletions(-)

jump to
M src/platform/psp2/CMakeLists.txtsrc/platform/psp2/CMakeLists.txt

@@ -1,6 +1,6 @@

file(GLOB PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/psp2/*.c) -set(PLATFORM_LIBRARY -lvita2d -lSceCtrl_stub -lSceRtc_stub -lSceGxm_stub -lSceDisplay_stub -lm_stub) +set(PLATFORM_LIBRARY -lvita2d -lSceCtrl_stub -lSceRtc_stub -lSceGxm_stub -lSceDisplay_stub -lSceAudio_stub -lm_stub) add_executable(${BINARY_NAME}.elf ${PLATFORM_SRC}) target_link_libraries(${BINARY_NAME}.elf ${BINARY_NAME} ${PLATFORM_LIBRARY})
M src/platform/psp2/main.csrc/platform/psp2/main.c

@@ -5,13 +5,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this

* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gba/gba.h" #include "gba/input.h" +#include "gba/audio.h" #include "gba/video.h" #include "gba/renderers/video-software.h" +#include "util/circle-buffer.h" #include "util/memory.h" +#include "util/threading.h" #include "util/vfs.h" #include "platform/psp2/sce-vfs.h" +#include "third-party/blip_buf/blip_buf.h" +#include <psp2/audioout.h> #include <psp2/ctrl.h> #include <psp2/display.h> #include <psp2/gxm.h>

@@ -26,11 +31,46 @@

#define PSP2_HORIZONTAL_PIXELS 960 #define PSP2_VERTICAL_PIXELS 544 #define PSP2_INPUT 0x50535032 +#define PSP2_SAMPLES 64 +#define PSP2_AUDIO_BUFFER_SIZE (PSP2_SAMPLES * 19) + +struct GBAPSP2AudioContext { + struct CircleBuffer buffer; + Mutex mutex; + Condition cond; + bool running; +}; static void _mapVitaKey(struct GBAInputMap* map, int pspKey, enum GBAKey key) { GBAInputBindKey(map, PSP2_INPUT, __builtin_ctz(pspKey), key); } +static THREAD_ENTRY _audioThread(void* context) { + struct GBAPSP2AudioContext* audio = (struct GBAPSP2AudioContext*) context; + struct GBAStereoSample buffer[PSP2_AUDIO_BUFFER_SIZE]; + int audioPort = sceAudioOutOpenPort(PSP2_AUDIO_OUT_PORT_TYPE_MAIN, PSP2_AUDIO_BUFFER_SIZE, 48000, PSP2_AUDIO_OUT_MODE_STEREO); + while (audio->running) { + MutexLock(&audio->mutex); + int len = CircleBufferSize(&audio->buffer); + len /= sizeof(buffer[0]); + if (len > PSP2_AUDIO_BUFFER_SIZE) { + len = PSP2_AUDIO_BUFFER_SIZE; + } + if (len > 0) { + len &= ~(PSP2_AUDIO_MIN_LEN - 1); + CircleBufferRead(&audio->buffer, buffer, len * sizeof(buffer[0])); + MutexUnlock(&audio->mutex); + sceAudioOutSetConfig(audioPort, len, -1, -1); + sceAudioOutOutput(audioPort, buffer); + MutexLock(&audio->mutex); + } + ConditionWait(&audio->cond, &audio->mutex); + MutexUnlock(&audio->mutex); + } + sceAudioOutReleasePort(audioPort); + return 0; +} + int main() { printf("%s initializing", projectName); bool running = true;

@@ -89,6 +129,17 @@ GBALoadROM(gba, rom, save, 0);

printf("%s loaded.", "ROM"); ARMReset(cpu); + double ratio = GBAAudioCalculateRatio(1, 60, 1); + blip_set_rates(gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 48000 * ratio); + blip_set_rates(gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 48000 * ratio); + + struct GBAPSP2AudioContext audioContext; + CircleBufferInit(&audioContext.buffer, PSP2_AUDIO_BUFFER_SIZE * sizeof(struct GBAStereoSample)); + MutexInit(&audioContext.mutex); + ConditionInit(&audioContext.cond); + audioContext.running = true; + Thread audioThread; + ThreadCreate(&audioThread, _audioThread, &audioContext); printf("%s all set and ready to roll.", projectName);

@@ -122,6 +173,23 @@ if (angles != GBA_KEY_NONE) {

activeKeys |= 1 << angles; } + MutexLock(&audioContext.mutex); + while (blip_samples_avail(gba->audio.left) >= PSP2_SAMPLES) { + if (CircleBufferSize(&audioContext.buffer) + PSP2_SAMPLES * sizeof(struct GBAStereoSample) > CircleBufferCapacity(&audioContext.buffer)) { + break; + } + struct GBAStereoSample samples[PSP2_SAMPLES]; + blip_read_samples(gba->audio.left, &samples[0].left, PSP2_SAMPLES, true); + blip_read_samples(gba->audio.right, &samples[0].right, PSP2_SAMPLES, true); + int i; + for (i = 0; i < PSP2_SAMPLES; ++i) { + CircleBufferWrite16(&audioContext.buffer, samples[i].left); + CircleBufferWrite16(&audioContext.buffer, samples[i].right); + } + } + ConditionWake(&audioContext.cond); + MutexUnlock(&audioContext.mutex); + vita2d_start_drawing(); vita2d_clear_screen(); vita2d_draw_texture_scale(tex, 120, 32, 3.0f, 3.0f);

@@ -140,6 +208,15 @@ rom->close(rom);

save->close(save); GBAInputMapDeinit(&inputMap); + + MutexLock(&audioContext.mutex); + audioContext.running = false; + ConditionWake(&audioContext.cond); + MutexUnlock(&audioContext.mutex); + ThreadJoin(audioThread); + CircleBufferDeinit(&audioContext.buffer); + MutexDeinit(&audioContext.mutex); + ConditionDeinit(&audioContext.cond); mappedMemoryFree(gba, 0); mappedMemoryFree(cpu, 0);
M src/platform/psp2/threading.hsrc/platform/psp2/threading.h

@@ -118,6 +118,7 @@

static inline int ThreadCreate(Thread* thread, ThreadEntry entry, void* context) { Thread id = sceKernelCreateThread("SceThread", _sceThreadEntry, 0x40, 0x10000, 0, 0x70000, 0); if (id < 0) { + *thread = 0; return id; } *thread = id;