Add surround 5.1 support (#832)

* Support for 6 channels.

* Add option to configure Surround 5.1 audio.

* Clean up.

* Force 6 channels for now.

* Support stereo and surround.

* Apply comments.

* Fix SDLAudioPlayer.

* Apply clang format.

* Fix SDLAudioPlayer.

* adapt var name

* Apply suggestions from code review

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Fix correct name of var.

* Fix format.

* Prefix enum.

---------

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>
This commit is contained in:
tortugaveloz
2025-03-21 22:51:17 -04:00
committed by GitHub
co-authored by briaguya
parent 62f9df4f74
commit 6636c2cf4d
11 changed files with 93 additions and 17 deletions
+2
View File
@@ -20,6 +20,7 @@ set(CVAR_GAME_OVERLAY_FONT "gOverlayFont" CACHE STRING "")
set(CVAR_MENU_BAR_OPEN "gOpenMenuBar" CACHE STRING "")
set(CVAR_PREFIX_CONTROLLERS "gControllers" CACHE STRING "")
set(CVAR_PREFIX_ADVANCED_RESOLUTION "gAdvancedResolution" CACHE STRING "")
set(CVAR_AUDIO_CHANNELS_SETTING "gAudioChannelsSetting" CACHE STRING "")
add_compile_definitions(
CVAR_VSYNC_ENABLED="${CVAR_VSYNC_ENABLED}"
@@ -44,4 +45,5 @@ add_compile_definitions(
CVAR_MENU_BAR_OPEN="${CVAR_MENU_BAR_OPEN}"
CVAR_PREFIX_CONTROLLERS="${CVAR_PREFIX_CONTROLLERS}"
CVAR_PREFIX_ADVANCED_RESOLUTION="${CVAR_PREFIX_ADVANCED_RESOLUTION}"
CVAR_AUDIO_CHANNELS_SETTING="${CVAR_AUDIO_CHANNELS_SETTING}"
)
+8
View File
@@ -27,6 +27,10 @@ int32_t AudioPlayer::GetDesiredBuffered() const {
return mAudioSettings.DesiredBuffered;
}
AudioChannelsSetting AudioPlayer::GetAudioChannels() const {
return mAudioSettings.AudioSurround;
}
void AudioPlayer::SetSampleRate(int32_t rate) {
mAudioSettings.SampleRate = rate;
}
@@ -38,4 +42,8 @@ void AudioPlayer::SetSampleLength(int32_t length) {
void AudioPlayer::SetDesiredBuffered(int32_t size) {
mAudioSettings.DesiredBuffered = size;
}
void AudioPlayer::SetAudioChannels(AudioChannelsSetting surround) {
mAudioSettings.AudioSurround = surround;
}
} // namespace Ship
+6
View File
@@ -2,6 +2,7 @@
#include "stdint.h"
#include "stddef.h"
#include <string>
#include "public/bridge/audiobridge.h"
namespace Ship {
@@ -9,6 +10,7 @@ struct AudioSettings {
int32_t SampleRate = 44100;
int32_t SampleLength = 1024;
int32_t DesiredBuffered = 2480;
AudioChannelsSetting AudioSurround = AudioChannelsSetting::audioStereo;
};
class AudioPlayer {
@@ -30,12 +32,16 @@ class AudioPlayer {
int32_t GetDesiredBuffered() const;
AudioChannelsSetting GetAudioChannels() const;
void SetSampleRate(int32_t rate);
void SetSampleLength(int32_t length);
void SetDesiredBuffered(int32_t size);
void SetAudioChannels(AudioChannelsSetting surround);
protected:
virtual bool DoInit() = 0;
+3 -3
View File
@@ -13,11 +13,12 @@ bool SDLAudioPlayer::DoInit() {
SPDLOG_ERROR("SDL init error: %s\n", SDL_GetError());
return false;
}
mNumChannels = this->GetAudioChannels() == AudioChannelsSetting::audioSurround51 ? 6 : 2;
SDL_AudioSpec want, have;
SDL_zero(want);
want.freq = this->GetSampleRate();
want.format = AUDIO_S16SYS;
want.channels = 2;
want.channels = mNumChannels;
want.samples = this->GetSampleLength();
want.callback = NULL;
mDevice = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
@@ -30,8 +31,7 @@ bool SDLAudioPlayer::DoInit() {
}
int SDLAudioPlayer::Buffered() {
// 4 is sizeof(int16_t) * num_channels (2 for stereo)
return SDL_GetQueuedAudioSize(mDevice) / 4;
return SDL_GetQueuedAudioSize(mDevice) / (sizeof(int16_t) * mNumChannels);
}
void SDLAudioPlayer::Play(const uint8_t* buf, size_t len) {
+1
View File
@@ -17,5 +17,6 @@ class SDLAudioPlayer : public AudioPlayer {
private:
SDL_AudioDeviceID mDevice;
int32_t mNumChannels = 2;
};
} // namespace Ship
+35 -14
View File
@@ -28,18 +28,40 @@ bool WasapiAudioPlayer::SetupStream() {
ThrowIfFailed(mDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &mDevice));
ThrowIfFailed(mDevice->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, IID_PPV_ARGS_Helper(&mClient)));
WAVEFORMATEX desired;
desired.wFormatTag = WAVE_FORMAT_PCM;
desired.nChannels = 2;
desired.nSamplesPerSec = this->GetSampleRate();
desired.nAvgBytesPerSec = desired.nSamplesPerSec * 2 * 2;
desired.nBlockAlign = 4;
desired.wBitsPerSample = 16;
desired.cbSize = 0;
auto audioSurround = this->GetAudioChannels();
if (audioSurround == AudioChannelsSetting::audioStereo) {
mNumChannels = 2;
WAVEFORMATEX desired;
desired.wFormatTag = WAVE_FORMAT_PCM;
desired.nChannels = mNumChannels; // Stereo audio
desired.wBitsPerSample = 16; // 16-bit audio
desired.nSamplesPerSec = this->GetSampleRate();
desired.nBlockAlign = desired.nChannels * desired.wBitsPerSample / 8;
desired.nAvgBytesPerSec = desired.nSamplesPerSec * desired.nBlockAlign; // 2 bytes per sample (16-bit audio)
desired.cbSize = 0;
ThrowIfFailed(mClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY,
2000000, 0, &desired, nullptr));
ThrowIfFailed(mClient->Initialize(
AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY,
2000000, 0, &desired, nullptr));
} else if (audioSurround == AudioChannelsSetting::audioSurround51) {
mNumChannels = 6;
WAVEFORMATEXTENSIBLE desired;
desired.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
desired.Format.nChannels = mNumChannels; // 6 channels for 5.1 audio
desired.Format.wBitsPerSample = 16; // 16-bit audio
desired.Format.nSamplesPerSec = this->GetSampleRate();
desired.Format.nBlockAlign = desired.Format.nChannels * desired.Format.wBitsPerSample / 8;
desired.Format.nAvgBytesPerSec =
desired.Format.nSamplesPerSec * desired.Format.nBlockAlign; // 2 bytes per sample (16-bit audio)
desired.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
desired.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
desired.Samples.wValidBitsPerSample = 16;
desired.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
ThrowIfFailed(mClient->Initialize(
AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY,
2000000, 0, (WAVEFORMATEX*)&desired, nullptr));
}
ThrowIfFailed(mClient->GetBufferSize(&mBufferFrameCount));
ThrowIfFailed(mClient->GetService(IID_PPV_ARGS(&mRenderClient)));
@@ -82,8 +104,7 @@ void WasapiAudioPlayer::Play(const uint8_t* buf, size_t len) {
}
}
try {
UINT32 frames = len / 4;
UINT32 frames = len / (mNumChannels * sizeof(int16_t));
UINT32 padding;
ThrowIfFailed(mClient->GetCurrentPadding(&padding));
@@ -97,7 +118,7 @@ void WasapiAudioPlayer::Play(const uint8_t* buf, size_t len) {
BYTE* data;
ThrowIfFailed(mRenderClient->GetBuffer(frames, &data));
memcpy(data, buf, frames * 4);
memcpy(data, buf, frames * mNumChannels * sizeof(int16_t));
ThrowIfFailed(mRenderClient->ReleaseBuffer(frames, 0));
if (!mStarted && padding + frames > 1500) {
+1
View File
@@ -40,6 +40,7 @@ class WasapiAudioPlayer : public AudioPlayer, public IMMNotificationClient {
UINT32 mBufferFrameCount = 0;
bool mInitialized = false;
bool mStarted = false;
int32_t mNumChannels = 2;
};
} // namespace Ship
#endif
+13
View File
@@ -226,6 +226,19 @@ AudioBackend Config::GetCurrentAudioBackend() {
return AudioBackend::SDL;
}
AudioChannelsSetting Config::GetCurrentAudioChannelsSetting() {
int32_t surround =
GetInt("CVars." CVAR_AUDIO_CHANNELS_SETTING, static_cast<int32_t>(AudioChannelsSetting::audioMax));
switch (surround) {
case AudioChannelsSetting::audioSurround51:
return AudioChannelsSetting::audioSurround51;
case AudioChannelsSetting::audioStereo:
case AudioChannelsSetting::audioMax:
default:
return AudioChannelsSetting::audioStereo;
}
}
void Config::SetCurrentAudioBackend(AudioBackend backend) {
switch (backend) {
case AudioBackend::WASAPI:
+1
View File
@@ -67,6 +67,7 @@ class Config {
void SetCurrentAudioBackend(AudioBackend backend);
WindowBackend GetWindowBackend();
void SetWindowBackend(WindowBackend backend);
AudioChannelsSetting GetCurrentAudioChannelsSetting();
/**
* @brief Adds a ConfigVersionUpdater instance to the list to be run later via RunVersionUpdates
+19
View File
@@ -30,6 +30,25 @@ int32_t AudioPlayerGetDesiredBuffered() {
return audio->GetDesiredBuffered();
}
AudioChannelsSetting GetAudioChannels() {
auto audio = Ship::Context::GetInstance()->GetAudio()->GetAudioPlayer();
if (audio == nullptr) {
return audioStereo;
}
return audio->GetAudioChannels();
}
int32_t GetNumAudioChannels() {
switch (GetAudioChannels()) {
case audioSurround51:
return 6;
default:
return 2;
}
}
void AudioPlayerPlayFrame(const uint8_t* buf, size_t len) {
auto audio = Ship::Context::GetInstance()->GetAudio()->GetAudioPlayer();
if (audio == nullptr) {
+4
View File
@@ -6,12 +6,16 @@
#include "stdint.h"
#include "stddef.h"
typedef enum AudioChannelsSetting { audioStereo, audioSurround51, audioMax } AudioChannelsSetting;
#ifdef __cplusplus
extern "C" {
#endif
int32_t AudioPlayerBuffered();
int32_t AudioPlayerGetDesiredBuffered();
AudioChannelsSetting GetAudioChannels();
int32_t GetNumAudioChannels();
void AudioPlayerPlayFrame(const uint8_t* buf, size_t len);
#ifdef __cplusplus