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" #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 static int
SWITCHAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) 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_bool supported_format = SDL_FALSE;
SDL_AudioFormat test_format; SDL_AudioFormat test_format;
Result res;
res = audoutInitialize(); u32 size;
if (res != 0) { int mpid;
return SDL_SetError("audoutInitialize failed (0x%x)", res);
}
res = audoutStartAudioOut();
if (res != 0) {
audoutExit();
return SDL_SetError("audoutStartAudioOut failed (0x%x)", res);
}
this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden)); this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden));
if (this->hidden == NULL) { if (this->hidden == NULL) {
@ -57,11 +59,24 @@ SWITCHAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
} }
SDL_zerop(this->hidden); 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); test_format = SDL_FirstAudioFormat(this->spec.format);
while ((!supported_format) && (test_format)) { while ((!supported_format) && (test_format)) {
if (test_format == AUDIO_S16LSB) { if (test_format == AUDIO_S16SYS) {
supported_format = SDL_TRUE; supported_format = SDL_TRUE;
} else { }
else {
test_format = SDL_NextAudioFormat(); 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.format = test_format;
this->spec.freq = 48000;
this->spec.channels = 2;
SDL_CalculateAudioSpec(&this->spec); 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++) { for (int i = 0; i < 2; i++) {
u32 size = (u32) (this->spec.size + 0xfff) & ~0xfff; this->hidden->buffer[i].data_raw = this->hidden->pool;
this->hidden->buffer[i] = memalign(0x1000, size); this->hidden->buffer[i].size = this->spec.size * 2;
memset(this->hidden->buffer[i], 0, size); this->hidden->buffer[i].start_sample_offset = i * this->spec.samples;
this->hidden->source_buffer[i].next = NULL; this->hidden->buffer[i].end_sample_offset = this->hidden->buffer[i].start_sample_offset + this->spec.samples;
this->hidden->source_buffer[i].buffer = this->hidden->buffer[i]; this->hidden->buffer_tmp = malloc(this->spec.size);
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]);
} }
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; return 0;
} }
static void static void
SWITCHAUDIO_PlayDevice(_THIS) 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 static void
SWITCHAUDIO_WaitDevice(_THIS) SWITCHAUDIO_WaitDevice(_THIS)
{ {
} }
static Uint8 static Uint8
*SWITCHAUDIO_GetDeviceBuf(_THIS) *SWITCHAUDIO_GetDeviceBuf(_THIS)
{ {
audoutWaitPlayFinish(&this->hidden->released_buffer, return this->hidden->buffer_tmp;
&this->hidden->released_count, U64_MAX);
return this->hidden->released_buffer->buffer;
} }
static void static void
SWITCHAUDIO_CloseDevice(_THIS) SWITCHAUDIO_CloseDevice(_THIS)
{ {
if (this->hidden->buffer[0]) { if (this->hidden->audr_driver) {
free(this->hidden->buffer[0]); audrvClose(&this->hidden->driver);
}
if (this->hidden->buffer[1]) {
free(this->hidden->buffer[1]);
} }
audoutStopAudioOut(); if (this->hidden->audr_device) {
audoutExit(); audrenExit();
}
if (this->hidden->buffer_tmp) {
free(this->hidden->buffer_tmp);
}
SDL_free(this->hidden); SDL_free(this->hidden);
} }

View File

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