ref: 5bcc0ec393f7d07f66eed47966400c8ecef77d81
parent: 617f7a25d42a7366fcc6abeec6559c467193240e
author: Clownacy <Clownacy@users.noreply.github.com>
date: Fri Apr 17 19:43:17 EDT 2020
New way to allocate Wii U voices The previous method wasn't good enough: we were still maxing-out at 96 (did the Decaf devs misread that as hex? Is that why the emulator's limit is 150 instead?). Anyway, this new solution is a little brutish, but I can't think of anything else that would work: right now, I have the Organya thread constantly polling a linked-list of the currently-loaded sounds, and checking if their voices have finished playing or not. If they've finished, they get freed. When AudioBackend_PlaySound is called, if checks if the sound's voice has been freed or not, and reallocates it if it has. There doesn't seem to be a noticable overhead to this, and it keeps the number of currently-allocated voices *very* low (from 10 to 20 on average).
--- a/src/Backends/Audio/WiiU.cpp
+++ b/src/Backends/Audio/WiiU.cpp
@@ -6,8 +6,8 @@
#include <string.h>
#include <coreinit/cache.h>
+#include <coreinit/mutex.h>
#include <coreinit/thread.h>
-
#include <sndcore2/core.h>
#include <sndcore2/voice.h>
#include <sndcore2/drcvs.h>
@@ -26,11 +26,20 @@
unsigned short pan_l;
unsigned short pan_r;
AXVoiceDeviceMixData mix_data[6];
+
+ struct AudioBackend_Sound *next;
};
static void (*organya_callback)(void);
static unsigned int organya_milliseconds;
+static unsigned long ticks_per_second;
+
+static OSMutex mutex;
+static OSMutex organya_mutex;
+
+static AudioBackend_Sound *sound_list_head;
+
static double MillibelToScale(long volume)
{
// Volume is in hundredths of a decibel, from 0 to -10000
@@ -38,13 +47,11 @@
return pow(10.0, volume / 2000.0);
}
-static unsigned long ticks_per_second;
-
static unsigned long GetTicksMilliseconds(void)
{
static uint64_t accumulator;
- static unsigned long last_tick; // For some dumbass reason, OSTick is signed, so force unsigned here instead
+ static unsigned long last_tick;
unsigned long current_tick = OSGetTick();
@@ -61,31 +68,57 @@
{
OSTestThreadCancel();
+ OSLockMutex(&organya_mutex);
+
if (organya_milliseconds == 0)
{
- OSSleepTicks(1);
+ OSUnlockMutex(&organya_mutex);
+
+ // Do nothing
+ OSSleepTicks(ticks_per_second / 1000);
}
else
{
+ OSUnlockMutex(&organya_mutex);
+
+ // Update Organya
static unsigned long next_ticks;
- unsigned long ticks;
for (;;)
{
- ticks = GetTicksMilliseconds();
+ unsigned long ticks = GetTicksMilliseconds();
if (ticks >= next_ticks)
- {
- next_ticks += organya_milliseconds;
break;
- }
- OSSleepTicks(1);
+ OSSleepTicks(ticks_per_second / 1000);
}
- if (organya_callback != NULL)
- organya_callback();
+ OSLockMutex(&organya_mutex);
+ next_ticks += organya_milliseconds;
+ OSUnlockMutex(&organya_mutex);
+
+ OSLockMutex(&mutex);
+ organya_callback();
+ OSUnlockMutex(&mutex);
}
+
+ // Free any voices that aren't playing anymore
+ OSLockMutex(&mutex);
+
+ for (AudioBackend_Sound *sound = sound_list_head; sound != NULL; sound = sound->next)
+ {
+ if (sound->voice != NULL)
+ {
+ if (!AXIsVoiceRunning(sound->voice))
+ {
+ AXFreeVoice(sound->voice);
+ sound->voice = NULL;
+ }
+ }
+ }
+
+ OSUnlockMutex(&mutex);
}
return 0;
@@ -105,8 +138,13 @@
ticks_per_second = OSGetSystemInfo()->busClockSpeed / 4;
+ OSInitMutex(&mutex);
+ OSInitMutex(&organya_mutex);
+
OSRunThread(OSGetDefaultThread(0), ThreadFunction, 0, NULL);
+// AXRegisterFrameCallback(FrameCallback);
+
return true;
}
@@ -143,6 +181,11 @@
sound->pan_l = 0x8000;
sound->pan_r = 0x8000;
+ OSLockMutex(&mutex);
+ sound->next = sound_list_head;
+ sound_list_head = sound;
+ OSUnlockMutex(&mutex);
+
return sound;
}
@@ -154,8 +197,23 @@
void AudioBackend_DestroySound(AudioBackend_Sound *sound)
{
- AudioBackend_StopSound(sound);
+ OSLockMutex(&mutex);
+ // Unhook sound from the linked-list
+ for (AudioBackend_Sound **sound_pointer = &sound_list_head; *sound_pointer != NULL; sound_pointer = &(*sound_pointer)->next)
+ {
+ if (*sound_pointer == sound)
+ {
+ *sound_pointer = sound->next;
+ break;
+ }
+ }
+
+ OSUnlockMutex(&mutex);
+
+ if (sound->voice != NULL)
+ AXFreeVoice(sound->voice);
+
free(sound->samples);
free(sound);
}
@@ -162,6 +220,8 @@
void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping)
{
+ OSLockMutex(&mutex);
+
if (sound->voice == NULL)
{
AXVoice *voice = AXAcquireVoice(31, NULL, NULL);
@@ -206,26 +266,34 @@
AXSetVoiceLoop(sound->voice, looping ? AX_VOICE_LOOP_ENABLED : AX_VOICE_LOOP_DISABLED);
AXSetVoiceState(sound->voice, AX_VOICE_STATE_PLAYING);
}
+
+ OSUnlockMutex(&mutex);
}
void AudioBackend_StopSound(AudioBackend_Sound *sound)
{
+ OSLockMutex(&mutex);
+
if (sound->voice != NULL)
- {
- AXVoice *voice = sound->voice;
- sound->voice = NULL;
- AXFreeVoice(voice);
- }
+ AXSetVoiceState(sound->voice, AX_VOICE_STATE_STOPPED);
+
+ OSUnlockMutex(&mutex);
}
void AudioBackend_RewindSound(AudioBackend_Sound *sound)
{
+ OSLockMutex(&mutex);
+
if (sound->voice != NULL)
AXSetVoiceCurrentOffset(sound->voice, 0);
+
+ OSUnlockMutex(&mutex);
}
void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency)
{
+ OSLockMutex(&mutex);
+
sound->frequency = frequency;
if (sound->voice != NULL)
@@ -233,10 +301,14 @@
float srcratio = (float)frequency / (float)AXGetInputSamplesPerSec();
AXSetVoiceSrcRatio(sound->voice, srcratio);
}
+
+ OSUnlockMutex(&mutex);
}
void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume)
{
+ OSLockMutex(&mutex);
+
sound->volume = (unsigned short)(0x8000 * MillibelToScale(volume));
if (sound->voice != NULL)
@@ -245,10 +317,14 @@
AXSetVoiceVe(sound->voice, &vol);
}
+
+ OSUnlockMutex(&mutex);
}
void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan)
{
+ OSLockMutex(&mutex);
+
sound->pan_l = (unsigned short)(0x8000 * MillibelToScale(-pan));
sound->pan_r = (unsigned short)(0x8000 * MillibelToScale(pan));
@@ -260,10 +336,16 @@
AXSetVoiceDeviceMix(sound->voice, AX_DEVICE_TYPE_DRC, 0, sound->mix_data);
AXSetVoiceDeviceMix(sound->voice, AX_DEVICE_TYPE_TV, 0, sound->mix_data);
}
+
+ OSUnlockMutex(&mutex);
}
void AudioBackend_SetOrganyaCallback(void (*callback)(void), unsigned int milliseconds)
{
+ OSLockMutex(&organya_mutex);
+
organya_callback = callback;
organya_milliseconds = milliseconds;
+
+ OSUnlockMutex(&organya_mutex);
}