Fix the game using too many Wii U voices

Now it just allocates channels on-demand, rather than ahead-of-time.
This commit is contained in:
Clownacy 2020-04-16 22:42:33 +01:00
parent a7ebdb75e5
commit edc9299007

View file

@ -18,7 +18,12 @@
struct AudioBackend_Sound struct AudioBackend_Sound
{ {
unsigned char *samples; unsigned char *samples;
size_t length;
AXVoice *voice; AXVoice *voice;
unsigned int frequency;
unsigned short volume;
unsigned short pan_l;
unsigned short pan_r;
}; };
static double MillibelToScale(long volume) static double MillibelToScale(long volume)
@ -59,55 +64,23 @@ AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsig
if (samples_copy != NULL) if (samples_copy != NULL)
{ {
// Convert to signed
for (size_t i = 0; i < length; ++i) for (size_t i = 0; i < length; ++i)
samples_copy[i] = samples[i] - 0x80; samples_copy[i] = samples[i] - 0x80;
DCStoreRange(samples_copy, length); 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->samples = samples_copy;
sound->voice = voice; sound->length = length;
sound->voice = NULL;
sound->frequency = frequency;
sound->volume = 0x8000;
sound->pan_l = 0x8000;
sound->pan_r = 0x8000;
return sound; return sound;
} }
free(samples_copy);
}
free(sound); free(sound);
} }
@ -116,41 +89,100 @@ AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsig
void AudioBackend_DestroySound(AudioBackend_Sound *sound) void AudioBackend_DestroySound(AudioBackend_Sound *sound)
{ {
AXFreeVoice(sound->voice); AudioBackend_StopSound(sound);
free(sound->samples); free(sound->samples);
free(sound); free(sound);
} }
void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping) void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping)
{ {
if (sound->voice == NULL)
{
AXVoice *voice = AXAcquireVoice(31, NULL, NULL);
if (voice != NULL)
{
AXVoiceOffsets offs;
AXVoiceVeData vol = {
.volume = sound->volume,
};
AXVoiceBegin(voice);
AXSetVoiceType(voice, 0);
AXSetVoiceVe(voice, &vol);
static AXVoiceDeviceMixData mix_data[1][6];
mix_data[0][0].bus[0].volume = sound->pan_l;
mix_data[0][1].bus[0].volume = sound->pan_r;
AXSetVoiceDeviceMix(voice, AX_DEVICE_TYPE_DRC, 0, mix_data[0]);
AXSetVoiceDeviceMix(voice, AX_DEVICE_TYPE_TV, 0, mix_data[0]);
float srcratio = (float)sound->frequency / (float)AXGetInputSamplesPerSec();
AXSetVoiceSrcRatio(voice, srcratio);
AXSetVoiceSrcType(voice, AX_VOICE_SRC_TYPE_LINEAR);
offs.dataType = AX_VOICE_FORMAT_LPCM8;
offs.endOffset = sound->length;
offs.loopingEnabled = AX_VOICE_LOOP_DISABLED;
offs.loopOffset = 0;
offs.currentOffset = 0;
offs.data = sound->samples;
AXSetVoiceOffsets(voice, &offs);
AXVoiceEnd(voice);
sound->voice = voice;
}
}
if (sound->voice != NULL)
{
AXSetVoiceLoop(sound->voice, looping ? AX_VOICE_LOOP_ENABLED : AX_VOICE_LOOP_DISABLED); AXSetVoiceLoop(sound->voice, looping ? AX_VOICE_LOOP_ENABLED : AX_VOICE_LOOP_DISABLED);
AXSetVoiceState(sound->voice, AX_VOICE_STATE_PLAYING); AXSetVoiceState(sound->voice, AX_VOICE_STATE_PLAYING);
}
} }
void AudioBackend_StopSound(AudioBackend_Sound *sound) void AudioBackend_StopSound(AudioBackend_Sound *sound)
{ {
AXSetVoiceState(sound->voice, AX_VOICE_STATE_STOPPED); if (sound->voice != NULL)
AXSetVoiceCurrentOffset(sound->voice, 0); {
AXFreeVoice(sound->voice);
sound->voice = NULL;
}
} }
void AudioBackend_RewindSound(AudioBackend_Sound *sound) void AudioBackend_RewindSound(AudioBackend_Sound *sound)
{ {
if (sound->voice != NULL)
AXSetVoiceCurrentOffset(sound->voice, 0); AXSetVoiceCurrentOffset(sound->voice, 0);
} }
void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency) void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency)
{ {
sound->frequency = frequency;
if (sound->voice != NULL)
{
float srcratio = (float)frequency / (float)AXGetInputSamplesPerSec(); float srcratio = (float)frequency / (float)AXGetInputSamplesPerSec();
AXSetVoiceSrcRatio(sound->voice, srcratio); AXSetVoiceSrcRatio(sound->voice, srcratio);
}
} }
void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume) void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume)
{ {
sound->volume = (unsigned short)(0x8000 * MillibelToScale(volume));
if (sound->voice != NULL)
{
AXVoiceVeData vol = { AXVoiceVeData vol = {
.volume = (unsigned short)(0x8000 * MillibelToScale(volume)), .volume = sound->volume,
}; };
AXSetVoiceVe(sound->voice, &vol); AXSetVoiceVe(sound->voice, &vol);
}
} }
void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan) void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan)
@ -159,8 +191,11 @@ void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan)
mix_data[0][0].bus[0].volume = (unsigned short)(0x8000 * MillibelToScale(-pan)); mix_data[0][0].bus[0].volume = (unsigned short)(0x8000 * MillibelToScale(-pan));
mix_data[0][1].bus[0].volume = (unsigned short)(0x8000 * MillibelToScale(pan)); mix_data[0][1].bus[0].volume = (unsigned short)(0x8000 * MillibelToScale(pan));
if (sound->voice != NULL)
{
AXSetVoiceDeviceMix(sound->voice, AX_DEVICE_TYPE_DRC, 0, mix_data[0]); AXSetVoiceDeviceMix(sound->voice, AX_DEVICE_TYPE_DRC, 0, mix_data[0]);
AXSetVoiceDeviceMix(sound->voice, AX_DEVICE_TYPE_TV, 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 AudioBackend_SetOrganyaCallback(void (*callback)(void), unsigned int milliseconds)