From 75a31005d119dd6f99f0197424c6b8322c047e75 Mon Sep 17 00:00:00 2001 From: Clownacy Date: Sun, 11 Oct 2020 14:27:39 +0100 Subject: [PATCH] Add basic 3DS audio support It's using the software mixer for now. I might be able to make it hardware-accelerated in the future. --- CMakeLists.txt | 8 ++ src/Backends/Audio/SoftwareMixer/3DS.cpp | 159 +++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 src/Backends/Audio/SoftwareMixer/3DS.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cbab1a1a..0c3a1b0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -368,6 +368,14 @@ elseif(BACKEND_AUDIO MATCHES "WiiU-Software") "src/Backends/Audio/SoftwareMixer/Backend.h" "src/Backends/Audio/SoftwareMixer/WiiU-Software.cpp" ) +elseif(BACKEND_AUDIO MATCHES "3DS") + target_sources(CSE2 PRIVATE + "src/Backends/Audio/SoftwareMixer.cpp" + "src/Backends/Audio/SoftwareMixer/Mixer.cpp" + "src/Backends/Audio/SoftwareMixer/Mixer.h" + "src/Backends/Audio/SoftwareMixer/Backend.h" + "src/Backends/Audio/SoftwareMixer/3DS.cpp" + ) elseif(BACKEND_AUDIO MATCHES "Null") target_sources(CSE2 PRIVATE "src/Backends/Audio/Null.cpp" diff --git a/src/Backends/Audio/SoftwareMixer/3DS.cpp b/src/Backends/Audio/SoftwareMixer/3DS.cpp new file mode 100644 index 00000000..e48a565a --- /dev/null +++ b/src/Backends/Audio/SoftwareMixer/3DS.cpp @@ -0,0 +1,159 @@ +#include "Backend.h" + +#include +#include + +#include <3ds.h> + +#include "../../Misc.h" + +#define SAMPLE_RATE 32000 // The native sample rate is 32728.4980469 +#define FRAMES_PER_BUFFER (SAMPLE_RATE / 30) // 33.333 milliseconds + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static void (*parent_callback)(long *stream, size_t frames_total); + +static short *stream_buffer; + +static ndspWaveBuf dsp_buffers[2]; +static bool current_dsp_buffer; + +static void FullBuffer(short *stream, size_t frames_total) +{ + size_t frames_done = 0; + + while (frames_done != frames_total) + { + long mix_buffer[FRAMES_PER_BUFFER * 2]; // 2 because stereo + + size_t subframes = MIN(FRAMES_PER_BUFFER, frames_total - frames_done); + + memset(mix_buffer, 0, subframes * sizeof(long) * 2); + + parent_callback(mix_buffer, subframes); + + for (size_t i = 0; i < subframes * 2; ++i) + { + if (mix_buffer[i] > 0x7FFF) + *stream++ = 0x7FFF; + else if (mix_buffer[i] < -0x7FFF) + *stream++ = -0x7FFF; + else + *stream++ = mix_buffer[i]; + } + + frames_done += subframes; + } + + DSP_FlushDataCache(stream, frames_total * sizeof(short) * 2); +} + +static void Callback(void *user_data) +{ + (void)user_data; + + if (dsp_buffers[current_dsp_buffer].status == NDSP_WBUF_DONE) + { + FullBuffer(dsp_buffers[current_dsp_buffer].data_pcm16, dsp_buffers[current_dsp_buffer].nsamples); + + ndspChnWaveBufAdd(0, &dsp_buffers[current_dsp_buffer]); + + current_dsp_buffer = !current_dsp_buffer; + } +} + +unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total)) +{ + parent_callback = callback; + + current_dsp_buffer = false; + + stream_buffer = (short*)linearAlloc(FRAMES_PER_BUFFER * sizeof(short) * 2 * 2); + + if (stream_buffer != NULL) + { + if (ndspInit() == 0) + { + ndspSetCallback(Callback, NULL); + + ndspSetOutputMode(NDSP_OUTPUT_STEREO); + + ndspChnSetInterp(0, NDSP_INTERP_LINEAR); + ndspChnSetRate(0, SAMPLE_RATE); + ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16); + + float mix[12]; + mix[0] = 1.0f; + mix[1] = 1.0f; + mix[2] = 0.0f; + mix[3] = 0.0f; + mix[4] = 0.0f; + mix[5] = 0.0f; + mix[6] = 0.0f; + mix[7] = 0.0f; + mix[8] = 0.0f; + mix[9] = 0.0f; + mix[10] = 0.0f; + mix[11] = 0.0f; + ndspChnSetMix(0, mix); + + memset(dsp_buffers, 0, sizeof(dsp_buffers)); + dsp_buffers[0].data_vaddr = &stream_buffer[FRAMES_PER_BUFFER * 2 * 0]; + dsp_buffers[0].nsamples = FRAMES_PER_BUFFER; + dsp_buffers[1].data_vaddr = &stream_buffer[FRAMES_PER_BUFFER * 2 * 1]; + dsp_buffers[1].nsamples = FRAMES_PER_BUFFER; + + FullBuffer(stream_buffer, FRAMES_PER_BUFFER * 2); + + return SAMPLE_RATE; + } + else + { + Backend_PrintError("ndspInit failed"); + } + + linearFree(stream_buffer); + } + else + { + Backend_PrintError("linearAlloc failed"); + } + + return 0; +} + +void SoftwareMixerBackend_Deinit(void) +{ + ndspExit(); + + linearFree(stream_buffer); +} + +bool SoftwareMixerBackend_Start(void) +{ + ndspChnWaveBufAdd(0, &dsp_buffers[0]); + ndspChnWaveBufAdd(0, &dsp_buffers[1]); + + return true; +} + +void SoftwareMixerBackend_LockMixerMutex(void) +{ +// ma_mutex_lock(&mutex); +} + +void SoftwareMixerBackend_UnlockMixerMutex(void) +{ +// ma_mutex_unlock(&mutex); +} + +void SoftwareMixerBackend_LockOrganyaMutex(void) +{ +// ma_mutex_lock(&organya_mutex); +} + +void SoftwareMixerBackend_UnlockOrganyaMutex(void) +{ +// ma_mutex_unlock(&organya_mutex); +}