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/*.iso
/tests/xbox/*.exe /tests/xbox/*.exe
/tests/xbox/test.mp3 /tests/xbox/test.mp3
/tests/vita/build/
/tests/*.c /tests/*.c
/tests/*.cpp /tests/*.cpp
/website/docs/ /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_WEBAUDIO "Disable the Web Audio backend" OFF)
option(MINIAUDIO_NO_DREAMCAST "Disable the Dreamcast 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_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_NULL "Disable the null backend" OFF)
option(MINIAUDIO_NO_SDL2 "Disable the SDL2 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) 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_WEBAUDIO "Enable the Web Audio backend" OFF)
option(MINIAUDIO_ENABLE_DREAMCAST "Enable the Dreamcast 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_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_NULL "Enable the null backend" OFF)
option(MINIAUDIO_ENABLE_SDL2 "Enable the SDL2 backend" OFF) option(MINIAUDIO_ENABLE_SDL2 "Enable the SDL2 backend" OFF)
option(MINIAUDIO_NO_DECODING "Disable decoding APIs" 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(WEBAUDIO)
normalize_backend_enabled_option(DREAMCAST) normalize_backend_enabled_option(DREAMCAST)
normalize_backend_enabled_option(XAUDIO) normalize_backend_enabled_option(XAUDIO)
normalize_backend_enabled_option(VITA)
normalize_backend_enabled_option(NULL) normalize_backend_enabled_option(NULL)
normalize_backend_enabled_option(SDL2) normalize_backend_enabled_option(SDL2)
@@ -300,6 +303,9 @@ endif()
if(MINIAUDIO_NO_XAUDIO) if(MINIAUDIO_NO_XAUDIO)
list(APPEND COMPILE_DEFINES MA_NO_XAUDIO) list(APPEND COMPILE_DEFINES MA_NO_XAUDIO)
endif() endif()
if(MINIAUDIO_NO_VITA)
list(APPEND COMPILE_DEFINES MA_NO_VITA)
endif()
if(MINIAUDIO_NO_NULL) if(MINIAUDIO_NO_NULL)
list(APPEND COMPILE_DEFINES MA_NO_NULL) list(APPEND COMPILE_DEFINES MA_NO_NULL)
endif() endif()
@@ -357,6 +363,9 @@ if(MINIAUDIO_ENABLE_ONLY_SPECIFIC_BACKENDS)
if(MINIAUDIO_ENABLE_XAUDIO) if(MINIAUDIO_ENABLE_XAUDIO)
list(APPEND COMPILE_DEFINES MA_ENABLE_XAUDIO) list(APPEND COMPILE_DEFINES MA_ENABLE_XAUDIO)
endif() endif()
if(MINIAUDIO_ENABLE_VITA)
list(APPEND COMPILE_DEFINES MA_ENABLE_VITA)
endif()
if(MINIAUDIO_ENABLE_NULL) if(MINIAUDIO_ENABLE_NULL)
list(APPEND COMPILE_DEFINES MA_ENABLE_NULL) list(APPEND COMPILE_DEFINES MA_ENABLE_NULL)
endif() 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) | | Web Audio | ma_device_backend_webaudio | Web (via Emscripten) |
| Dreamcast | ma_device_backend_dreamcast | KallistiOS | | Dreamcast | ma_device_backend_dreamcast | KallistiOS |
| XAudio | ma_device_backend_xaudio | NXDK | | 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) | | 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 are not forced to use this configuration, but if you deviate from it miniaudio will need to do data
conversion. 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 16. Optimization Tips
===================== =====================
@@ -7482,6 +7506,34 @@ MA_API ma_device_config_xaudio ma_device_config_xaudio_init(void);
/* END miniaudio_xaudio.h */ /* 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 */ /* BEG miniaudio_null.h */
typedef struct ma_context_config_null typedef struct ma_context_config_null
{ {
@@ -7914,6 +7966,7 @@ struct ma_device_config
ma_device_config_webaudio webaudio; ma_device_config_webaudio webaudio;
ma_device_config_dreamcast dreamcast; ma_device_config_dreamcast dreamcast;
ma_device_config_xaudio xaudio; ma_device_config_xaudio xaudio;
ma_device_config_vita vita;
ma_device_config_null null_backend; ma_device_config_null null_backend;
}; };
@@ -8055,6 +8108,7 @@ struct ma_context_config
ma_context_config_webaudio webaudio; ma_context_config_webaudio webaudio;
ma_context_config_dreamcast dreamcast; ma_context_config_dreamcast dreamcast;
ma_context_config_xaudio xaudio; ma_context_config_xaudio xaudio;
ma_context_config_vita vita;
ma_context_config_null null_backend; ma_context_config_null null_backend;
}; };
@@ -20338,6 +20392,9 @@ BACKENDS
#if defined(MA_XBOX) #if defined(MA_XBOX)
#define MA_SUPPORT_XAUDIO #define MA_SUPPORT_XAUDIO
#endif #endif
#if defined(MA_VITA)
#define MA_SUPPORT_VITA
#endif
/* All platforms should support custom backends. */ /* All platforms should support custom backends. */
#define MA_SUPPORT_CUSTOM #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)) #if defined(MA_SUPPORT_XAUDIO) && !defined(MA_NO_XAUDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_XAUDIO))
#define MA_HAS_XAUDIO #define MA_HAS_XAUDIO
#endif #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)) #if defined(MA_SUPPORT_NULL) && !defined(MA_NO_NULL) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_NULL))
#define MA_HAS_NULL #define MA_HAS_NULL
#endif #endif
@@ -48766,6 +48826,347 @@ MA_API ma_device_config_xaudio ma_device_config_xaudio_init(void)
/* END miniaudio_xaudio.c */ /* 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) 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) { if (pVTable == ma_device_backend_xaudio) {
return &pConfig->xaudio; return &pConfig->xaudio;
} }
if (pVTable == ma_device_backend_vita) {
return &pConfig->vita;
}
if (pVTable == ma_device_backend_null) { if (pVTable == ma_device_backend_null) {
return &pConfig->null_backend; 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_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_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_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); } if (backendsCap > count) { pBackends[count++] = ma_device_backend_config_init(ma_device_backend_null, NULL); }
return count; 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) { if (pVTable == ma_device_backend_xaudio) {
return &pConfig->xaudio; return &pConfig->xaudio;
} }
if (pVTable == ma_device_backend_vita) {
return &pConfig->vita;
}
if (pVTable == ma_device_backend_null) { if (pVTable == ma_device_backend_null) {
return &pConfig->null_backend; 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;
}