switch: use audren audio

fix suspend, allow freqs other than 48khz
This commit is contained in:
Cpasjuste 2019-01-22 21:52:39 +01:00 committed by Dave Murphy
parent 0c22a3c059
commit 12f161236f
2 changed files with 117 additions and 45 deletions

View File

@ -33,23 +33,25 @@
#include "SDL_switchaudio.h"
static const AudioRendererConfig arConfig =
{
.output_rate = AudioRendererOutputRate_48kHz,
.num_voices = 24,
.num_effects = 0,
.num_sinks = 1,
.num_mix_objs = 1,
.num_mix_buffers = 2,
};
static int
SWITCHAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
Result res;
static const u8 sink_channels[] = {0, 1};
SDL_bool supported_format = SDL_FALSE;
SDL_AudioFormat test_format;
res = audoutInitialize();
if (res != 0) {
return SDL_SetError("audoutInitialize failed (0x%x)", res);
}
res = audoutStartAudioOut();
if (res != 0) {
audoutExit();
return SDL_SetError("audoutStartAudioOut failed (0x%x)", res);
}
Result res;
u32 size;
int mpid;
this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden));
if (this->hidden == NULL) {
@ -57,11 +59,24 @@ SWITCHAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
SDL_zerop(this->hidden);
res = audrenInitialize(&arConfig);
if (R_FAILED(res)) {
return SDL_SetError("audrenInitialize failed (0x%x)", res);
}
this->hidden->audr_device = true;
res = audrvCreate(&this->hidden->driver, &arConfig, 2);
if (R_FAILED(res)) {
return SDL_SetError("audrvCreate failed (0x%x)", res);
}
this->hidden->audr_driver = true;
test_format = SDL_FirstAudioFormat(this->spec.format);
while ((!supported_format) && (test_format)) {
if (test_format == AUDIO_S16LSB) {
if (test_format == AUDIO_S16SYS) {
supported_format = SDL_TRUE;
} else {
}
else {
test_format = SDL_NextAudioFormat();
}
}
@ -70,60 +85,116 @@ SWITCHAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
this->spec.format = test_format;
this->spec.freq = 48000;
this->spec.channels = 2;
SDL_CalculateAudioSpec(&this->spec);
size = (u32) ((this->spec.size * 2) + 0xfff) & ~0xfff;
this->hidden->pool = memalign(0x1000, size);
for (int i = 0; i < 2; i++) {
u32 size = (u32) (this->spec.size + 0xfff) & ~0xfff;
this->hidden->buffer[i] = memalign(0x1000, size);
memset(this->hidden->buffer[i], 0, size);
this->hidden->source_buffer[i].next = NULL;
this->hidden->source_buffer[i].buffer = this->hidden->buffer[i];
this->hidden->source_buffer[i].buffer_size =
(u64) this->spec.size / this->spec.channels / 4;
this->hidden->source_buffer[i].data_size = (u64) this->spec.size;
this->hidden->source_buffer[i].data_offset = (u64) 0;
audoutAppendAudioOutBuffer(&this->hidden->source_buffer[i]);
this->hidden->buffer[i].data_raw = this->hidden->pool;
this->hidden->buffer[i].size = this->spec.size * 2;
this->hidden->buffer[i].start_sample_offset = i * this->spec.samples;
this->hidden->buffer[i].end_sample_offset = this->hidden->buffer[i].start_sample_offset + this->spec.samples;
this->hidden->buffer_tmp = malloc(this->spec.size);
}
mpid = audrvMemPoolAdd(&this->hidden->driver, this->hidden->pool, size);
audrvMemPoolAttach(&this->hidden->driver, mpid);
audrvDeviceSinkAdd(&this->hidden->driver, AUDREN_DEFAULT_DEVICE_NAME, 2, sink_channels);
res = audrenStartAudioRenderer();
if (R_FAILED(res)) {
return SDL_SetError("audrenStartAudioRenderer failed (0x%x)", res);
}
audrvVoiceInit(&this->hidden->driver, 0, this->spec.channels, PcmFormat_Int16, this->spec.freq);
audrvVoiceSetDestinationMix(&this->hidden->driver, 0, AUDREN_FINAL_MIX_ID);
if (this->spec.channels == 1) {
audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 0);
audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 1);
}
else {
audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 0);
audrvVoiceSetMixFactor(&this->hidden->driver, 0, 0.0f, 0, 1);
audrvVoiceSetMixFactor(&this->hidden->driver, 0, 0.0f, 1, 0);
audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 1, 1);
}
audrvVoiceStart(&this->hidden->driver, 0);
return 0;
}
static void
SWITCHAUDIO_PlayDevice(_THIS)
{
audoutAppendAudioOutBuffer(this->hidden->released_buffer);
int current = -1;
for (int i = 0; i < 2; i++) {
if (this->hidden->buffer[i].state == AudioDriverWaveBufState_Free
|| this->hidden->buffer[i].state == AudioDriverWaveBufState_Done) {
current = i;
break;
}
}
if (current >= 0) {
Uint8 *ptr = (Uint8 *) (this->hidden->pool + (current * this->spec.size));
memcpy(ptr, this->hidden->buffer_tmp, this->spec.size);
armDCacheFlush(ptr, this->spec.size);
audrvVoiceAddWaveBuf(&this->hidden->driver, 0, &this->hidden->buffer[current]);
}
else if (!audrvVoiceIsPlaying(&this->hidden->driver, 0)) {
audrvVoiceStart(&this->hidden->driver, 0);
}
audrvUpdate(&this->hidden->driver);
if (current >= 0) {
while (this->hidden->buffer[current].state != AudioDriverWaveBufState_Playing) {
audrvUpdate(&this->hidden->driver);
audrenWaitFrame();
}
}
else {
current = -1;
for (int i = 0; i < 2; i++) {
if (this->hidden->buffer[i].state == AudioDriverWaveBufState_Playing) {
current = i;
break;
}
}
while (this->hidden->buffer[current].state == AudioDriverWaveBufState_Playing) {
audrvUpdate(&this->hidden->driver);
audrenWaitFrame();
}
}
}
static void
SWITCHAUDIO_WaitDevice(_THIS)
{
}
static Uint8
*SWITCHAUDIO_GetDeviceBuf(_THIS)
{
audoutWaitPlayFinish(&this->hidden->released_buffer,
&this->hidden->released_count, U64_MAX);
return this->hidden->released_buffer->buffer;
return this->hidden->buffer_tmp;
}
static void
SWITCHAUDIO_CloseDevice(_THIS)
{
if (this->hidden->buffer[0]) {
free(this->hidden->buffer[0]);
}
if (this->hidden->buffer[1]) {
free(this->hidden->buffer[1]);
if (this->hidden->audr_driver) {
audrvClose(&this->hidden->driver);
}
audoutStopAudioOut();
audoutExit();
if (this->hidden->audr_device) {
audrenExit();
}
if (this->hidden->buffer_tmp) {
free(this->hidden->buffer_tmp);
}
SDL_free(this->hidden);
}

View File

@ -30,11 +30,12 @@
struct SDL_PrivateAudioData
{
void *buffer[2];
AudioOutBuffer source_buffer[2];
AudioOutBuffer *released_buffer;
u32 released_count;
AudioDriver driver;
AudioDriverWaveBuf buffer[2];
void *buffer_tmp;
void *pool;
bool audr_device;
bool audr_driver;
};
#endif /* SDL_switchaudio_h_ */