mirror of
https://github.com/izzy2lost/libultraship.git
synced 2026-06-19 01:16:13 -07:00
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:
@@ -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}"
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -17,5 +17,6 @@ class SDLAudioPlayer : public AudioPlayer {
|
||||
|
||||
private:
|
||||
SDL_AudioDeviceID mDevice;
|
||||
int32_t mNumChannels = 2;
|
||||
};
|
||||
} // namespace Ship
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user