Add PS Vita backend.

This commit is contained in:
David Reid
2026-03-01 07:53:00 +10:00
parent d7ce0506f6
commit bc52a82903
5 changed files with 569 additions and 0 deletions
+1
View File
@@ -43,6 +43,7 @@
/tests/xbox/*.iso
/tests/xbox/*.exe
/tests/xbox/test.mp3
/tests/vita/build/
/tests/*.c
/tests/*.cpp
/website/docs/
+9
View File
@@ -38,6 +38,7 @@ option(MINIAUDIO_NO_OPENSL "Disable the OpenSL|ES backend"
option(MINIAUDIO_NO_WEBAUDIO "Disable the Web Audio backend" OFF)
option(MINIAUDIO_NO_DREAMCAST "Disable the Dreamcast backend" OFF)
option(MINIAUDIO_NO_XAUDIO "Disable the XAudio (OG Xbox) backend" OFF)
option(MINIAUDIO_NO_VITA "Disable the Vita backend" OFF)
option(MINIAUDIO_NO_NULL "Disable the null backend" OFF)
option(MINIAUDIO_NO_SDL2 "Disable the SDL2 backend" OFF)
option(MINIAUDIO_ENABLE_ONLY_SPECIFIC_BACKENDS "Only enable specific backends. Backends can be enabled with MINIAUDIO_ENABLE_[BACKEND]." OFF)
@@ -57,6 +58,7 @@ option(MINIAUDIO_ENABLE_OPENSL "Enable the OpenSL|ES backend"
option(MINIAUDIO_ENABLE_WEBAUDIO "Enable the Web Audio backend" OFF)
option(MINIAUDIO_ENABLE_DREAMCAST "Enable the Dreamcast backend" OFF)
option(MINIAUDIO_ENABLE_XAUDIO "Enable the XAudio (OG Xbox) backend" OFF)
option(MINIAUDIO_ENABLE_VITA "Enable the Vita backend" OFF)
option(MINIAUDIO_ENABLE_NULL "Enable the null backend" OFF)
option(MINIAUDIO_ENABLE_SDL2 "Enable the SDL2 backend" OFF)
option(MINIAUDIO_NO_DECODING "Disable decoding APIs" OFF)
@@ -117,6 +119,7 @@ normalize_backend_enabled_option(OPENSL)
normalize_backend_enabled_option(WEBAUDIO)
normalize_backend_enabled_option(DREAMCAST)
normalize_backend_enabled_option(XAUDIO)
normalize_backend_enabled_option(VITA)
normalize_backend_enabled_option(NULL)
normalize_backend_enabled_option(SDL2)
@@ -300,6 +303,9 @@ endif()
if(MINIAUDIO_NO_XAUDIO)
list(APPEND COMPILE_DEFINES MA_NO_XAUDIO)
endif()
if(MINIAUDIO_NO_VITA)
list(APPEND COMPILE_DEFINES MA_NO_VITA)
endif()
if(MINIAUDIO_NO_NULL)
list(APPEND COMPILE_DEFINES MA_NO_NULL)
endif()
@@ -357,6 +363,9 @@ if(MINIAUDIO_ENABLE_ONLY_SPECIFIC_BACKENDS)
if(MINIAUDIO_ENABLE_XAUDIO)
list(APPEND COMPILE_DEFINES MA_ENABLE_XAUDIO)
endif()
if(MINIAUDIO_ENABLE_VITA)
list(APPEND COMPILE_DEFINES MA_ENABLE_VITA)
endif()
if(MINIAUDIO_ENABLE_NULL)
list(APPEND COMPILE_DEFINES MA_ENABLE_NULL)
endif()
+408
View File
@@ -3740,6 +3740,7 @@ example, ALSA, which is specific to Linux, will not be included in the Windows b
| Web Audio | ma_device_backend_webaudio | Web (via Emscripten) |
| Dreamcast | ma_device_backend_dreamcast | KallistiOS |
| XAudio | ma_device_backend_xaudio | NXDK |
| PS Vita | ma_device_backend_vita | Vita SDK |
| Null | ma_device_backend_null | Cross Platform (not used on Web) |
+-------------+------------------------------+--------------------------------------------------------+
@@ -3883,6 +3884,29 @@ use a period size smaller than 1024, but in my testing I found that it can resul
are not forced to use this configuration, but if you deviate from it miniaudio will need to do data
conversion.
15.8. PlayStation Vita
----------------------
The Vita backend uses Vita SDK.
The following device configuration is optimal:
Format: ma_foramt_s16
Channels: 2
Sample Rate: 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100 or 48000
Period Size: Multiple of 64, between 64 and 65472
noFixedSizedCallback: True
If you follow this configuration you can be guaranteed an optimized passthrough pipeline, except
when using a sample rate other than 48000 on the Main port (see below).
The BGM port (SCE_AUDIO_OUT_PORT_TYPE_BGM) is used by default. You can use the Main port by
configuring it in the device config:
deviceConfig.vita.portType = MA_VITA_PORT_TYPE_MAIN; // Or MA_VITA_PORT_TYPE_BGM
When using MA_VITA_PORT_TYPE_MAIN, the native sample rate will always be 48000 and using anything
else will invoke miniaudio's resampler which will have overhead.
16. Optimization Tips
=====================
@@ -7482,6 +7506,34 @@ MA_API ma_device_config_xaudio ma_device_config_xaudio_init(void);
/* END miniaudio_xaudio.h */
/* BEG miniaudio_vita.h */
extern ma_device_backend_vtable* ma_device_backend_vita;
MA_API ma_device_backend_vtable* ma_vita_get_vtable(void);
typedef struct
{
int _unused;
} ma_context_config_vita;
MA_API ma_context_config_vita ma_context_config_vita_init(void);
typedef enum
{
MA_VITA_PORT_TYPE_BGM = 0,
MA_VITA_PORT_TYPE_MAIN = 1
} ma_vita_port_type;
typedef struct
{
ma_vita_port_type portType;
} ma_device_config_vita;
MA_API ma_device_config_vita ma_device_config_vita_init(void);
/* END miniaudio_vita.h */
/* BEG miniaudio_null.h */
typedef struct ma_context_config_null
{
@@ -7914,6 +7966,7 @@ struct ma_device_config
ma_device_config_webaudio webaudio;
ma_device_config_dreamcast dreamcast;
ma_device_config_xaudio xaudio;
ma_device_config_vita vita;
ma_device_config_null null_backend;
};
@@ -8055,6 +8108,7 @@ struct ma_context_config
ma_context_config_webaudio webaudio;
ma_context_config_dreamcast dreamcast;
ma_context_config_xaudio xaudio;
ma_context_config_vita vita;
ma_context_config_null null_backend;
};
@@ -20338,6 +20392,9 @@ BACKENDS
#if defined(MA_XBOX)
#define MA_SUPPORT_XAUDIO
#endif
#if defined(MA_VITA)
#define MA_SUPPORT_VITA
#endif
/* All platforms should support custom backends. */
#define MA_SUPPORT_CUSTOM
@@ -20396,6 +20453,9 @@ BACKENDS
#if defined(MA_SUPPORT_XAUDIO) && !defined(MA_NO_XAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_XAUDIO))
#define MA_HAS_XAUDIO
#endif
#if defined(MA_SUPPORT_VITA) && !defined(MA_NO_VITA) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_VITA))
#define MA_HAS_VITA
#endif
#if defined(MA_SUPPORT_NULL) && !defined(MA_NO_NULL) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_NULL))
#define MA_HAS_NULL
#endif
@@ -48766,6 +48826,347 @@ MA_API ma_device_config_xaudio ma_device_config_xaudio_init(void)
/* END miniaudio_xaudio.c */
/* BEG miniaudio_vita.c */
#if defined(MA_HAS_VITA)
#include <psp2/audioout.h>
typedef struct ma_context_state_vita
{
int _unused;
} ma_context_state_vita;
typedef struct ma_device_state_vita
{
int port;
ma_bool32 isRunning; /* Used for tracking whether or not the background thread should be terminated. */
ma_thread thread; /* Need to call sceAudioOutOutput() from a separate thread because it is always blocking. */
ma_uint32 subBufferIndex;
ma_uint32 validSubBufferCount;
void* pSubBuffers;
} ma_device_state_vita;
static ma_context_state_vita* ma_context_get_backend_state__vita(ma_context* pContext)
{
return (ma_context_state_vita*)ma_context_get_backend_state(pContext);
}
static ma_device_state_vita* ma_device_get_backend_state__vita(ma_device* pDevice)
{
return (ma_device_state_vita*)ma_device_get_backend_state(pDevice);
}
static void ma_backend_info__vita(ma_device_backend_info* pBackendInfo)
{
pBackendInfo->pName = "PlayStation Vita";
}
static ma_result ma_context_init__vita(ma_context* pContext, const void* pContextBackendConfig, void** ppContextState)
{
ma_context_state_vita* pContextStateVita;
const ma_context_config_vita* pContextConfigVita = (ma_context_config_vita*)pContextBackendConfig;
pContextStateVita = (ma_context_state_vita*)ma_calloc(sizeof(*pContextStateVita), ma_context_get_allocation_callbacks(pContext));
if (pContextStateVita == NULL) {
return MA_OUT_OF_MEMORY;
}
(void)pContextConfigVita;
(void)pContext;
*ppContextState = pContextStateVita;
return MA_SUCCESS;
}
static void ma_context_uninit__vita(ma_context* pContext)
{
ma_context_state_vita* pContextStateVita = ma_context_get_backend_state__vita(pContext);
ma_free(pContextStateVita, ma_context_get_allocation_callbacks(pContext));
}
static ma_result ma_context_enumerate_devices__vita(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pCallbackUserData)
{
ma_context_state_vita* pContextStateVita = ma_context_get_backend_state__vita(pContext);
ma_device_info deviceInfo;
ma_device_enumeration_result enumerationResult;
(void)pContextStateVita;
/* Playback. */
MA_ZERO_OBJECT(&deviceInfo);
deviceInfo.isDefault = MA_TRUE;
deviceInfo.id.custom.i = 0;
ma_strncpy_s(deviceInfo.name, sizeof(deviceInfo.name), "Default Playback Device", (size_t)-1);
/* Only s16 and mono/stereo is natively supported. */
ma_device_info_add_native_data_format(&deviceInfo, ma_format_s16, 1, 2, 8000, 48000);
enumerationResult = callback(ma_device_type_playback, &deviceInfo, pCallbackUserData);
if (enumerationResult == MA_DEVICE_ENUMERATION_ABORT) {
return MA_SUCCESS;
}
return MA_SUCCESS;
}
static void* ma_device_get_sub_buffer__vita(ma_device* pDevice, ma_uint32 subBufferIndex)
{
ma_device_state_vita* pDeviceStateVita = ma_device_get_backend_state__vita(pDevice);
return ma_offset_ptr(pDeviceStateVita->pSubBuffers, pDevice->playback.internalPeriodSizeInFrames * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels) * subBufferIndex);
}
static ma_thread_result MA_THREADCALL ma_device_audio_thread__vita(void* pUserData)
{
ma_device* pDevice = (ma_device*)pUserData;
ma_device_state_vita* pDeviceStateVita = ma_device_get_backend_state__vita(pDevice);
while (ma_atomic_load_explicit_32(&pDeviceStateVita->isRunning, ma_atomic_memory_order_relaxed)) {
if (ma_atomic_load_explicit_32(&pDeviceStateVita->validSubBufferCount, ma_atomic_memory_order_acquire) > 0) {
ma_uint32 subBufferIndex = ma_atomic_load_explicit_32(&pDeviceStateVita->subBufferIndex, ma_atomic_memory_order_relaxed);
sceAudioOutOutput(pDeviceStateVita->port, ma_device_get_sub_buffer__vita(pDevice, subBufferIndex));
ma_atomic_store_explicit_32(&pDeviceStateVita->subBufferIndex, (subBufferIndex + 1) & 1, ma_atomic_memory_order_relaxed);
ma_atomic_fetch_sub_explicit_32(&pDeviceStateVita->validSubBufferCount, 1, ma_atomic_memory_order_release);
} else {
/* Just a dumb sleep so we don't peg the CPU while the device is not stopped. */
ma_sleep(10);
}
}
return (ma_thread_result)0;
}
static ma_result ma_device_init__vita(ma_device* pDevice, const void* pDeviceBackendConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture, void** ppDeviceState)
{
ma_result result;
ma_device_state_vita* pDeviceStateVita;
ma_device_config_vita* pDeviceConfigVita = (ma_device_config_vita*)pDeviceBackendConfig;
ma_context_state_vita* pContextStateVita = ma_context_get_backend_state__vita(ma_device_get_context(pDevice));
ma_device_config_vita defaultConfig;
ma_device_type deviceType = ma_device_get_type(pDevice);
ma_log* pLog = ma_device_get_log(pDevice);
ma_format format;
ma_uint32 channels;
ma_uint32 sampleRate;
ma_uint32 periodSizeInFrames;
SceAudioOutPortType portType;
(void)pContextStateVita;
(void)pDescriptorCapture;
/* Use a default config if one was not provided. This is not mandated by miniaudio, but it's good practice. */
if (pDeviceConfigVita == NULL) {
defaultConfig = ma_device_config_vita_init();
pDeviceConfigVita = &defaultConfig;
}
/* Return an error for any unsupported device types. */
if (deviceType != ma_device_type_playback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
pDeviceStateVita = (ma_device_state_vita*)ma_calloc(sizeof(*pDeviceStateVita), ma_device_get_allocation_callbacks(pDevice));
if (pDeviceStateVita == NULL) {
return MA_OUT_OF_MEMORY;
}
/* Port type. */
portType = SCE_AUDIO_OUT_PORT_TYPE_BGM;
if (pDeviceConfigVita->portType == MA_VITA_PORT_TYPE_MAIN) {
portType = SCE_AUDIO_OUT_PORT_TYPE_MAIN;
}
/* Format is always s16. */
format = ma_format_s16;
/* Channels is always mono or stereo. Default to stereo. */
channels = pDescriptorPlayback->channels;
if (channels != 1 && channels != 2) {
channels = 1;
}
/* Sample rate. */
sampleRate = 0;
if (pDescriptorPlayback->sampleRate != 0) {
if (portType == SCE_AUDIO_OUT_PORT_TYPE_BGM) {
ma_uint32 bgmSampleRates[] = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000};
ma_uint32 iSampleRate;
for (iSampleRate = 0; iSampleRate < ma_countof(bgmSampleRates); iSampleRate += 1) {
if (pDescriptorPlayback->sampleRate == bgmSampleRates[iSampleRate]) {
sampleRate = bgmSampleRates[iSampleRate];
}
}
}
}
if (sampleRate == 0) {
sampleRate = 48000;
}
/* The period size must be a multiple of 64. */
periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, sampleRate);
periodSizeInFrames = ma_clamp((periodSizeInFrames + 63) & ~63, SCE_AUDIO_MIN_LEN, SCE_AUDIO_MAX_LEN);
pDeviceStateVita->pSubBuffers = ma_malloc(periodSizeInFrames * ma_get_bytes_per_frame(format, channels) * 2, ma_device_get_allocation_callbacks(pDevice));
if (pDeviceStateVita->pSubBuffers == NULL) {
return MA_OUT_OF_MEMORY;
}
pDeviceStateVita->port = sceAudioOutOpenPort(portType, (int)periodSizeInFrames, (int)sampleRate, (channels == 1) ? SCE_AUDIO_OUT_MODE_MONO : SCE_AUDIO_OUT_MODE_STEREO);
if (pDeviceStateVita->port < 0) {
ma_free(pDeviceStateVita->pSubBuffers, ma_device_get_allocation_callbacks(pDevice));
ma_log_postf(pLog, MA_LOG_LEVEL_ERROR, "[Vita] Failed to open port.");
return MA_ERROR;
}
/* Make sure the running status is set appropriately so the audio thread doesn't immediately terminate itself. */
ma_atomic_store_explicit_32(&pDeviceStateVita->isRunning, 1, ma_atomic_memory_order_relaxed);
/*
Because sceAudioOutOutput() is always blocking, in order to do non-blocking processing, we'll need to call
it on a separate thread. Make sure the thread is created last.
*/
result = ma_thread_create(&pDeviceStateVita->thread, ma_thread_priority_default, 0, ma_device_audio_thread__vita, pDevice, ma_device_get_allocation_callbacks(pDevice));
if (result != MA_SUCCESS) {
sceAudioOutReleasePort(pDeviceStateVita->port);
ma_free(pDeviceStateVita->pSubBuffers, ma_device_get_allocation_callbacks(pDevice));
ma_log_postf(pLog, MA_LOG_LEVEL_ERROR, "[Vita] Failed to create audio thread.");
return MA_ERROR;
}
/* Update the descriptor with the actual internal settings. */
pDescriptorPlayback->format = format;
pDescriptorPlayback->channels = channels;
pDescriptorPlayback->sampleRate = sampleRate;
pDescriptorPlayback->periodSizeInFrames = periodSizeInFrames;
pDescriptorPlayback->periodCount = 2;
*ppDeviceState = pDeviceStateVita;
return MA_SUCCESS;
}
static void ma_device_uninit__vita(ma_device* pDevice)
{
ma_device_state_vita* pDeviceStateVita = ma_device_get_backend_state__vita(pDevice);
/* Kill the thread first. */
ma_atomic_store_explicit_32(&pDeviceStateVita->isRunning, 0, ma_atomic_memory_order_relaxed);
ma_thread_wait(&pDeviceStateVita->thread);
sceAudioOutReleasePort(pDeviceStateVita->port);
ma_free(pDeviceStateVita->pSubBuffers, ma_device_get_allocation_callbacks(pDevice));
ma_free(pDeviceStateVita, ma_device_get_allocation_callbacks(pDevice));
}
static ma_result ma_device_start__vita(ma_device* pDevice)
{
ma_device_state_vita* pDeviceStateVita = ma_device_get_backend_state__vita(pDevice);
ma_atomic_store_explicit_32(&pDeviceStateVita->subBufferIndex, 0, ma_atomic_memory_order_relaxed);
ma_atomic_store_explicit_32(&pDeviceStateVita->validSubBufferCount, 0, ma_atomic_memory_order_relaxed);
/* Don't actually do anything here. We start by simply outputting data. Stopping is just not outputting data. */
return MA_SUCCESS;
}
static ma_result ma_device_stop__vita(ma_device* pDevice)
{
ma_device_state_vita* pDeviceStateVita = ma_device_get_backend_state__vita(pDevice);
/* Wait for the buffers to be drained. */
while (ma_atomic_load_explicit_32(&pDeviceStateVita->validSubBufferCount, ma_atomic_memory_order_relaxed) > 0) {
ma_sleep(1);
}
return MA_SUCCESS;
}
static ma_result ma_device_step__vita(ma_device* pDevice, ma_blocking_mode blockingMode)
{
ma_device_state_vita* pDeviceStateVita = ma_device_get_backend_state__vita(pDevice);
for (;;) {
if (!ma_device_is_started(pDevice)) {
return MA_DEVICE_NOT_STARTED;
}
if (ma_atomic_load_explicit_32(&pDeviceStateVita->validSubBufferCount, ma_atomic_memory_order_acquire) < 2) {
ma_uint32 subBufferIndex = ma_atomic_load_explicit_32(&pDeviceStateVita->subBufferIndex, ma_atomic_memory_order_relaxed);
ma_device_handle_backend_data_callback(pDevice, ma_device_get_sub_buffer__vita(pDevice, subBufferIndex), NULL, pDevice->playback.internalPeriodSizeInFrames);
ma_atomic_fetch_add_explicit_32(&pDeviceStateVita->validSubBufferCount, 1, ma_atomic_memory_order_release);
return MA_SUCCESS;
}
/* Getting here means there was no data to process. */
if (blockingMode == MA_BLOCKING_MODE_NON_BLOCKING) {
return MA_SUCCESS;
}
/* Getting here means there was no data to process and we're running in blocking mode. Sleep for a bit and keep trying. */
ma_sleep(1);
}
}
static void ma_device_wakeup__vita(ma_device* pDevice)
{
/* Nothing to do here. */
(void)pDevice;
}
static ma_device_backend_vtable ma_gDeviceBackendVTable_Vita =
{
ma_backend_info__vita,
ma_context_init__vita,
ma_context_uninit__vita,
ma_context_enumerate_devices__vita,
ma_device_init__vita,
ma_device_uninit__vita,
ma_device_start__vita,
ma_device_stop__vita,
ma_device_step__vita,
ma_device_wakeup__vita
};
ma_device_backend_vtable* ma_device_backend_vita = &ma_gDeviceBackendVTable_Vita;
#else
ma_device_backend_vtable* ma_device_backend_vita = NULL;
#endif /* MA_HAS_VITA */
MA_API ma_device_backend_vtable* ma_vita_get_vtable(void)
{
return ma_device_backend_vita;
}
MA_API ma_context_config_vita ma_context_config_vita_init(void)
{
ma_context_config_vita config;
MA_ZERO_OBJECT(&config);
return config;
}
MA_API ma_device_config_vita ma_device_config_vita_init(void)
{
ma_device_config_vita config;
MA_ZERO_OBJECT(&config);
config.portType = MA_VITA_PORT_TYPE_BGM;
return config;
}
/* END miniaudio_vita.c */
MA_API void ma_get_device_backend_info(ma_device_backend_vtable* pBackendVTable, ma_device_backend_info* pBackendInfo)
{
@@ -49800,6 +50201,9 @@ static const void* ma_context_config_find_backend_config(const ma_context_config
if (pVTable == ma_device_backend_xaudio) {
return &pConfig->xaudio;
}
if (pVTable == ma_device_backend_vita) {
return &pConfig->vita;
}
if (pVTable == ma_device_backend_null) {
return &pConfig->null_backend;
}
@@ -49831,6 +50235,7 @@ MA_API ma_uint32 ma_get_stock_device_backends(ma_device_backend_config* pBackend
if (backendsCap > count) { pBackends[count++] = ma_device_backend_config_init(ma_device_backend_webaudio, NULL); }
if (backendsCap > count) { pBackends[count++] = ma_device_backend_config_init(ma_device_backend_dreamcast, NULL); }
if (backendsCap > count) { pBackends[count++] = ma_device_backend_config_init(ma_device_backend_xaudio, NULL); }
if (backendsCap > count) { pBackends[count++] = ma_device_backend_config_init(ma_device_backend_vita, NULL); }
if (backendsCap > count) { pBackends[count++] = ma_device_backend_config_init(ma_device_backend_null, NULL); }
return count;
@@ -50302,6 +50707,9 @@ static const void* ma_device_config_find_backend_config(const ma_device_config*
if (pVTable == ma_device_backend_xaudio) {
return &pConfig->xaudio;
}
if (pVTable == ma_device_backend_vita) {
return &pConfig->vita;
}
if (pVTable == ma_device_backend_null) {
return &pConfig->null_backend;
}
+37
View File
@@ -0,0 +1,37 @@
cmake_minimum_required(VERSION 3.16)
if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
if(DEFINED ENV{VITASDK})
set(CMAKE_TOOLCHAIN_FILE "$ENV{VITASDK}/share/vita.toolchain.cmake" CACHE PATH "toolchain file")
else()
message(FATAL_ERROR "Please define VITASDK to point to your SDK path!")
endif()
endif()
project(miniaudio_vita)
include("${VITASDK}/share/vita.cmake" REQUIRED)
set(VITA_APP_NAME "miniaudio_vita")
set(VITA_TITLEID "MINIAUDIO00001")
set(VITA_VERSION "01.00")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_executable(${PROJECT_NAME}
miniaudio_vita.c
)
target_link_libraries(${PROJECT_NAME}
m
SceAudio_stub
SceDisplay_stub
SceCtrl_stub
)
vita_create_self(${PROJECT_NAME}.self ${PROJECT_NAME})
vita_create_vpk(${PROJECT_NAME}.vpk ${VITA_TITLEID} ${PROJECT_NAME}.self
VERSION ${VITA_VERSION}
NAME ${VITA_APP_NAME}
)
+114
View File
@@ -0,0 +1,114 @@
/* Uncomment this and update the path to enable the debug screen. */
/*#include "/opt/toolchains/vitasdk/samples/common/debugScreen.c"*/
#if defined(DEBUG_SCREEN_H)
#define HAS_DEBUG_SCREEN
#endif
#ifdef HAS_DEBUG_SCREEN
#define printf psvDebugScreenPrintf
#endif
#define MA_DEBUG_OUTPUT
#include "../../miniaudio.c"
#include <psp2/ctrl.h>
static void data_callback(ma_device* pDevice, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount)
{
static int c = 0;
ma_data_source* pDataSource = (ma_data_source*)ma_device_get_user_data(pDevice);
ma_data_source_read_pcm_frames(pDataSource, pFramesOut, frameCount, NULL);
(void)pFramesIn;
(void)pDevice;
}
int main()
{
ma_result result;
ma_device_config deviceConfig;
ma_device device;
ma_waveform waveform;
ma_decoder decoder;
SceCtrlData ctrlPeek, ctrlPress;
#ifdef HAS_DEBUG_SCREEN
psvDebugScreenInit();
#endif
deviceConfig = ma_device_config_init(ma_device_type_playback);
//deviceConfig.threadingMode = MA_THREADING_MODE_SINGLE_THREADED;
deviceConfig.playback.format = ma_format_s16;
deviceConfig.playback.channels = 2;
deviceConfig.sampleRate = 48000;
deviceConfig.dataCallback = data_callback;
deviceConfig.pUserData = &waveform;
deviceConfig.periodSizeInFrames = 1024;
#if 0
ma_device_backend_config backend = ma_device_backend_config_init(ma_device_backend_vita, NULL);
result = ma_device_init_ex(&backend, 1, NULL, &deviceConfig, &device);
#else
result = ma_device_init(NULL, &deviceConfig, &device);
#endif
if (result != MA_SUCCESS) {
return 1;
}
/* Initialize the waveform before starting the device. */
{
ma_waveform_config waveformConfig = ma_waveform_config_init(device.playback.format, device.playback.channels, device.sampleRate, ma_waveform_type_sine, 0.1f, 400);
ma_waveform_init(&waveformConfig, &waveform);
}
/* Decoder. */
#if 0
{
ma_decoder_config decoderConfig = ma_decoder_config_init(device.playback.format, device.playback.channels, device.sampleRate);
ma_decoder_init_file("test.mp3", &decoderConfig, &decoder);
}
#endif
result = ma_device_start(&device);
if (result != MA_SUCCESS) {
return 1;
}
for (;;) {
ctrlPress = ctrlPeek;
sceCtrlPeekBufferPositive(0, &ctrlPeek, 1);
ctrlPress.buttons = ctrlPeek.buttons & ~ctrlPress.buttons;
if(ctrlPress.buttons == SCE_CTRL_SQUARE) {
if (ma_device_is_started(&device)) {
printf("STOPPING\n");
ma_device_stop(&device);
} else {
printf("STARTING\n");
ma_device_start(&device);
}
}
if(ctrlPress.buttons == SCE_CTRL_CROSS) {
break;
}
if (ma_device_get_threading_mode(&device) == MA_THREADING_MODE_SINGLE_THREADED) {
ma_device_step(&device, MA_BLOCKING_MODE_NON_BLOCKING);
/*
I found that if I don't relax the CPU a bit I'll get glitching when running in vita3k. Maybe the loop is pinning the CPU
at 100% and starving the audio system?
*/
ma_sleep(1);
} else {
ma_sleep(1);
}
}
ma_waveform_uninit(&waveform);
ma_device_uninit(&device);
return 0;
}