ref: 75a31005d119dd6f99f0197424c6b8322c047e75
parent: 7013c28e2682641cd9c2b33b62ca67f09ce8ce7e
author: Clownacy <Clownacy@users.noreply.github.com>
date: Sun Oct 11 10:27:39 EDT 2020
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.
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -368,6 +368,14 @@
"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"
--- /dev/null
+++ b/src/Backends/Audio/SoftwareMixer/3DS.cpp
@@ -1,0 +1,159 @@
+#include "Backend.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#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);
+}