shithub: cstory

Download patch

ref: a7ebdb75e5e120374c98e1a11bcb5bda427e952e
parent: 6bd4e89f9d2ed40fa3e18190a3e8e3f94b885588
author: Clownacy <Clownacy@users.noreply.github.com>
date: Thu Apr 16 18:19:00 EDT 2020

Added unfinished Wii U audio backend

Currently doesn't produce sound unless you stop Organya from calling
AudioBackend_CreateSound, because it exhausts the Wii U's 150-sound
pool before the SFX get any of them.

--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@
 option(BUILD_DOCONFIG "Compile a DoConfig clone tool - not useful for console ports" ON)
 
 set(BACKEND_RENDERER "SDLTexture" CACHE STRING "Which renderer the game should use: 'OpenGL3' for an OpenGL 3.2 renderer, 'OpenGLES2' for an OpenGL ES 2.0 renderer, 'SDLTexture' for SDL2's hardware-accelerated Texture API, 'SDLSurface' for SDL2's software-rendered Surface API, or 'Software' for a handwritten software renderer")
-set(BACKEND_AUDIO "SDL2" CACHE STRING "Which audio backend the game should use: 'SDL2', 'miniaudio', or 'Null'")
+set(BACKEND_AUDIO "SDL2" CACHE STRING "Which audio backend the game should use: 'SDL2', 'miniaudio', 'WiiU', or 'Null'")
 set(BACKEND_PLATFORM "SDL2" CACHE STRING "Which platform backend the game should use: 'SDL2', 'GLFW3', 'WiiU', or 'Null'")
 
 option(LTO "Enable link-time optimisation" OFF)
@@ -330,6 +330,10 @@
 	endif()
 
 	target_link_libraries(CSE2 PRIVATE ${CMAKE_DL_LIBS})
+elseif(BACKEND_AUDIO MATCHES "WiiU")
+	target_sources(CSE2 PRIVATE
+		"src/Backends/Audio/WiiU.cpp"
+	)
 elseif(BACKEND_AUDIO MATCHES "Null")
 	target_sources(CSE2 PRIVATE
 		"src/Backends/Audio/Null.cpp"
--- a/README.md
+++ b/README.md
@@ -75,6 +75,7 @@
 `-DBACKEND_RENDERER=Software` | Use the handwritten software renderer
 `-DBACKEND_AUDIO=SDL2` | Use the SDL2-driven software audio-mixer
 `-DBACKEND_AUDIO=miniaudio` | Use the miniaudio-driven software audio-mixer
+`-DBACKEND_AUDIO=WiiU` | Use the hardware-accelerated audio backend for the Wii U
 `-DBACKEND_AUDIO=Null` | Use the dummy audio backend (doesn't produce any sound)
 `-DBACKEND_PLATFORM=SDL2` | Use SDL2 for windowing and OS-abstraction
 `-DBACKEND_PLATFORM=GLFW3` | Use GLFW3 for windowing and OS-abstraction
--- /dev/null
+++ b/src/Backends/Audio/WiiU.cpp
@@ -1,0 +1,170 @@
+#include "../Audio.h"
+
+#include <math.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <coreinit/cache.h>
+
+#include <sndcore2/core.h>
+#include <sndcore2/voice.h>
+#include <sndcore2/drcvs.h>
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define CLAMP(x, y, z) MIN(MAX((x), (y)), (z))
+
+struct AudioBackend_Sound
+{
+	unsigned char *samples;
+	AXVoice *voice;
+};
+
+static double MillibelToScale(long volume)
+{
+	// Volume is in hundredths of a decibel, from 0 to -10000
+	volume = CLAMP(volume, -10000, 0);
+	return pow(10.0, volume / 2000.0);
+}
+
+bool AudioBackend_Init(void)
+{
+	if (!AXIsInit())
+	{
+		static AXInitParams initparams =
+		{
+			.renderer = AX_INIT_RENDERER_48KHZ,
+			.pipeline = AX_INIT_PIPELINE_SINGLE,
+		};
+
+		AXInitWithParams(&initparams);
+	}
+
+	return true;
+}
+
+void AudioBackend_Deinit(void)
+{
+	AXQuit();
+}
+
+AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length)
+{
+	AudioBackend_Sound *sound = (AudioBackend_Sound*)malloc(sizeof(AudioBackend_Sound));
+
+	if (sound != NULL)
+	{
+		unsigned char *samples_copy = (unsigned char*)malloc(length);
+
+		if (samples_copy != NULL)
+		{
+			for (size_t i = 0; i < length; ++i)
+				samples_copy[i] = samples[i] - 0x80;
+
+			DCStoreRange(samples_copy, length);
+
+			AXVoice *voice = AXAcquireVoice(31, NULL, NULL);
+
+			if (voice != NULL)
+			{
+				AXVoiceOffsets offs;
+				AXVoiceVeData vol = {
+					.volume = 0x8000,
+				};
+
+				AXVoiceBegin(voice);
+
+				AXSetVoiceType(voice, 0);
+				AXSetVoiceVe(voice, &vol);
+
+				static AXVoiceDeviceMixData mix_data[1][6];
+				mix_data[0][0].bus[0].volume = 0x8000;
+				mix_data[0][1].bus[0].volume = 0x8000;
+
+				AXSetVoiceDeviceMix(voice, AX_DEVICE_TYPE_DRC, 0, mix_data[0]);
+				AXSetVoiceDeviceMix(voice, AX_DEVICE_TYPE_TV, 0, mix_data[0]);
+
+				float srcratio = (float)frequency / (float)AXGetInputSamplesPerSec();
+				AXSetVoiceSrcRatio(voice, srcratio);
+				AXSetVoiceSrcType(voice, AX_VOICE_SRC_TYPE_LINEAR);
+
+				offs.dataType = AX_VOICE_FORMAT_LPCM8;
+				offs.endOffset = length;
+				offs.loopingEnabled = AX_VOICE_LOOP_DISABLED;
+				offs.loopOffset = 0;
+				offs.currentOffset = 0;
+				offs.data = samples_copy;
+				AXSetVoiceOffsets(voice, &offs);
+
+				AXVoiceEnd(voice);
+
+				sound->samples = samples_copy;
+				sound->voice = voice;
+
+				return sound;
+			}
+
+			free(samples_copy);
+		}
+
+		free(sound);
+	}
+
+	return NULL;
+}
+
+void AudioBackend_DestroySound(AudioBackend_Sound *sound)
+{
+	AXFreeVoice(sound->voice);
+	free(sound->samples);
+	free(sound);
+}
+
+void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping)
+{
+	AXSetVoiceLoop(sound->voice, looping ? AX_VOICE_LOOP_ENABLED : AX_VOICE_LOOP_DISABLED);
+	AXSetVoiceState(sound->voice, AX_VOICE_STATE_PLAYING);
+}
+
+void AudioBackend_StopSound(AudioBackend_Sound *sound)
+{
+	AXSetVoiceState(sound->voice, AX_VOICE_STATE_STOPPED);
+	AXSetVoiceCurrentOffset(sound->voice, 0);
+}
+
+void AudioBackend_RewindSound(AudioBackend_Sound *sound)
+{
+	AXSetVoiceCurrentOffset(sound->voice, 0);
+}
+
+void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency)
+{
+	float srcratio = (float)frequency / (float)AXGetInputSamplesPerSec();
+	AXSetVoiceSrcRatio(sound->voice, srcratio);
+}
+
+void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume)
+{
+	AXVoiceVeData vol = {
+		.volume = (unsigned short)(0x8000 * MillibelToScale(volume)),
+	};
+
+	AXSetVoiceVe(sound->voice, &vol);
+}
+
+void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan)
+{
+	static AXVoiceDeviceMixData mix_data[1][6];
+	mix_data[0][0].bus[0].volume = (unsigned short)(0x8000 * MillibelToScale(-pan));
+	mix_data[0][1].bus[0].volume = (unsigned short)(0x8000 * MillibelToScale(pan));
+
+	AXSetVoiceDeviceMix(sound->voice, AX_DEVICE_TYPE_DRC, 0, mix_data[0]);
+	AXSetVoiceDeviceMix(sound->voice, AX_DEVICE_TYPE_TV, 0, mix_data[0]);
+}
+
+void AudioBackend_SetOrganyaCallback(void (*callback)(void), unsigned int milliseconds)
+{
+	(void)callback;
+	(void)milliseconds;
+}