shithub: cstory

Download patch

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);
+}