Add miniaudio andren for switch

Add miniaudio audren without thread


Add miniaudio audren with thread


Add miniaudio audren with thread single file


Add miniaudio audren with thread kind of working


Add miniaudio audren with thread working
This commit is contained in:
Luiz Pestana 2022-06-01 14:43:12 -03:00
parent 0d7f4ab4f8
commit 0dd2ff5c1b
5 changed files with 269 additions and 238 deletions

View File

@ -396,7 +396,6 @@ ifeq ($(PLATFORM),PLATFORM_WEB)
endif endif
ifeq ($(PLATFORM),PLATFORM_NX) ifeq ($(PLATFORM),PLATFORM_NX)
LDLIBS = -lraylib -lEGL -lGLESv2 -lglapi -ldrm_nouveau -lnx -lm LDLIBS = -lraylib -lEGL -lGLESv2 -lglapi -ldrm_nouveau -lnx -lm
LDLIBS += `$(PREFIX)pkg-config --libs sdl2`
endif endif
# Define source code object files required # Define source code object files required

View File

@ -64,8 +64,6 @@ ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lraylib -lEGL -lGLESv2 -lglapi -ldrm_nouveau -lnx -lm LIBS := -lraylib -lEGL -lGLESv2 -lglapi -ldrm_nouveau -lnx -lm
# remove the next line if you dont need audio
LIBS += `$(PREFIX)pkg-config --libs sdl2`
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing # list of directories containing libraries, this must be the top level containing

View File

@ -1,233 +0,0 @@
/******************************************************************************
SDL Backend
******************************************************************************/
struct
{
ma_uint32 deviceID;
} device_sdl;
struct
{
ma_handle hSDL;
ma_proc SDL_InitSubSystem;
ma_proc SDL_QuitSubSystem;
ma_proc SDL_GetNumAudioDevices;
ma_proc SDL_GetAudioDeviceName;
ma_proc SDL_CloseAudioDevice;
ma_proc SDL_OpenAudioDevice;
ma_proc SDL_PauseAudioDevice;
} context_sdl;
#define MA_SDL_INIT_AUDIO 0x00000010
#define MA_AUDIO_U8 0x0008
#define MA_AUDIO_S16 0x8010
#define MA_AUDIO_S32 0x8020
#define MA_AUDIO_F32 0x8120
#define MA_SDL_AUDIO_ALLOW_FREQUENCY_CHANGE 0x00000001
#define MA_SDL_AUDIO_ALLOW_FORMAT_CHANGE 0x00000002
#define MA_SDL_AUDIO_ALLOW_CHANNELS_CHANGE 0x00000004
#define MA_SDL_AUDIO_ALLOW_ANY_CHANGE (MA_SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | MA_SDL_AUDIO_ALLOW_FORMAT_CHANGE | MA_SDL_AUDIO_ALLOW_CHANNELS_CHANGE)
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
typedef int (* MA_PFN_SDL_InitSubSystem)(ma_uint32 flags);
typedef void (* MA_PFN_SDL_QuitSubSystem)(ma_uint32 flags);
typedef int (* MA_PFN_SDL_GetNumAudioDevices)(int iscapture);
typedef const char* (* MA_PFN_SDL_GetAudioDeviceName)(int index, int iscapture);
typedef void (* MA_PFN_SDL_CloseAudioDevice)(SDL_AudioDeviceID dev);
typedef SDL_AudioDeviceID (* MA_PFN_SDL_OpenAudioDevice)(const char* device, int iscapture, const SDL_AudioSpec* desired, SDL_AudioSpec* obtained, int allowed_changes);
typedef void (* MA_PFN_SDL_PauseAudioDevice)(SDL_AudioDeviceID dev, int pause_on);
static SDL_AudioFormat ma_format_to_sdl(ma_format format)
{
switch (format)
{
case ma_format_unknown: return 0;
case ma_format_u8: return MA_AUDIO_U8;
case ma_format_s16: return MA_AUDIO_S16;
case ma_format_s24: return MA_AUDIO_S32; // Closest match.
case ma_format_s32: return MA_AUDIO_S32;
case ma_format_f32: return MA_AUDIO_F32;
default: return 0;
}
}
static ma_format ma_format_from_sdl(SDL_AudioFormat format)
{
switch (format)
{
case MA_AUDIO_U8: return ma_format_u8;
case MA_AUDIO_S16: return ma_format_s16;
case MA_AUDIO_S32: return ma_format_s32;
case MA_AUDIO_F32: return ma_format_f32;
default: return ma_format_unknown;
}
}
static ma_result ma_context_get_device_info__sdl(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(deviceType == ma_device_type_playback);
pDeviceInfo->isDefault = MA_TRUE;
SDL_AudioSpec desiredSpec, obtainedSpec;
MA_ZERO_OBJECT(&desiredSpec);
SDL_AudioDeviceID tempDeviceID = ((MA_PFN_SDL_OpenAudioDevice)context_sdl.SDL_OpenAudioDevice)(NULL, 0, &desiredSpec, &obtainedSpec, MA_SDL_AUDIO_ALLOW_ANY_CHANGE);
((MA_PFN_SDL_CloseAudioDevice)context_sdl.SDL_CloseAudioDevice)(tempDeviceID);
ma_format format = ma_format_from_sdl(obtainedSpec.format);
if (format == ma_format_unknown) {
format = ma_format_f32;
}
pDeviceInfo->nativeDataFormatCount = 0;
ma_device_info_add_native_data_format(pDeviceInfo, format, obtainedSpec.channels, obtainedSpec.freq, 0);
return MA_SUCCESS;
}
static ma_result ma_device_uninit__sdl(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
((MA_PFN_SDL_CloseAudioDevice)context_sdl.SDL_CloseAudioDevice)(device_sdl.deviceID);
return MA_SUCCESS;
}
static void ma_audio_callback__sdl(void* pUserData, ma_uint8* pBuffer, int bufferSizeInBytes)
{
ma_device* pDevice = (ma_device*)pUserData;
MA_ASSERT(pDevice != NULL);
ma_uint32 bytesPerFrame = ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
ma_uint32 frameCount = (ma_uint32)bufferSizeInBytes / bytesPerFrame;
ma_device_handle_backend_data_callback(pDevice, pBuffer, NULL, frameCount);
}
static ma_result ma_device_init__sdl(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(pConfig != NULL);
MA_ASSERT(pConfig->deviceType == ma_device_type_playback);
if (pDescriptorPlayback->sampleRate == 0) {
pDescriptorPlayback->sampleRate = MA_DEFAULT_SAMPLE_RATE;
}
pDescriptorPlayback->periodSizeInFrames = pDescriptorPlayback->periodCount * ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
/* SDL wants the buffer size to be a power of 2 for some reason. */
if (pDescriptorPlayback->periodSizeInFrames > 32768) {
pDescriptorPlayback->periodSizeInFrames = 32768;
} else {
pDescriptorPlayback->periodSizeInFrames = ma_next_power_of_2(pDescriptorPlayback->periodSizeInFrames);
}
MA_ASSERT(pDescriptorPlayback->periodSizeInFrames <= 32768);
/* We now have enough information to set up the device. */
SDL_AudioSpec desiredSpec, obtainedSpec;
MA_ZERO_OBJECT(&desiredSpec);
desiredSpec.freq = (int)pDescriptorPlayback->sampleRate;
desiredSpec.format = ma_format_to_sdl(pDescriptorPlayback->format);
desiredSpec.channels = (ma_uint8)pDescriptorPlayback->channels;
desiredSpec.samples = (ma_uint16)pDescriptorPlayback->periodSizeInFrames;
desiredSpec.callback = ma_audio_callback__sdl;
desiredSpec.userdata = pDevice;
/* We'll fall back to f32 if we don't have an appropriate mapping between SDL and miniaudio. */
if (desiredSpec.format == ma_format_unknown) {
desiredSpec.format = MA_AUDIO_F32;
}
device_sdl.deviceID = ((MA_PFN_SDL_OpenAudioDevice)context_sdl.SDL_OpenAudioDevice)(NULL, 0, &desiredSpec, &obtainedSpec, MA_SDL_AUDIO_ALLOW_ANY_CHANGE);
/* The descriptor needs to be updated with our actual settings. */
pDescriptorPlayback->format = ma_format_from_sdl(obtainedSpec.format);
pDescriptorPlayback->channels = obtainedSpec.channels;
pDescriptorPlayback->sampleRate = (ma_uint32)obtainedSpec.freq;
ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels);
pDescriptorPlayback->periodSizeInFrames = obtainedSpec.samples;
pDescriptorPlayback->periodCount = 1; /* SDL doesn't use the notion of period counts, so just set to 1. */
return MA_SUCCESS;
}
static ma_result ma_device_start__sdl(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
((MA_PFN_SDL_PauseAudioDevice)context_sdl.SDL_PauseAudioDevice)(device_sdl.deviceID, 0);
return MA_SUCCESS;
}
static ma_result ma_device_stop__sdl(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
((MA_PFN_SDL_PauseAudioDevice)context_sdl.SDL_PauseAudioDevice)(device_sdl.deviceID, 1);
ma_device__set_state(pDevice, ma_device_state_stopped);
ma_stop_proc onStop = pDevice->onStop;
if (onStop) {
onStop(pDevice);
}
return MA_SUCCESS;
}
static ma_result ma_context_uninit__sdl(ma_context* pContext)
{
MA_ASSERT(pContext != NULL);
((MA_PFN_SDL_QuitSubSystem)context_sdl.SDL_QuitSubSystem)(MA_SDL_INIT_AUDIO);
return MA_SUCCESS;
}
static ma_result ma_context_init__sdl(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
{
MA_ASSERT(pContext != NULL);
(void)pConfig; /* Unused. */
context_sdl.SDL_InitSubSystem = (ma_proc)SDL_InitSubSystem;
context_sdl.SDL_QuitSubSystem = (ma_proc)SDL_QuitSubSystem;
context_sdl.SDL_GetNumAudioDevices = (ma_proc)SDL_GetNumAudioDevices;
context_sdl.SDL_GetAudioDeviceName = (ma_proc)SDL_GetAudioDeviceName;
context_sdl.SDL_CloseAudioDevice = (ma_proc)SDL_CloseAudioDevice;
context_sdl.SDL_OpenAudioDevice = (ma_proc)SDL_OpenAudioDevice;
context_sdl.SDL_PauseAudioDevice = (ma_proc)SDL_PauseAudioDevice;
int resultSDL = ((MA_PFN_SDL_InitSubSystem)context_sdl.SDL_InitSubSystem)(MA_SDL_INIT_AUDIO);
if (resultSDL != 0) {
return MA_ERROR;
}
pCallbacks->onContextInit = ma_context_init__sdl;
pCallbacks->onContextUninit = ma_context_uninit__sdl;
pCallbacks->onContextEnumerateDevices = NULL;
pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__sdl;
pCallbacks->onDeviceInit = ma_device_init__sdl;
pCallbacks->onDeviceUninit = ma_device_uninit__sdl;
pCallbacks->onDeviceStart = ma_device_start__sdl;
pCallbacks->onDeviceStop = ma_device_stop__sdl;
pCallbacks->onDeviceRead = NULL;
pCallbacks->onDeviceWrite = NULL;
pCallbacks->onDeviceDataLoop = NULL;
return MA_SUCCESS;
}

View File

@ -164,6 +164,7 @@ typedef struct tagBITMAPINFOHEADER {
#define MA_FREE RL_FREE #define MA_FREE RL_FREE
#if defined(PLATFORM_NX) #if defined(PLATFORM_NX)
#define MA_NO_RUNTIME_LINKING
#define MA_ENABLE_ONLY_SPECIFIC_BACKENDS #define MA_ENABLE_ONLY_SPECIFIC_BACKENDS
#define MA_ENABLE_CUSTOM #define MA_ENABLE_CUSTOM
#endif #endif
@ -176,7 +177,7 @@ typedef struct tagBITMAPINFOHEADER {
//#define MA_DEBUG_OUTPUT //#define MA_DEBUG_OUTPUT
#include "external/miniaudio.h" // Audio device initialization and management #include "external/miniaudio.h" // Audio device initialization and management
#if defined(PLATFORM_NX) #if defined(PLATFORM_NX)
#include "external/miniaudio_sdl.h" #include <miniaudio_audren.h> // Custom audio device for switch
#endif #endif
#undef PlaySound // Win32 API: windows.h > mmsystem.h defines PlaySound macro #undef PlaySound // Win32 API: windows.h > mmsystem.h defines PlaySound macro
@ -432,7 +433,7 @@ void InitAudioDevice(void)
ma_backend backends[] = { ma_backend backends[] = {
ma_backend_custom ma_backend_custom
}; };
ctxConfig.custom.onContextInit = ma_context_init__sdl; ctxConfig.custom.onContextInit = ma_context_init__audren;
ma_result result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &ctxConfig, &AUDIO.System.context); ma_result result = ma_context_init(backends, sizeof(backends)/sizeof(backends[0]), &ctxConfig, &AUDIO.System.context);
#else #else
ma_result result = ma_context_init(NULL, 0, &ctxConfig, &AUDIO.System.context); ma_result result = ma_context_init(NULL, 0, &ctxConfig, &AUDIO.System.context);

View File

@ -0,0 +1,266 @@
/******************************************************************************
Audren Backend
******************************************************************************/
#ifndef miniaudio_audren_h
#define miniaudio_audren_h
#include <stdio.h>
#include <malloc.h>
#include <stdint.h>
#include <switch.h>
#define LIBNX_AUDREN_BUFFER_COUNT 5
static const AudioRendererConfig audio_renderer_config =
{
.output_rate = AudioRendererOutputRate_48kHz,
.num_voices = 24,
.num_effects = 0,
.num_sinks = 1,
.num_mix_objs = 1,
.num_mix_buffers = 2,
};
static const int sample_rate = 48000;
static const int num_channels = 2;
static const uint8_t sink_channels[] = { 0, 1 };
typedef struct
{
AudioDriver drv;
char* mempool;
AudioDriverWaveBuf wavebufs[LIBNX_AUDREN_BUFFER_COUNT];
AudioDriverWaveBuf* current_wavebuf;
char* current_pool_ptr;
size_t current_size;
size_t buffer_size;
size_t samples;
Mutex update_lock;
} libnx_audren_t;
static ssize_t libnx_audren_audio_get_free_wavebuf_idx(libnx_audren_t* aud)
{
unsigned i;
for (i = 0; i < LIBNX_AUDREN_BUFFER_COUNT; i++)
{
if (aud->wavebufs[i].state == AudioDriverWaveBufState_Free || aud->wavebufs[i].state == AudioDriverWaveBufState_Done)
return i;
}
return -1;
}
static size_t libnx_audren_audio_append(libnx_audren_t* aud, const char *buf, size_t size)
{
void *dstbuf = NULL;
ssize_t free_idx = -1;
if (!aud->current_wavebuf)
{
free_idx = libnx_audren_audio_get_free_wavebuf_idx(aud);
if (free_idx == -1)
return 0;
aud->current_wavebuf = &aud->wavebufs[free_idx];
aud->current_pool_ptr = aud->mempool + (free_idx * aud->buffer_size);
aud->current_size = 0;
}
if (size > aud->buffer_size - aud->current_size)
size = aud->buffer_size - aud->current_size;
dstbuf = aud->current_pool_ptr + aud->current_size;
memcpy(dstbuf, buf, size);
armDCacheFlush(dstbuf, size);
aud->current_size += size;
if (aud->current_size == aud->buffer_size)
{
audrvVoiceAddWaveBuf(&aud->drv, 0, aud->current_wavebuf);
mutexLock(&aud->update_lock);
audrvUpdate(&aud->drv);
mutexUnlock(&aud->update_lock);
if (!audrvVoiceIsPlaying(&aud->drv, 0))
{
audrvVoiceStart(&aud->drv, 0);
}
aud->current_wavebuf = NULL;
}
return size;
}
static ma_result ma_device_write__audren(ma_device* pDevice, const void* pFrames, ma_uint32 frameCount, ma_uint32* pFramesWritten)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(pFrames != NULL);
MA_ASSERT(pDevice->pContext->pUserData != NULL);
libnx_audren_t *aud = (libnx_audren_t*)pDevice->pContext->pUserData;
if (pFramesWritten != NULL)
*pFramesWritten = 0;
if (ma_device_get_state(pDevice) != ma_device_state_started)
return MA_DEVICE_NOT_INITIALIZED;
char *buf = (char*)pFrames;
size_t size = frameCount * ma_get_bytes_per_frame(pDevice->playback.internalFormat, pDevice->playback.internalChannels);
size_t written = 0;
while (written < size)
{
written += libnx_audren_audio_append(aud, buf + written, size - written);
if (written != size)
{
mutexLock(&aud->update_lock);
audrvUpdate(&aud->drv);
mutexUnlock(&aud->update_lock);
audrenWaitFrame();
}
}
if (written == 0)
return MA_IO_ERROR;
*pFramesWritten = frameCount;
return MA_SUCCESS;
}
static ma_result ma_device_init__audren(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(pConfig != NULL);
MA_ASSERT(pDevice->pContext->pUserData != NULL);
libnx_audren_t *aud = (libnx_audren_t*)pDevice->pContext->pUserData;
if (pConfig->deviceType == ma_device_type_loopback) {
return MA_DEVICE_TYPE_NOT_SUPPORTED;
}
pDescriptorPlayback->format = ma_format_s16;
pDescriptorPlayback->channels = num_channels;
pDescriptorPlayback->sampleRate = sample_rate;
ma_channel_map_init_standard(ma_standard_channel_map_default, pDescriptorPlayback->channelMap, ma_countof(pDescriptorPlayback->channelMap), pDescriptorPlayback->channels);
pDescriptorPlayback->periodSizeInFrames = ma_calculate_buffer_size_in_frames_from_descriptor(pDescriptorPlayback, pDescriptorPlayback->sampleRate, pConfig->performanceProfile);
aud->buffer_size = pDescriptorPlayback->periodSizeInFrames * ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels);
aud->samples = (aud->buffer_size / num_channels / sizeof(int16_t));
aud->current_size = 0;
size_t mempool_size = (aud->buffer_size * LIBNX_AUDREN_BUFFER_COUNT + (AUDREN_MEMPOOL_ALIGNMENT-1)) &~ (AUDREN_MEMPOOL_ALIGNMENT-1);
aud->mempool = memalign(AUDREN_MEMPOOL_ALIGNMENT, mempool_size);
audrenInitialize(&audio_renderer_config);
audrvCreate(&aud->drv, &audio_renderer_config, num_channels);
unsigned i;
for(i = 0; i < LIBNX_AUDREN_BUFFER_COUNT; i++)
{
aud->wavebufs[i].data_raw = aud->mempool;
aud->wavebufs[i].size = mempool_size;
aud->wavebufs[i].start_sample_offset = i * aud->samples;
aud->wavebufs[i].end_sample_offset = aud->wavebufs[i].start_sample_offset + aud->samples;
}
aud->current_wavebuf = NULL;
int mpid = audrvMemPoolAdd(&aud->drv, aud->mempool, mempool_size);
audrvMemPoolAttach(&aud->drv, mpid);
audrvDeviceSinkAdd(&aud->drv, AUDREN_DEFAULT_DEVICE_NAME, num_channels, sink_channels);
audrenStartAudioRenderer();
audrvVoiceInit(&aud->drv, 0, num_channels, PcmFormat_Int16, sample_rate);
audrvVoiceSetDestinationMix(&aud->drv, 0, AUDREN_FINAL_MIX_ID);
unsigned j;
for(i = 0; i < num_channels; i++)
for(j = 0; j < num_channels; j++)
audrvVoiceSetMixFactor(&aud->drv, 0, i == j ? 1.0f : 0.0f, i, j);
mutexInit(&aud->update_lock);
return MA_SUCCESS;
}
static ma_result ma_context_get_device_info__audren(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_info* pDeviceInfo)
{
MA_ASSERT(pContext != NULL);
MA_ASSERT(deviceType == ma_device_type_playback);
pDeviceInfo->isDefault = MA_TRUE;
pDeviceInfo->nativeDataFormatCount = 0;
ma_device_info_add_native_data_format(pDeviceInfo, ma_format_s16, num_channels, sample_rate, 0);
return MA_SUCCESS;
}
static ma_result ma_device_start__audren(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(pDevice->pContext->pUserData != NULL);
libnx_audren_t *aud = (libnx_audren_t*)pDevice->pContext->pUserData;
audrvVoiceStart(&aud->drv, 0);
return MA_SUCCESS;
}
static ma_result ma_device_stop__audren(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(pDevice->pContext->pUserData != NULL);
libnx_audren_t *aud = (libnx_audren_t*)pDevice->pContext->pUserData;
audrvVoiceStop(&aud->drv, 0);
return MA_SUCCESS;
}
static ma_result ma_device_uninit__audren(ma_device* pDevice)
{
MA_ASSERT(pDevice != NULL);
MA_ASSERT(pDevice->pContext->pUserData != NULL);
libnx_audren_t *aud = (libnx_audren_t*)pDevice->pContext->pUserData;
audrvVoiceStop(&aud->drv, 0);
audrvClose(&aud->drv);
audrenExit();
if (aud->mempool)
free(aud->mempool);
free(aud);
return MA_SUCCESS;
}
static ma_result ma_context_init__audren(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks)
{
MA_ASSERT(pContext != NULL);
pContext->pUserData = (libnx_audren_t*)calloc(1, sizeof(libnx_audren_t));
(void)pConfig; /* Unused. */
pCallbacks->onContextInit = ma_context_init__audren;
pCallbacks->onContextUninit = NULL;
pCallbacks->onContextEnumerateDevices = NULL;
pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__audren;
pCallbacks->onDeviceInit = ma_device_init__audren;
pCallbacks->onDeviceUninit = ma_device_uninit__audren;
pCallbacks->onDeviceStart = ma_device_start__audren;
pCallbacks->onDeviceStop = ma_device_stop__audren;
pCallbacks->onDeviceRead = NULL;
pCallbacks->onDeviceWrite = ma_device_write__audren;
pCallbacks->onDeviceDataLoop = NULL;
return MA_SUCCESS;
}
#endif